public bool TryGetNonce(Span <byte> nonce32, ReadOnlySpan <byte> msg32, ReadOnlySpan <byte> key32, ReadOnlySpan <byte> algo16, uint counter) { using var sha = new Secp256k1.SHA256(); /* Hash x||msg as per the spec */ sha.Write(key32.Slice(0, 32)); sha.Write(msg32.Slice(0, 32)); /* Hash in algorithm, which is not in the spec, but may be critical to * users depending on it to avoid nonce reuse across algorithms. */ if (algo16.Length == 16) { sha.Write(algo16.Slice(0, 16)); } if (data != null) { sha.Write(data.AsSpan().Slice(0, 32)); } sha.GetHash(nonce32); return(true); }
public bool TrySignBIP140(ReadOnlySpan <byte> msg32, INonceFunctionHardened?nonceFunction, out SecpSchnorrSignature?signature) { signature = null; if (msg32.Length != 32) { return(false); } using var sha = new Secp256k1.SHA256(); Span <byte> buf = stackalloc byte[32]; Span <byte> sig64 = stackalloc byte[64]; Span <byte> pk_buf = stackalloc byte[32]; Span <byte> sec_key = stackalloc byte[32]; if (nonceFunction == null) { nonceFunction = new BIP340NonceFunction(true); } var pk = CreatePubKey().Q; var sk = this.sec; /* Because we are signing for a x-only pubkey, the secret key is negated * before signing if the point corresponding to the secret key does not * have an even Y. */ if (pk.y.IsOdd) { sk = sk.Negate(); } sk.WriteToSpan(sec_key); pk.x.WriteToSpan(pk_buf); var ret = nonceFunction.TryGetNonce(buf, msg32, sec_key, pk_buf, BIP340NonceFunction.ALGO_BIP340); var k = new Scalar(buf, out _); ret &= !k.IsZero; Scalar.CMov(ref k, Scalar.One, ret ? 0 : 1); var rj = ctx.EcMultGenContext.MultGen(k); var r = rj.ToGroupElement(); var ry = r.y.NormalizeVariable(); if (ry.IsOdd) { k = k.Negate(); } var rx = r.x.NormalizeVariable(); rx.WriteToSpan(sig64); /* tagged hash(r.x, pk.x, msg32) */ sha.InitializeTagged(ECXOnlyPubKey.TAG_BIP0340Challenge); sha.Write(sig64.Slice(0, 32)); sha.Write(pk_buf); sha.Write(msg32); sha.GetHash(buf); /* Set scalar e to the challenge hash modulo the curve order as per * BIP340. */ var e = new Scalar(buf, out _); e = e * sk; e = e + k; e.WriteToSpan(sig64.Slice(32)); ret &= SecpSchnorrSignature.TryCreate(sig64, out signature); k = default; sk = default; sec_key.Fill(0); sig64.Fill(0); if (!ret) { signature = null; } return(ret); }