public PubKey Derivate(byte[] cc, uint nChild, out byte[] ccChild) { if (!IsCompressed) { throw new InvalidOperationException("The pubkey must be compressed"); } if ((nChild >> 31) != 0) { throw new InvalidOperationException("A public key can't derivate an hardened child"); } #if HAS_SPAN Span <byte> vout = stackalloc byte[64]; vout.Clear(); Span <byte> pubkey = stackalloc byte[33]; this.ToBytes(pubkey, out _); Hashes.BIP32Hash(cc, nChild, pubkey[0], pubkey.Slice(1), vout); ccChild = new byte[32];; vout.Slice(32, 32).CopyTo(ccChild); return(new PubKey(this.ECKey.AddTweak(vout.Slice(0, 32)), true)); #else byte[] lr = null; byte[] l = new byte[32]; byte[] r = new byte[32]; var pubKey = ToBytes(); lr = Hashes.BIP32Hash(cc, nChild, pubKey[0], pubKey.Skip(1).ToArray()); Array.Copy(lr, l, 32); Array.Copy(lr, 32, r, 0, 32); ccChild = r; BigInteger N = ECKey.CURVE.N; BigInteger parse256LL = new BigInteger(1, l); if (parse256LL.CompareTo(N) >= 0) { throw new InvalidOperationException("You won a prize ! this should happen very rarely. Take a screenshot, and roll the dice again."); } var q = ECKey.CURVE.G.Multiply(parse256LL).Add(ECKey.GetPublicKeyParameters().Q); if (q.IsInfinity) { throw new InvalidOperationException("You won the big prize ! this would happen only 1 in 2^127. Take a screenshot, and roll the dice again."); } q = q.Normalize(); var p = new NBitcoin.BouncyCastle.Math.EC.FpPoint(ECKey.CURVE.Curve, q.XCoord, q.YCoord, true); return(new PubKey(p.GetEncoded())); #endif }
public PubKey Derivate(byte[] cc, uint nChild, out byte[] ccChild) { byte[] lr = null; var l = new byte[32]; var r = new byte[32]; if ((nChild >> 31) == 0) { byte[] pubKey = ToBytes(); lr = Hashes.BIP32Hash(cc, nChild, pubKey[0], pubKey.Skip(1).ToArray()); } else { throw new InvalidOperationException("A public key can't derivate an hardened child"); } Array.Copy(lr, l, 32); Array.Copy(lr, 32, r, 0, 32); ccChild = r; BigInteger N = ECKey.CURVE.N; var parse256LL = new BigInteger(1, l); if (parse256LL.CompareTo(N) >= 0) { throw new InvalidOperationException("You won a prize ! this should happen very rarely. Take a screenshot, and roll the dice again."); } ECPoint q = ECKey.CURVE.G.Multiply(parse256LL).Add(ECKey.GetPublicKeyParameters().Q); if (q.IsInfinity) { throw new InvalidOperationException("You won the big prize ! this would happen only 1 in 2^127. Take a screenshot, and roll the dice again."); } q = q.Normalize(); var p = new NBitcoin.BouncyCastle.Math.EC.FpPoint(ECKey.CURVE.Curve, q.XCoord, q.YCoord, true); return(new PubKey(p.GetEncoded())); }
protected FpCurve(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor) : base(q) { this.m_q = q; this.m_r = r; this.m_infinity = new FpPoint(this, null, null); this.m_a = a; this.m_b = b; this.m_order = order; this.m_cofactor = cofactor; this.m_coord = FP_DEFAULT_COORDS; }
public FpCurve(BigInteger q, BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor) : base(q) { this.m_q = q; this.m_r = FpFieldElement.CalculateResidue(q); this.m_infinity = new FpPoint(this, null, null); this.m_a = FromBigInteger(a); this.m_b = FromBigInteger(b); this.m_order = order; this.m_cofactor = cofactor; this.m_coord = FP_DEFAULT_COORDS; }
public static ECKey RecoverFromSignature(int recId, ECDSASignature sig, uint256 message, bool compressed) { if(recId < 0) throw new ArgumentException("recId should be positive"); if(sig.R.SignValue < 0) throw new ArgumentException("r should be positive"); if(sig.S.SignValue < 0) throw new ArgumentException("s should be positive"); if(message == null) throw new ArgumentNullException("message"); var curve = ECKey.Secp256k1; // 1.0 For j from 0 to h (h == recId here and the loop is outside this function) // 1.1 Let x = r + jn var n = curve.N; var i = NBitcoin.BouncyCastle.Math.BigInteger.ValueOf((long)recId / 2); var x = sig.R.Add(i.Multiply(n)); // 1.2. Convert the integer x to an octet string X of length mlen using the conversion routine // specified in Section 2.3.7, where mlen = ⌈(log2 p)/8⌉ or mlen = ⌈m/8⌉. // 1.3. Convert the octet string (16 set binary digits)||X to an elliptic curve point R using the // conversion routine specified in Section 2.3.4. If this conversion routine outputs “invalid”, then // do another iteration of Step 1. // // More concisely, what these points mean is to use X as a compressed public key. var prime = ((FpCurve)curve.Curve).Q; if(x.CompareTo(prime) >= 0) { return null; } // Compressed keys require you to know an extra bit of data about the y-coord as there are two possibilities. // So it's encoded in the recId. ECPoint R = DecompressKey(x, (recId & 1) == 1); // 1.4. If nR != point at infinity, then do another iteration of Step 1 (callers responsibility). if(!R.Multiply(n).IsInfinity) return null; // 1.5. Compute e from M using Steps 2 and 3 of ECDSA signature verification. var e = new NBitcoin.BouncyCastle.Math.BigInteger(1, message.ToBytes()); // 1.6. For k from 1 to 2 do the following. (loop is outside this function via iterating recId) // 1.6.1. Compute a candidate public key as: // Q = mi(r) * (sR - eG) // // Where mi(x) is the modular multiplicative inverse. We transform this into the following: // Q = (mi(r) * s ** R) + (mi(r) * -e ** G) // Where -e is the modular additive inverse of e, that is z such that z + e = 0 (mod n). In the above equation // ** is point multiplication and + is point addition (the EC group operator). // // We can find the additive inverse by subtracting e from zero then taking the mod. For example the additive // inverse of 3 modulo 11 is 8 because 3 + 8 mod 11 = 0, and -3 mod 11 = 8. var eInv = NBitcoin.BouncyCastle.Math.BigInteger.Zero.Subtract(e).Mod(n); var rInv = sig.R.ModInverse(n); var srInv = rInv.Multiply(sig.S).Mod(n); var eInvrInv = rInv.Multiply(eInv).Mod(n); var q = (FpPoint)ECAlgorithms.SumOfTwoMultiplies(curve.G, eInvrInv, R, srInv); if(compressed) { q = new FpPoint(curve.Curve, q.X, q.Y, true); } return new ECKey(q.GetEncoded(), false); }