public void TestGenerateTrytesAndMultiSqueeze() { var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); var isNetStandard = path.Contains("Standard"); var netStandardExtension = isNetStandard ? "../" : ""; // CSV from Python lib. Thanks alot! using (var reader = new StreamReader(@"../" + netStandardExtension + "../Cryptography/generate_trytes_and_multi_squeeze.csv")) { var i = 0; while (!reader.EndOfStream) { var line = reader.ReadLine(); if (line == null || i == 0) { i++; continue; } var values = line.Split(','); var trytes = values[0]; var hashes1 = values[1]; var hashes2 = values[2]; var hashes3 = values[3]; var trits = Converter.TrytesToTrits(trytes); var kerl = new Kerl(); kerl.Absorb(trits); var tritsOut = new int[Constants.TritHashLength]; kerl.Squeeze(tritsOut); var trytesOut = Converter.TritsToTrytes(tritsOut); Assert.AreEqual(hashes1, trytesOut); tritsOut = new int[Constants.TritHashLength]; kerl.Squeeze(tritsOut); trytesOut = Converter.TritsToTrytes(tritsOut); Assert.AreEqual(hashes2, trytesOut); tritsOut = new int[Constants.TritHashLength]; kerl.Squeeze(tritsOut); trytesOut = Converter.TritsToTrytes(tritsOut); Assert.AreEqual(hashes3, trytesOut); i++; } } }
public void TestGenerateTrytesAndMultiSqueeze() { // CSV from Python lib. Thanks alot! using (var reader = new StreamReader(@"../../Tests/Cryptography/generate_trytes_and_multi_squeeze.csv")) { var i = 0; while (!reader.EndOfStream) { var line = reader.ReadLine(); if (line == null || i == 0) { i++; continue; } var values = line.Split(','); var trytes = values[0]; var hashes1 = values[1]; var hashes2 = values[2]; var hashes3 = values[3]; var trits = Converter.TrytesToTrits(trytes); var kerl = new Kerl(); kerl.Absorb(trits); var tritsOut = new int[Kerl.HashLength]; kerl.Squeeze(tritsOut); var trytesOut = Converter.TritsToTrytes(tritsOut); Assert.AreEqual(hashes1, trytesOut); tritsOut = new int[Kerl.HashLength]; kerl.Squeeze(tritsOut); trytesOut = Converter.TritsToTrytes(tritsOut); Assert.AreEqual(hashes2, trytesOut); tritsOut = new int[Kerl.HashLength]; kerl.Squeeze(tritsOut); trytesOut = Converter.TritsToTrytes(tritsOut); Assert.AreEqual(hashes3, trytesOut); i++; } } }
/// <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); }
bool ValidBundle_SingleItem(string transactionTrytes) { var tran = new TransactionItem(transactionTrytes); var bundleHash = tran.Bundle; var bundleTrytes = tran.GetBundleTrytes(); var curl = new Kerl(); String trxTrytes = transactionTrytes.Substring(2187, 162); Assert.AreEqual(bundleTrytes, trxTrytes); // Absorb bundle hash + value + timestamp + lastIndex + currentIndex trytes. curl.Absorb(Utils.Converter.ToTrits(trxTrytes)); int[] bundleFromTrxs = new int[243]; curl.Squeeze(bundleFromTrxs); String bundleFromTxString = Utils.Converter.ToTrytes(bundleFromTrxs); // Check if bundle hash is the same as returned by tx object if (!bundleFromTxString.Equals(bundleHash)) { throw new ArgumentException($"INVALID_BUNDLE_HASH_ERROR: Expected: {bundleFromTxString} but your bundle is {bundleHash}"); } // Last tx in the bundle should have currentIndex === lastIndex //bundle.setLength(bundle.getTransactions().size()); return(tran.CurrentIndex == tran.LastIndex); }
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; } } }
public void kurlMultiAbsorbMultiSqueeze() { int[] initial_value = Converter.ToTrits("G9JYBOMPUXHYHKSNRNMMSSZCSHOFYOYNZRSZMAAYWDYEIMVVOGKPJBVBM9TDPULSFUNMTVXRKFIDOHUXXVYDLFSZYZTWQYTE9SPYYWYTXJYQ9IFGYOLZXWZBKWZN9QOOTBQMWMUBLEWUEEASRHRTNIQWJQNDWRYLCA"); ICurl k = new Kerl(); k.Absorb(initial_value, 0, initial_value.Length); int[] hash_value = new int[Curl.HashLength * 2]; k.Squeeze(hash_value, 0, hash_value.Length); String hash = Converter.ToTrytes(hash_value); Assert.AreEqual("LUCKQVACOGBFYSPPVSSOXJEKNSQQRQKPZC9NXFSMQNRQCGGUL9OHVVKBDSKEQEBKXRNUJSRXYVHJTXBPDWQGNSCDCBAIRHAQCOWZEBSNHIJIGPZQITIBJQ9LNTDIBTCQ9EUWKHFLGFUVGGUWJONK9GBCDUIMAYMMQX", hash); }
public void kurlOneAbsorb() { int[] initial_value = Converter.ToTrits("EMIDYNHBWMBCXVDEFOFWINXTERALUKYYPPHKP9JJFGJEIUY9MUDVNFZHMMWZUYUSWAIOWEVTHNWMHANBH"); ICurl k = new Kerl(); k.Absorb(initial_value, 0, initial_value.Length); int[] hash_value = new int[Curl.HashLength]; k.Squeeze(hash_value, 0, hash_value.Length); String hash = Converter.ToTrytes(hash_value); Assert.AreEqual("EJEAOOZYSAWFPZQESYDHZCGYNSTWXUMVJOVDWUNZJXDGWCLUFGIMZRMGCAZGKNPLBRLGUNYWKLJTYEAQX", hash); }
public void kurlMultiSqueeze() { int[] initial_value = Converter.ToTrits("9MIDYNHBWMBCXVDEFOFWINXTERALUKYYPPHKP9JJFGJEIUY9MUDVNFZHMMWZUYUSWAIOWEVTHNWMHANBH"); ICurl k = new Kerl(); k.Absorb(initial_value, 0, initial_value.Length); int[] hash_value = new int[Curl.HashLength * 2]; k.Squeeze(hash_value, 0, hash_value.Length); String hash = Converter.ToTrytes(hash_value); Assert.AreEqual("G9JYBOMPUXHYHKSNRNMMSSZCSHOFYOYNZRSZMAAYWDYEIMVVOGKPJBVBM9TDPULSFUNMTVXRKFIDOHUXXVYDLFSZYZTWQYTE9SPYYWYTXJYQ9IFGYOLZXWZBKWZN9QOOTBQMWMUBLEWUEEASRHRTNIQWJQNDWRYLCA", hash); }
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)); }
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"); }
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"); }
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"); }
public void Test() { var trits = Converter.GetTrits(input); var kerl = new Kerl(); kerl.Initialize(); kerl.Absorb(trits, 0, trits.Length); var hashTrits = new sbyte[Curl.HASH_LENGTH]; kerl.Squeeze(hashTrits, 0, Curl.HASH_LENGTH); var hash = Converter.GetTrytes(hashTrits); Assert.AreEqual(expected, hash); //assert.deepEqual(test.expected, hash); }
public void TestKerlOneAbsorb() { var tritValue = Converter.TrytesToTrits("KFNNRVYTYYYNHJLBTXOEFYBZTHGXHTX9XKXB9KUZDHGLKBQGPQCNHPGDSGYKWGHVXVLHPOEAWREBIVK99"); var kerl = new Kerl(); kerl.Absorb(tritValue); var hashValue = new int[Kerl.HashLength]; kerl.Squeeze(hashValue); var hash = Converter.TritsToTrytes(hashValue); Assert.AreEqual("SHTKPLZWIXLDVHAEAGFSVWNDGVIX9SDVGEHAFGXEIMLWSHDTQYNZZKPBGMUF9GNEWIGIFYWWMSCLJ9RCD", hash); }
public void KurlMultiSqueeze() { var tritValue = Converter.TrytesToTrits("9MIDYNHBWMBCXVDEFOFWINXTERALUKYYPPHKP9JJFGJEIUY9MUDVNFZHMMWZUYUSWAIOWEVTHNWMHANBH"); var kerl = new Kerl(); kerl.Absorb(tritValue); var hashValue = new int[Constants.TritHashLength * 2]; kerl.Squeeze(hashValue); var hash = Converter.TritsToTrytes(hashValue); Assert.AreEqual("G9JYBOMPUXHYHKSNRNMMSSZCSHOFYOYNZRSZMAAYWDYEIMVVOGKPJBVBM9TDPULSFUNMTVXRKFIDOHUXXVYDLFSZYZTWQYTE9SPYYWYTXJYQ9IFGYOLZXWZBKWZN9QOOTBQMWMUBLEWUEEASRHRTNIQWJQNDWRYLCA", hash); }
public void KerlOneAbsorbMethod2() { var input = "EMIDYNHBWMBCXVDEFOFWINXTERALUKYYPPHKP9JJFGJEIUY9MUDVNFZHMMWZUYUSWAIOWEVTHNWMHANBH"; var expected = "EJEAOOZYSAWFPZQESYDHZCGYNSTWXUMVJOVDWUNZJXDGWCLUFGIMZRMGCAZGKNPLBRLGUNYWKLJTYEAQX"; var trits = Converter.GetTrits(input); var kerl = new Kerl(); kerl.Absorb(trits, 0, trits.Length); var hashTrits = new sbyte[Kerl.HASH_LENGTH]; kerl.Squeeze(hashTrits, 0, Kerl.HASH_LENGTH); var hash = Converter.GetTrytes(hashTrits); Assert.AreEqual(expected, hash); }
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"); }
public void KerlMultiAbsorbMultiSqueeze() { var input = "G9JYBOMPUXHYHKSNRNMMSSZCSHOFYOYNZRSZMAAYWDYEIMVVOGKPJBVBM9TDPULSFUNMTVXRKFIDOHUXXVYDLFSZYZTWQYTE9SPYYWYTXJYQ9IFGYOLZXWZBKWZN9QOOTBQMWMUBLEWUEEASRHRTNIQWJQNDWRYLCA"; var expected = "LUCKQVACOGBFYSPPVSSOXJEKNSQQRQKPZC9NXFSMQNRQCGGUL9OHVVKBDSKEQEBKXRNUJSRXYVHJTXBPDWQGNSCDCBAIRHAQCOWZEBSNHIJIGPZQITIBJQ9LNTDIBTCQ9EUWKHFLGFUVGGUWJONK9GBCDUIMAYMMQX"; var trits = Converter.GetTrits(input); var kerl = new Kerl(); kerl.Initialize(); kerl.Absorb(trits, 0, trits.Length); var hashTrits = new sbyte[Kerl.HASH_LENGTH * 2]; kerl.Squeeze(hashTrits, 0, Kerl.HASH_LENGTH * 2); var hash = Converter.GetTrytes(hashTrits); Assert.AreEqual(expected, hash); }
public void KerlAbsorbMultiSqueeze() { var input = "9MIDYNHBWMBCXVDEFOFWINXTERALUKYYPPHKP9JJFGJEIUY9MUDVNFZHMMWZUYUSWAIOWEVTHNWMHANBH"; var expected = "G9JYBOMPUXHYHKSNRNMMSSZCSHOFYOYNZRSZMAAYWDYEIMVVOGKPJBVBM9TDPULSFUNMTVXRKFIDOHUXXVYDLFSZYZTWQYTE9SPYYWYTXJYQ9IFGYOLZXWZBKWZN9QOOTBQMWMUBLEWUEEASRHRTNIQWJQNDWRYLCA"; var trits = Converter.GetTrits(input); var kerl = new Kerl(); kerl.Initialize(); kerl.Absorb(trits, 0, trits.Length); var hashTrits = new sbyte[Kerl.HASH_LENGTH * 2]; kerl.Squeeze(hashTrits, 0, Kerl.HASH_LENGTH * 2); var hash = Converter.GetTrytes(hashTrits); Assert.AreEqual(expected, hash); }
public void KerlAbsorbSqueeze() { var input = "GYOMKVTSNHVJNCNFBBAH9AAMXLPLLLROQY99QN9DLSJUHDPBLCFFAIQXZA9BKMBJCYSFHFPXAHDWZFEIZ"; var expected = "OXJCNFHUNAHWDLKKPELTBFUCVW9KLXKOGWERKTJXQMXTKFKNWNNXYD9DMJJABSEIONOSJTTEVKVDQEWTW"; var trits = Converter.GetTrits(input); var kerl = new Kerl(); kerl.Initialize(); kerl.Absorb(trits, 0, trits.Length); var hashTrits = new sbyte[Kerl.HASH_LENGTH]; kerl.Squeeze(hashTrits, 0, Kerl.HASH_LENGTH); var hash = Converter.GetTrytes(hashTrits); Assert.AreEqual(expected, hash); }
/// <summary> /// The from address. /// </summary> /// <param name="address"> /// The address. /// </param> /// <returns> /// The <see cref="Checksum"/>. /// </returns> public static Checksum FromAddress(Address address) { var addressTrits = Converter.TrytesToTrits(address.Value); var kerl = new Kerl(); kerl.Absorb(addressTrits); var checksumTrits = new int[Constants.TritHashLength]; kerl.Squeeze(checksumTrits); var tritsToTrytes = Converter.TritsToTrytes(checksumTrits); var checksum = tritsToTrytes.Substring(81 - Length, Length); return(new Checksum(checksum)); }
/// <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); }
/// <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; } }
/// <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); }