Пример #1
0
        /// <summary>
        /// Create the signing bag with matching scripts and private keys
        /// Then sign the inputs.
        /// </summary>
        public Transaction Sign(CoinParameters parameters, SignRawTransaction rawTransactions)
        {
            var transaction = this.Serializer.FromHex(rawTransactions.RawTransactionHex);
            var bag         = new TransactionSigner.SignerBag {
                Items = new List <TransactionSigner.RedeemScript>()
            };
            var keys = rawTransactions.PrivateKeys.Select(s => new BitcoinPrivateKey(parameters, s)).ToList();

            // create a linked object between the pub key hash and its outpoint
            var inputs = rawTransactions.Inputs
                         .Select(input => new { Input = input, PubKeyHash = new Script.Script(CryptoUtil.ConvertHex(input.ScriptPubKey)).TryGetPubKeyHash() })
                         .Where(p => p.PubKeyHash.IsNotNull()).ToList();

            // compare private keys with redeem script pub key hash and add to the bag
            foreach (var key in keys)
            {
                // there should be at least one redeem script per private key
                var inserts = inputs.Where(f => f.PubKeyHash.SequenceEqual(key.Hash160)).ToList();
                Thrower.If(inserts.None()).Throw <TransactionException>("Private key had no matching redeem script '{0}'".StringFormat(key.PublicKey.ToAddress(parameters).ToString()));
                inserts.ForEach(insert => bag.Add(insert.Input.TransactionId, insert.Input.Output, insert.Input.ScriptPubKey, key));
            }

            this.Signer.SignInputs(transaction, bag);

            return(transaction);
        }
Пример #2
0
        /// <summary>
        /// The resolve.
        /// </summary>
        public static bool PopulateCoinParameters(CoinParameters param)
        {
            // places to look for the network parameters
            // https://github.com/bitcoin/bitcoin/blob/d612837814020ae832499d18e6ee5eb919a87907/src/chainparams.cpp
            // https://github.com/CrypticApplications/MTR-Update/blob/master/src/base58.h
            // example MTR => private key prefix is [128 + CBitcoinAddress::PUBKEY_ADDRESS]

            List <int> vals;

            if (Params.TryGetValue(param.CoinTag, out vals))
            {
                param.PublicKeyAddressVersion = vals.ElementAt(0);
                param.ScriptAddressVersion    = vals.ElementAt(1);
                param.ExtendedKeyIndex        = vals.ElementAt(2);
                param.PrivateKeyVersion       = vals.ElementAt(3);

                Thrower.If(param.PrivateKeyVersion == -1).Throw <AddressException>();
                Thrower.If(param.ExtendedKeyIndex == -1).Throw <AddressException>();
                Thrower.If(param.PublicKeyAddressVersion == -1).Throw <AddressException>();

                return(true);
            }

            return(false);
        }
Пример #3
0
        public void SignInputs(Transaction transaction, SignerBag bag)
        {
            foreach (var transactionInput in transaction.Inputs)
            {
                var redeem = bag.Find(transactionInput.Outpoint);
                Thrower.If(redeem.IsNull()).Throw <TransactionException>("redeem script was not found");

                var redeemScript = new Script.Script(CryptoUtil.ConvertHex(redeem.ScriptPubKeyHex));

                var signature = this.CalculateSignature(transaction, transactionInput.Outpoint, redeem.PrivateKey.Key, redeemScript, Transaction.SigHash.All);

                var signedScript = ScriptBuilder.CreateInputScript(signature, redeem.PrivateKey.Key);

                transactionInput.ScriptBytes = signedScript.GetProgram();
            }
        }
Пример #4
0
        /// <summary>
        /// Create a bitcoin address from an imported string.
        /// </summary>
        public static Address Create(CoinParameters coinParameters, string address)
        {
            var decoded = Base58Encoding.DecodeWithCheckSum(address);
            var version = decoded.First();
            var hash    = decoded.Skip(1).ToArray();

            Thrower.If(hash.Length != Length).Throw <AddressException>("Invalid length? expected={0} found={1}", Length, hash.Length);
            Thrower.If(
                version != coinParameters.PublicKeyAddressVersion &&
                version != coinParameters.ScriptAddressVersion)
            .Throw <AddressException>("Mismatched version number, trying to cross networks? expected={0},{1} found={2}", coinParameters.PublicKeyAddressVersion, coinParameters.ScriptAddressVersion, version);

            return(new Address {
                Hash160 = hash, CoinParameters = coinParameters, AddressVersion = version
            });
        }
Пример #5
0
        /// <summary>
        /// Returns the public key in this script. If a script contains two constants and nothing else, it is assumed to
        /// be a scriptSig (input) for a pay-to-address output and the second constant is returned (the first is the
        /// signature). If a script contains a constant and an ScriptOpCodes.OP_CHECKSIG opcode, the constant is returned as it is
        /// assumed to be a direct pay-to-key scriptPubKey (output) and the first constant is the public key.
        /// </summary>
        public byte[] GetPubKey()
        {
            Thrower.If(this.Chunks.Count() != 2).Throw <ScriptException>("Script not of right size, expecting 2 but got " + this.Chunks.Count());

            ScriptChunk firstChunk  = this.Chunks.ElementAt(0);
            ScriptChunk secondChunk = this.Chunks.ElementAt(1);

            if (firstChunk.Data != null && firstChunk.Data.Length > 2 && secondChunk.Data != null && secondChunk.Data.Length > 2)
            {
                // If we have two large constants assume the input to a pay-to-address output.
                return(secondChunk.Data);
            }

            if (secondChunk.EqualsOpCode(ScriptOpCodes.OP_CHECKSIG) && firstChunk.Data != null && firstChunk.Data.Length > 2)
            {
                // A large constant followed by an ScriptOpCodes.OP_CHECKSIG is the key.
                return(firstChunk.Data);
            }

            throw new ScriptException("Script did not match expected form: " + this);
        }
Пример #6
0
        public TransactionSignature CalculateSignature(Transaction transaction, TransactionOutPoint outPoint, EcKey key, Script.Script redeemScript, Transaction.SigHash hashType)
        {
            // at the moment only signing all the outputs is supported
            Thrower.If(hashType != Transaction.SigHash.All).Throw <TransactionException>("Only SigHash type 'All' supported");

            //// clone the transaction and clear all the inputs
            //// only the inputs for the equivalent output needs to be present for signing
            var signTx = transaction.Clone();

            signTx.Inputs.ForEach(input => input.ScriptBytes = Enumerable.Empty <byte>().ToArray());

            // set the redeem script and clear it of 'OP_CODESEPARATOR'
            var connectedScript       = redeemScript.GetProgram();
            var redeemConnectedScript = Script.Script.RemoveAllInstancesOfOp(connectedScript, ScriptOpCodes.OP_CODESEPARATOR);

            signTx.FindInput(outPoint).ScriptBytes = redeemConnectedScript;

            // serialize then hash the transaction to HEX and sign it.
            var trxHex = this.Serializer.ToHex(signTx, hashType);
            var hash   = CryptoUtil.Sha256HashTwice(CryptoUtil.ConvertHex(trxHex));

            return(new TransactionSignature(key.Sign(hash), hashType));
        }
Пример #7
0
 public ExtendedKeyPathBip44 AddChange(uint index)
 {
     Thrower.If(this.Items.Count() > 3).Throw <AddressException>("Change was already added");
     this.AddChild(index);
     return(this);
 }