bool CBInitHDKeyFromData(CBHDKey * key, uint8_t * data, CBHDKeyVersion versionBytes, CBHDKeyType type){ CBInitHDKey(key); // Set version bytes key->versionBytes = versionBytes; // Chain code memcpy(key->chainCode, data + 13, 32); if (type == CB_HD_KEY_TYPE_PRIVATE){ // Private memcpy(key->keyPair->privkey, data + 46, 32); // Calculate public key CBKeyGetPublicKey(CBHDKeyGetPrivateKey(key), CBHDKeyGetPublicKey(key)); }else // Assume public memcpy(CBHDKeyGetPublicKey(key), data + 45, 33); // Depth key->depth = data[4]; if (key->depth == 0) { // Master key->childID.priv = false; key->childID.childNumber = 0; for (uint8_t x = 5; x < 9; x++) if (data[x] != 0) { CBLogError("The fingerprint of the master key is not zero."); return false; } }else{ // Not master uint32_t childNum = CBArrayToInt32BigEndian(data, 9); key->childID.priv = childNum >> 31; key->childID.childNumber = childNum & 0x8fffffff; } return true; }
void CBHDKeySerialise(CBHDKey * key, uint8_t * data){ CBInt32ToArrayBigEndian(data, 0, key->versionBytes); if (key->depth == 0) // Master memset(data + 4, 0, 9); else{ // Not master data[4] = key->depth; memcpy(data + 5, key->parentFingerprint, 4); // Child number CBInt32ToArrayBigEndian(data, 9, CBHDKeyGetChildNumber(key->childID)); } // Chain code memcpy(data + 13, key->chainCode, 32); if (CBHDKeyGetType(key->versionBytes) == CB_HD_KEY_TYPE_PRIVATE) { // Private data[45] = 0; memcpy(data + 46, CBHDKeyGetPrivateKey(key), 32); }else // Assume public memcpy(data + 45, CBHDKeyGetPublicKey(key), 33); }
bool CBHDKeyDeriveChild(CBHDKey * parentKey, CBHDKeyChildID childID, CBHDKey * childKey){ uint8_t hash[64], inputData[37]; CBHDKeyType type = CBHDKeyGetType(parentKey->versionBytes); // Add childID to inputData CBInt32ToArrayBigEndian(inputData, 33, CBHDKeyGetChildNumber(childID)); if (childID.priv) { // Private key derivation // Parent must be private if (type != CB_HD_KEY_TYPE_PRIVATE) { CBLogError("Attempting to derive a public-key without public-key derivation, or the key was of an unknown type."); return false; } // Add private key inputData[0] = 0; memcpy(inputData + 1, CBHDKeyGetPrivateKey(parentKey), 32); }else{ // Public key derivation // Can be public or private if (type == CB_HD_KEY_TYPE_UNKNOWN) { CBLogError("Attempting to derive a key from an unknown key."); return false; } // Add the public key memcpy(inputData, CBHDKeyGetPublicKey(parentKey), 33); } // Get HMAC-SHA512 hash CBHDKeyHmacSha512(inputData, parentKey->chainCode, hash); // Copy over chain code, childID and version bytes memcpy(childKey->chainCode, hash + 32, 32); childKey->childID = childID; childKey->versionBytes = parentKey->versionBytes; // Set fingerprint of parent memcpy(childKey->parentFingerprint, CBHDKeyGetHash(parentKey), 4); // Set depth childKey->depth = parentKey->depth + 1; // Calculate key if (type == CB_HD_KEY_TYPE_PRIVATE) { // Calculating the private key // Add private key to first 32 bytes and modulo the order the curve // Split into four 64bit integers and add each one bool overflow = 0; for (uint8_t x = 4; x--;) { uint64_t a = CBArrayToInt64BigEndian(hash, 8*x); uint64_t b = CBArrayToInt64BigEndian(CBHDKeyGetPrivateKey(parentKey), 8*x) + overflow; uint64_t c = a + b; overflow = (c < b)? 1 : 0; CBInt64ToArrayBigEndian(CBHDKeyGetPrivateKey(childKey), 8*x, c); } if (overflow || memcmp(CBHDKeyGetPrivateKey(childKey), CB_CURVE_ORDER, 32) > 0) { // Take away CB_CURVE_ORDER bool carry = 0; for (uint8_t x = 4; x--;) { uint64_t a = CBArrayToInt64BigEndian(CBHDKeyGetPrivateKey(childKey), 8*x); uint64_t b = CBArrayToInt64BigEndian(CB_CURVE_ORDER, 8*x) + carry; carry = a < b; a -= b; CBInt64ToArrayBigEndian(CBHDKeyGetPrivateKey(childKey), 8*x, a); } } // Derive public key from private key CBKeyGetPublicKey(childKey->keyPair->privkey, CBHDKeyGetPublicKey(childKey)); // Do not bother checking validity??? }else{ // Calculating the public key // Multiply the first 32 bytes by the base point (derive public key) and add to the public key point. CBKeyGetPublicKey(hash, CBHDKeyGetPublicKey(childKey)); CBAddPoints(CBHDKeyGetPublicKey(childKey), CBHDKeyGetPublicKey(parentKey)); } return true; }