@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
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MMR index calculation functions
|
|
3
|
+
*
|
|
4
|
+
* These functions are needed by the massifs module for computing
|
|
5
|
+
* firstIndex and peakStackLen.
|
|
6
|
+
*
|
|
7
|
+
* Also exports the core mmrIndex function for converting leaf indices to MMR indices.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Returns the number of peaks preceding iLeaf that the future tree requires.
|
|
11
|
+
*
|
|
12
|
+
* This corresponds to the number of preceding nodes that will be required to
|
|
13
|
+
* derive future interior nodes. If those preceding nodes are maintained in a
|
|
14
|
+
* stack, this is the current length of the stack.
|
|
15
|
+
*
|
|
16
|
+
* Translated from go-merklelog/mmr/spurs.go LeafMinusSpurSum
|
|
17
|
+
*/
|
|
18
|
+
export declare function leafMinusSpurSum(leafIndex: bigint): bigint;
|
|
19
|
+
/**
|
|
20
|
+
* Returns the MMR index of the first leaf in the massif blob identified by massifIndex
|
|
21
|
+
*
|
|
22
|
+
* Translated from go-merklelog/massifs/massifstart.go MassifFirstLeaf
|
|
23
|
+
*/
|
|
24
|
+
export declare function massifFirstLeaf(massifHeight: number, massifIndex: number): bigint;
|
|
25
|
+
/**
|
|
26
|
+
* Returns the node index for the leaf e
|
|
27
|
+
*
|
|
28
|
+
* Args:
|
|
29
|
+
* - leafIndex: the leaf index, where the leaves are numbered consecutively, ignoring interior nodes.
|
|
30
|
+
*
|
|
31
|
+
* Returns:
|
|
32
|
+
* The mmr index for the element leafIndex
|
|
33
|
+
*
|
|
34
|
+
* Translated from go-merklelog/mmr/mmrindex.go MMRIndex
|
|
35
|
+
*/
|
|
36
|
+
export declare function mmrIndex(leafIndex: bigint): bigint;
|
|
37
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mmr/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAQ1D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,GAClB,MAAM,CAYR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAalD"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MMR index calculation functions
|
|
3
|
+
*
|
|
4
|
+
* These functions are needed by the massifs module for computing
|
|
5
|
+
* firstIndex and peakStackLen.
|
|
6
|
+
*
|
|
7
|
+
* Also exports the core mmrIndex function for converting leaf indices to MMR indices.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Returns the number of peaks preceding iLeaf that the future tree requires.
|
|
11
|
+
*
|
|
12
|
+
* This corresponds to the number of preceding nodes that will be required to
|
|
13
|
+
* derive future interior nodes. If those preceding nodes are maintained in a
|
|
14
|
+
* stack, this is the current length of the stack.
|
|
15
|
+
*
|
|
16
|
+
* Translated from go-merklelog/mmr/spurs.go LeafMinusSpurSum
|
|
17
|
+
*/
|
|
18
|
+
export function leafMinusSpurSum(leafIndex) {
|
|
19
|
+
let sum = leafIndex;
|
|
20
|
+
let current = leafIndex >> 1n;
|
|
21
|
+
while (current > 0n) {
|
|
22
|
+
sum -= current;
|
|
23
|
+
current >>= 1n;
|
|
24
|
+
}
|
|
25
|
+
return sum;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Returns the MMR index of the first leaf in the massif blob identified by massifIndex
|
|
29
|
+
*
|
|
30
|
+
* Translated from go-merklelog/massifs/massifstart.go MassifFirstLeaf
|
|
31
|
+
*/
|
|
32
|
+
export function massifFirstLeaf(massifHeight, massifIndex) {
|
|
33
|
+
// The number of nodes 'm' in a massif is: m = (1 << h) - 1
|
|
34
|
+
const m = BigInt((1 << massifHeight) - 1);
|
|
35
|
+
// The number of leaves 'f' in every massif: f = (m + 1) / 2
|
|
36
|
+
const f = (m + 1n) >> 1n;
|
|
37
|
+
// The first leaf index is then: leafIndex = f * massifIndex
|
|
38
|
+
const leafIndex = f * BigInt(massifIndex);
|
|
39
|
+
// Apply MMRIndex to the leaf index to get the MMR index
|
|
40
|
+
return mmrIndex(leafIndex);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Returns the node index for the leaf e
|
|
44
|
+
*
|
|
45
|
+
* Args:
|
|
46
|
+
* - leafIndex: the leaf index, where the leaves are numbered consecutively, ignoring interior nodes.
|
|
47
|
+
*
|
|
48
|
+
* Returns:
|
|
49
|
+
* The mmr index for the element leafIndex
|
|
50
|
+
*
|
|
51
|
+
* Translated from go-merklelog/mmr/mmrindex.go MMRIndex
|
|
52
|
+
*/
|
|
53
|
+
export function mmrIndex(leafIndex) {
|
|
54
|
+
let sum = 0n;
|
|
55
|
+
let current = leafIndex;
|
|
56
|
+
while (current > 0n) {
|
|
57
|
+
// Find the position of the most significant bit (height)
|
|
58
|
+
const h = BigInt(current.toString(2).length);
|
|
59
|
+
sum += (1n << h) - 1n;
|
|
60
|
+
const half = 1n << (h - 1n);
|
|
61
|
+
current -= half;
|
|
62
|
+
}
|
|
63
|
+
return sum;
|
|
64
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Uint64 } from "../uint64/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* MMR Math Functions
|
|
4
|
+
*
|
|
5
|
+
* Core mathematical functions for Merkle Mountain Range operations.
|
|
6
|
+
* Uses Uint64 wrapper for all arithmetic to ensure correctness.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Returns the zero-based height index (g) of an MMR index
|
|
10
|
+
*
|
|
11
|
+
* The height index of a leaf is 0.
|
|
12
|
+
* Translated from go-merklelog/mmr/indexheight.go IndexHeight
|
|
13
|
+
*/
|
|
14
|
+
export declare function heightIndex(mmrIndex: Uint64): number;
|
|
15
|
+
/**
|
|
16
|
+
* Returns the one-based height (h) of an MMR index
|
|
17
|
+
*
|
|
18
|
+
* h = g + 1 where g is the height index
|
|
19
|
+
*/
|
|
20
|
+
export declare function height(mmrIndex: Uint64): number;
|
|
21
|
+
/**
|
|
22
|
+
* Converts leaf index to MMR index
|
|
23
|
+
*
|
|
24
|
+
* @param leafIndex - Zero-based leaf index
|
|
25
|
+
* @returns MMR index
|
|
26
|
+
*/
|
|
27
|
+
export declare function mmrIndexFromLeafIndex(leafIndex: Uint64): Uint64;
|
|
28
|
+
/**
|
|
29
|
+
* Converts MMR index to leaf index
|
|
30
|
+
*
|
|
31
|
+
* @param mmrIndex - MMR index
|
|
32
|
+
* @returns Leaf index
|
|
33
|
+
*/
|
|
34
|
+
export declare function leafIndex(mmrIndex: Uint64): Uint64;
|
|
35
|
+
/**
|
|
36
|
+
* Converts MMR index to MMR position (index + 1)
|
|
37
|
+
*
|
|
38
|
+
* @param mmrIndex - Zero-based MMR index
|
|
39
|
+
* @returns One-based MMR position
|
|
40
|
+
*/
|
|
41
|
+
export declare function mmrPosition(mmrIndex: Uint64): Uint64;
|
|
42
|
+
/**
|
|
43
|
+
* Returns the number of nodes given a height index (g)
|
|
44
|
+
*
|
|
45
|
+
* n = 2^(g+1) - 1 = (2 << g) - 1
|
|
46
|
+
* Translated from go-merklelog/mmr/size.go HeightIndexSize
|
|
47
|
+
*/
|
|
48
|
+
export declare function mmrSizeFromHeightIndex(heightIndex: number): Uint64;
|
|
49
|
+
/**
|
|
50
|
+
* Returns the number of leaves in the largest valid MMR whose size is
|
|
51
|
+
* <= `mmrSize`.
|
|
52
|
+
*
|
|
53
|
+
* Mirrors go-merklelog `LeafCount`, which is defined as `PeaksBitmap(mmrSize)`:
|
|
54
|
+
* the leaf count's binary representation maps directly onto the peak structure
|
|
55
|
+
* (each set bit is a perfect subtree). The naive `(n + 1) / 2` is only correct
|
|
56
|
+
* for single-peak (perfect) sizes — e.g. size 4 (3 leaves) gives 2 with the
|
|
57
|
+
* naive form but 3 here — so it must not be used. When `mmrSize` is not a valid
|
|
58
|
+
* MMR size this returns the leaf count of the highest valid size <= `mmrSize`.
|
|
59
|
+
*/
|
|
60
|
+
export declare function leafCount(mmrSize: Uint64): Uint64;
|
|
61
|
+
/**
|
|
62
|
+
* Returns the number of leaves given a height index
|
|
63
|
+
*
|
|
64
|
+
* f = 2^g = 1 << g
|
|
65
|
+
*/
|
|
66
|
+
export declare function leafCountFromHeightIndex(heightIndex: number): Uint64;
|
|
67
|
+
//# sourceMappingURL=math.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"math.d.ts","sourceRoot":"","sources":["../../src/mmr/math.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C;;;;;GAKG;AAEH;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAIpD;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE/C;AAgDD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAI/D;AAiBD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAclD;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAElE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEjD;AAwBD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEpE"}
|
package/dist/mmr/math.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { Uint64 } from "../uint64/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* MMR Math Functions
|
|
4
|
+
*
|
|
5
|
+
* Core mathematical functions for Merkle Mountain Range operations.
|
|
6
|
+
* Uses Uint64 wrapper for all arithmetic to ensure correctness.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Returns the zero-based height index (g) of an MMR index
|
|
10
|
+
*
|
|
11
|
+
* The height index of a leaf is 0.
|
|
12
|
+
* Translated from go-merklelog/mmr/indexheight.go IndexHeight
|
|
13
|
+
*/
|
|
14
|
+
export function heightIndex(mmrIndex) {
|
|
15
|
+
// Convert from zero-based index to 1-based position
|
|
16
|
+
const pos = mmrIndex.add(new Uint64(1));
|
|
17
|
+
return posHeight(pos);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Returns the one-based height (h) of an MMR index
|
|
21
|
+
*
|
|
22
|
+
* h = g + 1 where g is the height index
|
|
23
|
+
*/
|
|
24
|
+
export function height(mmrIndex) {
|
|
25
|
+
return heightIndex(mmrIndex) + 1;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* PosHeight - obtains height from a 1-based position
|
|
29
|
+
*
|
|
30
|
+
* Translated from go-merklelog/mmr/indexheight.go PosHeight
|
|
31
|
+
*/
|
|
32
|
+
function posHeight(pos) {
|
|
33
|
+
let current = pos;
|
|
34
|
+
while (!allOnes(current)) {
|
|
35
|
+
current = jumpLeftPerfect(current);
|
|
36
|
+
}
|
|
37
|
+
return bitLength(current) - 1;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* JumpLeftPerfect - jumps left to the leftmost node at the same height
|
|
41
|
+
*
|
|
42
|
+
* Translated from go-merklelog/mmr/indexheight.go JumpLeftPerfect
|
|
43
|
+
*/
|
|
44
|
+
function jumpLeftPerfect(pos) {
|
|
45
|
+
const bitLen = bitLength(pos);
|
|
46
|
+
const mostSignificantBit = new Uint64(1).shl(bitLen - 1);
|
|
47
|
+
return pos.sub(mostSignificantBit.sub(new Uint64(1)));
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Checks if a value has all bits set (all ones in binary)
|
|
51
|
+
*/
|
|
52
|
+
function allOnes(value) {
|
|
53
|
+
// A value has all ones if value + 1 is a power of 2
|
|
54
|
+
const next = value.add(new Uint64(1));
|
|
55
|
+
const bitLen = bitLength(next);
|
|
56
|
+
const powerOf2 = new Uint64(1).shl(bitLen - 1);
|
|
57
|
+
return next.equals(powerOf2);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Returns the number of bits needed to represent the value
|
|
61
|
+
*/
|
|
62
|
+
function bitLength(value) {
|
|
63
|
+
const bigInt = value.toBigInt();
|
|
64
|
+
if (bigInt === 0n) {
|
|
65
|
+
return 0;
|
|
66
|
+
}
|
|
67
|
+
return bigInt.toString(2).length;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Converts leaf index to MMR index
|
|
71
|
+
*
|
|
72
|
+
* @param leafIndex - Zero-based leaf index
|
|
73
|
+
* @returns MMR index
|
|
74
|
+
*/
|
|
75
|
+
export function mmrIndexFromLeafIndex(leafIndex) {
|
|
76
|
+
// Use the mmrIndex function from index.ts
|
|
77
|
+
// Import it dynamically to avoid circular dependency
|
|
78
|
+
return new Uint64(mmrIndexFromLeafIndexInternal(leafIndex.toBigInt()));
|
|
79
|
+
}
|
|
80
|
+
// Internal helper that matches the implementation in index.ts
|
|
81
|
+
function mmrIndexFromLeafIndexInternal(leafIndex) {
|
|
82
|
+
let sum = 0n;
|
|
83
|
+
let current = leafIndex;
|
|
84
|
+
while (current > 0n) {
|
|
85
|
+
const h = BigInt(current.toString(2).length);
|
|
86
|
+
sum += (1n << h) - 1n;
|
|
87
|
+
const half = 1n << (h - 1n);
|
|
88
|
+
current -= half;
|
|
89
|
+
}
|
|
90
|
+
return sum;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Converts MMR index to leaf index
|
|
94
|
+
*
|
|
95
|
+
* @param mmrIndex - MMR index
|
|
96
|
+
* @returns Leaf index
|
|
97
|
+
*/
|
|
98
|
+
export function leafIndex(mmrIndex) {
|
|
99
|
+
// This needs to be implemented based on the MMR structure
|
|
100
|
+
// For now, we'll use an iterative approach
|
|
101
|
+
let current = mmrIndex;
|
|
102
|
+
let leafCount = new Uint64(0);
|
|
103
|
+
while (current.toBigInt() > 0n) {
|
|
104
|
+
const h = heightIndex(current);
|
|
105
|
+
const peakSize = new Uint64(1).shl(h + 1).sub(new Uint64(1)); // (1 << (h+1)) - 1
|
|
106
|
+
leafCount = leafCount.add(new Uint64(1).shl(h)); // Add 2^h leaves
|
|
107
|
+
current = current.sub(peakSize);
|
|
108
|
+
}
|
|
109
|
+
return leafCount.sub(new Uint64(1)); // Convert to zero-based
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Converts MMR index to MMR position (index + 1)
|
|
113
|
+
*
|
|
114
|
+
* @param mmrIndex - Zero-based MMR index
|
|
115
|
+
* @returns One-based MMR position
|
|
116
|
+
*/
|
|
117
|
+
export function mmrPosition(mmrIndex) {
|
|
118
|
+
return mmrIndex.add(new Uint64(1));
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Returns the number of nodes given a height index (g)
|
|
122
|
+
*
|
|
123
|
+
* n = 2^(g+1) - 1 = (2 << g) - 1
|
|
124
|
+
* Translated from go-merklelog/mmr/size.go HeightIndexSize
|
|
125
|
+
*/
|
|
126
|
+
export function mmrSizeFromHeightIndex(heightIndex) {
|
|
127
|
+
return new Uint64(1).shl(heightIndex + 1).sub(new Uint64(1));
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Returns the number of leaves in the largest valid MMR whose size is
|
|
131
|
+
* <= `mmrSize`.
|
|
132
|
+
*
|
|
133
|
+
* Mirrors go-merklelog `LeafCount`, which is defined as `PeaksBitmap(mmrSize)`:
|
|
134
|
+
* the leaf count's binary representation maps directly onto the peak structure
|
|
135
|
+
* (each set bit is a perfect subtree). The naive `(n + 1) / 2` is only correct
|
|
136
|
+
* for single-peak (perfect) sizes — e.g. size 4 (3 leaves) gives 2 with the
|
|
137
|
+
* naive form but 3 here — so it must not be used. When `mmrSize` is not a valid
|
|
138
|
+
* MMR size this returns the leaf count of the highest valid size <= `mmrSize`.
|
|
139
|
+
*/
|
|
140
|
+
export function leafCount(mmrSize) {
|
|
141
|
+
return new Uint64(peaksBitmap(mmrSize.toBigInt()));
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Returns the peaks bitmap for an MMR size (go-merklelog `PeaksBitmap`).
|
|
145
|
+
*
|
|
146
|
+
* The numeric value equals the leaf count of the largest valid MMR with size
|
|
147
|
+
* <= `mmrSize`; each set bit marks a perfect subtree (peak) at that height.
|
|
148
|
+
*/
|
|
149
|
+
function peaksBitmap(mmrSize) {
|
|
150
|
+
if (mmrSize === 0n)
|
|
151
|
+
return 0n;
|
|
152
|
+
let pos = mmrSize;
|
|
153
|
+
let peakSize = (1n << BigInt(bitLength(new Uint64(mmrSize)))) - 1n;
|
|
154
|
+
let peakMap = 0n;
|
|
155
|
+
while (peakSize > 0n) {
|
|
156
|
+
peakMap <<= 1n;
|
|
157
|
+
if (pos >= peakSize) {
|
|
158
|
+
pos -= peakSize;
|
|
159
|
+
peakMap |= 1n;
|
|
160
|
+
}
|
|
161
|
+
peakSize >>= 1n;
|
|
162
|
+
}
|
|
163
|
+
return peakMap;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Returns the number of leaves given a height index
|
|
167
|
+
*
|
|
168
|
+
* f = 2^g = 1 << g
|
|
169
|
+
*/
|
|
170
|
+
export function leafCountFromHeightIndex(heightIndex) {
|
|
171
|
+
return new Uint64(1).shl(heightIndex);
|
|
172
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Proof types for MMR inclusion and consistency proofs
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Proof - Inclusion or consistency proof structure
|
|
6
|
+
*/
|
|
7
|
+
export interface Proof {
|
|
8
|
+
/** The proof path (sibling hashes) */
|
|
9
|
+
path: Uint8Array[];
|
|
10
|
+
/** The leaf index being proven */
|
|
11
|
+
leafIndex?: bigint;
|
|
12
|
+
/** The MMR index being proven */
|
|
13
|
+
mmrIndex?: bigint;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Peak - A peak node in the MMR
|
|
17
|
+
*/
|
|
18
|
+
export interface Peak {
|
|
19
|
+
/** The MMR index of the peak */
|
|
20
|
+
index: bigint;
|
|
21
|
+
/** The hash value of the peak */
|
|
22
|
+
hash: Uint8Array;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Hasher interface for cryptographic hashing operations.
|
|
26
|
+
* digest() is async so callers can use crypto.subtle (Workers, browser) or
|
|
27
|
+
* wrap Node's crypto.createHash (e.g. digest(): Promise.resolve(syncDigest())).
|
|
28
|
+
*/
|
|
29
|
+
export interface Hasher {
|
|
30
|
+
/** Reset the hasher state */
|
|
31
|
+
reset(): void;
|
|
32
|
+
/** Update the hasher with data */
|
|
33
|
+
update(data: Uint8Array): void;
|
|
34
|
+
/** Finalize and return the hash */
|
|
35
|
+
digest(): Promise<Uint8Array>;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/mmr/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,WAAW,KAAK;IACpB,sCAAsC;IACtC,IAAI,EAAE,UAAU,EAAE,CAAC;IACnB,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,IAAI;IACnB,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,iCAAiC;IACjC,IAAI,EAAE,UAAU,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,MAAM;IACrB,6BAA6B;IAC7B,KAAK,IAAI,IAAI,CAAC;IACd,kCAAkC;IAClC,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IAC/B,mCAAmC;IACnC,MAAM,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;CAC/B"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Uint64 - A BigInt-based wrapper for 64-bit unsigned integer operations
|
|
3
|
+
*
|
|
4
|
+
* Provides arithmetic and bitwise operations for 64-bit unsigned integers,
|
|
5
|
+
* ensuring all operations stay within the 64-bit range using BigInt.asUintN(64, value).
|
|
6
|
+
*/
|
|
7
|
+
export declare class Uint64 {
|
|
8
|
+
private readonly value;
|
|
9
|
+
/**
|
|
10
|
+
* Creates a new Uint64 instance
|
|
11
|
+
* @param value - The initial value as number, bigint, or string
|
|
12
|
+
*/
|
|
13
|
+
constructor(value: number | bigint | string | Uint64);
|
|
14
|
+
/**
|
|
15
|
+
* Addition with overflow handling (wraps around at 2^64)
|
|
16
|
+
* @param other - The value to add
|
|
17
|
+
* @returns New Uint64 instance with the result
|
|
18
|
+
*/
|
|
19
|
+
add(other: Uint64): Uint64;
|
|
20
|
+
/**
|
|
21
|
+
* Subtraction with underflow handling (wraps around at 0)
|
|
22
|
+
* @param other - The value to subtract
|
|
23
|
+
* @returns New Uint64 instance with the result
|
|
24
|
+
*/
|
|
25
|
+
sub(other: Uint64): Uint64;
|
|
26
|
+
/**
|
|
27
|
+
* Left shift
|
|
28
|
+
* @param bits - Number of bits to shift left
|
|
29
|
+
* @returns New Uint64 instance with the result
|
|
30
|
+
*/
|
|
31
|
+
shl(bits: number): Uint64;
|
|
32
|
+
/**
|
|
33
|
+
* Right shift (logical, zero-fill)
|
|
34
|
+
* @param bits - Number of bits to shift right
|
|
35
|
+
* @returns New Uint64 instance with the result
|
|
36
|
+
*/
|
|
37
|
+
shr(bits: number): Uint64;
|
|
38
|
+
/**
|
|
39
|
+
* Bitwise AND
|
|
40
|
+
* @param other - The value to AND with
|
|
41
|
+
* @returns New Uint64 instance with the result
|
|
42
|
+
*/
|
|
43
|
+
and(other: Uint64): Uint64;
|
|
44
|
+
/**
|
|
45
|
+
* Bitwise OR
|
|
46
|
+
* @param other - The value to OR with
|
|
47
|
+
* @returns New Uint64 instance with the result
|
|
48
|
+
*/
|
|
49
|
+
or(other: Uint64): Uint64;
|
|
50
|
+
/**
|
|
51
|
+
* Bitwise XOR
|
|
52
|
+
* @param other - The value to XOR with
|
|
53
|
+
* @returns New Uint64 instance with the result
|
|
54
|
+
*/
|
|
55
|
+
xor(other: Uint64): Uint64;
|
|
56
|
+
/**
|
|
57
|
+
* Bitwise complement (one's complement)
|
|
58
|
+
* @returns New Uint64 instance with the result
|
|
59
|
+
*/
|
|
60
|
+
not(): Uint64;
|
|
61
|
+
/**
|
|
62
|
+
* Mask lower bits (equivalent to value & ((1 << bits) - 1))
|
|
63
|
+
* @param bits - Number of lower bits to keep
|
|
64
|
+
* @returns New Uint64 instance with the result
|
|
65
|
+
*/
|
|
66
|
+
mask(bits: number): Uint64;
|
|
67
|
+
/**
|
|
68
|
+
* Returns the value as a BigInt
|
|
69
|
+
* @returns The 64-bit unsigned value as BigInt
|
|
70
|
+
*/
|
|
71
|
+
toBigInt(): bigint;
|
|
72
|
+
/**
|
|
73
|
+
* Returns the value as a number (with range check)
|
|
74
|
+
* @returns The value as number if it fits in Number.MAX_SAFE_INTEGER
|
|
75
|
+
* @throws Error if value exceeds Number.MAX_SAFE_INTEGER
|
|
76
|
+
*/
|
|
77
|
+
toNumber(): number;
|
|
78
|
+
/**
|
|
79
|
+
* Returns the value as a string
|
|
80
|
+
* @returns String representation of the value
|
|
81
|
+
*/
|
|
82
|
+
toString(): string;
|
|
83
|
+
/**
|
|
84
|
+
* Equality comparison
|
|
85
|
+
* @param other - The value to compare with
|
|
86
|
+
* @returns True if values are equal
|
|
87
|
+
*/
|
|
88
|
+
equals(other: Uint64): boolean;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/uint64/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAE/B;;;OAGG;gBACS,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM;IASpD;;;;OAIG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAK1B;;;;OAIG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAK1B;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAQzB;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAQzB;;;;OAIG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAK1B;;;;OAIG;IACH,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAKzB;;;;OAIG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAK1B;;;OAGG;IACH,GAAG,IAAI,MAAM;IAMb;;;;OAIG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAY1B;;;OAGG;IACH,QAAQ,IAAI,MAAM;IAIlB;;;;OAIG;IACH,QAAQ,IAAI,MAAM;IASlB;;;OAGG;IACH,QAAQ,IAAI,MAAM;IAIlB;;;;OAIG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;CAG/B"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Uint64 - A BigInt-based wrapper for 64-bit unsigned integer operations
|
|
3
|
+
*
|
|
4
|
+
* Provides arithmetic and bitwise operations for 64-bit unsigned integers,
|
|
5
|
+
* ensuring all operations stay within the 64-bit range using BigInt.asUintN(64, value).
|
|
6
|
+
*/
|
|
7
|
+
export class Uint64 {
|
|
8
|
+
value;
|
|
9
|
+
/**
|
|
10
|
+
* Creates a new Uint64 instance
|
|
11
|
+
* @param value - The initial value as number, bigint, or string
|
|
12
|
+
*/
|
|
13
|
+
constructor(value) {
|
|
14
|
+
if (value instanceof Uint64) {
|
|
15
|
+
this.value = value.value;
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
const bigIntValue = typeof value === "bigint" ? value : BigInt(value);
|
|
19
|
+
this.value = BigInt.asUintN(64, bigIntValue);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Addition with overflow handling (wraps around at 2^64)
|
|
24
|
+
* @param other - The value to add
|
|
25
|
+
* @returns New Uint64 instance with the result
|
|
26
|
+
*/
|
|
27
|
+
add(other) {
|
|
28
|
+
const result = this.value + other.value;
|
|
29
|
+
return new Uint64(BigInt.asUintN(64, result));
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Subtraction with underflow handling (wraps around at 0)
|
|
33
|
+
* @param other - The value to subtract
|
|
34
|
+
* @returns New Uint64 instance with the result
|
|
35
|
+
*/
|
|
36
|
+
sub(other) {
|
|
37
|
+
const result = this.value - other.value;
|
|
38
|
+
return new Uint64(BigInt.asUintN(64, result));
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Left shift
|
|
42
|
+
* @param bits - Number of bits to shift left
|
|
43
|
+
* @returns New Uint64 instance with the result
|
|
44
|
+
*/
|
|
45
|
+
shl(bits) {
|
|
46
|
+
if (bits < 0 || bits > 63) {
|
|
47
|
+
throw new Error("Shift amount must be between 0 and 63");
|
|
48
|
+
}
|
|
49
|
+
const result = this.value << BigInt(bits);
|
|
50
|
+
return new Uint64(BigInt.asUintN(64, result));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Right shift (logical, zero-fill)
|
|
54
|
+
* @param bits - Number of bits to shift right
|
|
55
|
+
* @returns New Uint64 instance with the result
|
|
56
|
+
*/
|
|
57
|
+
shr(bits) {
|
|
58
|
+
if (bits < 0 || bits > 63) {
|
|
59
|
+
throw new Error("Shift amount must be between 0 and 63");
|
|
60
|
+
}
|
|
61
|
+
const result = this.value >> BigInt(bits);
|
|
62
|
+
return new Uint64(BigInt.asUintN(64, result));
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Bitwise AND
|
|
66
|
+
* @param other - The value to AND with
|
|
67
|
+
* @returns New Uint64 instance with the result
|
|
68
|
+
*/
|
|
69
|
+
and(other) {
|
|
70
|
+
const result = this.value & other.value;
|
|
71
|
+
return new Uint64(BigInt.asUintN(64, result));
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Bitwise OR
|
|
75
|
+
* @param other - The value to OR with
|
|
76
|
+
* @returns New Uint64 instance with the result
|
|
77
|
+
*/
|
|
78
|
+
or(other) {
|
|
79
|
+
const result = this.value | other.value;
|
|
80
|
+
return new Uint64(BigInt.asUintN(64, result));
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Bitwise XOR
|
|
84
|
+
* @param other - The value to XOR with
|
|
85
|
+
* @returns New Uint64 instance with the result
|
|
86
|
+
*/
|
|
87
|
+
xor(other) {
|
|
88
|
+
const result = this.value ^ other.value;
|
|
89
|
+
return new Uint64(BigInt.asUintN(64, result));
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Bitwise complement (one's complement)
|
|
93
|
+
* @returns New Uint64 instance with the result
|
|
94
|
+
*/
|
|
95
|
+
not() {
|
|
96
|
+
// For unsigned 64-bit, complement is ~value masked to 64 bits
|
|
97
|
+
const result = ~this.value;
|
|
98
|
+
return new Uint64(BigInt.asUintN(64, result));
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Mask lower bits (equivalent to value & ((1 << bits) - 1))
|
|
102
|
+
* @param bits - Number of lower bits to keep
|
|
103
|
+
* @returns New Uint64 instance with the result
|
|
104
|
+
*/
|
|
105
|
+
mask(bits) {
|
|
106
|
+
if (bits < 0 || bits > 64) {
|
|
107
|
+
throw new Error("Mask bits must be between 0 and 64");
|
|
108
|
+
}
|
|
109
|
+
if (bits === 64) {
|
|
110
|
+
return new Uint64(this.value);
|
|
111
|
+
}
|
|
112
|
+
const maskValue = (BigInt(1) << BigInt(bits)) - BigInt(1);
|
|
113
|
+
const result = this.value & maskValue;
|
|
114
|
+
return new Uint64(BigInt.asUintN(64, result));
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Returns the value as a BigInt
|
|
118
|
+
* @returns The 64-bit unsigned value as BigInt
|
|
119
|
+
*/
|
|
120
|
+
toBigInt() {
|
|
121
|
+
return this.value;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Returns the value as a number (with range check)
|
|
125
|
+
* @returns The value as number if it fits in Number.MAX_SAFE_INTEGER
|
|
126
|
+
* @throws Error if value exceeds Number.MAX_SAFE_INTEGER
|
|
127
|
+
*/
|
|
128
|
+
toNumber() {
|
|
129
|
+
if (this.value > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
130
|
+
throw new Error(`Value ${this.value} exceeds Number.MAX_SAFE_INTEGER (${Number.MAX_SAFE_INTEGER})`);
|
|
131
|
+
}
|
|
132
|
+
return Number(this.value);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Returns the value as a string
|
|
136
|
+
* @returns String representation of the value
|
|
137
|
+
*/
|
|
138
|
+
toString() {
|
|
139
|
+
return this.value.toString();
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Equality comparison
|
|
143
|
+
* @param other - The value to compare with
|
|
144
|
+
* @returns True if values are equal
|
|
145
|
+
*/
|
|
146
|
+
equals(other) {
|
|
147
|
+
return this.value === other.value;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for Uint8Array operations
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Compares two Uint8Arrays for equality
|
|
6
|
+
*
|
|
7
|
+
* Simple and efficient byte-by-byte comparison. Optimized for small
|
|
8
|
+
* fixed-size arrays like trie keys (32 bytes) and extraBytes (24 bytes).
|
|
9
|
+
*
|
|
10
|
+
* @param a - First array to compare
|
|
11
|
+
* @param b - Second array to compare
|
|
12
|
+
* @returns true if arrays are equal, false otherwise
|
|
13
|
+
*/
|
|
14
|
+
export declare function arraysEqual(a: Uint8Array, b: Uint8Array): boolean;
|
|
15
|
+
//# sourceMappingURL=arrays.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"arrays.d.ts","sourceRoot":"","sources":["../../src/utils/arrays.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,OAAO,CAUjE"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for Uint8Array operations
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Compares two Uint8Arrays for equality
|
|
6
|
+
*
|
|
7
|
+
* Simple and efficient byte-by-byte comparison. Optimized for small
|
|
8
|
+
* fixed-size arrays like trie keys (32 bytes) and extraBytes (24 bytes).
|
|
9
|
+
*
|
|
10
|
+
* @param a - First array to compare
|
|
11
|
+
* @param b - Second array to compare
|
|
12
|
+
* @returns true if arrays are equal, false otherwise
|
|
13
|
+
*/
|
|
14
|
+
export function arraysEqual(a, b) {
|
|
15
|
+
if (a.length !== b.length) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
for (let i = 0; i < a.length; i++) {
|
|
19
|
+
if (a[i] !== b[i]) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return true;
|
|
24
|
+
}
|