You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(keys): derive ML-DSA-65 keys from BIP-39 seed phrases (#224)
Adopts the SLIP-0010 ML-DSA extension from satoshilabs/slips#1968 (also
QIP-0002 and the Lattice HD Wallets construction): master node
HMAC-SHA512(key = "ML-DSA-65 seed", data = BIP-39 seed), standard
hardened-only child steps, and the 32-byte node secret used as the
FIPS 204 seed xi.
parseSeedPhrase now takes an options object ({ path, keyType }) in
addition to the existing path-string form. The SLIP-0010 code moves to
utils/hd.ts, parametrized by curve salt, and is verified against the
official ed25519 vectors and the slips#1968 ML-DSA-65 vectors (which are
validated against the NIST ACVP ML-DSA-keyGen-FIPS204 KATs).
Path parsing now accepts bare "m" (master node) and rejects indexes
>= 2^31, which previously wrapped silently.
Add ML-DSA-65 key derivation from BIP-39 seed phrases. `parseSeedPhrase` now accepts an options object with a `keyType` of `"ed25519"` (default) or `"ml-dsa-65"`, deriving post-quantum keys via the SLIP-0010 construction from satoshilabs/slips#1968 (master node `HMAC-SHA512(key = "ML-DSA-65 seed", data = BIP-39 seed)`, hardened-only children, node secret used as the FIPS 204 seed ξ). Validated against the slips#1968 test vectors.
For a key generated by `MlDsa65KeyPair`, the serialized secret key is the 32-byte seed (`ml-dsa-65:<base58 seed>`). `parseKey` also accepts the 4032-byte raw expanded secret key that nearcore / near-cli write to credential files (`ml-dsa-65:<base58 raw key>`), so existing credentials load too. Either form round-trips. The public key is 1952 bytes and signatures are 3309 bytes.
170
170
171
+
#### Deriving from a seed phrase
172
+
173
+
`parseSeedPhrase` can derive an ML-DSA-65 key from a BIP-39 mnemonic, so a post-quantum key is recoverable from the same phrase a wallet already backs up:
Derivation follows the SLIP-0010 extension proposed in [satoshilabs/slips#1968](https://github.com/satoshilabs/slips/pull/1968): the master node is `HMAC-SHA512(key = "ML-DSA-65 seed", data = BIP-39 seed)`, children use the standard SLIP-0010 hardened-only step, and the derived 32-byte node secret is the FIPS 204 seed ξ fed to ML-DSA key generation. Because the master salt differs from ed25519's, the ML-DSA-65 key derived from a phrase is unrelated to the ed25519 key derived from that same phrase.
186
+
171
187
<Notetitle="On-chain key handles">
172
188
On-chain, an ML-DSA-65 access key is stored as a 32-byte hash, so `view_access_key_list` returns it as `ml-dsa-65-hash:...`, **not** the full key. Parse that form with `parseMlDsa65Handle()` for display and comparison — it is a read-only handle and cannot be used to sign or as an `addKey` public key (the full key is not recoverable from it).
0 commit comments