public void MultipleSignatureWays() { var privKeyStr = Encoders.Hex.DecodeData("8e812436a0e3323166e1f0e8ba79e19e217b2c4a53c970d4cca0cfb1078979df"); Key key = new Key(privKeyStr); Assert.AreEqual("04a5bb3b28466f578e6e93fbfd5f75cee1ae86033aa4bbea690e3312c087181eb366f9a1d1d6a437a9bf9fc65ec853b9fd60fa322be3997c47144eb20da658b3d1", key.PubKey.Decompress().ToHex()); var messageToSign = "159817a085f113d099d3d93c051410e9bfe043cc5c20e43aa9a083bf73660145"; var messageBytes = Encoders.Hex.DecodeData(messageToSign); ECDSASignature signature = key.Sign(new uint256(messageBytes), true); SecpECDSASignature.TryCreateFromDer(signature.ToDER(), out SecpECDSASignature sig); var(r, s) = sig; var R = r.ToBytes(); var S = s.ToBytes(); Assert.AreEqual("38b7dac5ee932ac1bf2bc62c05b792cd93c3b4af61dc02dbb4b93dacb758123f", R.ToHexString()); Assert.AreEqual("08bf123eabe77480787d664ca280dc1f20d9205725320658c39c6c143fd5642d", S.ToHexString()); // Compact signature byte[] signatureCompact = key.SignCompact(new uint256(messageBytes), true); if (signatureCompact.Length != 65) { throw new ArgumentException(paramName: nameof(signatureCompact), message: "Signature truncated, expected 65"); } var ss = signatureCompact.AsSpan(); int recid = (ss[0] - 27) & 3; if (!( SecpRecoverableECDSASignature.TryCreateFromCompact(ss.Slice(1), recid, out SecpRecoverableECDSASignature sigR) && sigR is SecpRecoverableECDSASignature ) ) { throw new InvalidOperationException("Impossible to recover the public key"); } // V from comapct signature var(r1, s1, v1) = sigR; Assert.AreEqual(v1, 0); // Recoverable signature with Secp256k1 lib NBitcoin.Secp256k1.ECPrivKey privKey = Context.Instance.CreateECPrivKey(new Scalar(key.ToBytes())); Assert.AreEqual(key.PubKey.ToBytes(), privKey.CreatePubKey().ToBytes()); privKey.TrySignRecoverable(messageBytes, out SecpRecoverableECDSASignature sigRec); var(r2, s2, v2) = sigRec; Assert.AreEqual(r2, r); Assert.AreEqual(s2, s); Assert.AreEqual(v2, v1); }
private byte[] adaptorExtractSecret(byte[] sig, byte[] adaptorSig, byte[] adaptor) { Assert.True(SecpECDSAAdaptorSignature.TryCreate(adaptorSig, out var adaptorSigObj)); Assert.True(SecpECDSASignature.TryCreateFromDer(sig, out var sigObj)); Assert.True(Context.Instance.TryCreatePubKey(adaptor, out var pubkey)); Assert.True(adaptorSigObj.TryExtractSecret(sigObj, pubkey, out var secret)); var result = new byte[32]; secret.WriteToSpan(result); return(result); }
public Key ExtractAttestation(Transaction tx) { if (State.OracleInfo is null || State.Remote?.OutcomeSigs is null || State.Us?.OutcomeSigs is null || State.Funding is null) { throw new InvalidOperationException("Invalid state"); } foreach (var input in tx.Inputs) { if (input.PrevOut != State.Funding.FundCoin.Outpoint) { continue; } foreach (var data in input.WitScript.Pushes) { if (data.Length == 0) { continue; } if (!SecpECDSASignature.TryCreateFromDer(data.AsSpan(0, data.Length - 1), out var sig) || sig is null) { continue; } var outcomeSigsByOutcome = State.Remote.OutcomeSigs .Concat(State.Us.OutcomeSigs) .GroupBy(c => c.Key, c => c.Value); foreach (var outcomeSigs in outcomeSigsByOutcome) { if (!State.OracleInfo.TryComputeSigpoint(outcomeSigs.Key, out var sigpoint) || sigpoint is null) { continue; } foreach (var outcomeSig in outcomeSigs) { if (outcomeSig.TryExtractSecret(sig, sigpoint, out var key) && key is ECPrivKey) { return(new Key(key.ToBytes())); } } } } } throw new InvalidOperationException("No attestation to extract from this transaction"); }
public Key ExtractAttestation(Transaction tx) { if (State.OracleInfo is null || State.Remote?.OutcomeSigs is null || State.Us?.OutcomeSigs is null || State.Funding is null) { throw new InvalidOperationException("Invalid state"); } foreach (var input in tx.Inputs) { if (input.PrevOut != State.Funding.FundCoin.Outpoint) { continue; } foreach (var data in input.WitScript.Pushes) { if (data.Length == 0) { continue; } if (!SecpECDSASignature.TryCreateFromDer(data.AsSpan(0, data.Length - 1), out var sig) || sig is null) { continue; } int i = -1; foreach (var outcome in s.OffererPayoffs.Select(c => c.Outcome)) { i++; if (!State.OracleInfo.TryComputeSigpoint(outcome, out var sigpoint) || sigpoint is null) { continue; } foreach (var outcomeSig in new[] { State.Us.OutcomeSigs[i], State.Remote.OutcomeSigs[i] }) { if (outcomeSig.TryExtractSecret(sig, sigpoint, out var key) && key is ECPrivKey) { return(new Key(key.ToBytes())); } } } } } throw new InvalidOperationException("No attestation to extract from this transaction"); }