diff options
Diffstat (limited to 'src/bip32.cpp')
| -rw-r--r-- | src/bip32.cpp | 109 |
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 | ||
| 117 | static 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 | |||
| 117 | bool BIP39EntropyToMnemonic(const std::vector<unsigned char>& entropy, | 154 | bool 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 | ||
| 287 | bool BIP32DeriveHardenedChild(const BIP32PrivateNode& parent, | 324 | bool 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 | ||
| 404 | bool 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 | |||
| 430 | bool 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 |