verify method

bool verify(
  1. NonceSession session
)

BIP-327 PartialSigVerify: sG == R_i + ea_i*P_i

Implementation

bool verify(NonceSession session) {
  final aggR = session.aggregateNonces();
  final rPoint = ecBytesToPoint(aggR);

  EcPoint aggR1 = EcPoint.infinity();
  EcPoint aggR2 = EcPoint.infinity();
  for (final nonce in session.nonces) {
    aggR1 = ecPointAdd(aggR1, ecBytesToPoint(nonce.r1));
    aggR2 = ecPointAdd(aggR2, ecBytesToPoint(nonce.r2));
  }
  // BIP-327 sec. GetSessionValues: noncecoef DOES include the message (b is
  // hashed over aggnonce || Q_x || msg).
  final vR1Bytes = aggR1.isInfinity ? Uint8List(33) : ecPointToBytes(aggR1, compressed: true);
  final vR2Bytes = aggR2.isInfinity ? Uint8List(33) : ecPointToBytes(aggR2, compressed: true);
  final bInput = concatBytes(
      [vR1Bytes, vR2Bytes, session.aggKey.xOnly, session.message]);
  final bHash = taggedHash('MuSig/noncecoef', bInput);
  final b = bytesToBigInt(bHash) % secp256k1N;

  final rX = bigIntToBytes(rPoint.x, 32);
  final challengeInput = concatBytes([
    rX,
    session.aggKey.xOnly,
    session.message,
  ]);
  final eHash = taggedHash('BIP0340/challenge', challengeInput);
  final e = bytesToBigInt(eHash) % secp256k1N;

  NoncePair? signerNonce;
  final signerIdx = session.aggKey.publicKeys.indexWhere(
      (pk) => bytesEqual(pk.bytes, signerKey.bytes));
  if (signerIdx >= 0 && signerIdx < session.nonces.length) {
    signerNonce = session.nonces[signerIdx];
  }
  if (signerNonce == null) {
    return false; // signer not found in session
  }

  // R_i = R1_i + b * R2_i
  final r1i = ecBytesToPoint(signerNonce.r1);
  final r2i = ecBytesToPoint(signerNonce.r2);
  EcPoint rI = ecPointAdd(r1i, ecScalarMult(b, r2i));

  if (!rPoint.y.isEven) {
    rI = EcPoint(rI.x, (secp256k1P - rI.y) % secp256k1P);
  }

  final aBytes = session.aggKey.coefficient(signerKey);
  final a = bytesToBigInt(aBytes);
  EcPoint pi = ecBytesToPoint(signerKey.bytes);
  BigInt effectiveA = a;
  if (!session.aggKey.yIsEven) {
    effectiveA = (secp256k1N - a) % secp256k1N;
  }

  final eaPi = ecScalarMult((e * effectiveA) % secp256k1N, pi);

  // s*G == R_i + e*a_i*P_i
  final s = bytesToBigInt(partialS);
  final sG = ecScalarMult(s, secp256k1G);
  final expected = ecPointAdd(rI, eaPi);
  return sG == expected;
}