sign method
List<int>
sign({
- required List<
int> secnonce, - required List<
int> sk, - required MuSig2Session session,
- Secp256k1ECmultGenContext? context,
override
Generates a MuSig2 partial signature
Implementation
@override
List<int> sign({
required List<int> secnonce,
required List<int> sk,
required MuSig2Session session,
Secp256k1ECmultGenContext? context,
}) {
if (secnonce.length != MuSig2Constants.secnoncelength) {
throw ArgumentException.invalidOperationArguments(
"sign",
name: "secnonce",
reason: "Invalid secret nonce bytes length.",
expecteLen: MuSig2Constants.secnoncelength,
);
}
final values = MuSig2UtilsConst.decodeSessionConst(session);
final r = Secp256k1Utils.loadPublicKey(values.r.toBytes());
if (r == null) {
throw ArgumentException.invalidOperationArguments(
"signConst",
name: "r",
reason: "Invalid session public r public key.",
);
}
final isOdd = Secp256k1.secp256k1FeIsOdd(r.y);
final k1 = Secp256k1Utils.scalarFromBytes(
secnonce.sublist(0, MuSig2Constants.xOnlyBytesLength),
);
final k2 = Secp256k1Utils.scalarFromBytes(
secnonce.sublist(
MuSig2Constants.xOnlyBytesLength,
MuSig2Constants.xOnlyBytesLength * 2,
),
);
final k1Scalar = k1.clone();
final k2Scalar = k2.clone();
Secp256k1.secp256k1ScalarCondNegate(k1Scalar, isOdd);
Secp256k1.secp256k1ScalarCondNegate(k2Scalar, isOdd);
final d = Secp256k1Utils.scalarFromBytes(sk);
context ??= Secp256k1Utils.initalizeBlindEcMultContext();
Secp256k1Gej R = Secp256k1Gej();
Secp256k1.secp256k1ECmultGen(context, R, d);
Secp256k1Ge mid1 = Secp256k1Utils.secp256k1MultBase(
scalar: d,
context: context,
);
// Secp256k1.secp256k1GeSetGej(mid1, R);
final pkBytes = Secp256k1Utils.secp256k1ECkeyPubkeySerialize(mid1, true);
if (pkBytes == null) {
throw ArgumentException.invalidOperationArguments(
"sign",
name: "sk",
reason: "Invalid secret key.",
);
}
final pkOffset = MuSig2Constants.xOnlyBytesLength * 2;
if (!BytesUtils.bytesEqualConst(
secnonce.sublist(
pkOffset,
pkOffset + EcdsaKeysConst.pubKeyCompressedByteLen,
),
pkBytes,
)) {
throw ArgumentException.invalidOperationArguments(
"sign",
reason: "Missmatch between secret key and public key.",
);
}
final a = MuSig2Utils.getSessionKeyAggCoeffConst(
session: session,
pkBytes: pkBytes,
);
final aggPk = Secp256k1Utils.loadPublicKey(values.publicKey.toBytes());
if (aggPk == null) {
throw ArgumentException.invalidOperationArguments(
"sign",
reason: "Invalid agg public key.",
);
}
Secp256k1Scalar g = Secp256k1Const.secp256k1ScalarOne.clone();
if (Secp256k1.secp256k1FeIsOdd(aggPk.y) != 0) {
Secp256k1.secp256k1ScalarNegate(g, g);
}
Secp256k1Scalar gcc = Secp256k1Utils.scalarFromBytes(values.gacc);
Secp256k1Scalar b = Secp256k1Utils.scalarFromBytes(values.b);
Secp256k1Scalar e = Secp256k1Utils.scalarFromBytes(values.e);
Secp256k1.secp256k1ScalarMul(g, gcc, g);
Secp256k1.secp256k1ScalarMul(d, g, d);
Secp256k1Scalar s1 = Secp256k1Scalar();
Secp256k1Scalar s2 = Secp256k1Scalar();
Secp256k1.secp256k1ScalarMul(s1, b, k2Scalar);
Secp256k1.secp256k1ScalarAdd(s1, s1, k1Scalar);
Secp256k1.secp256k1ScalarMul(s2, e, a);
Secp256k1.secp256k1ScalarMul(s2, s2, d);
Secp256k1.secp256k1ScalarAdd(s1, s1, s2);
if (Secp256k1.secp256k1ScalarIsZero(s1).toBool) {
throw const CryptoSignException(
'Signing failed due to generate signature scalar.',
);
}
final rS1 = Secp256k1Utils.generatePublicKeyBlind(scalar: k1);
final rS2 = Secp256k1Utils.generatePublicKeyBlind(scalar: k2);
if (rS1 == null || rS2 == null) {
throw const CryptoSignException(
'Signing failed due to generate pubnonce.',
);
}
final signature = Secp256k1Utils.scalarToBytes(
s1,
clean: true,
validate: false,
);
final List<int> pubnonce = [...rS1, ...rS2];
final verify = partialSigVerify(
signature: signature,
pubnonce: pubnonce,
pk: pkBytes,
session: session,
);
if (!verify) {
throw CryptoSignException.signatureVerificationFailed;
}
return signature;
}