diff --git a/src/privatekey.cpp b/src/privatekey.cpp index 182d7781be800f..41dadb55a17c2a 100644 --- a/src/privatekey.cpp +++ b/src/privatekey.cpp @@ -19,6 +19,35 @@ namespace bls { const size_t PrivateKey::PRIVATE_KEY_SIZE; +PrivateKey PrivateKey::FromSeedBIP32(const Bytes& seed) { + // "BLS private key seed" in ascii + const uint8_t hmacKey[] = {66, 76, 83, 32, 112, 114, 105, 118, 97, 116, 101, + 32, 107, 101, 121, 32, 115, 101, 101, 100}; + + auto* hash = Util::SecAlloc( + PrivateKey::PRIVATE_KEY_SIZE); + + // Hash the seed into sk + md_hmac(hash, seed.begin(), (int)seed.size(), hmacKey, sizeof(hmacKey)); + + bn_t order; + bn_new(order); + g1_get_ord(order); + + // Make sure private key is less than the curve order + bn_t* skBn = Util::SecAlloc(1); + bn_new(*skBn); + bn_read_bin(*skBn, hash, PrivateKey::PRIVATE_KEY_SIZE); + bn_mod_basic(*skBn, *skBn, order); + + PrivateKey k; + bn_copy(k.keydata, *skBn); + + Util::SecFree(skBn); + Util::SecFree(hash); + return k; +} + // Construct a private key from a bytearray. PrivateKey PrivateKey::FromBytes(const Bytes& bytes, bool modOrder) { diff --git a/src/privatekey.hpp b/src/privatekey.hpp index 37058abc0dad5d..f918ceaefb5008 100644 --- a/src/privatekey.hpp +++ b/src/privatekey.hpp @@ -31,6 +31,9 @@ class PrivateKey { // less than the group order (which is in bls.hpp). static const size_t PRIVATE_KEY_SIZE = 32; + // Construct a private key from a BIP32 based seed. + static PrivateKey FromSeedBIP32(const Bytes& seed); + // Construct a private key from a bytearray. static PrivateKey FromBytes(const Bytes& bytes, bool modOrder = false); diff --git a/src/test.cpp b/src/test.cpp index bb9c0edd5455b1..007c82b96bf9e4 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -121,6 +121,13 @@ TEST_CASE("class PrivateKey") { REQUIRE_THROWS(PrivateKey::FromBytes(Bytes(buffer, PrivateKey::PRIVATE_KEY_SIZE), false)); REQUIRE_NOTHROW(PrivateKey::FromBytes(Bytes(buffer, PrivateKey::PRIVATE_KEY_SIZE), true)); } + SECTION("BIP32 Seed") { + uint8_t aliceSeed[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + PrivateKey pk1 = PrivateKey::FromSeedBIP32(Bytes(aliceSeed, 10)); + vector privateKey = pk1.Serialize(true); + vector knownPrivateKey = Util::HexToBytes("46891c2cec49593c81921e473db7480029e0fc1eb933c6b93d81f5370eb19fbd"); + REQUIRE(privateKey == knownPrivateKey); + } SECTION("keydata checks") { PrivateKey pk1 = PrivateKey::FromByteVector(getRandomSeed(), true); G1Element g1 = pk1.GetG1Element();