diff --git a/README.md b/README.md index 98264579..607c6ce4 100644 --- a/README.md +++ b/README.md @@ -23,12 +23,13 @@ Each SLIP should provide a concise technical specification of the feature and a | SLIP-0018 | reserved (CoSi) | Standard | Draft | | [SLIP-0019](slip-0019.md) | Proof of Ownership | Standard | Accepted | | [SLIP-0020](slip-0020.md) | Proof of User Confirmation | Standard | Draft | -| [SLIP-0021](slip-0021.md) | Hierarchical derivation of symmetric keys | Standard | Final | +| [SLIP-0021](slip-0021.md) | Hierarchical derivation of secret keys | Standard | Final | | [SLIP-0022](slip-0022.md) | FIDO2 Credential ID format for HD wallets | Standard | Final | | [SLIP-0023](slip-0023.md) | Cardano HD master node derivation from a master seed | Standard | Final | | [SLIP-0024](slip-0024.md) | Trezor payment request format | Standard | Draft | | [SLIP-0025](slip-0025.md) | Key derivation for CoinJoin accounts | Standard | Draft | | SLIP-0026 | reserved (CoSi) | Standard | Draft | +| [SLIP-0027](slip-0027.md) | Variable-length secrets for cryptographic schemes | Standard | Draft | | [SLIP-0032](slip-0032.md) | Extended serialization format for BIP-32 wallets | Standard | Draft | | [SLIP-0039](slip-0039.md) | Shamir's Secret-Sharing for Mnemonic Codes | Standard | Final | | [SLIP-0044](slip-0044.md) | Registered coin types for BIP-0044 | Standard | Active | diff --git a/slip-0019.md b/slip-0019.md index 9f4789c3..62a082e8 100644 --- a/slip-0019.md +++ b/slip-0019.md @@ -36,7 +36,7 @@ proofOfOwnership = proofBody || proofSignature ### Ownership identifier -Let *k* be a secret *ownership identification key* derived from the wallet's master secret using the [SLIP-0021](https://github.com/satoshilabs/slips/blob/master/slip-0021.md) method for hierarchical derivation of symmetric keys as: +Let *k* be a secret *ownership identification key* derived from the wallet's master secret using the [SLIP-0021](https://github.com/satoshilabs/slips/blob/master/slip-0021.md) method for hierarchical derivation of secret keys as: ``` k = Key(m/"SLIP-0019"/"Ownership identification key") diff --git a/slip-0021.md b/slip-0021.md index c37636c5..8beece85 100644 --- a/slip-0021.md +++ b/slip-0021.md @@ -1,8 +1,8 @@ -# SLIP-0021 : Hierarchical derivation of symmetric keys +# SLIP-0021 : Hierarchical derivation of secret keys ``` Number: SLIP-0021 -Title: Hierarchical derivation of symmetric keys +Title: Hierarchical derivation of secret keys Type: Standard Status: Final Authors: Andrew R. Kozlik @@ -13,21 +13,21 @@ Created: 2019-06-25 ## Abstract -This document describes a method of deriving a hierarchy of symmetric keys from a master secret, such as the recovery seed used in cryptocurrency wallets. +This document describes a method of deriving a hierarchy of secret keys from a master secret, such as the recovery seed used in cryptocurrency wallets. ## Motivation -The [BIP-0032](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) and [SLIP-0010](https://github.com/satoshilabs/slips/blob/master/slip-0010.md) specifications define how to derive a hierarchy of private/public key pairs from a master seed for the elliptic curves secp256k1, NIST P-256 and ed25519. However, there does not exist any similar specification for the derivation of keys for symmetric-key algorithms, which are needed for example in password encryption or encryption of Bitcoin metadata. [SLIP-0011](https://github.com/satoshilabs/slips/blob/master/slip-0010.md) deals with this problem by first using BIP-0032 to derive a secp256k1 private key and then deriving the symmetric key from this private key. However, BIP-0032 was not designed to be used in this way and it also implies that an implementation of SLIP-0011 requires secp256k1 arithmetic, which should not be needed for symmetric key derivation. The purpose of this specification is to lay down a common framework for the deterministic derivation of a hierarchy of symmetric keys from a master seed. +The [BIP-0032](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) and [SLIP-0010](https://github.com/satoshilabs/slips/blob/master/slip-0010.md) specifications define how to derive a hierarchy of private/public key pairs from a master seed for the elliptic curves secp256k1, NIST P-256 and ed25519. These derivations are tied to elliptic-curve arithmetic and produce keys whose use is constrained to those curves. Many applications instead require raw secret key material that is not bound to a specific algebraic structure, for example, keys for symmetric-key algorithms used in password encryption or encryption of Bitcoin metadata, or seeds for other cryptographic schemes. [SLIP-0011](https://github.com/satoshilabs/slips/blob/master/slip-0010.md) addresses part of this need by first using BIP-0032 to derive a secp256k1 private key and then deriving a symmetric key from it, but BIP-0032 was not designed to be used in this way, and an implementation of SLIP-0011 requires secp256k1 arithmetic that should not be needed for raw key derivation. The purpose of this specification is to lay down a common framework for the deterministic derivation of a hierarchy of secret keys from a master seed. ## Master node generation -We adapt the master node generation from BIP-0032 and SLIP-0010. To achieve proper domain separation from the secp256k1, NIST P-256 and ed25519 key hierarchies, we use the string “Symmetric key seed” instead of the curve name. Let *S* be the master secret, such as that defined in [SLIP-0039](https://github.com/satoshilabs/slips/blob/master/slip-0039.md) or the binary seed defined in [BIP-0039](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki). Then the master node *m* is derived as follows: +We adapt the master node generation from BIP-0032 and SLIP-0010. To achieve proper domain separation from the secp256k1, NIST P-256 and ed25519 key hierarchies, we use the string “Symmetric key seed” instead of the curve name. Despite its name, the derived nodes are not restricted to use with symmetric-key algorithms. Let *S* be the master secret, such as that defined in [SLIP-0039](https://github.com/satoshilabs/slips/blob/master/slip-0039.md) or the binary seed defined in [BIP-0039](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki). Then the master node *m* is derived as follows: ``` m = HMAC-SHA512(key = b"Symmetric key seed", msg = S) ``` -The master node is used to derive child nodes, each of which can in turn be used to derive lower-level child nodes of their own and so on. Each node is associated with a 256-bit symmetric key. The master node is thus the root of a key tree. +The master node is used to derive child nodes, each of which can in turn be used to derive lower-level child nodes of their own and so on. Each node is associated with a 256-bit secret key. The master node is thus the root of a key tree. ## Child node derivation @@ -68,7 +68,7 @@ This standard is designed in accordance with [NIST SP 800-108](https://doi.org/1 ### Key length -Each node is associated with a 256-bit symmetric key. This key length is considered sufficiently secure for a number of years to come, see [keylength.com](https://www.keylength.com/en/compare/). It is also compatible with all major symmetric-key algorithms in use today, such as AES-256, ChaCha20Poly1305 or HMAC. The key derivation functions specified in NIST SP 800-108 allow for the derivation of variable length keys. Nevertheless, since such a feature appears to be of little use, a fixed key length was chosen to keep the implementation of this SLIP as simple as possible. +Each node is associated with a 256-bit secret key. This key length is considered sufficiently secure for a number of years to come, see [keylength.com](https://www.keylength.com/en/compare/). It is also compatible with all major symmetric-key algorithms in use today, such as AES-256, ChaCha20Poly1305 or HMAC, and matches the seed length accepted by many other cryptographic schemes. The key derivation functions specified in NIST SP 800-108 allow for the derivation of variable length keys. Nevertheless, since such a feature appears to be of little use, a fixed key length was chosen to keep the implementation of this SLIP as simple as possible. ### Key separation diff --git a/slip-0022.md b/slip-0022.md index d4782f7a..8a221684 100644 --- a/slip-0022.md +++ b/slip-0022.md @@ -93,7 +93,7 @@ a5 # map(5) The CBOR encoded credential data is encrypted using Chacha20Poly1305 as defined in [RFC 8439](https://tools.ietf.org/html/rfc8439). In case of FIDO2 the SHA-256 hash of the rpId is used as the AAD input to the cipher. In case of U2F the application parameter (SHA-256 hash of the UTF-8 encoding of the application identity) is used as the AAD input to the cipher. -The encryption key *k* is the same for all credential IDs of the same version which are generated by an authenticator with a given master secret. The key is derived from the master secret using the [SLIP-0021](https://github.com/satoshilabs/slips/blob/master/slip-0021.md) method for hierarchical derivation of symmetric keys as: +The encryption key *k* is the same for all credential IDs of the same version which are generated by an authenticator with a given master secret. The key is derived from the master secret using the [SLIP-0021](https://github.com/satoshilabs/slips/blob/master/slip-0021.md) method for hierarchical derivation of secret keys as: ``` k = Key(m/"SLIP-0022"/version/"Encryption key") @@ -113,7 +113,7 @@ where *version* is the first four bytes of the credential ID interpreted as a 32 ## Derivation of hmac-secret CredRandom -The CredRandom value used in the hmac-secret extension is derived from the master secret and the credential ID using the SLIP-0021 method for hierarchical derivation of symmetric keys as: +The CredRandom value used in the hmac-secret extension is derived from the master secret and the credential ID using the SLIP-0021 method for hierarchical derivation of secret keys as: ``` CredRandom = Key(m/"SLIP-0022"/version/"hmac-secret"/credentialId) @@ -195,4 +195,4 @@ The rationale behind using the authentication tag for the SLIP-0010 key path is * [IANA-COSE-REG](https://www.iana.org/assignments/cose/cose.xhtml): IANA CBOR Object Signing and Encryption (COSE) Registries. * [RFC 7049](https://tools.ietf.org/html/rfc7049): Concise Binary Object Representation (CBOR) * [SLIP-0010](https://github.com/satoshilabs/slips/blob/master/slip-0010.md): Universal private key derivation from master private key -* [SLIP-0021](https://github.com/satoshilabs/slips/blob/master/slip-0021.md): Hierarchical derivation of symmetric keys +* [SLIP-0021](https://github.com/satoshilabs/slips/blob/master/slip-0021.md): Hierarchical derivation of secret keys diff --git a/slip-0024.md b/slip-0024.md index a0b57914..9691de07 100644 --- a/slip-0024.md +++ b/slip-0024.md @@ -201,7 +201,7 @@ In order to simplify the communication protocol with the wallet, it is more conv The address authentication code defined in this section should only be issued for addresses that are fully controlled by the wallet, i.e. only for non-multisig addresses. -Let *k* be a secret *address authentication key* derived from the wallet's master secret using the [SLIP-0021](https://github.com/satoshilabs/slips/blob/master/slip-0021.md) method for hierarchical derivation of symmetric keys as: +Let *k* be a secret *address authentication key* derived from the wallet's master secret using the [SLIP-0021](https://github.com/satoshilabs/slips/blob/master/slip-0021.md) method for hierarchical derivation of secret keys as: ``` k = Key(m/"SLIP-0024"/"Address MAC key") diff --git a/slip-0027.md b/slip-0027.md new file mode 100644 index 00000000..8e473556 --- /dev/null +++ b/slip-0027.md @@ -0,0 +1,178 @@ +# SLIP-0027 : Variable-length secrets for cryptographic schemes + +``` +Number: SLIP-0027 +Title: Variable-length secrets for cryptographic schemes +Type: Standard +Status: Draft +Authors: Andrew R. Kozlik + Petr Sedláček + Ondrej Vejpustek +Created: 2026-04-20 +``` + +## Abstract + +This document extends [SLIP-0021](https://github.com/satoshilabs/slips/blob/master/slip-0021.md) with a method for deriving secret keying material of arbitrary length from any SLIP-0021 node, and defines a path structure under which secrets for specific cryptographic schemes are derived, with a registry of currently supported schemes. + +## Motivation + +SLIP-0021 defines a hierarchy of fixed-length 256-bit secret keys derived from a master secret using only HMAC-SHA512. The fixed key length was chosen for simplicity, as the SLIP-0021 design rationale notes: "since such a feature [variable length] appears to be of little use, a fixed key length was chosen to keep the implementation of this SLIP as simple as possible." + +The standardization of post-quantum cryptography has changed this. NIST FIPS 204 (ML-DSA) accepts a 32-byte seed for key generation, which fits SLIP-0021 natively, but other present and future schemes require keying material of other lengths. A general-purpose deterministic secret derivation framework should support all such schemes from a single master secret without requiring additional cryptographic primitives. + +BIP-0032 and SLIP-0010 derive a hierarchy of key pairs in a way that supports public derivation: for the elliptic-curve schemes they cover, child public keys can be derived from parent public keys without access to the corresponding private keys. This is possible because of the homomorphism between scalar addition and point addition that elliptic-curve schemes provide. Schemes without such structure, including all current post-quantum signature standards, do not admit public derivation. For these schemes, the SLIP-0021 approach of deriving a secret seed and then invoking the scheme's standard key generation function is more straightforward and applies uniformly to any scheme that accepts a fixed-length seed. + +This specification has two purposes: + +1. To define a method for deriving secret keying material of arbitrary length from a SLIP-0021 node, using only HMAC-SHA512. +2. To define a path structure under which secrets for specific cryptographic schemes are derived, together with a registry of currently supported schemes. + +This specification is a strict extension of SLIP-0021. All existing SLIP-0021 derivations remain unchanged. + +## Variable-length secret derivation + +Let *N* be a SLIP-0021 node, i.e., a 64-byte string. The 32-byte secret key of *N* is defined by SLIP-0021 as: + +``` +Key(N) = N[32:64] +``` + +The variable-length expanded secret of *N* is defined as: + +``` +Expand(N, retry, length) = T[0:length] +``` + +where + +``` +block_count = ceil(length / 64) +T = HMAC-SHA512(key = Key(N), msg = retry || 0x00) + || HMAC-SHA512(key = Key(N), msg = retry || 0x01) + || ... + || HMAC-SHA512(key = Key(N), msg = retry || block_count - 1) +``` + +and the input parameters satisfy: + +* *retry* is a single byte, 0 ≤ *retry* ≤ 255. +* *length* is the desired output length in bytes, an integer with 1 ≤ *length* ≤ 16384. +* The block index is encoded as a single byte. The two-byte HMAC message *retry* || *block* is the byte *retry* followed by the byte *block*. + +## Cryptographic scheme secret derivation + +Secrets for cryptographic schemes are derived under the path: + +``` +m / "SLIP-0027" / scheme / +``` + +where *scheme* is the canonical name of the scheme and parameter set as listed in the registry below. The labels following *scheme* are application-defined. This specification does not constrain their structure. Applications using integer labels SHOULD encode them in accordance with the recommendation in the section "Encoding of integer labels". Applications deriving secrets for a blockchain asset SHOULD identify the asset by its registered SLIP-0044 coin type as the first label following *scheme*, encoded in accordance with the section "Encoding of integer labels". + +Let *N* be the SLIP-0021 node at any path of the form above. The scheme-specific secret is + +``` +Expand(N, 0, length) +``` + +where *length* is taken from the registry row corresponding to *scheme*. The Usage column of the registry specifies how the resulting bytes are interpreted by the scheme, including any rejection-and-retry behavior. When a scheme specifies retry, the application invokes Expand(*N*, *retry*, *length*) with *retry* incremented from 0 until the scheme accepts the output. + +### Scheme registry + +| `scheme` | `length` | Usage | +|---|---|---| +| `ML-DSA-44` | 32 | Used as the 32-byte seed *ξ* input to `ML-DSA.KeyGen_internal` (FIPS 204, Algorithm 6). No retry. | +| `ML-DSA-65` | 32 | Used as the 32-byte seed *ξ* input to `ML-DSA.KeyGen_internal` (FIPS 204, Algorithm 6). No retry. | +| `ML-DSA-87` | 32 | Used as the 32-byte seed *ξ* input to `ML-DSA.KeyGen_internal` (FIPS 204, Algorithm 6). No retry. | + +Future schemes are added by extending this table. Each row fully specifies the bytes consumed and their interpretation. + +### Example paths + +An account key on an account-based chain, here coin type 60 (Ether), account 2: + +``` +m / "SLIP-0027" / "ML-DSA-44" / "60" / "2" +``` + +An address key on a UTXO-based chain, here coin type 0 (Bitcoin), account 2, internal chain (change) 1, address index 14: + +``` +m / "SLIP-0027" / "ML-DSA-44" / "0" / "2" / "1" / "14" +``` + +The labels following the coin type are illustrative. Their structure is application-defined and may be standardized by future SLIPs. + +## Encoding of integer labels + +When an integer is used as a path label, it SHOULD be encoded as its shortest possible decimal ASCII representation. Specifically: + +* The integer MUST be non-negative. +* The encoding consists of ASCII digits 0–9 only. +* No leading zeros are permitted, except that the integer 0 is encoded as the single byte `"0"`. + +This recommendation matches the convention of SLIP-0021 and ensures a canonical, dependency-free encoding. Applications requiring signed or otherwise structured indices may define their own encoding, provided it is documented in the application's specification. + +## Test vectors + +TODO. + +## Design rationale + +### Construction + +Expand is an instance of the Counter Mode KDF specified in NIST SP 800-108, with HMAC-SHA512 as the PRF, an empty Label, and an empty Context. Context binding is instead provided by the SLIP-0021 path leading to *N*. Distinct secrets come from distinct paths. The security of Expand reduces to the assumption that HMAC-SHA512 is a pseudorandom function, which is the same assumption underlying SLIP-0021 itself. No new cryptographic primitive or assumption is introduced. + +### Counter mode + +Counter mode and feedback mode (NIST SP 800-108) offer equivalent provable security under the PRF assumption. Counter mode is chosen because it is structurally simpler and because the defense-in-depth motivation sometimes given for feedback mode does not apply here: any HMAC-SHA512 weakness severe enough to threaten counter-mode Expand would also break SLIP-0021 derivation, which rests on the same primitive under the same assumption. SLIP-0021 itself uses feedback at the tree level (each child's HMAC key is its parent's output) only because building a hierarchy requires it. Expansion has no such structural need. + +### Two-byte counter + +The HMAC message consists of two bytes: *retry* followed by *block*. The block byte enables outputs longer than one HMAC block (64 bytes). The retry byte enables schemes that reject some derived outputs (e.g., when a scalar must lie in a particular range) to derive a fresh independent output without leaving the derivation framework. The two indices occupy independent ranges, so the maximum output length and the maximum number of retries do not interact. + +The retry byte precedes the block byte so that, for a given *retry* value, the *block_count* HMAC inputs are contiguous in counter space. This matches the natural most-significant-first encoding of a two-byte counter. + +### Self-contained nodes + +Expand takes only the node *N* as input. No parent context is required. A node may therefore be exported and used to derive arbitrary-length secrets without granting any ability to derive sibling nodes. This preserves the SLIP-0021 invariant that knowledge of Key(*N*) is independent of the ability to derive child nodes of *N*. + +### Uniform use of Expand + +The scheme registry derives every secret via Expand, even when *length* is 32 and Key(*N*) has the required length. A single rule for all lengths avoids a special case, and it preserves a strict separation of roles. At SLIP-0027 paths, Key(*N*) acts only as a PRF key and never as an output secret, so no secret is ever used both as an HMAC key and as an application key. + +### Scheme naming + +Each scheme is named using its canonical FIPS or RFC spelling, including the parameter set (e.g., `ML-DSA-44` rather than `ML-DSA`). Different parameter sets of the same scheme family are different cryptographic schemes at different security levels and are listed as separate rows. This ensures that two applications referencing the same path produce interoperable secrets without implicit assumptions about parameter selection. + +### Path structure + +The path after *scheme* is left to the application. This avoids prematurely committing to a particular structure (e.g., BIP-0032-style account indices, named identities, or random tags) and allows future SLIPs to define application-specific path layouts on top of SLIP-0027. + +### Encoding of integer labels + +The recommended decimal ASCII encoding is chosen for three reasons: + +1. It has no implementation cost. Every programming environment supports integer-to-decimal conversion natively, with no library dependency. +2. It is canonical when restricted as specified (no leading zeros, non-negative), so two implementations independently encoding the same integer always produce the same bytes. +3. It is human-readable, which aids debugging, test vector inspection, and error reporting. + +Fixed-width binary encodings (e.g., 4-byte big-endian) were considered but rejected because they impose an artificial range limit without offering any compensating advantage in this context, where the encoded bytes are consumed by HMAC rather than transmitted on the wire. Variable-width binary encodings (DER, CBOR, varint) were rejected because they add implementation complexity and library dependencies inconsistent with the minimalist design of SLIP-0021. + +### Backward compatibility + +This specification does not modify SLIP-0021. All existing SLIP-0021 derivations and outputs remain bit-for-bit unchanged. The function Expand is a new operation that is distinct from Key. In particular, Expand(*N*, 0, 32) is not equal to Key(*N*). Applications that require the SLIP-0021 32-byte secret key continue to use Key(*N*) unchanged. Applications that require variable-length material call Expand. + +### Maximum output length + +The maximum output length is 256 × 64 = 16384 bytes. This is sufficient for any plausible cryptographic key, signature scheme seed, or combined keying material. + +## References + +* [SLIP-0021: Hierarchical derivation of secret keys](https://github.com/satoshilabs/slips/blob/master/slip-0021.md) +* [BIP-0032: Hierarchical Deterministic Wallets](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) +* [SLIP-0010: Universal private key derivation from master private key](https://github.com/satoshilabs/slips/blob/master/slip-0010.md) +* [SLIP-0044: Registered coin types for BIP-0044](https://github.com/satoshilabs/slips/blob/master/slip-0044.md) +* [NIST FIPS 204: Module-Lattice-Based Digital Signature Standard](https://doi.org/10.6028/NIST.FIPS.204) +* [NIST Special Publication 800-108: Recommendation for Key Derivation Using Pseudorandom Functions](https://doi.org/10.6028/NIST.SP.800-108)