TVM Cells
Cells are the primary storage and serialization unit in TON.
Ordinary Cell Limits
- Data bits:
0..=1023. - References:
0..=4. - Level:
0..=3. - Exotic flag: false.
Descriptor Bytes
First byte:
refs_count + 8 * exotic + 32 * level
Second byte:
floor(bits / 8) + ceil(bits / 8)
Top-Up Bit
If data bit length is not divisible by 8, serialized data includes a 1 top-up bit immediately after the last data bit, then zero bits until byte boundary.
Fixed-Width Integer Bits
TLB uintN values are stored as exactly N bits in big-endian bit order, most significant bit first. When N is not divisible by 8, the first value bit still occupies the next available high bit in the target byte; unused bits in the final byte are zero in the in-memory cell data and are separate from the serialized top-up bit.
Unsigned fixed-width values must satisfy 0 <= value < 2^N. N = 0 is valid only for zero.
TLB intN values use fixed-width two’s-complement encoding. A signed value must be in:
-2^(N - 1) <= value <= 2^(N - 1) - 1
For N = 0, only zero is valid. Readers decode intN by reading the unsigned bit string, checking bit N - 1, and subtracting 2^N when the sign bit is set.
CellBuilder::store_uint::<T>, Builder::store_uint::<T>, and Slice::load_uint::<T> use the natural width of unsigned Rust primitives (u8, u16, u32, u64, and u128). Non-natural widths that fit in the chosen output type use store_uint_custom::<T>(value, bits) and load_uint_custom::<T>(bits), for example a TL-B uint5 field read as u8.
CellBuilder::store_big_uint, CellBuilder::store_big_int, Builder::store_big_uint, Builder::store_big_int, Slice::load_big_uint, and Slice::load_big_int support widths up to the ordinary cell data limit of 1023 bits. Signed primitive helpers keep their width argument and delegate to the same canonical encoding rules.
VarUInteger
TLB VarUInteger n stores an unsigned byte length in n bits, followed by exactly that many big-endian value bytes. Zero is encoded as a zero length and no value bytes. The byte length itself must fit in the n-bit length field.
TON coin amounts use VarUInteger 16, which means a 4-bit byte length followed by at most 15 value bytes. Values requiring 16 bytes are invalid even if they fit in Rust u128.
Depth
- No refs: depth
0. - With refs:
1 + max(ref.depth). - Serialized as two-byte big-endian values in representation hash calculation.
Representation Hash
For ordinary cells:
- descriptors,
- top-up-padded data,
- reference depths,
- reference hashes,
- SHA-256.
Golden fixtures for ordinary cells are checked directly against this preimage, not against BoC bytes:
| Cell | Representation preimage | SHA-256 representation hash |
|---|---|---|
| Empty ordinary cell | 0000 | 96a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7 |
One-bit ordinary cell containing 1 | 0001c0 | 7c6c1a965fd501d2938c2c0e06626bdaa3531357016e169070c9ef79c4c46bc0 |
Full-byte ordinary cell containing ab | 0002ab | 57c2a1a13baa2762109ed68be0c396f2303ce17e3dde7917d0e74b4072b1dbc7 |
32-bit ordinary cell containing 0000000f | 00080000000f | 57b520dbcb9d135863fc33963cde9f6db2ded1430d88056810a2c9434a3860f9 |
One-bit root containing 1, with refs to the empty and one-bit fixtures | 0201c00000000096a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc77c6c1a965fd501d2938c2c0e06626bdaa3531357016e169070c9ef79c4c46bc0 | 383598f93bde0afbe68b632ae75d5ffa6747df1284e2f4abb86cd2c5840514fe |
One-bit middle containing 1, with ref to the empty fixture | 0101c0000096a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc7 | 9770d42f6d781e048a432b849b56d5329de4667b37cfb918429a23f90cb9884b |
Full-byte root containing ab, with ref to the one-bit middle fixture | 0102ab00019770d42f6d781e048a432b849b56d5329de4667b37cfb918429a23f90cb9884b | 9f19f1fa052329a70f79c2adaef4e9f4e73eb88be389918473adc5f9a2801181 |
Full-byte root containing ab, with refs to the empty and one-bit middle fixtures | 0202ab0000000196a296d224f285c67bee93c30f8a309157f0daa35dc5b87e410b78630a09cfc79770d42f6d781e048a432b849b56d5329de4667b37cfb918429a23f90cb9884b | 6d112e22e9b4f47922b27cb78ffb8c4c3be4be304cdcb9ad24560e3104827eb6 |
The multi-level fixtures above keep ordinary-cell depth handling explicit:
- the empty leaf has depth
0, descriptor0000, and no child data, - the one-bit middle cell has depth
1, descriptor0101, and child depth bytes0000, - the full-byte chained root has depth
2, descriptor0102, and child depth bytes0001, - the two-reference root has depth
2, descriptor0202, and child depth bytes0000 0001before both child hashes.
Exotic Cells
The crate models supported exotic cells explicitly through ExoticCellKind.
Ordinary constructors such as Cell::new() and Cell::with_data() always
create ordinary cells. Exotic cells are constructed by BoC decoding or by
Cell::with_exotic_data(data, bit_len, references), which validates the tag,
payload length, reference count, and derived level.
The first byte of every exotic cell data payload is the type tag:
| Tag | Kind | Payload | References | Derived level |
|---|---|---|---|---|
0x01 | Pruned branch | tag, one-byte level mask 1..=7, one 32-byte hash for each set mask bit, then one two-byte big-endian depth for each set mask bit | 0 | index of the most significant set mask bit plus one, therefore 1..=3 |
0x02 | Library reference | tag plus a 32-byte library cell representation hash, exactly 264 bits | 0 | 0 |
0x03 | Merkle proof | tag, one 32-byte proof hash, one two-byte big-endian proof depth, exactly 280 bits | 1 | max(ref.level - 1, 0) |
0x04 | Merkle update | tag, old 32-byte proof hash, new 32-byte proof hash, old two-byte depth, new two-byte depth, exactly 552 bits | 2 | max(old_ref.level - 1, new_ref.level - 1, 0) |
The BoC descriptor still carries the exotic flag outside the data bits:
refs_count + 8 * 1 + 32 * derived_level
BoC decoding rejects an exotic cell if the descriptor level does not match the level derived from its kind-specific rules. The decoder also rejects unsupported exotic tags, tags missing from short payloads, invalid pruned branch masks, wrong reference counts, and wrong exact payload lengths.
Cell::hash() remains the SHA-256 representation hash of the serialized cell
representation, including the exotic descriptor bit and top-up-padded data.
Cell::depth() remains the representation depth of the decoded cell graph:
pruned and library cells have no references and therefore depth 0; Merkle
proof and Merkle update cells have graph depth based on their explicit
references. Kind-specific proof depths and pruned-branch depths are available
through ExoticCellKind; callers must use those fields for proof semantics
instead of treating Cell::depth() as the deleted subtree depth.
The implementation does not yet expose hash_i/depth_i multi-level helpers.
Proof verification code must add those helpers before validating higher hashes
with CHASHI/CHASHIX-style semantics.
Crate Mapping
src/tvm/cell.rs:Cell,CellBuilder.src/tvm/builder.rs: convenience builder.src/tvm/slice.rs: reader.
Tests Needed
- overflow and underflow tests.
- upstream or pytoniq-core golden fixtures for exotic cells and BoC bytes.