@forestrie/merklelog 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +83 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/massifs/indexformat.d.ts +146 -0
- package/dist/massifs/indexformat.d.ts.map +1 -0
- package/dist/massifs/indexformat.js +191 -0
- package/dist/massifs/logformat.d.ts +49 -0
- package/dist/massifs/logformat.d.ts.map +1 -0
- package/dist/massifs/logformat.js +49 -0
- package/dist/massifs/massif.d.ts +86 -0
- package/dist/massifs/massif.d.ts.map +1 -0
- package/dist/massifs/massif.js +143 -0
- package/dist/massifs/massiffull.d.ts +14 -0
- package/dist/massifs/massiffull.d.ts.map +1 -0
- package/dist/massifs/massiffull.js +21 -0
- package/dist/massifs/massiflogentries.d.ts +23 -0
- package/dist/massifs/massiflogentries.d.ts.map +1 -0
- package/dist/massifs/massiflogentries.js +31 -0
- package/dist/massifs/massifstart.d.ts +63 -0
- package/dist/massifs/massifstart.d.ts.map +1 -0
- package/dist/massifs/massifstart.js +39 -0
- package/dist/massifs/mmrindex.d.ts +15 -0
- package/dist/massifs/mmrindex.d.ts.map +1 -0
- package/dist/massifs/mmrindex.js +24 -0
- package/dist/massifs/peakstackend.d.ts +21 -0
- package/dist/massifs/peakstackend.d.ts.map +1 -0
- package/dist/massifs/peakstackend.js +29 -0
- package/dist/massifs/types.d.ts +20 -0
- package/dist/massifs/types.d.ts.map +1 -0
- package/dist/massifs/types.js +23 -0
- package/dist/massifs/urkleindex.d.ts +116 -0
- package/dist/massifs/urkleindex.d.ts.map +1 -0
- package/dist/massifs/urkleindex.js +169 -0
- package/dist/massifs/v2storagepaths.d.ts +17 -0
- package/dist/massifs/v2storagepaths.d.ts.map +1 -0
- package/dist/massifs/v2storagepaths.js +46 -0
- package/dist/mmr/algorithms-sync.d.ts +17 -0
- package/dist/mmr/algorithms-sync.d.ts.map +1 -0
- package/dist/mmr/algorithms-sync.js +42 -0
- package/dist/mmr/algorithms.d.ts +79 -0
- package/dist/mmr/algorithms.d.ts.map +1 -0
- package/dist/mmr/algorithms.js +155 -0
- package/dist/mmr/index.d.ts +37 -0
- package/dist/mmr/index.d.ts.map +1 -0
- package/dist/mmr/index.js +64 -0
- package/dist/mmr/math.d.ts +67 -0
- package/dist/mmr/math.d.ts.map +1 -0
- package/dist/mmr/math.js +172 -0
- package/dist/mmr/types.d.ts +37 -0
- package/dist/mmr/types.d.ts.map +1 -0
- package/dist/mmr/types.js +4 -0
- package/dist/uint64/index.d.ts +90 -0
- package/dist/uint64/index.d.ts.map +1 -0
- package/dist/uint64/index.js +149 -0
- package/dist/utils/arrays.d.ts +15 -0
- package/dist/utils/arrays.d.ts.map +1 -0
- package/dist/utils/arrays.js +24 -0
- package/package.json +41 -0
- package/src/index.ts +68 -0
- package/src/massifs/indexformat.ts +217 -0
- package/src/massifs/logformat.ts +54 -0
- package/src/massifs/massif.ts +182 -0
- package/src/massifs/massiffull.ts +28 -0
- package/src/massifs/massiflogentries.ts +40 -0
- package/src/massifs/massifstart.ts +67 -0
- package/src/massifs/mmrindex.ts +32 -0
- package/src/massifs/peakstackend.ts +34 -0
- package/src/massifs/types.ts +55 -0
- package/src/massifs/urkleindex.ts +273 -0
- package/src/massifs/v2storagepaths.ts +61 -0
- package/src/mmr/algorithms-sync.ts +46 -0
- package/src/mmr/algorithms.ts +194 -0
- package/src/mmr/index.ts +75 -0
- package/src/mmr/math.ts +190 -0
- package/src/mmr/types.ts +39 -0
- package/src/uint64/index.ts +164 -0
- package/src/utils/arrays.ts +25 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Robin Bryce
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# @forestrie/merklelog
|
|
2
|
+
|
|
3
|
+
TypeScript implementation of the MMR (Merkle Mountain Range) merklelog format.
|
|
4
|
+
|
|
5
|
+
This package provides TypeScript implementations of the algorithms and data structures defined by the [go-merklelog](https://github.com/forestrie/go-merklelog) project.
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
The package is organized into three main modules:
|
|
10
|
+
|
|
11
|
+
- **uint64**: BigInt-based wrapper for 64-bit unsigned integer operations
|
|
12
|
+
- **mmr**: Core MMR algorithms including inclusion proofs, consistency proofs, and mathematical operations
|
|
13
|
+
- **massifs**: Efficient buffer-based access to massif blob data
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm add @forestrie/merklelog
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
### Uint64
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { Uint64 } from "@forestrie/merklelog";
|
|
27
|
+
|
|
28
|
+
const a = new Uint64(42);
|
|
29
|
+
const b = new Uint64(10);
|
|
30
|
+
const sum = a.add(b);
|
|
31
|
+
console.log(sum.toBigInt()); // 52n
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Massif
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { Massif } from "@forestrie/merklelog";
|
|
38
|
+
|
|
39
|
+
const buffer = new Uint8Array(/* massif blob data */);
|
|
40
|
+
const massif = new Massif(buffer);
|
|
41
|
+
|
|
42
|
+
// Read fields dynamically
|
|
43
|
+
const lastID = massif.lastID;
|
|
44
|
+
const massifIndex = massif.massifIndex;
|
|
45
|
+
|
|
46
|
+
// Get complete start information
|
|
47
|
+
const start = massif.getStart();
|
|
48
|
+
|
|
49
|
+
// Access field by index
|
|
50
|
+
const field = massif.fieldref(0); // Returns 32-byte field at index 0
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### MMR Algorithms
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { bagPeaks, verifyInclusion, Hasher } from "@forestrie/merklelog";
|
|
57
|
+
|
|
58
|
+
// Bag peaks to compute root (hasher.digest() is async)
|
|
59
|
+
const root = await bagPeaks(hasher, peakHashes);
|
|
60
|
+
|
|
61
|
+
// Verify inclusion proof
|
|
62
|
+
const isValid = await verifyInclusion(hasher, leafHash, proof, root);
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Terminology
|
|
66
|
+
|
|
67
|
+
This package follows the terminology defined in the [term cheatsheet](https://raw.githubusercontent.com/forestrie/go-merklelog/refs/heads/main/term-cheatsheet.md):
|
|
68
|
+
|
|
69
|
+
- **mmrIndex**: Zero-based index of a node in the MMR
|
|
70
|
+
- **mmrPosition**: One-based position of a node (mmrIndex + 1)
|
|
71
|
+
- **leafIndex**: Zero-based index of a leaf node
|
|
72
|
+
- **heightIndex (g)**: Zero-based height index
|
|
73
|
+
- **height (h)**: One-based height (g + 1)
|
|
74
|
+
|
|
75
|
+
## References
|
|
76
|
+
|
|
77
|
+
- [go-merklelog](https://github.com/forestrie/go-merklelog) - Original Go implementation
|
|
78
|
+
- [Term Cheatsheet](https://raw.githubusercontent.com/forestrie/go-merklelog/refs/heads/main/term-cheatsheet.md)
|
|
79
|
+
- [MMR Math Cheatsheet](https://raw.githubusercontent.com/forestrie/go-merklelog/refs/heads/main/mmr-math-cheatsheet.md)
|
|
80
|
+
|
|
81
|
+
## License
|
|
82
|
+
|
|
83
|
+
See LICENSE file in the repository.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @forestrie/merklelog - TypeScript implementation of MMR Merklelog format
|
|
3
|
+
*
|
|
4
|
+
* This package provides TypeScript implementations of the MMR (Merkle Mountain Range)
|
|
5
|
+
* merklelog format as defined by the go-merklelog project.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
export { Uint64 } from "./uint64/index.js";
|
|
10
|
+
export { Massif } from "./massifs/massif.js";
|
|
11
|
+
export type { MassifStart, LeafComponent, LeafEnumeratorSpec, LeafEntry, } from "./massifs/types.js";
|
|
12
|
+
export { MassifStartFmt } from "./massifs/types.js";
|
|
13
|
+
export { LogFormat, Urkle, Bloom, IndexV2, leafCountForMassifHeight, leafTableBytes, nodeCountMax, nodeStoreBytes, bloomMBits, bloomBitsetBytes, bloomRegionBytes, indexDataBytesV2, peakStackEnd, massifLogEntries, urkleLeafTableStartFieldIndex, urkleLeafTableStartByteOffset, createLeafEnumerator, leafComponentByteOffset, leafComponentSize, computeLastMMRIndex, isMassifFull, } from "./massifs/types.js";
|
|
14
|
+
export { parseV2StorageObjectPath } from "./massifs/v2storagepaths.js";
|
|
15
|
+
export { mmrIndex, massifFirstLeaf, leafMinusSpurSum } from "./mmr/index.js";
|
|
16
|
+
export { heightIndex, height, mmrIndexFromLeafIndex, leafIndex, mmrPosition, mmrSizeFromHeightIndex, leafCount, leafCountFromHeightIndex, } from "./mmr/math.js";
|
|
17
|
+
export { bagPeaks, calculateRoot, verifyInclusion, verifyConsistency, } from "./mmr/algorithms.js";
|
|
18
|
+
export { createSyncHasher } from "./mmr/algorithms-sync.js";
|
|
19
|
+
export type { Proof, Peak } from "./mmr/types.js";
|
|
20
|
+
export type { Hasher } from "./mmr/types.js";
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAG3C,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,YAAY,EACV,WAAW,EACX,aAAa,EACb,kBAAkB,EAClB,SAAS,GACV,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EACL,SAAS,EACT,KAAK,EACL,KAAK,EACL,OAAO,EACP,wBAAwB,EACxB,cAAc,EACd,YAAY,EACZ,cAAc,EACd,UAAU,EACV,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,EACZ,gBAAgB,EAChB,6BAA6B,EAC7B,6BAA6B,EAC7B,oBAAoB,EACpB,uBAAuB,EACvB,iBAAiB,EACjB,mBAAmB,EACnB,YAAY,GACb,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAGvE,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAC7E,OAAO,EACL,WAAW,EACX,MAAM,EACN,qBAAqB,EACrB,SAAS,EACT,WAAW,EACX,sBAAsB,EACtB,SAAS,EACT,wBAAwB,GACzB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,QAAQ,EACR,aAAa,EACb,eAAe,EACf,iBAAiB,GAClB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,YAAY,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAClD,YAAY,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @forestrie/merklelog - TypeScript implementation of MMR Merklelog format
|
|
3
|
+
*
|
|
4
|
+
* This package provides TypeScript implementations of the MMR (Merkle Mountain Range)
|
|
5
|
+
* merklelog format as defined by the go-merklelog project.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
// Export uint64 module
|
|
10
|
+
export { Uint64 } from "./uint64/index.js";
|
|
11
|
+
// Export massifs module
|
|
12
|
+
export { Massif } from "./massifs/massif.js";
|
|
13
|
+
export { MassifStartFmt } from "./massifs/types.js";
|
|
14
|
+
export { LogFormat, Urkle, Bloom, IndexV2, leafCountForMassifHeight, leafTableBytes, nodeCountMax, nodeStoreBytes, bloomMBits, bloomBitsetBytes, bloomRegionBytes, indexDataBytesV2, peakStackEnd, massifLogEntries, urkleLeafTableStartFieldIndex, urkleLeafTableStartByteOffset, createLeafEnumerator, leafComponentByteOffset, leafComponentSize, computeLastMMRIndex, isMassifFull, } from "./massifs/types.js";
|
|
15
|
+
export { parseV2StorageObjectPath } from "./massifs/v2storagepaths.js";
|
|
16
|
+
// Export mmr module
|
|
17
|
+
export { mmrIndex, massifFirstLeaf, leafMinusSpurSum } from "./mmr/index.js";
|
|
18
|
+
export { heightIndex, height, mmrIndexFromLeafIndex, leafIndex, mmrPosition, mmrSizeFromHeightIndex, leafCount, leafCountFromHeightIndex, } from "./mmr/math.js";
|
|
19
|
+
export { bagPeaks, calculateRoot, verifyInclusion, verifyConsistency, } from "./mmr/algorithms.js";
|
|
20
|
+
export { createSyncHasher } from "./mmr/algorithms-sync.js";
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Index format constants for v2 massif format
|
|
3
|
+
*
|
|
4
|
+
* Constants for the urkle trie and bloom filter index regions.
|
|
5
|
+
* Based on the Go implementations in:
|
|
6
|
+
* - go-merklelog/urkle/types.go
|
|
7
|
+
* - go-merklelog/bloom/types.go
|
|
8
|
+
* - go-merklelog/massifs/indexformat_v2.go
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Urkle - Constants for urkle trie format
|
|
12
|
+
*/
|
|
13
|
+
export declare namespace Urkle {
|
|
14
|
+
/** Fixed width of hashes and values (32 bytes) */
|
|
15
|
+
const HashBytes = 32;
|
|
16
|
+
/** Byte width of leafOrdinal in proofs and leaf hashes */
|
|
17
|
+
const LeafOrdinalBytes = 4;
|
|
18
|
+
/**
|
|
19
|
+
* LeafRecordBytes is the fixed byte width of a leaf table record.
|
|
20
|
+
*
|
|
21
|
+
* v1 layout (extended for Forestrie v2 index needs):
|
|
22
|
+
* - key_be8 (uint64, 8 bytes)
|
|
23
|
+
* - valueBytes[32] (committed by trie hash)
|
|
24
|
+
* - extra1[24] (auxiliary; not committed by the trie hash)
|
|
25
|
+
* - extra2[32] (auxiliary; not committed by the trie hash)
|
|
26
|
+
* - extra3[32] (auxiliary; not committed by the trie hash)
|
|
27
|
+
*
|
|
28
|
+
* NOTE: Record size is intentionally a multiple of 32 bytes. To achieve this
|
|
29
|
+
* without truncating valueBytes, we sacrifice 8 bytes from the first extra
|
|
30
|
+
* field.
|
|
31
|
+
*/
|
|
32
|
+
const LeafRecordBytes = 128;
|
|
33
|
+
/** Fixed byte width of a node store record */
|
|
34
|
+
const NodeRecordBytes = 64;
|
|
35
|
+
/** Size of FrontierStateV1 snapshot for resuming append-only construction */
|
|
36
|
+
const FrontierStateV1Bytes = 544;
|
|
37
|
+
const LeafKeyBytes = 8;
|
|
38
|
+
const LeafValueBytes = 32;
|
|
39
|
+
const LeafExtra1Bytes: number;
|
|
40
|
+
const LeafExtraBytes = 32;
|
|
41
|
+
const LeafValueOffset = 8;
|
|
42
|
+
const LeafExtraOffset: number;
|
|
43
|
+
const LeafExtra1Offset: number;
|
|
44
|
+
const LeafExtra2Offset: number;
|
|
45
|
+
const LeafExtra3Offset: number;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Bloom - Constants for bloom filter format
|
|
49
|
+
*/
|
|
50
|
+
export declare namespace Bloom {
|
|
51
|
+
/** Fixed element width (Forestrie log value width) */
|
|
52
|
+
const ValueBytes = 32;
|
|
53
|
+
/** Number of parallel Bloom filters in this format */
|
|
54
|
+
const Filters = 4;
|
|
55
|
+
/** Fixed header size for BloomHeaderV1 */
|
|
56
|
+
const HeaderBytesV1 = 32;
|
|
57
|
+
/** Magic string for BloomHeaderV1 */
|
|
58
|
+
const MagicV1 = "BLM1";
|
|
59
|
+
/** Version number for v1 */
|
|
60
|
+
const VersionV1 = 1;
|
|
61
|
+
/** BitOrderLSB0: bit 0 is the least-significant bit of byte 0 */
|
|
62
|
+
const BitOrderLSB0 = 0;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* IndexV2 - V2 massif index configuration constants
|
|
66
|
+
*/
|
|
67
|
+
export declare namespace IndexV2 {
|
|
68
|
+
/**
|
|
69
|
+
* BloomBitsPerElement is the fixed sizing knob for the v2 massif BloomRegion.
|
|
70
|
+
* mBits = bitsPerElement * leafCount, per filter.
|
|
71
|
+
*/
|
|
72
|
+
const BloomBitsPerElement = 10;
|
|
73
|
+
/**
|
|
74
|
+
* BloomK is the number of hash-derived bit positions set per inserted element.
|
|
75
|
+
* For b=10, k≈round(0.693*b)=7.
|
|
76
|
+
*/
|
|
77
|
+
const BloomK = 7;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Returns the fixed leaf capacity N for a massif height (one-based).
|
|
81
|
+
*
|
|
82
|
+
* In massifs, massifHeight is the one-based height h, so leaf capacity is:
|
|
83
|
+
* N = 2^(h-1)
|
|
84
|
+
*
|
|
85
|
+
* @param massifHeight - One-based massif height
|
|
86
|
+
* @returns Leaf capacity for the massif
|
|
87
|
+
*/
|
|
88
|
+
export declare function leafCountForMassifHeight(massifHeight: number): bigint;
|
|
89
|
+
/**
|
|
90
|
+
* Returns the required leaf table bytes for leafCount leaves.
|
|
91
|
+
*
|
|
92
|
+
* @param leafCount - Number of leaves
|
|
93
|
+
* @returns Byte size of the leaf table
|
|
94
|
+
*/
|
|
95
|
+
export declare function leafTableBytes(leafCount: bigint): bigint;
|
|
96
|
+
/**
|
|
97
|
+
* Returns the maximum number of nodes in a binary trie with leafCount keys.
|
|
98
|
+
* For a Patricia/crit-bit style binary trie, node count is <= 2N-1.
|
|
99
|
+
*
|
|
100
|
+
* @param leafCount - Number of leaves
|
|
101
|
+
* @returns Maximum node count
|
|
102
|
+
*/
|
|
103
|
+
export declare function nodeCountMax(leafCount: bigint): bigint;
|
|
104
|
+
/**
|
|
105
|
+
* Returns the required node store bytes for leafCount leaves.
|
|
106
|
+
*
|
|
107
|
+
* @param leafCount - Number of leaves
|
|
108
|
+
* @returns Byte size of the node store
|
|
109
|
+
*/
|
|
110
|
+
export declare function nodeStoreBytes(leafCount: bigint): bigint;
|
|
111
|
+
/**
|
|
112
|
+
* Computes mBits = bitsPerElement * leafCount, returning 0 if overflow.
|
|
113
|
+
*
|
|
114
|
+
* @param leafCount - Number of leaves
|
|
115
|
+
* @param bitsPerElement - Bits per element (default: IndexV2.BloomBitsPerElement)
|
|
116
|
+
* @returns mBits value, or 0 if overflow
|
|
117
|
+
*/
|
|
118
|
+
export declare function bloomMBits(leafCount: bigint, bitsPerElement?: bigint): bigint;
|
|
119
|
+
/**
|
|
120
|
+
* Returns ceil(mBits/8) - the number of bytes for a single filter bitset.
|
|
121
|
+
*
|
|
122
|
+
* @param mBits - Number of bits
|
|
123
|
+
* @returns Byte size of one filter bitset
|
|
124
|
+
*/
|
|
125
|
+
export declare function bloomBitsetBytes(mBits: bigint): bigint;
|
|
126
|
+
/**
|
|
127
|
+
* Returns the required byte length for a 4-way BloomRegion given mBits:
|
|
128
|
+
* HeaderBytesV1 + 4 * ceil(mBits/8)
|
|
129
|
+
*
|
|
130
|
+
* @param mBits - Number of bits per filter
|
|
131
|
+
* @returns Total byte size of bloom region (header + 4 bitsets)
|
|
132
|
+
*/
|
|
133
|
+
export declare function bloomRegionBytes(mBits: bigint): bigint;
|
|
134
|
+
/**
|
|
135
|
+
* Returns the byte size of the v2 index data region, excluding the fixed 32B
|
|
136
|
+
* index header.
|
|
137
|
+
*
|
|
138
|
+
* v2 index header (32B) is BloomHeaderV1, and the index data is:
|
|
139
|
+
* bloom bitsets || urkle frontier || urkle leaf table || urkle node store
|
|
140
|
+
*
|
|
141
|
+
* @param leafCount - Number of leaves
|
|
142
|
+
* @returns Byte size of index data region
|
|
143
|
+
* @throws Error if mBits overflows
|
|
144
|
+
*/
|
|
145
|
+
export declare function indexDataBytesV2(leafCount: bigint): bigint;
|
|
146
|
+
//# sourceMappingURL=indexformat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indexformat.d.ts","sourceRoot":"","sources":["../../src/massifs/indexformat.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;GAEG;AACH,yBAAiB,KAAK,CAAC;IACrB,kDAAkD;IAC3C,MAAM,SAAS,KAAK,CAAC;IAE5B,0DAA0D;IACnD,MAAM,gBAAgB,IAAI,CAAC;IAElC;;;;;;;;;;;;;OAaG;IACI,MAAM,eAAe,MAAM,CAAC;IAEnC,8CAA8C;IACvC,MAAM,eAAe,KAAK,CAAC;IAElC,6EAA6E;IACtE,MAAM,oBAAoB,MAAM,CAAC;IAGjC,MAAM,YAAY,IAAI,CAAC;IACvB,MAAM,cAAc,KAAY,CAAC;IACjC,MAAM,eAAe,QAAgB,CAAC;IACtC,MAAM,cAAc,KAAY,CAAC;IAEjC,MAAM,eAAe,IAAe,CAAC;IACrC,MAAM,eAAe,QAAmC,CAAC;IACzD,MAAM,gBAAgB,QAAkB,CAAC;IACzC,MAAM,gBAAgB,QAAqC,CAAC;IAC5D,MAAM,gBAAgB,QAAoC,CAAC;CACnE;AAED;;GAEG;AACH,yBAAiB,KAAK,CAAC;IACrB,sDAAsD;IAC/C,MAAM,UAAU,KAAK,CAAC;IAE7B,sDAAsD;IAC/C,MAAM,OAAO,IAAI,CAAC;IAEzB,0CAA0C;IACnC,MAAM,aAAa,KAAK,CAAC;IAEhC,qCAAqC;IAC9B,MAAM,OAAO,SAAS,CAAC;IAE9B,4BAA4B;IACrB,MAAM,SAAS,IAAI,CAAC;IAE3B,iEAAiE;IAC1D,MAAM,YAAY,IAAI,CAAC;CAC/B;AAED;;GAEG;AACH,yBAAiB,OAAO,CAAC;IACvB;;;OAGG;IACI,MAAM,mBAAmB,KAAK,CAAC;IAEtC;;;OAGG;IACI,MAAM,MAAM,IAAI,CAAC;CACzB;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAKrE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAKtD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,SAAS,EAAE,MAAM,EACjB,cAAc,GAAE,MAA4C,GAC3D,MAAM,CAOR;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGtD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAmB1D"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Index format constants for v2 massif format
|
|
3
|
+
*
|
|
4
|
+
* Constants for the urkle trie and bloom filter index regions.
|
|
5
|
+
* Based on the Go implementations in:
|
|
6
|
+
* - go-merklelog/urkle/types.go
|
|
7
|
+
* - go-merklelog/bloom/types.go
|
|
8
|
+
* - go-merklelog/massifs/indexformat_v2.go
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Urkle - Constants for urkle trie format
|
|
12
|
+
*/
|
|
13
|
+
export var Urkle;
|
|
14
|
+
(function (Urkle) {
|
|
15
|
+
/** Fixed width of hashes and values (32 bytes) */
|
|
16
|
+
Urkle.HashBytes = 32;
|
|
17
|
+
/** Byte width of leafOrdinal in proofs and leaf hashes */
|
|
18
|
+
Urkle.LeafOrdinalBytes = 4;
|
|
19
|
+
/**
|
|
20
|
+
* LeafRecordBytes is the fixed byte width of a leaf table record.
|
|
21
|
+
*
|
|
22
|
+
* v1 layout (extended for Forestrie v2 index needs):
|
|
23
|
+
* - key_be8 (uint64, 8 bytes)
|
|
24
|
+
* - valueBytes[32] (committed by trie hash)
|
|
25
|
+
* - extra1[24] (auxiliary; not committed by the trie hash)
|
|
26
|
+
* - extra2[32] (auxiliary; not committed by the trie hash)
|
|
27
|
+
* - extra3[32] (auxiliary; not committed by the trie hash)
|
|
28
|
+
*
|
|
29
|
+
* NOTE: Record size is intentionally a multiple of 32 bytes. To achieve this
|
|
30
|
+
* without truncating valueBytes, we sacrifice 8 bytes from the first extra
|
|
31
|
+
* field.
|
|
32
|
+
*/
|
|
33
|
+
Urkle.LeafRecordBytes = 128; // 8 + 32 + 24 + 32 + 32
|
|
34
|
+
/** Fixed byte width of a node store record */
|
|
35
|
+
Urkle.NodeRecordBytes = 64;
|
|
36
|
+
/** Size of FrontierStateV1 snapshot for resuming append-only construction */
|
|
37
|
+
Urkle.FrontierStateV1Bytes = 544; // 32 + 64*8
|
|
38
|
+
// Leaf record field offsets
|
|
39
|
+
Urkle.LeafKeyBytes = 8;
|
|
40
|
+
Urkle.LeafValueBytes = Urkle.HashBytes;
|
|
41
|
+
Urkle.LeafExtra1Bytes = Urkle.HashBytes - 8; // 24
|
|
42
|
+
Urkle.LeafExtraBytes = Urkle.HashBytes; // 32
|
|
43
|
+
Urkle.LeafValueOffset = Urkle.LeafKeyBytes; // 8
|
|
44
|
+
Urkle.LeafExtraOffset = Urkle.LeafValueOffset + Urkle.LeafValueBytes; // 40
|
|
45
|
+
Urkle.LeafExtra1Offset = Urkle.LeafExtraOffset; // 40
|
|
46
|
+
Urkle.LeafExtra2Offset = Urkle.LeafExtra1Offset + Urkle.LeafExtra1Bytes; // 64
|
|
47
|
+
Urkle.LeafExtra3Offset = Urkle.LeafExtra2Offset + Urkle.LeafExtraBytes; // 96
|
|
48
|
+
})(Urkle || (Urkle = {}));
|
|
49
|
+
/**
|
|
50
|
+
* Bloom - Constants for bloom filter format
|
|
51
|
+
*/
|
|
52
|
+
export var Bloom;
|
|
53
|
+
(function (Bloom) {
|
|
54
|
+
/** Fixed element width (Forestrie log value width) */
|
|
55
|
+
Bloom.ValueBytes = 32;
|
|
56
|
+
/** Number of parallel Bloom filters in this format */
|
|
57
|
+
Bloom.Filters = 4;
|
|
58
|
+
/** Fixed header size for BloomHeaderV1 */
|
|
59
|
+
Bloom.HeaderBytesV1 = 32;
|
|
60
|
+
/** Magic string for BloomHeaderV1 */
|
|
61
|
+
Bloom.MagicV1 = "BLM1";
|
|
62
|
+
/** Version number for v1 */
|
|
63
|
+
Bloom.VersionV1 = 1;
|
|
64
|
+
/** BitOrderLSB0: bit 0 is the least-significant bit of byte 0 */
|
|
65
|
+
Bloom.BitOrderLSB0 = 0;
|
|
66
|
+
})(Bloom || (Bloom = {}));
|
|
67
|
+
/**
|
|
68
|
+
* IndexV2 - V2 massif index configuration constants
|
|
69
|
+
*/
|
|
70
|
+
export var IndexV2;
|
|
71
|
+
(function (IndexV2) {
|
|
72
|
+
/**
|
|
73
|
+
* BloomBitsPerElement is the fixed sizing knob for the v2 massif BloomRegion.
|
|
74
|
+
* mBits = bitsPerElement * leafCount, per filter.
|
|
75
|
+
*/
|
|
76
|
+
IndexV2.BloomBitsPerElement = 10;
|
|
77
|
+
/**
|
|
78
|
+
* BloomK is the number of hash-derived bit positions set per inserted element.
|
|
79
|
+
* For b=10, k≈round(0.693*b)=7.
|
|
80
|
+
*/
|
|
81
|
+
IndexV2.BloomK = 7;
|
|
82
|
+
})(IndexV2 || (IndexV2 = {}));
|
|
83
|
+
/**
|
|
84
|
+
* Returns the fixed leaf capacity N for a massif height (one-based).
|
|
85
|
+
*
|
|
86
|
+
* In massifs, massifHeight is the one-based height h, so leaf capacity is:
|
|
87
|
+
* N = 2^(h-1)
|
|
88
|
+
*
|
|
89
|
+
* @param massifHeight - One-based massif height
|
|
90
|
+
* @returns Leaf capacity for the massif
|
|
91
|
+
*/
|
|
92
|
+
export function leafCountForMassifHeight(massifHeight) {
|
|
93
|
+
if (massifHeight === 0) {
|
|
94
|
+
return 0n;
|
|
95
|
+
}
|
|
96
|
+
return 1n << BigInt(massifHeight - 1);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Returns the required leaf table bytes for leafCount leaves.
|
|
100
|
+
*
|
|
101
|
+
* @param leafCount - Number of leaves
|
|
102
|
+
* @returns Byte size of the leaf table
|
|
103
|
+
*/
|
|
104
|
+
export function leafTableBytes(leafCount) {
|
|
105
|
+
return leafCount * BigInt(Urkle.LeafRecordBytes);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Returns the maximum number of nodes in a binary trie with leafCount keys.
|
|
109
|
+
* For a Patricia/crit-bit style binary trie, node count is <= 2N-1.
|
|
110
|
+
*
|
|
111
|
+
* @param leafCount - Number of leaves
|
|
112
|
+
* @returns Maximum node count
|
|
113
|
+
*/
|
|
114
|
+
export function nodeCountMax(leafCount) {
|
|
115
|
+
if (leafCount === 0n) {
|
|
116
|
+
return 0n;
|
|
117
|
+
}
|
|
118
|
+
return 2n * leafCount - 1n;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Returns the required node store bytes for leafCount leaves.
|
|
122
|
+
*
|
|
123
|
+
* @param leafCount - Number of leaves
|
|
124
|
+
* @returns Byte size of the node store
|
|
125
|
+
*/
|
|
126
|
+
export function nodeStoreBytes(leafCount) {
|
|
127
|
+
return nodeCountMax(leafCount) * BigInt(Urkle.NodeRecordBytes);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Computes mBits = bitsPerElement * leafCount, returning 0 if overflow.
|
|
131
|
+
*
|
|
132
|
+
* @param leafCount - Number of leaves
|
|
133
|
+
* @param bitsPerElement - Bits per element (default: IndexV2.BloomBitsPerElement)
|
|
134
|
+
* @returns mBits value, or 0 if overflow
|
|
135
|
+
*/
|
|
136
|
+
export function bloomMBits(leafCount, bitsPerElement = BigInt(IndexV2.BloomBitsPerElement)) {
|
|
137
|
+
const mBits = bitsPerElement * leafCount;
|
|
138
|
+
// Check overflow - mBits should fit in uint32
|
|
139
|
+
if (mBits > 0xffffffffn) {
|
|
140
|
+
return 0n;
|
|
141
|
+
}
|
|
142
|
+
return mBits;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Returns ceil(mBits/8) - the number of bytes for a single filter bitset.
|
|
146
|
+
*
|
|
147
|
+
* @param mBits - Number of bits
|
|
148
|
+
* @returns Byte size of one filter bitset
|
|
149
|
+
*/
|
|
150
|
+
export function bloomBitsetBytes(mBits) {
|
|
151
|
+
return (mBits + 7n) / 8n;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Returns the required byte length for a 4-way BloomRegion given mBits:
|
|
155
|
+
* HeaderBytesV1 + 4 * ceil(mBits/8)
|
|
156
|
+
*
|
|
157
|
+
* @param mBits - Number of bits per filter
|
|
158
|
+
* @returns Total byte size of bloom region (header + 4 bitsets)
|
|
159
|
+
*/
|
|
160
|
+
export function bloomRegionBytes(mBits) {
|
|
161
|
+
const bitsetBytes = bloomBitsetBytes(mBits);
|
|
162
|
+
return BigInt(Bloom.HeaderBytesV1) + BigInt(Bloom.Filters) * bitsetBytes;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Returns the byte size of the v2 index data region, excluding the fixed 32B
|
|
166
|
+
* index header.
|
|
167
|
+
*
|
|
168
|
+
* v2 index header (32B) is BloomHeaderV1, and the index data is:
|
|
169
|
+
* bloom bitsets || urkle frontier || urkle leaf table || urkle node store
|
|
170
|
+
*
|
|
171
|
+
* @param leafCount - Number of leaves
|
|
172
|
+
* @returns Byte size of index data region
|
|
173
|
+
* @throws Error if mBits overflows
|
|
174
|
+
*/
|
|
175
|
+
export function indexDataBytesV2(leafCount) {
|
|
176
|
+
const mBits = bloomMBits(leafCount);
|
|
177
|
+
if (mBits === 0n && leafCount > 0n) {
|
|
178
|
+
throw new Error("bloom mBits overflow");
|
|
179
|
+
}
|
|
180
|
+
if (leafCount === 0n) {
|
|
181
|
+
return 0n;
|
|
182
|
+
}
|
|
183
|
+
// Bloom region bytes includes the 32B header; we exclude that here because
|
|
184
|
+
// the massif index header is a fixed 32B already accounted for.
|
|
185
|
+
const bloomRegion = bloomRegionBytes(mBits);
|
|
186
|
+
const bloomBitsetsOnly = bloomRegion - BigInt(Bloom.HeaderBytesV1);
|
|
187
|
+
const frontierBytes = BigInt(Urkle.FrontierStateV1Bytes);
|
|
188
|
+
const ltBytes = leafTableBytes(leafCount);
|
|
189
|
+
const nsBytes = nodeStoreBytes(leafCount);
|
|
190
|
+
return bloomBitsetsOnly + frontierBytes + ltBytes + nsBytes;
|
|
191
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Massif log format constants
|
|
3
|
+
*
|
|
4
|
+
* Constants for calculating offsets and sizes in the massif blob format.
|
|
5
|
+
* Based on the Go implementation in go-merklelog/massifs/logformat.go
|
|
6
|
+
*
|
|
7
|
+
* Reference: https://github.com/datatrails/epic-8120-scalable-proof-mechanisms/blob/main/mmr/forestrie-mmrblobs.md#massif-basic-file-format
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* LogFormat - Constants for massif data format
|
|
11
|
+
*
|
|
12
|
+
* Matching the Go implementation in go-merklelog/massifs/logformat.go
|
|
13
|
+
*/
|
|
14
|
+
export declare namespace LogFormat {
|
|
15
|
+
/**
|
|
16
|
+
* ValueBytes defines the width of ALL entries in the log. This fixed width
|
|
17
|
+
* makes it possible to compute mmr current sizes based on knowing only the
|
|
18
|
+
* massif height and the number of bytes in the file.
|
|
19
|
+
*/
|
|
20
|
+
const ValueBytes = 32;
|
|
21
|
+
/**
|
|
22
|
+
* ReservedHeaderSlots reserves a place to put the urkle trie root, used for
|
|
23
|
+
* data recovery and proofs of exclusion, and any related material. And it
|
|
24
|
+
* gives us a little flex in the data format for the initial launch of
|
|
25
|
+
* forestrie. It would be frustrating to need a data migration for want of a
|
|
26
|
+
* few bytes.
|
|
27
|
+
*/
|
|
28
|
+
const ReservedHeaderSlots = 7;
|
|
29
|
+
/**
|
|
30
|
+
* StartHeaderSize - Size of the start header including reserved slots
|
|
31
|
+
*/
|
|
32
|
+
const StartHeaderSize: number;
|
|
33
|
+
/**
|
|
34
|
+
* StartHeaderEnd - End offset of the start header
|
|
35
|
+
*/
|
|
36
|
+
const StartHeaderEnd: number;
|
|
37
|
+
/**
|
|
38
|
+
* MaxMmrHeight - Maximum MMR height - no single log can be taller than this
|
|
39
|
+
* Matches the allowable bit size of an mmrIndex.
|
|
40
|
+
* Note that the max height *index* is 63
|
|
41
|
+
*/
|
|
42
|
+
const MaxMmrHeight = 64;
|
|
43
|
+
/**
|
|
44
|
+
* IndexHeaderBytes - Index header bytes - reserved space for index header.
|
|
45
|
+
* In v2, this 32B region is the BloomHeaderV1.
|
|
46
|
+
*/
|
|
47
|
+
const IndexHeaderBytes = 32;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=logformat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logformat.d.ts","sourceRoot":"","sources":["../../src/massifs/logformat.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;GAIG;AACH,yBAAiB,SAAS,CAAC;IACzB;;;;OAIG;IACI,MAAM,UAAU,KAAK,CAAC;IAE7B;;;;;;OAMG;IACI,MAAM,mBAAmB,IAAI,CAAC;IAErC;;OAEG;IACI,MAAM,eAAe,QAAgD,CAAC;IAE7E;;OAEG;IACI,MAAM,cAAc,QAAkB,CAAC;IAE9C;;;;OAIG;IACI,MAAM,YAAY,KAAK,CAAC;IAE/B;;;OAGG;IACI,MAAM,gBAAgB,KAAK,CAAC;CACpC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Massif log format constants
|
|
3
|
+
*
|
|
4
|
+
* Constants for calculating offsets and sizes in the massif blob format.
|
|
5
|
+
* Based on the Go implementation in go-merklelog/massifs/logformat.go
|
|
6
|
+
*
|
|
7
|
+
* Reference: https://github.com/datatrails/epic-8120-scalable-proof-mechanisms/blob/main/mmr/forestrie-mmrblobs.md#massif-basic-file-format
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* LogFormat - Constants for massif data format
|
|
11
|
+
*
|
|
12
|
+
* Matching the Go implementation in go-merklelog/massifs/logformat.go
|
|
13
|
+
*/
|
|
14
|
+
export var LogFormat;
|
|
15
|
+
(function (LogFormat) {
|
|
16
|
+
/**
|
|
17
|
+
* ValueBytes defines the width of ALL entries in the log. This fixed width
|
|
18
|
+
* makes it possible to compute mmr current sizes based on knowing only the
|
|
19
|
+
* massif height and the number of bytes in the file.
|
|
20
|
+
*/
|
|
21
|
+
LogFormat.ValueBytes = 32;
|
|
22
|
+
/**
|
|
23
|
+
* ReservedHeaderSlots reserves a place to put the urkle trie root, used for
|
|
24
|
+
* data recovery and proofs of exclusion, and any related material. And it
|
|
25
|
+
* gives us a little flex in the data format for the initial launch of
|
|
26
|
+
* forestrie. It would be frustrating to need a data migration for want of a
|
|
27
|
+
* few bytes.
|
|
28
|
+
*/
|
|
29
|
+
LogFormat.ReservedHeaderSlots = 7; // reserves n * ValueBytes at the front of the blob
|
|
30
|
+
/**
|
|
31
|
+
* StartHeaderSize - Size of the start header including reserved slots
|
|
32
|
+
*/
|
|
33
|
+
LogFormat.StartHeaderSize = LogFormat.ValueBytes + LogFormat.ValueBytes * LogFormat.ReservedHeaderSlots; // 256
|
|
34
|
+
/**
|
|
35
|
+
* StartHeaderEnd - End offset of the start header
|
|
36
|
+
*/
|
|
37
|
+
LogFormat.StartHeaderEnd = LogFormat.StartHeaderSize;
|
|
38
|
+
/**
|
|
39
|
+
* MaxMmrHeight - Maximum MMR height - no single log can be taller than this
|
|
40
|
+
* Matches the allowable bit size of an mmrIndex.
|
|
41
|
+
* Note that the max height *index* is 63
|
|
42
|
+
*/
|
|
43
|
+
LogFormat.MaxMmrHeight = 64;
|
|
44
|
+
/**
|
|
45
|
+
* IndexHeaderBytes - Index header bytes - reserved space for index header.
|
|
46
|
+
* In v2, this 32B region is the BloomHeaderV1.
|
|
47
|
+
*/
|
|
48
|
+
LogFormat.IndexHeaderBytes = 32;
|
|
49
|
+
})(LogFormat || (LogFormat = {}));
|