public static bool TrySignAdaptor(this ECPrivKey key, ReadOnlySpan <byte> msg32, ECPubKey adaptor, out SecpECDSAAdaptorSignature?adaptorSignature, out SecpECDSAAdaptorProof?proof) { if (key == null) { throw new ArgumentNullException(nameof(key)); } if (adaptor == null) { throw new ArgumentNullException(nameof(adaptor)); } if (msg32.Length < 32) { throw new ArgumentException(paramName: nameof(msg32), message: "msg32 should be at least 32 bytes"); } var adaptor_ge = adaptor.Q; var seckey32 = key.sec; SHA256 sha = new SHA256(); sha.Write(msg32.Slice(0, 32)); Span <byte> buf33 = stackalloc byte[33]; Internals.secp256k1_dleq_serialize_point(buf33, adaptor_ge); sha.Write(buf33); sha.GetHash(buf33); Span <byte> nonce32 = stackalloc byte[32]; nonce_function_dleq(buf33, key.sec, "ECDSAAdaptorNon", nonce32); var k = new Scalar(nonce32); if (k.IsZero) { adaptorSignature = default; proof = default; return(false); } var rpj = key.ctx.EcMultGenContext.MultGen(k); /* 2. R = k*Y; */ var rj = adaptor_ge.MultConst(k, 256); /* 4. [sic] proof = DLEQ_prove((G,R'),(Y, R)) */ if (!key.ctx.EcMultGenContext.secp256k1_dleq_proof("ECDSAAdaptorSig", k, adaptor_ge, out var dleq_proof_s, out var dleq_proof_e)) { adaptorSignature = default; proof = default; return(false); } /* 5. s' = k⁻¹(H(m) + x_coord(R)x) */ var r = rj.ToGroupElement(); var msg = new Scalar(msg32); if (!secp256k1_ecdsa_adaptor_sign_helper(msg, k, r, key.sec, out var sp)) { k = default; adaptorSignature = default; proof = default; return(false); } /* 6. return (R, R', s', proof) */ var rp = rpj.ToGroupElement(); proof = new SecpECDSAAdaptorProof(rp, dleq_proof_s, dleq_proof_e); adaptorSignature = new SecpECDSAAdaptorSignature(r, sp); k = default; return(true); }
public static bool SigVerify(this ECPubKey pubKey, SecpECDSAAdaptorSignature sig, SecpECDSAAdaptorProof proof, ReadOnlySpan <byte> msg32, ECPubKey adaptor) { if (pubKey == null) { throw new ArgumentNullException(nameof(pubKey)); } if (adaptor == null) { throw new ArgumentNullException(nameof(adaptor)); } if (msg32.Length < 32) { throw new ArgumentException(paramName: nameof(msg32), message: "msg32 should be at least 32 bytes"); } if (sig == null) { throw new ArgumentNullException(nameof(sig)); } var adaptor_ge = adaptor.Q; if (!secp256k1_dleq_verify(pubKey.ctx.EcMultContext, "ECDSAAdaptorSig", proof.s, proof.e, proof.rp, adaptor_ge, sig.r)) { return(false); } /* 2. return x_coord(R') == x_coord(s'⁻¹(H(m) * G + x_coord(R) * X)) */ var q = pubKey.Q; var msg = new Scalar(msg32); if (!pubKey.ctx.secp256k1_ecdsa_adaptor_sig_verify_helper(sig.r.x.ToScalar(), sig.sp, q, msg, out var rhs)) { return(false); } var lhs = proof.rp.ToGroupElementJacobian(); rhs = rhs.Negate(); lhs = lhs.AddVariable(rhs, out _); return(lhs.IsInfinity); }