Skip to content

Commit 36fa202

Browse files
committed
feat: add Cell.Hash()
1 parent 5119ffc commit 36fa202

File tree

2 files changed

+60
-5
lines changed

2 files changed

+60
-5
lines changed

TonLibDotNet.Tests/Cells/CellTests.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,19 @@ public void BeginReadOk(string hexData, bool augmented, string expectedBinData)
2525

2626
Assert.Equal(expected, actual);
2727
}
28+
29+
[Fact]
30+
public void HashOk()
31+
{
32+
// sample data from TestBOCBomb at https://github.com/xssnick/tonutils-go/blob/619c2aa1f6b992997bf322f8f9bfc4ae036a5181/tvm/cell/cell_test.go#L206-L215
33+
var boc_base64 = "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";
34+
var hash_hex = "EC89185485A679715A615BCA264BF01B4CB619BD28D9E17FF73D05CF5E01C0E0";
35+
36+
var boc = Boc.ParseFromBase64(boc_base64);
37+
var rootCell = boc.RootCells[0];
38+
var hash = rootCell.Hash();
39+
40+
Assert.Equal(hash_hex, Convert.ToHexString(hash).ToUpperInvariant());
41+
}
2842
}
2943
}

TonLibDotNet/Cells/Cell.cs

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
namespace TonLibDotNet.Cells
1+
using System.Buffers.Binary;
2+
using System.Security.Cryptography;
3+
4+
namespace TonLibDotNet.Cells
25
{
36
public class Cell
47
{
@@ -7,7 +10,7 @@ public class Cell
710
public const int MaxRefs = 4;
811

912
public Cell(ReadOnlySpan<byte> content, bool isAugmented, ICollection<Cell>? refs = null)
10-
: this (false, 0, content, isAugmented, refs)
13+
: this(false, 0, content, isAugmented, refs)
1114
{
1215
// Nothing.
1316
}
@@ -54,11 +57,14 @@ public Cell(bool isExotic, byte level, ReadOnlySpan<byte> content, bool isAugmen
5457
this.IsAugmented = isAugmented;
5558

5659
this.Refs = refs?.ToList().AsReadOnly() ?? new List<Cell>().AsReadOnly();
60+
this.Depth = Refs.Count == 0 ? (short)0 : (short)(Refs.Max(x => x.Depth) + 1);
5761
}
5862

59-
public bool IsExotic { get; set; }
63+
public bool IsExotic { get; init; }
64+
65+
public byte Level { get; init; }
6066

61-
public byte Level { get; set; }
67+
public short Depth { get; init; }
6268

6369
public byte[] Content { get; init; }
6470

@@ -68,6 +74,8 @@ public Cell(bool isExotic, byte level, ReadOnlySpan<byte> content, bool isAugmen
6874

6975
public int BitsCount { get; protected set; }
7076

77+
private byte[]? hashValue;
78+
7179
public static (byte refCount, bool isExotic, byte level, int dataLength, bool isAugmented) ParseDescriptors(byte d1, byte d2)
7280
{
7381
var refCount = d1 & 0b111;
@@ -101,12 +109,45 @@ public Slice BeginRead()
101109
{
102110
var bits = new bool[BitsCount];
103111

104-
for(var i = 0; i < BitsCount; i++)
112+
for (var i = 0; i < BitsCount; i++)
105113
{
106114
bits[i] = (Content[i / 8] & (0b1000_0000 >> (i & 0b111))) != 0;
107115
}
108116

109117
return new Slice(new ArraySegment<bool>(bits, 0, BitsCount), Refs);
110118
}
119+
120+
public byte[] Hash()
121+
{
122+
if (hashValue == null)
123+
{
124+
var bytes = new byte[2 + Content.Length + Refs.Count * (2 + 32)];
125+
126+
var (d1, d2) = GetDescriptors();
127+
bytes[0] = d1;
128+
bytes[1] = d2;
129+
Content.CopyTo(bytes, 2);
130+
131+
var pos = 2 + Content.Length;
132+
133+
Span<byte> depth = stackalloc byte[2];
134+
foreach (var r in Refs)
135+
{
136+
BinaryPrimitives.WriteInt16BigEndian(depth, r.Depth);
137+
depth.CopyTo(bytes.AsSpan(pos, 2));
138+
pos += 2;
139+
}
140+
141+
foreach (var r in Refs)
142+
{
143+
r.Hash().CopyTo(bytes, pos);
144+
pos += 32;
145+
}
146+
147+
hashValue = SHA256.HashData(bytes);
148+
}
149+
150+
return hashValue;
151+
}
111152
}
112153
}

0 commit comments

Comments
 (0)