deriveChild method

HDWallet deriveChild(
  1. int index
)

Derives a direct child wallet with the specified index.

Use index >= 2^31 for hardened derivation.

Implementation

HDWallet deriveChild(int index) {
  if (index < 0) {
    throw ArgumentError('Child index must be non-negative');
  }

  final isHardened = index >= (1 << 31);
  final data = <int>[];

  if (isHardened) {
    // Hardened derivation: use private key
    data.add(0x00);
    data.addAll(privateKey);
  } else {
    // Non-hardened derivation: use public key
    data.addAll(publicKey);
  }

  // Add index as big-endian 32-bit integer
  data.addAll(_intToBytes(index, 4));

  // BIP-32: Generate child key material using HMAC-SHA512
  final hmac = HmacSha512.compute(chainCode, Uint8List.fromList(data));
  final childPrivateKeyBytes = Uint8List.sublistView(hmac, 0, 32);
  final childChainCode = Uint8List.sublistView(hmac, 32, 64);

  // Validate child private key
  final childPrivateKeyInt = _bytesToBigInt(childPrivateKeyBytes);
  if (childPrivateKeyInt >= _secp256k1Order) {
    throw StateError('Invalid child private key generated');
  }

  // Calculate final child private key
  final parentPrivateKeyInt = _bytesToBigInt(privateKey);
  final finalChildPrivateKeyInt =
      (childPrivateKeyInt + parentPrivateKeyInt) % _secp256k1Order;

  if (finalChildPrivateKeyInt == BigInt.zero) {
    throw StateError('Invalid child private key (zero)');
  }

  final finalChildPrivateKey = _bigIntToBytes(finalChildPrivateKeyInt, 32);
  final childPublicKey =
      Secp256k1.getPublicKey(finalChildPrivateKey, compressed: true);

  // BIP-32: Parent fingerprint = first 4 bytes of HASH160(parent public key)
  // HASH160 = RIPEMD160(SHA256(data))
  final parentHash160 = Ripemd160.hash160(publicKey);
  final parentFingerprint = Uint8List.sublistView(parentHash160, 0, 4);

  // Build child path
  final childPath = path == 'm'
      ? 'm/${isHardened ? "${index - (1 << 31)}'" : index.toString()}'
      : '$path/${isHardened ? "${index - (1 << 31)}'" : index.toString()}';

  return HDWallet._(
    privateKey: finalChildPrivateKey,
    publicKey: childPublicKey,
    chainCode: childChainCode,
    depth: depth + 1,
    path: childPath,
    index: index,
    parentFingerprint: parentFingerprint,
  );
}