private void TestEncoding(long input) { int length = Pascal.EncodedLength(input); sbyte[] trits = new sbyte[length]; Pascal.Encode(input, trits); var result = Pascal.Decode(trits); Assert.AreEqual(input, result.Item1); Assert.AreEqual(trits.Length, result.Item2); }
public void TestValueDecoding() { var expected = new Tuple <int, int>(0, 4); var valueToDecode = new[] { 1, 0, 0, -1 }; var result = Pascal.Decode(valueToDecode); Assert.AreEqual(expected.Item1, result.Item1); Assert.AreEqual(expected.Item2, result.Item2); expected = new Tuple <int, int>(1000, 12); valueToDecode = new[] { -1, 0, 0, -1, 0, -1, 1, 0, 0, 0, 1, 0 }; result = Pascal.Decode(valueToDecode); Assert.AreEqual(expected.Item1, result.Item1); Assert.AreEqual(expected.Item2, result.Item2); valueToDecode = new[] { -1, 0, 0, -1, 0, -1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, -1 }; result = Pascal.Decode(valueToDecode); Assert.AreEqual(expected.Item1, result.Item1); Assert.AreEqual(expected.Item2, result.Item2); }
/// <inheritdoc /> public UnmaskedAuthenticatedMessage Unmask(Bundle payload, TryteString root, TryteString channelKey) { var payloadTrits = payload.Transactions.Select(t => t.Fragment).ToList().Merge().ToTrits(); // Get data indices var indexData = Pascal.Decode(payloadTrits); var index = indexData.Item1; var messageData = Pascal.Decode(payloadTrits.Skip(indexData.Item2).ToArray()); var messageLength = messageData.Item1; var nextRootStart = indexData.Item2 + messageData.Item2; var messageStart = nextRootStart + Constants.TritHashLength; var messageEnd = messageStart + messageLength; // Absorb key, root, index and message trits this.Curl.Reset(); this.Curl.Absorb(channelKey.ToTrits()); this.Curl.Absorb(root.ToTrits()); this.Curl.Absorb(payloadTrits.Take(nextRootStart).ToArray()); // decrypt metadata and create hmac var nextRoot = this.Mask.Unmask(payloadTrits.Skip(nextRootStart).Take(Constants.TritHashLength).ToArray(), this.Curl); var message = this.Mask.Unmask(payloadTrits.Skip(messageStart).Take(messageLength).ToArray(), this.Curl); var nonce = this.Mask.Unmask(payloadTrits.Skip(messageEnd).Take(Constants.TritHashLength / 3).ToArray(), this.Curl); var hmac = this.Curl.Rate(Constants.TritHashLength); // verify security level with hmac var securityLevel = this.SigningHelper.ChecksumSecurity(hmac); if (securityLevel == 0) { throw new ArgumentException("Given payload is invalid. (Security level can not be verified)"); } // decrypt remaining payload var decryptedMetadata = this.Mask.Unmask(payloadTrits.Skip(messageEnd + nonce.Length).ToArray(), this.Curl); this.Curl.Reset(); // get signature, derive digest and absorb it var signature = decryptedMetadata.Take(securityLevel * PrivateKey.FragmentLength).ToArray(); this.Curl.Absorb(this.SigningHelper.DigestFromSignature(hmac, signature)); // decode sibling information and recalculate root to verify payload var siblingsCountData = Pascal.Decode(decryptedMetadata.Skip(securityLevel * PrivateKey.FragmentLength).ToArray()); var siblingsCount = siblingsCountData.Item1; var recalculatedRoot = siblingsCount != 0 ? this.RecalculateRootWithSiblings(decryptedMetadata, securityLevel, siblingsCountData.Item2, siblingsCount, index) : new Hash(Converter.TritsToTrytes(this.Curl.Rate(Constants.TritHashLength))); if (recalculatedRoot.Value != root.Value) { throw new ArgumentException("Given payload is invalid. (Given root does not match payload root)"); } return(new UnmaskedAuthenticatedMessage { NextRoot = new Hash(Converter.TritsToTrytes(nextRoot)), Message = new TryteString(Converter.TritsToTrytes(message)), Root = new Hash(root.Value) }); }
/// <inheritdoc /> public UnmaskedAuthenticatedMessage Unmask(Bundle payload, TryteString root, TryteString channelKey) { var payloadTrits = payload.Transactions.Select(t => t.Fragment).ToList().Merge().ToTrits(); var indexData = Pascal.Decode(payloadTrits); var index = indexData.Item1; var messageData = Pascal.Decode(payloadTrits.Skip(indexData.Item2).ToArray()); var messageLength = messageData.Item1; var nextRootStart = indexData.Item2 + messageData.Item2; var messageStart = nextRootStart + Constants.TritHashLength; var messageEnd = messageStart + messageLength; this.Curl.Reset(); this.Curl.Absorb(channelKey.ToTrits()); this.Curl.Absorb(root.ToTrits()); this.Curl.Absorb(payloadTrits.Take(nextRootStart).ToArray()); var nextRoot = this.Mask.Unmask(payloadTrits.Skip(nextRootStart).Take(Constants.TritHashLength).ToArray(), this.Curl); var message = this.Mask.Unmask(payloadTrits.Skip(messageStart).Take(messageLength).ToArray(), this.Curl); var nonce = this.Mask.Unmask(payloadTrits.Skip(messageEnd).Take(Constants.TritHashLength / 3).ToArray(), this.Curl); var hmac = this.Curl.Rate(Constants.TritHashLength); var securityLevel = this.SigningHelper.ChecksumSecurity(hmac); if (securityLevel == 0) { throw new ArgumentException("Given payload is invalid. (Security level can not be verified)"); } var decryptedMetadata = this.Mask.Unmask(payloadTrits.Skip(messageEnd + nonce.Length).ToArray(), this.Curl); var signature = decryptedMetadata.Take(securityLevel * PrivateKey.FragmentLength).ToArray(); var digest = this.SigningHelper.DigestFromSignature(hmac, signature); this.Curl.Reset(); this.Curl.Absorb(digest); var siblingsCountData = Pascal.Decode(decryptedMetadata.Skip(securityLevel * PrivateKey.FragmentLength).ToArray()); var siblingsCount = siblingsCountData.Item1; Hash recalculatedRoot; if (siblingsCount != 0) { var siblings = decryptedMetadata.Skip((securityLevel * PrivateKey.FragmentLength) + siblingsCountData.Item2) .Take(siblingsCount * Constants.TritHashLength).ToArray(); recalculatedRoot = this.TreeFactory.RecalculateRoot( siblings, this.Curl.Rate(Constants.TritHashLength), index); } else { recalculatedRoot = new Hash(Converter.TritsToTrytes(this.Curl.Rate(Constants.TritHashLength))); } if (recalculatedRoot.Value != root.Value) { throw new ArgumentException("Given payload is invalid. (Given root does not match payload root)"); } return(new UnmaskedAuthenticatedMessage { NextRoot = new Hash(Converter.TritsToTrytes(nextRoot)), Message = new TryteString(Converter.TritsToTrytes(message)), Root = new Hash(root.Value) }); }
/// <summary> /// </summary> /// <param name="payload"></param> /// <param name="sideKey"></param> /// <param name="root"></param> /// <returns>(message,nextRoot)</returns> public Tuple <string, string> DecodeMessage(string payload, string sideKey, string root) { if (string.IsNullOrEmpty(sideKey)) { sideKey = "999999999999999999999999999999999999999999999999999999999999999999999999999999999"; } var payloadTrits = Converter.ToTrits(payload); var sideKeyTrits = Converter.ToTrits(sideKey); var rootTrits = Converter.ToTrits(root); ICurl curl = new Curl(SpongeFactory.Mode.CURLP27); // parse var result = Pascal.Decode(payloadTrits); var index = (int)result.Item1; var indexEnd = result.Item2; var tempTrits = new sbyte[payloadTrits.Length - indexEnd]; Array.Copy(payloadTrits, indexEnd, tempTrits, 0, tempTrits.Length); result = Pascal.Decode(tempTrits); var messageLength = (int)result.Item1; var messageLengthEnd = result.Item2; var nextRootStart = indexEnd + messageLengthEnd; var messageStart = nextRootStart + Constants.HashLength; var messageEnd = messageStart + messageLength; curl.Absorb(sideKeyTrits); curl.Absorb(rootTrits); if (messageLength > payloadTrits.Length) { throw new ArgumentOutOfRangeException(); } curl.Absorb(payloadTrits, 0, nextRootStart); MaskHelper.UnMaskSlice(payloadTrits, nextRootStart, messageStart - nextRootStart, curl); MaskHelper.UnMaskSlice(payloadTrits, messageStart, messageEnd - messageStart, curl); var pos = messageEnd; MaskHelper.UnMaskSlice(payloadTrits, pos, Constants.MessageNonceLength, curl); pos += Constants.HashLength / 3; var hmac = new sbyte[Constants.HashLength]; Array.Copy(curl.Rate, hmac, Constants.HashLength); var security = HashHelper.CheckSumSecurity(hmac); MaskHelper.UnMaskSlice(payloadTrits, pos, payloadTrits.Length - pos, curl); if (security == 0) { // InvalidHash curl.Reset(); throw new ApplicationException(); } var sigEnd = pos + security * Constants.KeyLength; HashHelper.DigestBundleSignature(hmac, payloadTrits, pos, sigEnd - pos, curl); Array.Copy(curl.Rate, hmac, Constants.HashLength); curl.Reset(); pos = sigEnd; tempTrits = new sbyte[payloadTrits.Length - pos]; Array.Copy(payloadTrits, pos, tempTrits, 0, tempTrits.Length); result = Pascal.Decode(tempTrits); curl.Absorb(hmac); if (result.Item1 != 0) { // get address lite Array.Copy(curl.Rate, hmac, Constants.HashLength); pos += result.Item2; var sibEnd = pos + (int)result.Item1; var siblings = new sbyte[sibEnd - pos]; Array.Copy(payloadTrits, pos, siblings, 0, siblings.Length); curl.Reset(); MerkleTree.Root(hmac, siblings, index, curl); } if (!curl.Rate.SequenceEqual(rootTrits)) { // InvalidSignature curl.Reset(); throw new ApplicationException(); } var message = Converter.ToTrytes(payloadTrits, messageStart, messageLength); var nextRoot = Converter.ToTrytes(payloadTrits, nextRootStart, Constants.HashLength); return(new Tuple <string, string>(message, nextRoot)); }