@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.
Files changed (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +83 -0
  3. package/dist/index.d.ts +21 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +20 -0
  6. package/dist/massifs/indexformat.d.ts +146 -0
  7. package/dist/massifs/indexformat.d.ts.map +1 -0
  8. package/dist/massifs/indexformat.js +191 -0
  9. package/dist/massifs/logformat.d.ts +49 -0
  10. package/dist/massifs/logformat.d.ts.map +1 -0
  11. package/dist/massifs/logformat.js +49 -0
  12. package/dist/massifs/massif.d.ts +86 -0
  13. package/dist/massifs/massif.d.ts.map +1 -0
  14. package/dist/massifs/massif.js +143 -0
  15. package/dist/massifs/massiffull.d.ts +14 -0
  16. package/dist/massifs/massiffull.d.ts.map +1 -0
  17. package/dist/massifs/massiffull.js +21 -0
  18. package/dist/massifs/massiflogentries.d.ts +23 -0
  19. package/dist/massifs/massiflogentries.d.ts.map +1 -0
  20. package/dist/massifs/massiflogentries.js +31 -0
  21. package/dist/massifs/massifstart.d.ts +63 -0
  22. package/dist/massifs/massifstart.d.ts.map +1 -0
  23. package/dist/massifs/massifstart.js +39 -0
  24. package/dist/massifs/mmrindex.d.ts +15 -0
  25. package/dist/massifs/mmrindex.d.ts.map +1 -0
  26. package/dist/massifs/mmrindex.js +24 -0
  27. package/dist/massifs/peakstackend.d.ts +21 -0
  28. package/dist/massifs/peakstackend.d.ts.map +1 -0
  29. package/dist/massifs/peakstackend.js +29 -0
  30. package/dist/massifs/types.d.ts +20 -0
  31. package/dist/massifs/types.d.ts.map +1 -0
  32. package/dist/massifs/types.js +23 -0
  33. package/dist/massifs/urkleindex.d.ts +116 -0
  34. package/dist/massifs/urkleindex.d.ts.map +1 -0
  35. package/dist/massifs/urkleindex.js +169 -0
  36. package/dist/massifs/v2storagepaths.d.ts +17 -0
  37. package/dist/massifs/v2storagepaths.d.ts.map +1 -0
  38. package/dist/massifs/v2storagepaths.js +46 -0
  39. package/dist/mmr/algorithms-sync.d.ts +17 -0
  40. package/dist/mmr/algorithms-sync.d.ts.map +1 -0
  41. package/dist/mmr/algorithms-sync.js +42 -0
  42. package/dist/mmr/algorithms.d.ts +79 -0
  43. package/dist/mmr/algorithms.d.ts.map +1 -0
  44. package/dist/mmr/algorithms.js +155 -0
  45. package/dist/mmr/index.d.ts +37 -0
  46. package/dist/mmr/index.d.ts.map +1 -0
  47. package/dist/mmr/index.js +64 -0
  48. package/dist/mmr/math.d.ts +67 -0
  49. package/dist/mmr/math.d.ts.map +1 -0
  50. package/dist/mmr/math.js +172 -0
  51. package/dist/mmr/types.d.ts +37 -0
  52. package/dist/mmr/types.d.ts.map +1 -0
  53. package/dist/mmr/types.js +4 -0
  54. package/dist/uint64/index.d.ts +90 -0
  55. package/dist/uint64/index.d.ts.map +1 -0
  56. package/dist/uint64/index.js +149 -0
  57. package/dist/utils/arrays.d.ts +15 -0
  58. package/dist/utils/arrays.d.ts.map +1 -0
  59. package/dist/utils/arrays.js +24 -0
  60. package/package.json +41 -0
  61. package/src/index.ts +68 -0
  62. package/src/massifs/indexformat.ts +217 -0
  63. package/src/massifs/logformat.ts +54 -0
  64. package/src/massifs/massif.ts +182 -0
  65. package/src/massifs/massiffull.ts +28 -0
  66. package/src/massifs/massiflogentries.ts +40 -0
  67. package/src/massifs/massifstart.ts +67 -0
  68. package/src/massifs/mmrindex.ts +32 -0
  69. package/src/massifs/peakstackend.ts +34 -0
  70. package/src/massifs/types.ts +55 -0
  71. package/src/massifs/urkleindex.ts +273 -0
  72. package/src/massifs/v2storagepaths.ts +61 -0
  73. package/src/mmr/algorithms-sync.ts +46 -0
  74. package/src/mmr/algorithms.ts +194 -0
  75. package/src/mmr/index.ts +75 -0
  76. package/src/mmr/math.ts +190 -0
  77. package/src/mmr/types.ts +39 -0
  78. package/src/uint64/index.ts +164 -0
  79. 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.
@@ -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 = {}));