Exemplo n.º 1
0
 /// <summary>
 /// Reconstructs a minimal tree representation from the given bytestream.
 /// <remarks>
 /// In order to verify transaction inclusion in a certain DLT block, a minimum tree can be requested from any node, after which
 ///  you must call the `reconstructMinimumTree()` function, followed by the `calculateTreeHash()` function.
 /// The root hash will be calculated based on the provided data. You can then compare this value with the value in a block header.
 /// </remarks>
 /// </summary>
 /// <param name="data"></param>
 public void reconstructMinimumTree(byte[] data)
 {
     lock (threadLock)
     {
         root            = new PITNode(0);
         root.childNodes = new SortedList <byte, PITNode>();
         using (BinaryReader br = new BinaryReader(new MemoryStream(data)))
         {
             PIT_MinimumTreeType type = (PIT_MinimumTreeType)br.ReadByte();
             levels     = br.ReadByte();
             hashLength = br.ReadByte();
             if (type == PIT_MinimumTreeType.SingleTX)
             {
                 readMinTreeInt(br, root);
             }
             else if (type == PIT_MinimumTreeType.Anonymized)
             {
                 readMinTreeAInt(br, root);
             }
             else if (type == PIT_MinimumTreeType.Matcher)
             {
                 readMinTreeMInt(br, root);
             }
         }
     }
 }
Exemplo n.º 2
0
 private bool delIntRec(byte[] binaryTxid, PITNode cn)
 {
     if (cn.data != null)
     {
         // we've reached the last non-leaf level
         if (cn.data.RemoveWhere(x => x.SequenceEqual(binaryTxid)) > 0)
         {
             cn.hash = null;
             return(true); // something has changed
         }
     }
     else if (cn.childNodes != null)
     {
         bool changed = false;
         byte cb      = binaryTxid[cn.level];
         if (cn.childNodes.ContainsKey(cb))
         {
             PITNode t_node = cn.childNodes[cb];
             changed = delIntRec(binaryTxid, t_node);
             if ((t_node.childNodes == null || t_node.childNodes.Count == 0) && (t_node.data == null || t_node.data.Count == 0))
             {
                 // the child node at `cb` has neither further children nor data, we can drop it
                 cn.childNodes.Remove(cb);
                 changed = true;
             }
             if (changed)
             {
                 // child node has no leaves
                 cn.hash = null;
             }
         }
         return(changed);
     }
     return(false);
 }
Exemplo n.º 3
0
        private void readMinTreeInt(BinaryReader br, PITNode cn)
        {
            byte type = br.ReadByte();

            if (type == 255)
            {
                // final non-leaf node, what follows are TXids
                int num_tx = br.ReadInt32();
                cn.data = new SortedSet <byte[]>(new ByteArrayComparer());
                for (int i = 0; i < num_tx; i++)
                {
                    int    txid_len = br.ReadInt32();
                    byte[] txid     = br.ReadBytes(txid_len);
                    cn.data.Add(txid);
                }
            }
            else if (type == 254)
            {
                // normal non-leaf node, following are hashes for child nodes and then the next node down
                int num_child = br.ReadInt32(); // children except for the downward
                cn.childNodes = new SortedList <byte, PITNode>(num_child + 1);
                for (int i = 0; i < num_child; i++)
                {
                    byte    cb1 = br.ReadByte();
                    PITNode n   = new PITNode(cn.level + 1);
                    n.hash = br.ReadBytes(hashLength);
                    cn.childNodes.Add(cb1, n);
                }
                // downwards direction:
                byte    cb     = br.ReadByte();
                PITNode n_down = new PITNode(cn.level + 1);
                readMinTreeInt(br, n_down);
                cn.childNodes.Add(cb, n_down);
            }
        }
Exemplo n.º 4
0
 private void writeMinTreeAInt(BinaryWriter wr, PITNode cn)
 {
     if (cn.data != null)
     {
         // leaf node - write node's hash and transactions (only if more than one)
         wr.Write((byte)255); // marker for the leaf node
         if (cn.data.Count > 1)
         {
             wr.Write(cn.data.Count);
             foreach (var txid in cn.data)
             {
                 wr.Write(txid.Length);
                 wr.Write(txid);
             }
         }
         else
         {
             wr.Write(0);       // zero transactions needed
             wr.Write(cn.hash); // in this case, only the hash needs to be given
         }
     }
     if (cn.childNodes != null)
     {
         wr.Write((byte)254); // marker for non-leaf node
         wr.Write(cn.childNodes.Count);
         foreach (var n in cn.childNodes)
         {
             wr.Write(n.Key);
             writeMinTreeAInt(wr, n.Value);
         }
     }
 }
Exemplo n.º 5
0
 private void writeMinTreeInt(byte[] binaryTxid, BinaryWriter wr, PITNode cn)
 {
     if (cn.data != null)
     {
         // final node - write all txids, because they are required to calculate node hash
         wr.Write((byte)255); // marker for the leaf node
         wr.Write(cn.data.Count);
         foreach (var txid in cn.data)
         {
             wr.Write(txid.Length);
             wr.Write(txid);
         }
     }
     if (cn.childNodes != null)
     {
         // intermediate node - write all prefixes and hashes, except for the downward tree, so the partial tree can be reconstructed
         wr.Write((byte)254); // marker for the non-leaf node
         wr.Write(cn.childNodes.Count - 1);
         byte cb = binaryTxid[cn.level];
         foreach (var n in cn.childNodes)
         {
             if (n.Key == cb)
             {
                 // skip our target branch - we will write that last
                 continue;
             }
             wr.Write(n.Key);
             wr.Write(n.Value.hash);
         }
         // follow the downwards direction for the transaction we're adding
         wr.Write(cb);
         writeMinTreeInt(binaryTxid, wr, cn.childNodes[cb]);
     }
 }
Exemplo n.º 6
0
 private void getAllIntRec(List <byte[]> output, PITNode cn)
 {
     if (cn.data != null)
     {
         // leaf node
         output.AddRange(cn.data);
     }
     else if (cn.childNodes != null)
     {
         foreach (PITNode n in cn.childNodes.Values)
         {
             getAllIntRec(output, n);
         }
     }
 }
Exemplo n.º 7
0
        private bool containsIntRec(byte[] binaryTxid, PITNode cn)
        {
            byte cb = binaryTxid[cn.level];

            if (cn.data != null)
            {
                if (cn.data.Any(x => x.SequenceEqual(binaryTxid)))
                {
                    return(true);
                }
            }
            if (cn.childNodes != null && cn.childNodes.ContainsKey(cb))
            {
                return(containsIntRec(binaryTxid, cn.childNodes[cb]));
            }
            return(false);
        }
Exemplo n.º 8
0
        private void readMinTreeMInt(BinaryReader br, PITNode cn)
        {
            byte type = br.ReadByte();

            if (type == 255)
            {
                // leaf node
                int count_txids = br.ReadInt32();
                cn.data = new SortedSet <byte[]>(new ByteArrayComparer());
                if (count_txids > 0)
                {
                    for (int i = 0; i < count_txids; i++)
                    {
                        int    txid_len = br.ReadInt32();
                        byte[] txid     = br.ReadBytes(txid_len);
                        cn.data.Add(txid);
                    }
                }
            }
            else if (type == 254)
            {
                byte num_pruned = br.ReadByte();
                cn.childNodes = new SortedList <byte, PITNode>(num_pruned);
                for (int i = 0; i < num_pruned; i++)
                {
                    byte    pb = br.ReadByte();
                    PITNode n  = new PITNode(cn.level + 1);
                    n.hash = br.ReadBytes(hashLength);
                    cn.childNodes.Add(pb, n);
                }
                byte num_full = br.ReadByte();
                for (int i = 0; i < num_full; i++)
                {
                    byte    fb = br.ReadByte();
                    PITNode n  = new PITNode(cn.level + 1);
                    readMinTreeMInt(br, n);
                    cn.childNodes.Add(fb, n);
                }
            }
        }
Exemplo n.º 9
0
        private bool addIntRec(byte[] binaryTxid, PITNode cn, byte level)
        {
            byte cb = binaryTxid[level];

            if (level >= (levels - 1))
            {
                // we've reached last (leaf) level
                if (cn.data == null)
                {
                    cn.data = new SortedSet <byte[]>(new ByteArrayComparer());
                }
                if (!cn.data.Contains(binaryTxid))
                {
                    cn.data.Add(binaryTxid);
                    cn.hash = null;
                    return(true); // something has changed
                }
                return(false);    // nothing has changed
            }
            bool changed = false;

            if (!cn.childNodes.ContainsKey(cb))
            {
                PITNode n = new PITNode(level + 1);
                if (level + 1 < levels - 1)
                {
                    n.childNodes = new SortedList <byte, PITNode>();
                }
                cn.childNodes.Add(cb, n);
                changed = true;
            }
            changed |= addIntRec(binaryTxid, cn.childNodes[cb], (byte)(level + 1));
            if (changed)
            {
                cn.hash = null;
            }
            return(changed);
        }
Exemplo n.º 10
0
 private void calcHashInt(PITNode cn)
 {
     if (cn.hash != null)
     {
         // hash is already cached (or retrieved in the minimal tree)
         return;
     }
     if (cn.data != null)
     {
         // last non-leaf level
         int    all_hashes_len = cn.data.Aggregate(0, (sum, x) => sum + x.Length);
         byte[] indata         = new byte[all_hashes_len];
         int    idx            = 0;
         foreach (var d in cn.data)
         {
             Array.Copy(d, 0, indata, idx, d.Length);
             idx += d.Length;
         }
         cn.hash = Crypto.sha512sqTrunc(indata, 0, indata.Length, hashLength);
     }
     else if (cn.childNodes != null)
     {
         byte[] indata = new byte[cn.childNodes.Count * hashLength];
         int    idx    = 0;
         foreach (var n in cn.childNodes)
         {
             if (n.Value.hash == null)
             {
                 calcHashInt(n.Value);
             }
             Array.Copy(n.Value.hash, 0, indata, idx * hashLength, n.Value.hash.Length);
             idx += 1;
         }
         cn.hash = Crypto.sha512sqTrunc(indata, 0, indata.Length, hashLength);
     }
 }
Exemplo n.º 11
0
 private void writeMinTreeMInt(BinaryWriter bw, IEnumerable <byte[]> included, PITNode cn)
 {
     if (cn.data != null)
     {
         // leaf node, we need to write all txids
         bw.Write((byte)255); // marker for the leaf node
         bw.Write(cn.data.Count);
         foreach (var txid in cn.data)
         {
             bw.Write(txid.Length);
             bw.Write(txid);
         }
     }
     else if (cn.childNodes != null)
     {
         bw.Write((byte)254); // marker for the non-leaf node
         // all child nodes/txids which should be followed
         List <byte> full_downward = cn.childNodes.Keys.Where(b => included.Any(i => i[cn.level] == b)).ToList();
         byte        num_pruned    = (byte)(cn.childNodes.Count - full_downward.Count);
         bw.Write(num_pruned);
         foreach (byte pb in cn.childNodes.Keys.Except(full_downward))
         {
             bw.Write(pb);
             bw.Write(cn.childNodes[pb].hash);
         }
         // write full explore nodes, if any
         bw.Write((byte)(cn.childNodes.Count - num_pruned));
         foreach (byte fb in full_downward)
         {
             bw.Write(fb);
             writeMinTreeMInt(bw, included.Where(i => i[cn.level] == fb), cn.childNodes[fb]);
         }
     }
 }