Example #1
0
        /// <summary>
        /// </summary>
        /// <param name="normalizedBundleFragment"></param>
        /// <param name="signatureFragment"></param>
        /// <returns></returns>
        public int[] Digest(int[] normalizedBundleFragment, int[] signatureFragment)
        {
            _curl.Reset();
            var buffer = new int[243];

            for (var i = 0; i < 27; i++)
            {
                buffer = ArrayUtils.SubArray(signatureFragment, i * 243, (i + 1) * 243);

                var jCurl = new Kerl();

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

                _curl.Absorb(buffer);
            }

            _curl.Squeeze(buffer);

            return(buffer);
        }
Example #2
0
        public static void FinalizeBundleHash(this IEnumerable <TransactionItem> transactionItems)
        {
            var validBundle = false;

            while (!validBundle)
            {
                var kerl = new Kerl();
                kerl.Reset();
                var transactionCount = transactionItems.Count();

                for (int i = 0; i < transactionCount; i++)
                {
                    var transaction = transactionItems.ElementAt(i);

                    var valueTrits = Converter.GetTrits(transaction.Value).ToLength(81);

                    var timestampTrits = Converter.GetTrits(transaction.Timestamp).ToLength(27);

                    var currentIndexTrits = Converter.GetTrits(transaction.CurrentIndex = ("" + i)).ToLength(27);

                    var lastIndexTrits = Converter.GetTrits(
                        transaction.LastIndex = ("" + (transactionCount - 1))).ToLength(27);

                    string stringToConvert = transaction.Address
                                             + Converter.GetTrytes(valueTrits)
                                             + transaction.Tag +
                                             Converter.GetTrytes(timestampTrits)
                                             + Converter.GetTrytes(currentIndexTrits) +
                                             Converter.GetTrytes(lastIndexTrits);

                    var t = Converter.GetTrits(stringToConvert);
                    kerl.Absorb(t, 0, t.Length);
                }

                sbyte[] hash = new sbyte[Curl.HASH_LENGTH];
                kerl.Squeeze(hash, 0, hash.Length);
                string hashInTrytes = Converter.GetTrytes(hash);

                foreach (var transaction in transactionItems)
                {
                    transaction.Bundle = hashInTrytes;
                }

                var normalizedHash = NormalizedBundle(hashInTrytes);
                if (normalizedHash.Contains(13))
                {
                    // Insecure bundle. Increment Tag and recompute bundle hash.
                    var firstTransaction = transactionItems.ElementAt(0);
                    var increasedTag     = Adder.Add(Converter.GetTrits(firstTransaction.Tag), new sbyte[1]);
                    firstTransaction.Tag = Converter.GetTrytes(increasedTag);
                }
                else
                {
                    validBundle = true;
                }
            }
        }
Example #3
0
        public void ShouldCreateValidHash1()
        {
            sbyte[] trits =
                Converter.ToTrits("GYOMKVTSNHVJNCNFBBAH9AAMXLPLLLROQY99QN9DLSJUHDPBLCFFAIQXZA9BKMBJCYSFHFPXAHDWZFEIZ");
            Kerl kerl = (Kerl)SpongeFactory.Create(SpongeFactory.Mode.KERL);

            kerl.Reset();
            kerl.Absorb(trits, 0, trits.Length);
            sbyte[] hashTrits = new sbyte[trits.Length];
            kerl.Squeeze(hashTrits, 0, 243);
            string hash = Converter.ToTrytes(hashTrits);

            Assert.AreEqual(hash, "OXJCNFHUNAHWDLKKPELTBFUCVW9KLXKOGWERKTJXQMXTKFKNWNNXYD9DMJJABSEIONOSJTTEVKVDQEWTW");
        }
Example #4
0
        private static string CalculateChecksum(string address)
        {
            // TODO inject curl
            ICurl curl = new Kerl();

            curl.Reset();
            curl.Absorb(Converter.ToTrits(address));
            var checksumTrits = new int[Sponge.HashLength];

            curl.Squeeze(checksumTrits);
            var checksum = Converter.ToTrytes(checksumTrits);

            return(checksum.Substring(72, 9));
        }
Example #5
0
        public void ShouldCreateValidHash2()
        {
            sbyte[] trits =
                Converter.ToTrits("9MIDYNHBWMBCXVDEFOFWINXTERALUKYYPPHKP9JJFGJEIUY9MUDVNFZHMMWZUYUSWAIOWEVTHNWMHANBH");
            Kerl kerl = (Kerl)SpongeFactory.Create(SpongeFactory.Mode.KERL);

            kerl.Reset();
            kerl.Absorb(trits, 0, trits.Length);
            sbyte[] hashTrits = new sbyte[trits.Length * 2];
            kerl.Squeeze(hashTrits, 0, 243 * 2);
            string hash = Converter.ToTrytes(hashTrits);

            Assert.AreEqual(hash,
                            "G9JYBOMPUXHYHKSNRNMMSSZCSHOFYOYNZRSZMAAYWDYEIMVVOGKPJBVBM9TDPULSFUNMTVXRKFIDOHUXXVYDLFSZYZTWQYTE9SPYYWYTXJYQ9IFGYOLZXWZBKWZN9QOOTBQMWMUBLEWUEEASRHRTNIQWJQNDWRYLCA");
        }
Example #6
0
        public void ShouldCreateValidHash1()
        {
            var trits = Converter.ToTrits(
                "GYOMKVTSNHVJNCNFBBAH9AAMXLPLLLROQY99QN9DLSJUHDPBLCFFAIQXZA9BKMBJCYSFHFPXAHDWZFEIZ");
            var kerl = new Kerl();

            kerl.Reset();
            kerl.Absorb(trits, 0, trits.Length);
            var hashTrits = new int[trits.Length];

            kerl.Squeeze(hashTrits, 0, 243);
            var hash = Converter.ToTrytes(hashTrits);

            Assert.AreEqual(hash, "OXJCNFHUNAHWDLKKPELTBFUCVW9KLXKOGWERKTJXQMXTKFKNWNNXYD9DMJJABSEIONOSJTTEVKVDQEWTW");
        }
Example #7
0
        public void ShouldCreateValidHash3()
        {
            sbyte[] trits =
                Converter.ToTrits(
                    "G9JYBOMPUXHYHKSNRNMMSSZCSHOFYOYNZRSZMAAYWDYEIMVVOGKPJBVBM9TDPULSFUNMTVXRKFIDOHUXXVYDLFSZYZTWQYTE9SPYYWYTXJYQ9IFGYOLZXWZBKWZN9QOOTBQMWMUBLEWUEEASRHRTNIQWJQNDWRYLCA");
            Kerl kerl = (Kerl)SpongeFactory.Create(SpongeFactory.Mode.KERL);

            kerl.Reset();
            kerl.Absorb(trits, 0, trits.Length);
            sbyte[] hashTrits = new sbyte[trits.Length];
            kerl.Squeeze(hashTrits, 0, 243 * 2);
            string hash = Converter.ToTrytes(hashTrits);

            Assert.AreEqual(hash,
                            "LUCKQVACOGBFYSPPVSSOXJEKNSQQRQKPZC9NXFSMQNRQCGGUL9OHVVKBDSKEQEBKXRNUJSRXYVHJTXBPDWQGNSCDCBAIRHAQCOWZEBSNHIJIGPZQITIBJQ9LNTDIBTCQ9EUWKHFLGFUVGGUWJONK9GBCDUIMAYMMQX");
        }
Example #8
0
        /// <summary>
        /// The compute hash.
        /// </summary>
        /// <returns>
        /// The <see cref="Hash"/>.
        /// </returns>
        private Hash ComputeHash()
        {
            Hash bundleHash;
            var  valid = false;
            var  kerl  = new Kerl();

            do
            {
                kerl.Reset();
                for (var i = 0; i < this.Transactions.Count; i++)
                {
                    this.Transactions[i].CurrentIndex = i;
                    this.Transactions[i].LastIndex    = this.Transactions.Count - 1;

                    var transactionTrits = Converter.TrytesToTrits(this.Transactions[i].SignatureValidationTrytes());
                    kerl.Absorb(transactionTrits);
                }

                var hashTrits = new int[Constants.TritHashLength];
                kerl.Squeeze(hashTrits);
                bundleHash = new Hash(Converter.TritsToTrytes(hashTrits));
                var normalizedBundleValue = Hash.Normalize(bundleHash);

                if (Array.IndexOf(normalizedBundleValue, 13) != -1)
                {
                    var obsoleteTagTrits = Converter.TrytesToTrits(this.Transactions[0].ObsoleteTag.Value);
                    Converter.Increment(obsoleteTagTrits, Hash.Length);
                    this.Transactions[0].ObsoleteTag = new Tag(Converter.TritsToTrytes(obsoleteTagTrits));
                }
                else
                {
                    valid = true;
                }
            }while (!valid);

            return(bundleHash);
        }
Example #9
0
        /// <summary>
        ///     This function returns the bundle which is associated with a transaction. Input can by any type of transaction (tail
        ///     and non-tail).
        ///     If there are conflicting bundles (because of a replay for example) it will return multiple bundles.
        ///     It also does important validation checking (signatures, sum, order) to ensure that the correct bundle is returned.
        /// </summary>
        /// <param name="transaction">the transaction encoded in trytes</param>
        /// <returns>an array of bundle, if there are multiple arrays it means that there are conflicting bundles.</returns>
        public Bundle GetBundle(string transaction)
        {
            if (!InputValidator.IsHash(transaction))
            {
                throw new ArgumentException("Invalid hashes provided.");
            }

            var bundle = TraverseBundle(transaction, null, new Bundle());

            if (bundle == null)
            {
                throw new ArgumentException("Unknown Bundle");
            }

            long totalSum   = 0;
            var  bundleHash = bundle.Transactions[0].Bundle;

            ICurl curl = new Kerl();

            curl.Reset();

            var signaturesToValidate = new List <Signature>();

            for (var index = 0; index < bundle.Transactions.Count; index++)
            {
                var bundleTransaction = bundle.Transactions[index];
                var bundleValue       = bundleTransaction.Value;
                totalSum += bundleValue;

                if (bundleTransaction.CurrentIndex != index)
                {
                    throw new InvalidBundleException("The index of the bundle " + bundleTransaction.CurrentIndex +
                                                     " did not match the expected index " + index);
                }

                // Get the transaction trytes
                var thisTxTrytes = bundleTransaction.ToTransactionTrytes().Substring(2187, 162);

                // Absorb bundle hash + value + timestamp + lastIndex + currentIndex trytes.
                curl.Absorb(Converter.ToTrits(thisTxTrytes));

                // Check if input transaction
                if (bundleValue < 0)
                {
                    var address = bundleTransaction.Address;
                    var sig     = new Signature {
                        Address = address
                    };
                    sig.SignatureFragments.Add(bundleTransaction.SignatureMessageFragment);

                    // Find the subsequent txs with the remaining signature fragment
                    for (var i = index + 1; i < bundle.Transactions.Count; i++)
                    {
                        var newBundleTx = bundle.Transactions[i];

                        // Check if new tx is part of the signature fragment
                        if (newBundleTx.Address == address && newBundleTx.Value == 0)
                        {
                            if (sig.SignatureFragments.IndexOf(newBundleTx.SignatureMessageFragment) == -1)
                            {
                                sig.SignatureFragments.Add(newBundleTx.SignatureMessageFragment);
                            }
                        }
                    }

                    signaturesToValidate.Add(sig);
                }
            }

            // Check for total sum, if not equal 0 return error
            if (totalSum != 0)
            {
                throw new InvalidBundleException("Invalid Bundle Sum");
            }

            var bundleFromTrxs = new int[243];

            curl.Squeeze(bundleFromTrxs);
            var bundleFromTxString = Converter.ToTrytes(bundleFromTrxs);

            // Check if bundle hash is the same as returned by tx object
            if (!bundleFromTxString.Equals(bundleHash))
            {
                throw new InvalidBundleException("Invalid Bundle Hash");
            }
            // Last tx in the bundle should have currentIndex === lastIndex
            bundle.Length = bundle.Transactions.Count;
            if (
                !bundle.Transactions[bundle.Length - 1].CurrentIndex.Equals(
                    bundle.Transactions[bundle.Length - 1].LastIndex))
            {
                throw new InvalidBundleException("Invalid Bundle");
            }

            // Validate the signatures
            foreach (var aSignaturesToValidate in signaturesToValidate)
            {
                var signatureFragments = aSignaturesToValidate.SignatureFragments.ToArray();
                var address            = aSignaturesToValidate.Address;
                var isValidSignature   = new Signing().ValidateSignatures(address, signatureFragments, bundleHash);

                if (!isValidSignature)
                {
                    throw new InvalidSignatureException();
                }
            }

            return(bundle);
        }
Example #10
0
        /// <summary>
        /// The finalize.
        /// </summary>
        public void Finalize()
        {
            if (this.Hash != null)
            {
                throw new InvalidOperationException("BundleHash is already finalized!");
            }

            if (this.Transactions.Count == 0)
            {
                throw new ArgumentException("At least one transaction must be added before finalizing bundle.");
            }

            var balance = this.Balance;

            if (balance < 0)
            {
                if (this.RemainderAddress != null && !string.IsNullOrEmpty(this.RemainderAddress.Value))
                {
                    this.Transactions.Add(new Transaction {
                        Address = this.RemainderAddress, Tag = Tag.Empty, Value = -balance, ObsoleteTag = Tag.Empty
                    });
                }
                else
                {
                    throw new InvalidOperationException("BundleHash balance is not even. Add remainder address.");
                }
            }

            if (balance > 0)
            {
                throw new InvalidOperationException("Insufficient value submitted.");
            }

            string bundleHashTrytes;
            var    valid = false;
            var    kerl  = new Kerl();

            do
            {
                kerl.Reset();
                for (var i = 0; i < this.Transactions.Count; i++)
                {
                    this.Transactions[i].CurrentIndex = i;
                    this.Transactions[i].LastIndex    = this.Transactions.Count - 1;

                    var transactionTrits = Converter.TrytesToTrits(this.Transactions[i].ToTrytes());
                    kerl.Absorb(transactionTrits);
                }

                var hash = new int[Kerl.HashLength];
                kerl.Squeeze(hash);
                bundleHashTrytes = Converter.TritsToTrytes(hash);
                var normalizedBundleValue = NormalizeBundle(bundleHashTrytes);

                if (Array.IndexOf(normalizedBundleValue, 13) != -1)
                {
                    var obsoleteTagTrits = Converter.TrytesToTrits(this.Transactions[0].ObsoleteTag.Value);
                    Converter.Increment(obsoleteTagTrits, 81);
                    this.Transactions[0].ObsoleteTag = new Tag(Converter.TritsToTrytes(obsoleteTagTrits));
                }
                else
                {
                    valid = true;
                }
            }while (!valid);

            this.Hash = new Hash(bundleHashTrytes);
            foreach (var transaction in this.Transactions)
            {
                transaction.BundleHash = this.Hash;
            }
        }