/// <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); }
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 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"); }
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 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 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"); }
/// <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> /// 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); }
/// <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; } }