upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/bip32.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/bip32.cpp')
-rw-r--r--src/bip32.cpp109
1 files changed, 93 insertions, 16 deletions
diff --git a/src/bip32.cpp b/src/bip32.cpp
index 6423974..6ba946a 100644
--- a/src/bip32.cpp
+++ b/src/bip32.cpp
@@ -114,6 +114,43 @@ static bool HmacSha512(const unsigned char* key, int keyLen,
114 len == 64; 114 len == 64;
115} 115}
116 116
117static bool PrivateKeyToCompressedPubKey(const std::vector<unsigned char>& privateKey,
118 unsigned char out[33],
119 std::string& errorOut)
120{
121 if (!IsValidPrivateKey(privateKey))
122 {
123 errorOut = "private key is invalid";
124 return false;
125 }
126
127 BIGNUM* bn = BN_bin2bn(&privateKey[0], 32, NULL);
128 BN_CTX* ctx = BN_CTX_new();
129 EC_GROUP* group = EC_GROUP_new_by_curve_name(NID_secp256k1);
130 EC_POINT* pub = group ? EC_POINT_new(group) : NULL;
131
132 bool ok = false;
133 if (bn && ctx && group && pub &&
134 EC_POINT_mul(group, pub, bn, NULL, NULL, ctx))
135 {
136 size_t n = EC_POINT_point2oct(group, pub, POINT_CONVERSION_COMPRESSED,
137 out, 33, ctx);
138 ok = n == 33;
139 }
140
141 BN_free(bn);
142 BN_CTX_free(ctx);
143 EC_POINT_free(pub);
144 EC_GROUP_free(group);
145
146 if (!ok)
147 {
148 errorOut = "could not serialize parent public key";
149 return false;
150 }
151 return true;
152}
153
117bool BIP39EntropyToMnemonic(const std::vector<unsigned char>& entropy, 154bool BIP39EntropyToMnemonic(const std::vector<unsigned char>& entropy,
118 std::string& mnemonicOut, 155 std::string& mnemonicOut,
119 std::string& errorOut) 156 std::string& errorOut)
@@ -284,10 +321,10 @@ bool BIP32MasterFromSeed(const std::vector<unsigned char>& seed,
284 return true; 321 return true;
285} 322}
286 323
287bool BIP32DeriveHardenedChild(const BIP32PrivateNode& parent, 324bool BIP32DeriveChild(const BIP32PrivateNode& parent,
288 unsigned int childIndex, 325 unsigned int childNumber,
289 BIP32PrivateNode& childOut, 326 BIP32PrivateNode& childOut,
290 std::string& errorOut) 327 std::string& errorOut)
291{ 328{
292 childOut.privateKey.clear(); 329 childOut.privateKey.clear();
293 childOut.chainCode.clear(); 330 childOut.chainCode.clear();
@@ -297,20 +334,21 @@ bool BIP32DeriveHardenedChild(const BIP32PrivateNode& parent,
297 errorOut = "parent private key or chain code is invalid"; 334 errorOut = "parent private key or chain code is invalid";
298 return false; 335 return false;
299 } 336 }
300 if (childIndex >= 0x80000000U) 337 unsigned char data[37];
338 if (childNumber & BIP32_HARDENED)
301 { 339 {
302 errorOut = "child index must be non-hardened; hardening is applied here"; 340 data[0] = 0x00;
303 return false; 341 memcpy(data + 1, &parent.privateKey[0], 32);
304 } 342 }
305 343 else
306 const unsigned int hardened = childIndex | 0x80000000U; 344 {
307 unsigned char data[37]; 345 if (!PrivateKeyToCompressedPubKey(parent.privateKey, data, errorOut))
308 data[0] = 0x00; 346 return false;
309 memcpy(data + 1, &parent.privateKey[0], 32); 347 }
310 data[33] = (unsigned char)((hardened >> 24) & 0xff); 348 data[33] = (unsigned char)((childNumber >> 24) & 0xff);
311 data[34] = (unsigned char)((hardened >> 16) & 0xff); 349 data[34] = (unsigned char)((childNumber >> 16) & 0xff);
312 data[35] = (unsigned char)((hardened >> 8) & 0xff); 350 data[35] = (unsigned char)((childNumber >> 8) & 0xff);
313 data[36] = (unsigned char)(hardened & 0xff); 351 data[36] = (unsigned char)(childNumber & 0xff);
314 352
315 unsigned char I[64]; 353 unsigned char I[64];
316 if (!HmacSha512(&parent.chainCode[0], 32, data, sizeof(data), I)) 354 if (!HmacSha512(&parent.chainCode[0], 32, data, sizeof(data), I))
@@ -363,4 +401,43 @@ bool BIP32DeriveHardenedChild(const BIP32PrivateNode& parent,
363 return true; 401 return true;
364} 402}
365 403
404bool BIP32DerivePath(const BIP32PrivateNode& root,
405 const std::vector<unsigned int>& path,
406 BIP32PrivateNode& nodeOut,
407 std::string& errorOut)
408{
409 nodeOut.privateKey.clear();
410 nodeOut.chainCode.clear();
411 errorOut.clear();
412 if (!IsValidPrivateKey(root.privateKey) || root.chainCode.size() != 32)
413 {
414 errorOut = "root private key or chain code is invalid";
415 return false;
416 }
417
418 BIP32PrivateNode cur = root;
419 for (size_t i = 0; i < path.size(); i++)
420 {
421 BIP32PrivateNode next;
422 if (!BIP32DeriveChild(cur, path[i], next, errorOut))
423 return false;
424 cur = next;
425 }
426 nodeOut = cur;
427 return true;
428}
429
430bool BIP32DeriveHardenedChild(const BIP32PrivateNode& parent,
431 unsigned int childIndex,
432 BIP32PrivateNode& childOut,
433 std::string& errorOut)
434{
435 if (childIndex >= BIP32_HARDENED)
436 {
437 errorOut = "child index must be non-hardened; hardening is applied here";
438 return false;
439 }
440 return BIP32DeriveChild(parent, childIndex | BIP32_HARDENED, childOut, errorOut);
441}
442
366} // namespace bitflash 443} // namespace bitflash