Example #1
0
        /// <summary>
        /// Initializes a new instance of <see cref="TransactionVerifier"/> using given parameters.
        /// </summary>
        /// <exception cref="ArgumentNullException"/>
        /// <param name="isMempool">Indicates whether this instance is used by the memory pool or block</param>
        /// <param name="utxoDatabase">UTXO database</param>
        /// <param name="memoryPool">Memory pool</param>
        /// <param name="consensus">Consensus rules</param>
        public TransactionVerifier(bool isMempool, IUtxoDatabase utxoDatabase, IMemoryPool memoryPool, IConsensus consensus)
        {
            if (utxoDatabase is null)
            {
                throw new ArgumentNullException(nameof(utxoDatabase), "UTXO database can not be null.");
            }
            if (memoryPool is null)
            {
                throw new ArgumentNullException(nameof(memoryPool), "Memory pool can not be null.");
            }
            if (consensus is null)
            {
                throw new ArgumentNullException(nameof(consensus), "Consensus rules can not be null.");
            }

            this.isMempool = isMempool;
            utxoDb         = utxoDatabase;
            mempool        = memoryPool;
            this.consensus = consensus;

            calc    = new EllipticCurveCalculator();
            scrSer  = new ScriptSerializer();
            hash160 = new Ripemd160Sha256();
            sha256  = new Sha256();
        }
Example #2
0
        /// <summary>
        /// Signs the given message and returns the <see cref="Signature"/> result with its recovery ID set to
        /// appropriate value according to the given <see cref="AddressType"/>.
        /// </summary>
        /// <exception cref="ArgumentException"/>
        /// <exception cref="ArgumentNullException"/>
        /// <param name="key">Private key to use</param>
        /// <param name="message">UTF-8 encoded message to sign (null and white space will be rejected)</param>
        /// <param name="addrType">Type of the corresponding address (will affect the recovery ID)</param>
        /// <param name="ignoreSegwit">
        /// [Default value = false]
        /// If true and address type is a SegWit address, sets the additional recovery ID value to 31.
        /// This is useful to return a recovery ID that can be verified with popular Bitcoin implementations such as Electrum.
        /// </param>
        /// <returns>Signature with the recovery ID set to appropriate value</returns>
        public Signature Sign(PrivateKey key, string message, AddressType addrType, bool ignoreSegwit = false)
        {
            if (key is null)
            {
                throw new ArgumentNullException(nameof(key), "Private key can not be null.");
            }
            if (string.IsNullOrWhiteSpace(message))
            {
                throw new ArgumentNullException(nameof(message), "Signing an empty message is not allowed in this implementation.");
            }

            byte[] toSign = GetBytesToSign(message);
            byte   recId  = addrType switch
            {
                AddressType.P2PKH_Uncompressed => 27,
                AddressType.P2PKH_Compressed => 31,
                AddressType.P2SH_P2WPKH => 35,
                AddressType.P2WPKH => 39,
                _ => throw new ArgumentException("Invalid address type.")
            };

            if (ignoreSegwit && (addrType == AddressType.P2SH_P2WPKH || addrType == AddressType.P2WPKH))
            {
                recId = 31;
            }

            var calc = new EllipticCurveCalculator();
            var sig  = calc.Sign(toSign, key.ToBytes());

            sig.RecoveryId += recId;
            return(sig);
        }
 public MessageSignatureService(IReport rep)
 {
     calc           = new EllipticCurveCalculator();
     addressBuilder = new Address();
     inputService   = new InputService();
     report         = rep;
 }
        /// <summary>
        /// Verifies the given signature against the message and for the given address.
        /// </summary>
        /// <exception cref="ArgumentException"/>
        /// <exception cref="ArgumentNullException"/>
        /// <exception cref="FormatException"/>
        /// <param name="message">UTF-8 encoded message to sign</param>
        /// <param name="address">Address of the key used to create the given signature</param>
        /// <param name="signature">Fixed length (65 byte) signature with a starting recovery ID encoded using Base-64</param>
        /// <param name="ignoreSegwit">
        /// [Default value = false]
        /// If true and address type is a SegWit address, accepts both correct recovery ID (as defined by this BIP)
        /// and the incorrect one.
        /// This is useful to verify signature produced by popular Bitcoin implementations such as Electrum.
        /// </param>
        /// <returns>True if the verification succeeds; otherwise false.</returns>
        public bool Verify(string message, string address, string signature, bool ignoreSegwit = false)
        {
            byte[] toSign = GetBytesToSign(message);

            byte[] sigBa = Convert.FromBase64String(signature);
            if (!Signature.TryReadWithRecId(sigBa, out Signature sig, out string error))
            {
                throw new FormatException(error);
            }

            Address     addr     = new Address();
            AddressType addrType = AddressType.P2PKH_Compressed;

            if (sig.RecoveryId < 27 || sig.RecoveryId > 43)
            {
                return(false);
            }
            else if (sig.RecoveryId >= 27 && sig.RecoveryId < 35)
            {
                if (!addr.VerifyType(address, Blockchain.Scripts.PubkeyScriptType.P2PKH, out _))
                {
                    // Special case where this BIP is not used to create the signature
                    if (ignoreSegwit && addr.VerifyType(address, Blockchain.Scripts.PubkeyScriptType.P2SH, out _))
                    {
                        addrType = AddressType.P2SH_P2WPKH;
                    }
                    else if (ignoreSegwit && addr.VerifyType(address, Blockchain.Scripts.PubkeyScriptType.P2WPKH, out _))
                    {
                        addrType = AddressType.P2WPKH;
                    }
                    else
                    {
                        return(false);
                    }
                }
                else
                {
                    addrType = sig.RecoveryId < 31 ? AddressType.P2PKH_Uncompressed : AddressType.P2PKH_Compressed;
                }
            }
            else if (sig.RecoveryId >= 35 && sig.RecoveryId < 39)
            {
                if (!addr.VerifyType(address, Blockchain.Scripts.PubkeyScriptType.P2SH, out _))
                {
                    return(false);
                }
                addrType = AddressType.P2SH_P2WPKH;
            }
            else if (sig.RecoveryId >= 39 && sig.RecoveryId < 43)
            {
                if (!addr.VerifyType(address, Blockchain.Scripts.PubkeyScriptType.P2WPKH, out _))
                {
                    return(false);
                }
                addrType = AddressType.P2WPKH;
            }

            EllipticCurveCalculator calc = new EllipticCurveCalculator();

            if (!calc.TryRecoverPublicKeys(toSign, sig, out EllipticCurvePoint[] points))
Example #5
0
        public PublicKey()
        {
            addrMaker = new Address();
            IECurveFp curve = new SecP256k1();

            calc     = new EllipticCurveCalculator(curve);
            byteSize = (int)Math.Ceiling((double)curve.SizeInBits / 8);
        }
Example #6
0
        public PublicKey[] GetPublicKeys(BIP0032Path path, uint count, uint startIndex = 0, uint step = 1)
        {
            if (isDisposed)
            {
                throw new ObjectDisposedException(nameof(BIP0032));
            }
            if (path is null)
            {
                throw new ArgumentNullException(nameof(path), "Path can not be null!");
            }
            if (ExtendedKeyDepth == byte.MaxValue || ExtendedKeyDepth + path.Indexes.Length + 1 > byte.MaxValue)
            {
                throw new ArgumentOutOfRangeException(nameof(ExtendedKeyDepth), "Can not get children since " +
                                                      "depth will be bigger than 1 byte");
            }

            PublicKey[] result = new PublicKey[count];
            if (!(PrvKey is null))
            {
                PrivateKey[] tempPK = GetPrivateKeys(path, count, startIndex, step);
                for (int j = 0; j < tempPK.Length; j++)
                {
                    result[j] = tempPK[j].ToPublicKey();
                    tempPK[j].Dispose();
                }
                return(result);
            }

            // If we are here it means PrivateKey was null
            bool anyHardened = path.Indexes.Any(x => IsHardendedIndex(x));

            if (anyHardened || IsHardendedIndex(startIndex))
            {
                throw new ArgumentException();
            }

            // Two quick fixes:
            if (count == 0)
            {
                return(null);
            }
            if (step < 1)
            {
                step = 1;
            }

            // First start deriving the extended keys for each index
            BigInteger prevPrvInt = PrvKey.ToBigInt();

            byte[]             prevPubBa    = PubKey.ToByteArray(true);
            EllipticCurvePoint prevPubPoint = PubKey.ToPoint();

            byte[] tempCC = ChainCode;
            byte[] tempLeft;
            EllipticCurveCalculator calc = new EllipticCurveCalculator();

            foreach (var index in path.Indexes)
            {
                // There is no hardened indexes thanks to first check
                FastStream stream = new FastStream(33 + 4);
                stream.Write(prevPubBa);
                stream.WriteBigEndian(index);
                HmacAndSplitData(stream.ToByteArray(), tempCC, out tempLeft, out tempCC);

                BigInteger kTemp = tempLeft.ToBigInt(true, true);
                // Note that we throw an exception here if the values were invalid (highly unlikely)
                // because it is the extended keys, we can't skip anything here.
                if (kTemp == 0 || kTemp >= N)
                {
                    throw new ArgumentException();
                }
                EllipticCurvePoint pt      = calc.AddChecked(calc.MultiplyByG(kTemp), prevPubPoint);
                PublicKey          tempPub = new PublicKey(pt);
                prevPubPoint = tempPub.ToPoint();
                prevPubBa    = tempPub.ToByteArray(true);
            }

            // Then derive the actual keys

            int  i          = 0;
            uint childIndex = startIndex;

            while (i < count)
            {
                // There is no hardened indexes thanks to first check
                FastStream stream = new FastStream(33 + 4);
                stream.Write(prevPubBa);
                stream.WriteBigEndian(childIndex);
                HmacAndSplitData(stream.ToByteArray(), tempCC, out tempLeft, out _);

                BigInteger kTemp = tempLeft.ToBigInt(true, true);
                // Note: we don't throw any exceptions here. We simply ignore invalid values (highly unlikely)
                // and move on to the next index. The returned value will always be filled with expected number of items.
                if (kTemp == 0 || kTemp >= N)
                {
                    continue;
                }
                EllipticCurvePoint pt   = calc.AddChecked(calc.MultiplyByG(kTemp), prevPubPoint);
                PublicKey          temp = new PublicKey(pt);
                result[i++] = temp;

                childIndex += step;
            }
            return(result);
        }
Example #7
0
        private unsafe bool LoopComp(string key, int missingCount, char missingChar, byte[] expectedHash)
        {
            int[]  missingIndexes = new int[missingCount];
            byte[] ba             = new byte[32];
            for (int i = 0, j = 0; i < ba.Length; i++)
            {
                int hi, lo;
                if (key[i * 2] == missingChar)
                {
                    hi = 0;
                    missingIndexes[j++] = i * 2;
                }
                else
                {
                    hi = key[i * 2] - 65;
                    hi = hi + 10 + ((hi >> 31) & 7);
                }
                if (key[i * 2 + 1] == '*')
                {
                    lo = 0;
                    missingIndexes[j++] = i * 2 + 1;
                }
                else
                {
                    lo = key[i * 2 + 1] - 65;
                    lo = lo + 10 + ((lo >> 31) & 7) & 0x0f;
                }

                ba[i] = (byte)(lo | hi << 4);
            }

            var cartesian = CartesianProduct.Create(Enumerable.Repeat(Enumerable.Range(0, 16), missingCount));
            EllipticCurveCalculator calc = new EllipticCurveCalculator();



            BigInteger         smallVal = new BigInteger(ba, true, true);
            EllipticCurvePoint smallPub = calc.MultiplyByG(smallVal);
            Ripemd160Sha256    hash     = new Ripemd160Sha256();

            Parallel.ForEach(cartesian, (item, loopState) =>
            {
                Span <byte> temp = new byte[32];

                int mis = 0;
                foreach (int keyItem in item)
                {
                    int misIndex = missingIndexes[mis];
                    if (misIndex % 2 == 0)
                    {
                        temp[misIndex / 2] |= (byte)(keyItem << 4);
                    }
                    else
                    {
                        temp[misIndex / 2] |= (byte)keyItem;
                    }
                    mis++;
                }

                BigInteger tempVal         = new BigInteger(temp, true, true);
                EllipticCurvePoint tempPub = calc.MultiplyByG(tempVal);
                EllipticCurvePoint pub     = calc.AddChecked(tempPub, smallPub);
                byte[] toHash = new byte[33];
                toHash[0]     = pub.Y.IsEven ? (byte)2 : (byte)3;
                byte[] xBytes = pub.X.ToByteArray(true, true);
                Buffer.BlockCopy(xBytes, 0, toHash, 33 - xBytes.Length, xBytes.Length);

                ReadOnlySpan <byte> actual = hash.ComputeHash(toHash);
                if (actual.SequenceEqual(expectedHash))
                {
                    char[] origHex = key.ToCharArray();
                    int index      = 0;
                    foreach (var keyItem in item)
                    {
                        origHex[missingIndexes[index++]] = GetHex(keyItem);
                    }
                    AddQueue($"Found a key: {new string(origHex)}");
                    loopState.Break();
                }
            });


            AddQueue("Failed to find any key.");
            return(false);
        }
Example #8
0
 public MnemonicSevice(IReport rep)
 {
     report       = rep;
     inputService = new InputService();
     calc         = new EllipticCurveCalculator();
 }
 public MessageSignatureService(Report rep) : base(rep)
 {
     calc           = new EllipticCurveCalculator(new SecP256k1());
     addressBuilder = new Address();
     inputService   = new InputService();
 }