Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Open more actions menu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

sml-kdf

CI

Key-derivation functions in pure Standard ML, complementing the PBKDF2 already in sml-crypto:

  • HKDF (RFC 5869) — extract-then-expand over HMAC-SHA-256 / HMAC-SHA-512.
  • scrypt (RFC 7914) — the memory-hard password KDF, with the Salsa20/8 core implemented in-repo and the PBKDF2-HMAC-SHA256 wrapper supplied by sml-crypto.

HMAC / SHA / PBKDF2 come from the vendored sml-crypto (and its bundled sml-codec). No FFI, no external dependencies, and deterministic — byte-identical under both MLton and Poly/ML.

Status

  • 24 assertions, green on MLton and Poly/ML (byte-identical output).
  • Vendors sml-crypto + sml-codec (Layout B), so the repo builds standalone.
  • Validated against the official RFC vectors:
    • RFC 5869 Appendix A — HKDF-SHA256 test cases 1, 2 and 3 (PRK and OKM, byte-exact), including the zero-length-salt/info case.
    • RFC 7914 — scrypt reference vectors ("", "", N=16, r=1, p=1) and ("password", "NaCl", N=1024, r=8, p=16), byte-exact (64-byte outputs).
  • All inputs/outputs are raw byte strings (one char per byte, 0–255).

Scope

This release ships HKDF + scrypt. Argon2id (RFC 9106) is a planned phase-2 milestone: Argon2 uses BLAKE2b internally and no BLAKE2b primitive yet exists in the ecosystem (sml-blake3 is BLAKE3, a different function), so Argon2id is intentionally deferred until a BLAKE2b primitive lands. PBKDF2 is not re-implemented here — it already lives in sml-crypto (Pbkdf2.pbkdf2Sha256/512).

Install

With smlpkg:

smlpkg add github.com/sjqtentacles/sml-kdf
smlpkg sync

Include the MLB from your own (it pulls in the vendored sml-crypto + sml-codec):

local
  $(SML_LIB)/basis/basis.mlb
  lib/github.com/sjqtentacles/sml-kdf/... (via smlpkg)
in
  ...
end

This brings structure Kdf (and the vendored crypto/codec structures) into scope.

Quick start

(* all values are raw byte strings: one char per byte, 0-255 *)

(* HKDF: derive a 32-byte key from input keying material *)
val okm = Kdf.Hkdf.derive Kdf.HmacSha256
  { salt = saltBytes, ikm = ikmBytes, info = "app context v1", len = 32 }

(* or the two HKDF steps separately *)
val prk = Kdf.Hkdf.extract Kdf.HmacSha256 {salt = saltBytes, ikm = ikmBytes}
val okm' = Kdf.Hkdf.expand Kdf.HmacSha256 {prk = prk, info = "ctx", len = 64}

(* scrypt: memory-hard key derivation *)
val key = Kdf.scrypt
  { password = "correct horse", salt = "battery staple"
  , n = 16384, r = 8, p = 1, dkLen = 32 }

Demo

make example runs examples/demo.sml (scrypt parameters kept small so it runs quickly):

sml-kdf demo
============
HKDF-SHA256:
  PRK (extract)    : 9bc354559c49cfb0108dce954481c14eb6d09c160f4e0f0a06722ef0f31f0deb
  OKM (expand, 32) : 4bde14d46f1d3146e11a87d3cec53b419908be2f4aa09ee254341eff6a8bee6b

scrypt (N=256, r=8, p=1, dkLen=32):
  derived key      : 09cd65d28b2dd2033a31ca20fb206310c0d80ff6ebbb9c756f724c8f80c14872

API

datatype prf = HmacSha256 | HmacSha512

exception Kdf of string

structure Hkdf :
  sig
    val extract : prf -> {salt:string, ikm:string} -> string
    val expand  : prf -> {prk:string, info:string, len:int} -> string
    val derive  : prf -> {salt:string, ikm:string, info:string, len:int} -> string
  end

val scrypt : {password:string, salt:string, n:int, r:int, p:int, dkLen:int}
          -> string
Function Behavior
Hkdf.extract prf {salt, ikm} HKDF-Extract: PRK = HMAC(salt, ikm); a zero-length salt is replaced by HashLen zero bytes per RFC 5869
Hkdf.expand prf {prk, info, len} HKDF-Expand to len bytes; raises Kdf if len > 255*HashLen
Hkdf.derive prf {salt, ikm, info, len} expand (extract …) in one call
scrypt {password, salt, n, r, p, dkLen} RFC 7914 scrypt; n is the cost (a power of two > 1), r the block factor, p the parallelisation factor; raises Kdf on invalid parameters

Conventions

  • Bytes as string. Keys, salts, IKM, info and outputs are raw byte strings (one char per byte, 0–255), matching the rest of the sjqtentacles crypto/codec family.
  • scrypt's core is Salsa20/8. RFC 7914's BlockMix/ROMix are built on the Salsa20/8 core (not SHA, not ChaCha20); it is implemented directly in this repo. SHA-256 appears only inside the outer/inner PBKDF2 wrapper, supplied by sml-crypto.
  • Pick parameters deliberately. scrypt is memory-hard by design; large N costs both time and memory. The supplied RFC N=1024, r=8, p=16 vector takes a few seconds (notably under Poly/ML).

Build & test

make test        # MLton
make test-poly   # Poly/ML
make all-tests   # both
make example     # build + run examples/demo.sml
make clean

License

MIT — see LICENSE.

About

Key-derivation functions in pure Standard ML: HKDF (RFC 5869) + scrypt (RFC 7914), with byte-exact RFC vectors. Dual-compiler (MLton + Poly/ML).

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages

Morty Proxy This is a proxified and sanitized view of the page, visit original site.