deriveChild method

HDKey deriveChild(
  1. int index
)

Implementation

HDKey deriveChild(int index) {
  bool isHardened = index >= HARDENED_OFFSET;
  ByteData indexByteData = ByteData(4);
  indexByteData.setUint32(0, index);

  ByteData data;

  if (isHardened) {
    // Hardened child
    trueOrThrow(
        this.privateKey != null,
        FormatException(
            'Could not derive hardened child key', this.privateKey));

    ByteData zb = ByteData(1);
    List<int> tmpPk = Uint8List.view(zb.buffer).toList();
    tmpPk.addAll(this.privateKey!.toList());

    List<int> tmpData = [];
    tmpData.addAll(tmpPk); // or we can use tmpData.addAll(pk);
    tmpData.addAll(Uint8List.view(indexByteData.buffer).toList());
    data = ByteData.view(Uint8List.fromList(tmpData).buffer);
  } else {
    // Normal child
    // data = serP(point(kpar)) || ser32(index)
    //      = serP(Kpar) || ser32(index)
    List<int> pk = this.publicKey!.toList(growable: true);
    pk.addAll(Uint8List.view(indexByteData.buffer));
    data = ByteData.view(Uint8List.fromList(pk).buffer);
  }

  Uint8List I = sha512(Uint8List.view(data.buffer), this.chainCode);
  Uint8List IL = I.sublist(0, 32);
  Uint8List IR = I.sublist(32);

  HDKey hd = new HDKey(this.versions);

  // Private parent key -> private child key
  if (this.privateKey != null) {
    // ki = parse256(IL) + kpar (mod n)
    try {
      hd.privateKey = privateKeyTweakAdd(this.privateKey!, IL);
      // throw if IL >= n || (privateKey + IL) === 0
    } catch (err) {
      print("privateKeyTweakAdd error: ${err.toString()}");
      // In case parse256(IL) >= n or ki == 0, one should proceed with the next value for i
      return this.deriveChild(index + 1);
    }
    // Public parent key -> public child key
  } else {
    // Ki = point(parse256(IL)) + Kpar
    //    = G*IL + Kpar
    try {
      hd.publicKey = publicKeyTweakAdd(this.publicKey!, IL, true);
      // throw if IL >= n || (g**IL + publicKey) is infinity
    } catch (err) {
      print("publicKeyTweakAdd error: ${err.toString()}");
      // In case parse256(IL) >= n or Ki is the point at infinity, one should proceed with the next value for i
      return this.deriveChild(index + 1);
    }
  }

  hd.chainCode = IR;
  hd.depth = this.depth + 1;
  hd.parentFingerprint = this.fingerprint;
  hd.index = index;

  return hd;
}