@@ -35,16 +35,25 @@ for different elliptic curves with different orders.
...
@@ -35,16 +35,25 @@ for different elliptic curves with different orders.
### Master key generation
### Master key generation
We adapt the master key generation from BIP-0032 to use a different
We adapt the master key generation from BIP-0032. To use different
key for different curve types. To avoid invalid master keys, the
private keys for different curves we use different keys for the HMAC
algorithm is retried with the intermediate hash as new seed if the key
hash that generates the master key. For the NIST P-256 curve the only
is invalid.
other difference is the different group order. In the algorithm below
we denote the group order of the elliptic curve with n. For ed25519
* Generate a seed byte sequence S of 512 bits according to BIP-0039.
curve the private keys are no longer multipliers for the group
* Calculate I = HMAC-SHA512(Key = Curve, Data = S)
generator; instead the hash of the private key is the multiplier. For
* Split I into two 32-byte sequences, I<sub>L</sub> and I<sub>R</sub>.
this reason, our scheme for ed25519 does not support public key
* Use parse<sub>256</sub>(I<sub>L</sub>) as master secret key, and I<sub>R</sub> as master chain code.
derivation and uses the produced hashes directly as private keys.
In case I<sub>L</sub> is 0 or ≥n, the master key would be invalid. In this case the procedure is repeated with S := I.
To avoid invalid master keys, the algorithm is retried with the
intermediate hash as new seed if the key is invalid.
1. Generate a seed byte sequence S of 512 bits according to BIP-0039.
2. Calculate I = HMAC-SHA512(Key = Curve, Data = S)
3. Split I into two 32-byte sequences, I<sub>L</sub> and I<sub>R</sub>.
4. Use parse<sub>256</sub>(I<sub>L</sub>) as master secret key, and I<sub>R</sub> as master chain code.
5. If curve is not ed25519 and I<sub>L</sub> is 0 or ≥ n (invalid key):
* Set S := I and continue at step 2.
The supported curves are
The supported curves are
...
@@ -74,17 +83,18 @@ or public keys.
...
@@ -74,17 +83,18 @@ or public keys.
Let n denote the order of the curve.
Let n denote the order of the curve.
The function CKDpriv((k<sub>par</sub>, c<sub>par</sub>), i) → (k<sub>i</sub>, c<sub>i</sub>) computes a child extended private key from the parent extended private key:
The function CKDpriv((k<sub>par</sub>, c<sub>par</sub>), i) → (k<sub>i</sub>, c<sub>i</sub>) computes a child extended private key from the parent extended private key:
* Check whether i ≥ 2<sup>31</sup> (whether the child is a hardened key).
1. Check whether i ≥ 2<sup>31</sup> (whether the child is a hardened key).
* If so (hardened child): let I = HMAC-SHA512(Key = c<sub>par</sub>, Data = 0x00 || ser<sub>256</sub>(k<sub>par</sub>) || ser<sub>32</sub>(i)). (Note: The 0x00 pads the private key to make it 33 bytes long.)
* If so (hardened child): let I = HMAC-SHA512(Key = c<sub>par</sub>, Data = 0x00 || ser<sub>256</sub>(k<sub>par</sub>) || ser<sub>32</sub>(i)). (Note: The 0x00 pads the private key to make it 33 bytes long.)
* If not (normal child):
* If not (normal child):
* If curve is ed25519 fail.
* If curve is ed25519: return failure.
* let I = HMAC-SHA512(Key = c<sub>par</sub>, Data = ser<sub>P</sub>(point(k<sub>par</sub>)) || ser<sub>32</sub>(i)).
* let I = HMAC-SHA512(Key = c<sub>par</sub>, Data = ser<sub>P</sub>(point(k<sub>par</sub>)) || ser<sub>32</sub>(i)).
* Split I into two 32-byte sequences, I<sub>L</sub> and I<sub>R</sub>.
2. Split I into two 32-byte sequences, I<sub>L</sub> and I<sub>R</sub>.
* The returned chain code c<sub>i</sub> is I<sub>R</sub>.
3. The returned chain code c<sub>i</sub> is I<sub>R</sub>.
* If curve is ed25519: The returned child key is I<sub>L</sub>.
4. If curve is ed25519: The returned child key k<sub>i</sub> is parse<sub>256</sub>(I<sub>L</sub>).
* In case parse<sub>256</sub>(I<sub>L</sub>) ≥ n or k<sub>i</sub> = 0, the resulting key is invalid.
5. If parse<sub>256</sub>(I<sub>L</sub>) ≥ n or parse<sub>256</sub>(I<sub>L</sub>) + k<sub>par</sub> = 0 (resulting key is invalid):
let I = HMAC-SHA512(Key = c<sub>par</sub>, Data = 0x01 || I<sub>R</sub> || ser<sub>32</sub>(i) and restart at the third step.
* let I = HMAC-SHA512(Key = c<sub>par</sub>, Data = 0x01 || I<sub>R</sub> || ser<sub>32</sub>(i) and restart at step 2.
* Otherwise: The returned child key k<sub>i</sub> is parse<sub>256</sub>(I<sub>L</sub>) + k<sub>par</sub> (mod n).
6. Otherwise: The returned child key k<sub>i</sub> is parse<sub>256</sub>(I<sub>L</sub>) + k<sub>par</sub> (mod n).
The HMAC-SHA512 function is specified in [http://tools.ietf.org/html/rfc4231 RFC 4231].
The HMAC-SHA512 function is specified in [http://tools.ietf.org/html/rfc4231 RFC 4231].
...
@@ -93,14 +103,15 @@ The HMAC-SHA512 function is specified in [http://tools.ietf.org/html/rfc4231 RFC
...
@@ -93,14 +103,15 @@ The HMAC-SHA512 function is specified in [http://tools.ietf.org/html/rfc4231 RFC
This function always fails for ed25519 since normal derivation is not supported.
This function always fails for ed25519 since normal derivation is not supported.
The function CKDpub((K<sub>par</sub>, c<sub>par</sub>), i) → (K<sub>i</sub>, c<sub>i</sub>) computes a child extended public key from the parent extended public key. It is only defined for non-hardened child keys.
The function CKDpub((K<sub>par</sub>, c<sub>par</sub>), i) → (K<sub>i</sub>, c<sub>i</sub>) computes a child extended public key from the parent extended public key. It is only defined for non-hardened child keys.
* Check whether i ≥ 2<sup>31</sup> (whether the child is a hardened key).
1. Check whether i ≥ 2<sup>31</sup> (whether the child is a hardened key).
* If so (hardened child): return failure
* If so (hardened child): return failure
* If not (normal child): let I = HMAC-SHA512(Key = c<sub>par</sub>, Data = ser<sub>P</sub>(K<sub>par</sub>) || ser<sub>32</sub>(i)).
* If not (normal child): let I = HMAC-SHA512(Key = c<sub>par</sub>, Data = ser<sub>P</sub>(K<sub>par</sub>) || ser<sub>32</sub>(i)).
* Split I into two 32-byte sequences, I<sub>L</sub> and I<sub>R</sub>.
2. Split I into two 32-byte sequences, I<sub>L</sub> and I<sub>R</sub>.
* The returned child key K<sub>i</sub> is point(parse<sub>256</sub>(I<sub>L</sub>)) + K<sub>par</sub>.
3. The returned child key K<sub>i</sub> is point(parse<sub>256</sub>(I<sub>L</sub>)) + K<sub>par</sub>.
* The returned chain code c<sub>i</sub> is I<sub>R</sub>.
4. The returned chain code c<sub>i</sub> is I<sub>R</sub>.
* In case parse<sub>256</sub>(I<sub>L</sub>) ≥ n or K<sub>i</sub> is the point at infinity, the resulting key is invalid.
5. If parse<sub>256</sub>(I<sub>L</sub>) ≥ n or K<sub>i</sub> is the point at infinity (the resulting key is invalid):
let I = HMAC-SHA512(Key = c<sub>par</sub>, Data = 0x01 || I<sub>R</sub> || ser<sub>32</sub>(i)) and restart at the third step.
* let I = HMAC-SHA512(Key = c<sub>par</sub>, Data = 0x01 || I<sub>R</sub> || ser<sub>32</sub>(i)) and restart at step 2.