verify method
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;
}