I need a cryptographic scheme to generate a deterministic chain of private keys that look random to outside observer but can always be reconstructed from a single root key, also:

  • Neither private keys nor their corresponding public keys should contain any information about each other.
  • In case of some private key leaking it should be impossible to reconstruct the subsequent keys (except for the root private key of course)

Here is my solution:

val privateKey0 = HMAC-SHA256(key: rootPrivateKey, data: "Chain")
val privateKey1 = HMAC-SHA256(key: rootPrivateKey ⊕ privateKey0, data: "Chain" || SHA256(privateKey0))
val privateKey2 = HMAC-SHA256(key: rootPrivateKey ⊕ privateKey1, data: "Chain" || SHA256(privateKey1))

Public key is computed as curve point multiplication on EC secp256k1:

val publicKey0 = privateKey0 * G(secp256k1)

Now I'm not a trained cryptographer so I want to ask if this scheme is viable? Are there any obvious flaws? If yes, how can it be improved?


I see no obvious security flaws, but it seems inefficient and is nonstandard.

You would be better off always using the root key as the HMAC key and basing the HMAC message/data on only the key index (or other identity) rather than previous keys. That way you can create any of the keys independently. That is essentially what HKDF does in HKDF-Expand.

If you wanted to use HKDF-Expand you would have something like:

val privateKey0 = HMAC-SHA256(key: rootPrivateKey, data: "key0" || 0x1)
val privateKey1 = HMAC-SHA256(key: rootPrivateKey, data: "key1" || 0x1)

The 0x1 is the byte with value 1. You could skip it since you use a hash with the same length as the derived keys, but including it allows you to easily define how to move to a larger elliptic curve (i.e. just use HKDF to generate a longer key).

  • $\begingroup$ Why do you need the 0x1 to move to a larger elliptic curve? $\endgroup$ – Navin Feb 28 '17 at 14:36
  • 1
    $\begingroup$ @Navin, that way you can use 0x2 for the second half with 512-bit curves etc. $\endgroup$ – otus Feb 28 '17 at 18:15
  • $\begingroup$ Oh I get it: You're using || to mean "concatenate". I thought you were suggesting a bitwise OR with 0x1 to ensure the data is never 0 for some reason :) $\endgroup$ – Navin Mar 1 '17 at 14:54
  • 1
    $\begingroup$ @Navin, yeah, || is the normal symbol for concatenation. Not sure why it has to be the same as logical OR in many other cases, but it is what it is. $\endgroup$ – otus Mar 1 '17 at 15:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.