signSafeTransaction function

String signSafeTransaction({
  1. required SafeTransaction tx,
  2. required List<SafeUtxoOutput> utxos,
  3. required List<String> views,
  4. required Key privateKey,
})

Implementation

String signSafeTransaction({
  required SafeTransaction tx,
  required List<SafeUtxoOutput> utxos,
  required List<String> views,
  required Key privateKey,
}) {
  final raw = encodeSafeTransaction(tx);
  final msg = Uint8List.fromList(blake3(hex.decode(raw)));

  assert(privateKey.raw.length >= 32,
      'invalid private key length: ${privateKey.raw.length}');
  final spenty = sha512Hash(privateKey.raw.sublist(0, 32));

  final y = Scalar()..setBytesWithClamping(spenty.sublist(0, 32));
  final signaturesMap = <Map<int, String>>[];
  for (var i = 0; i < tx.inputs.length; i++) {
    final input = tx.inputs[i];
    final utxo = utxos[i];

    if (utxo.transactionHash != input.hash || utxo.outputIndex != input.index) {
      throw Exception('invalid input: $input');
    }

    final view = hex.decode(views[i]);
    final x = Scalar()..setCanonicalBytes(view);
    final t = Scalar()..add(x, y);
    final key = PrivateKey(t.Bytes());
    final index = utxo.keys.indexOf(key.publicKey().hexString());
    if (index == -1) {
      throw Exception(
          'invalid public key for the input: $i ${utxo.keys}, ${key.publicKey().hexString()}');
    }
    final sigs = <int, String>{};
    final sig = key.sign(msg);
    sigs[index] = sig.toHexString();
    signaturesMap.add(sigs);
  }
  return encodeSafeTransaction(tx, sigs: signaturesMap);
}