示例#1
0
        public int[] Digest(int[] normalizedBundleFragment, int[] signatureFragment)
        {
            curl.Reset();
            int[] buffer = new int[243];

            for (int i = 0; i < 27; i++)
            {
                buffer = ArrayUtils.SubArray(signatureFragment, i * 243, 243);
                ;
                ICurl jCurl = curl.Clone();

                for (int j = normalizedBundleFragment[i] + 13; j-- > 0;)
                {
                    jCurl.Reset();
                    jCurl.Absorb(buffer);
                    jCurl.Squeeze(buffer);
                }
                curl.Absorb(buffer);
            }
            curl.Squeeze(buffer);

            return(buffer);
        }
示例#2
0
        /// <summary>
        ///     Main purpose of this function is to get an array of transfer objects as input, and then prepare the transfer by
        ///     generating the correct bundle,
        ///     as well as choosing and signing the inputs if necessary (if it's a value transfer). The output of this function is
        ///     an array of the raw transaction data (trytes)
        /// </summary>
        /// <param name="seed">81-tryte encoded address of recipient</param>
        /// <param name="security"></param>
        /// <param name="transfers">the transfers to prepare</param>
        /// <param name="inputs">Optional (default null). The inputs</param>
        /// <param name="remainderAddress">
        ///     Optional (default null). if defined, this address will be used for sending the remainder
        ///     value (of the inputs) to.
        /// </param>
        /// <param name="validateInputs"></param>
        /// <returns>a list containing the trytes of the new bundle</returns>
        public List <string> PrepareTransfers(
            string seed, int security,
            Transfer[] transfers,
            string remainderAddress,
            List <Input> inputs,
            bool validateInputs)
        {
            // validate seed
            if (!InputValidator.IsValidSeed(seed))
            {
                throw new IllegalStateException("Invalid seed provided.");
            }


            if (security < 1)
            {
                throw new ArgumentException("Invalid security level provided.");
            }

            // Input validation of transfers object
            InputValidator.CheckTransferArray(transfers);

            // Create a new bundle
            var bundle             = new Bundle();
            var signatureFragments = new List <string>();

            long totalValue = 0;
            var  tag        = "";

            //
            //  Iterate over all transfers, get totalValue
            //  and prepare the signatureFragments, message and tag
            //
            foreach (var transfer in transfers)
            {
                // remove the checksum of the address if provided
                transfer.Address = transfer.Address.RemoveChecksum();

                var signatureMessageLength = 1;

                // If message longer than 2187 trytes, increase signatureMessageLength (add 2nd transaction)
                if (transfer.Message.Length > Constants.MessageLength)
                {
                    // Get total length, message / maxLength (2187 trytes)
                    signatureMessageLength += (int)Math.Floor((double)transfer.Message.Length / Constants.MessageLength);

                    var msgCopy = transfer.Message;

                    // While there is still a message, copy it
                    while (!string.IsNullOrEmpty(msgCopy))
                    {
                        var fragment = msgCopy.Substring(0, 2187 > msgCopy.Length ? msgCopy.Length : 2187);
                        msgCopy = msgCopy.Substring(2187, msgCopy.Length - 2187);

                        // Pad remainder of fragment
                        while (fragment.Length < 2187)
                        {
                            fragment += '9';
                        }

                        signatureFragments.Add(fragment);
                    }
                }
                else
                {
                    // Else, get single fragment with 2187 of 9's trytes
                    var fragment = string.Empty;

                    if (!string.IsNullOrEmpty(transfer.Message))
                    {
                        fragment = transfer.Message.Substring(0,
                                                              transfer.Message.Length < 2187 ? transfer.Message.Length : 2187);
                    }

                    while (fragment.Length < 2187)
                    {
                        fragment += '9';
                    }

                    signatureFragments.Add(fragment);
                }

                // get current timestamp in seconds
                var timestamp = (long)Math.Floor((double)IotaApiUtils.CreateTimeStampNow() / 1000);

                // If no tag defined, get 27 tryte tag.

                tag = string.IsNullOrEmpty(transfer.Tag) ? "999999999999999999999999999" : transfer.Tag;


                // Pad for required 27 tryte length
                while (tag.Length < 27)
                {
                    tag += '9';
                }


                // Add first entries to the bundle
                // Slice the address in case the user provided a checksummed one
                bundle.AddEntry(signatureMessageLength, transfer.Address, transfer.Value, tag, timestamp);
                // Sum up total value
                totalValue += transfer.Value;
            }

            // Get inputs if we are sending tokens
            if (totalValue != 0)
            {
                if (inputs != null && inputs.Count > 0)
                {
                    // Get list if addresses of the provided inputs
                    var inputAddresses = new List <string>();
                    foreach (var input in inputs)
                    {
                        inputAddresses.Add(input.Address);
                    }

                    var balances = GetBalances(inputAddresses, 100);

                    var confirmedInputs = new List <Input>();

                    long totalBalance = 0;
                    for (var i = 0; i < balances.Balances.Count; i++)
                    {
                        var thisBalance = balances.Balances[i];
                        totalBalance += thisBalance;

                        // If input has balance, add it to confirmedInputs
                        if (thisBalance > 0)
                        {
                            var inputEl = inputs[i];
                            inputEl.Balance = thisBalance;

                            confirmedInputs.Add(inputEl);
                        }
                    }

                    // Return not enough balance error
                    if (totalValue > totalBalance)
                    {
                        throw new NotEnoughBalanceException(totalValue);
                    }

                    return(AddRemainder(seed, security, confirmedInputs, bundle, tag, totalValue, remainderAddress,
                                        signatureFragments));
                }

                //  Case 2: Get inputs deterministically
                //
                //  If no inputs provided, derive the addresses from the seed and
                //  confirm that the inputs exceed the threshold
                else
                {
                    var inputList = GetInputs(seed, security, 0, 0, (int)totalValue).InputsList;
                    return(AddRemainder(seed, security, inputList, bundle, tag, totalValue, remainderAddress,
                                        signatureFragments));
                }
            }

            // If no input required, don't sign and simply finalize the bundle
            bundle.FinalizeBundle(_curl.Clone());
            bundle.AddTrytes(signatureFragments);

            var bundleTrytes = new List <string>();

            bundle.Transactions.ForEach(tx => bundleTrytes.Add(tx.ToTransactionTrytes()));

            bundleTrytes.Reverse();
            return(bundleTrytes);
        }
示例#3
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="bundle"></param>
        /// <param name="curl"></param>
        /// <returns></returns>
        public static bool IsBundle(Bundle bundle, ICurl curl = null)
        {
            if (curl == null)
            {
                curl = SpongeFactory.Create(SpongeFactory.Mode.KERL);
            }


            long totalSum  = 0;
            int  lastIndex = bundle.Length - 1;

            for (int i = 0; i < bundle.Length; i++)
            {
                var tx = bundle.Transactions[i];
                totalSum += tx.Value;

                if (tx.CurrentIndex != i)
                {
                    throw new ArgumentException(Constants.INVALID_BUNDLE_ERROR);
                }
                if (tx.LastIndex != lastIndex)
                {
                    throw new ArgumentException(Constants.INVALID_BUNDLE_ERROR);
                }

                sbyte[] txTrits = Converter.ToTrits(tx.ToTrytes().Substring(2187, 162));
                curl.Absorb(txTrits);

                // continue if output or signature tx
                if (tx.Value >= 0)
                {
                    continue;
                }

                // here we have an input transaction (negative value)
                List <string> fragments = new List <string> {
                    tx.SignatureMessageFragment
                };

                // find the subsequent txs containing the remaining signature
                // message fragments for this input transaction
                for (int j = i; j < bundle.Length - 1; j++)
                {
                    Transaction tx2 = bundle.Transactions[j + 1];

                    // check if the tx is part of the input transaction
                    if (tx.Address.Equals(tx2.Address, StringComparison.Ordinal) && tx2.Value == 0)
                    {
                        // append the signature message fragment
                        fragments.Add(tx2.SignatureMessageFragment);
                    }
                }

                bool valid = new Signing(curl.Clone()).ValidateSignatures(tx.Address, fragments.ToArray(), tx.Bundle);
                if (!valid)
                {
                    throw new ArgumentException(Constants.INVALID_SIGNATURES_ERROR);
                }
            }

            // sum of all transaction must be 0
            if (totalSum != 0)
            {
                throw new ArgumentException(Constants.INVALID_BUNDLE_SUM_ERROR);
            }

            sbyte[] bundleHashTrits = new sbyte[Sponge.HASH_LENGTH];
            curl.Squeeze(bundleHashTrits, 0, Sponge.HASH_LENGTH);
            string bundleHash = Converter.ToTrytes(bundleHashTrits);

            if (!bundleHash.Equals(bundle.Transactions[0].Bundle, StringComparison.Ordinal))
            {
                throw new ArgumentException(Constants.INVALID_BUNDLE_HASH_ERROR);
            }
            return(true);
        }