-
Notifications
You must be signed in to change notification settings - Fork 5.9k
Expand BIP85 to include ECC key types #1968
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
3728f8e
56a8de8
31eea92
9479612
729f412
86a64f1
04995e6
00a7583
b7756c9
c44de46
8b1397a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -358,36 +358,255 @@ OUTPUT | |||||
| * DERIVED ENTROPY=f7cfe56f63dca2490f65fcbf9ee63dcd85d18f751b6b5e1c1b8733af6459c904a75e82b4a22efff9b9e69de2144b293aa8714319a054b6cb55826a8e51425209 | ||||||
| * DERIVED PWD=_s`{TW89)i4` | ||||||
|
|
||||||
| ===RSA=== | ||||||
| ===GPG Keys=== | ||||||
|
|
||||||
| Application number: 828365' | ||||||
|
|
||||||
| The derivation path format is: <code>m/83696968'/828365'/{key_bits}'/{key_index}'</code> | ||||||
| The derivation path format is: <code>m/83696968'/828365'/{key_type}'/{key_bits}'/{key_index}'</code> | ||||||
|
||||||
|
|
||||||
| The RSA key generator should use BIP85-DRNG as the input RNG function. | ||||||
| All path components are hardened (denoted by <code>'</code>). The key_type values are plain integers: | ||||||
|
|
||||||
| ===RSA GPG=== | ||||||
| {| | ||||||
| !OpenPGP Key Type | ||||||
| !key_type | ||||||
| |- | ||||||
| | RSA | ||||||
| | 0 | ||||||
| |- | ||||||
| | ECC(Curve25519) | ||||||
| | 1 | ||||||
| |- | ||||||
|
Comment on lines
+365
to
+378
|
||||||
| | ECC(secp256k1) | ||||||
| | 2 | ||||||
| |- | ||||||
| | ECC(NIST) | ||||||
| | 3 | ||||||
| |- | ||||||
| | ECC(Brainpool) | ||||||
| | 4 | ||||||
| |- | ||||||
| |} | ||||||
|
|
||||||
| The valid key_bits values and corresponding algorithms for each key_type are: | ||||||
|
|
||||||
| {| | ||||||
| !key_type | ||||||
| !key_bits | ||||||
| !OpenPGP Algorithm / Curve | ||||||
| |- | ||||||
| | 0 (RSA) | ||||||
| | 1024, 2048, 4096 | ||||||
| | RSA | ||||||
| |- | ||||||
| | 1 (Curve25519) | ||||||
| | 256 | ||||||
| | Ed25519 (certify/sign/auth), X25519 (encrypt) | ||||||
| |- | ||||||
| | 2 (secp256k1) | ||||||
| | 256 | ||||||
| | secp256k1 | ||||||
| |- | ||||||
| | 3 (NIST) | ||||||
| | 256, 384, 521 | ||||||
| | NIST P-256, P-384, P-521 respectively | ||||||
| |- | ||||||
| | 4 (Brainpool) | ||||||
| | 256, 384, 512 | ||||||
| | brainpoolP256r1, brainpoolP384r1, brainpoolP512r1 respectively | ||||||
| |- | ||||||
| |} | ||||||
|
|
||||||
| For key_types with a fixed curve (1 and 2), key_bits MUST be 256. Any other value is invalid. | ||||||
|
|
||||||
| BIP85-DRNG MUST be used as the input RNG function when key generation requires more than 64 bytes of random input. This applies to all RSA key sizes and to NIST P-521 (key_bits=521). All other supported ECC key types use the 64-byte HMAC output directly. | ||||||
|
|
||||||
| <b>ECC Scalar Derivation for Curves Exceeding 64 Bytes</b> | ||||||
|
|
||||||
| For elliptic curves whose base length (⌈log₂(order) / 8⌉) exceeds the | ||||||
| 64-byte HMAC-SHA512 entropy output — currently only NIST P-521 (base | ||||||
| length 66 bytes) — the private scalar MUST be derived using the | ||||||
| BIP85-DRNG (SHAKE256) as follows: | ||||||
|
|
||||||
| 1. Read `baselen` bytes from the DRNG (66 bytes for P-521). | ||||||
|
|
||||||
| 2. Interpret the bytes as a big-endian unsigned integer. | ||||||
|
|
||||||
| 3. Mask the integer to `order.bit_length()` bits: | ||||||
| `scalar = raw_int & ((1 << bit_length) - 1)` | ||||||
|
|
||||||
| 4. If `scalar == 0` or `scalar >= order`, apply the fallback: | ||||||
| `scalar = (scalar % (order - 1)) + 1` | ||||||
|
|
||||||
| Implementations MUST use bit masking (step 3) rather than direct | ||||||
| modular reduction (`raw_int % order`). The two methods produce | ||||||
| different scalars when the raw integer has more bits than the curve | ||||||
| order, because bit masking discards the top bits while modular | ||||||
| reduction folds them in. | ||||||
|
|
||||||
| For curves with base length ≤ 64 bytes (all others in this spec), | ||||||
| the scalar is derived directly from the first `baselen` bytes of the | ||||||
| 64-byte HMAC-SHA512 entropy, reduced modulo the curve order with the | ||||||
| same fallback. | ||||||
|
|
||||||
| <b>RSA Key Generation Algorithm</b> | ||||||
|
|
||||||
| RSA key generation from the BIP85-DRNG MUST use the FIPS 186-4 (§B.3.1, | ||||||
| §C.3.1) algorithm for probable prime generation. Specifically, the | ||||||
| Miller-Rabin primality test MUST use random bases drawn from the same | ||||||
| DRNG (randfunc) that generates prime candidates — NOT fixed or | ||||||
| deterministic witnesses. | ||||||
|
|
||||||
| The reference algorithm is PyCryptodome's `RSA.generate(key_bits, | ||||||
| randfunc=drng.read)`, which implements FIPS 186-4 with random | ||||||
| Miller-Rabin witnesses drawn from the provided `randfunc`. | ||||||
|
|
||||||
| Implementations that use fixed Miller-Rabin witnesses (e.g., small | ||||||
| primes 2, 3, 5, …) will consume DRNG bytes at a different rate than | ||||||
| the reference algorithm, producing different primes and therefore | ||||||
| different RSA keys from the same entropy. Such implementations are | ||||||
| NOT compliant with this specification. | ||||||
|
|
||||||
| The use of random witnesses is also cryptographically stronger, as | ||||||
| fixed small-prime witnesses cannot detect Carmichael numbers that are | ||||||
| strong pseudoprimes to all tested bases. | ||||||
|
|
||||||
| <b>Primary Keys and Subkeys</b> | ||||||
|
|
||||||
| In OpenPGP, a key consists of a primary key used for certification and one or more subkeys for encryption, signing, and authentication. This structure separates long-term identity (the primary key) from operational keys (subkeys), allowing subkeys to expire or be revoked independently without affecting the primary key identity. | ||||||
|
|
||||||
| Keys allocated for GPG purposes use the following scheme: | ||||||
|
|
||||||
| Keys allocated for RSA-GPG purposes use the following scheme: | ||||||
| * Primary key: <code>m/83696968'/828365'/{key_type}'/{key_bits}'/{key_index}'</code> | ||||||
| * Sub keys: <code>m/83696968'/828365'/{key_type}'/{key_bits}'/{key_index}'/{sub_key}'</code> | ||||||
| ** key_index is the parent key for CERTIFY capability | ||||||
| ** sub_key <code>0'</code> is used as the ENCRYPTION key | ||||||
| ** sub_key <code>1'</code> is used as the AUTHENTICATION key | ||||||
| ** sub_key <code>2'</code> is usually used as SIGNATURE key | ||||||
|
|
||||||
| - Main key <code>m/83696968'/828365'/{key_bits}'/{key_index}'</code> | ||||||
| - Sub keys: <code>m/83696968'/828365'/{key_bits}'/{key_index}'/{sub_key}'</code> | ||||||
| All subkeys SHOULD use the same key_type as the primary key. Mixed key types across primary and subkeys are out of scope for this specification. Additional subkeys may be added following the same role pattern, incrementing the sub_key index. | ||||||
|
||||||
| All subkeys SHOULD use the same key_type as the primary key. Mixed key types across primary and subkeys are out of scope for this specification. Additional subkeys may be added following the same role pattern, incrementing the sub_key index. | |
| All subkeys SHOULD use the same key_type (i.e. the same underlying curve family) as the primary key. Mixed key types across primary and subkeys are out of scope for this specification. For <code>key_type = Curve25519</code>, implementations MUST generate OpenPGP keys as follows: the primary CERTIFY key and any SIGNATURE or AUTHENTICATION subkeys MUST use Ed25519 (OpenPGP EdDSA with curve Ed25519), while ENCRYPTION subkeys MUST use X25519/Curve25519 ECDH (OpenPGP ECDH with curve Curve25519). Additional subkeys may be added following the same role pattern, incrementing the sub_key index. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely need test vectors and expected outputs for all applications and sub applications. I can also add it to the reference implementation but won't be able to get to that right away. PRs welcome. https://github.com/akarve/bipsea
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm happy to work up some test vectors and a reference implementation once there is some agreement on a general direction :)