@totemsdk/core 1.0.8 → 1.0.10

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 (142) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +5 -5
  3. package/dist/Streamable.js +54 -31
  4. package/dist/adapters/index.js +18 -8
  5. package/dist/adapters/types.js +19 -8
  6. package/dist/binio.js +5 -1
  7. package/dist/bip39.js +24 -14
  8. package/dist/derive.js +11 -7
  9. package/dist/index.js +130 -22
  10. package/dist/javaStreamables.js +49 -30
  11. package/dist/lease/LeaseMonitor.js +7 -3
  12. package/dist/lease/LeaseStore.js +7 -3
  13. package/dist/lease/WatermarkStore.js +7 -3
  14. package/dist/lease/index.js +13 -4
  15. package/dist/lease-client.js +8 -3
  16. package/dist/minima32.js +22 -13
  17. package/dist/minimaWireSerializer.js +20 -14
  18. package/dist/mmr.js +35 -23
  19. package/dist/mx.js +10 -1
  20. package/dist/params.js +9 -5
  21. package/dist/script.js +12 -7
  22. package/dist/scripts/contract-helpers.js +37 -26
  23. package/dist/scripts/dapp-types.js +11 -6
  24. package/dist/scripts/index.js +38 -4
  25. package/dist/scripts/types.js +26 -12
  26. package/dist/scripts/witness-serializer.js +48 -30
  27. package/dist/transaction.js +55 -46
  28. package/dist/treekey.js +74 -58
  29. package/dist/tx/TransactionLifecycle.js +11 -5
  30. package/dist/tx/TransactionReceiptStore.js +7 -3
  31. package/dist/tx/TransactionService.js +14 -10
  32. package/dist/tx/index.js +11 -3
  33. package/dist/tx/types.js +2 -1
  34. package/dist/util.js +5 -1
  35. package/dist/utils.js +12 -5
  36. package/dist/verify.js +36 -25
  37. package/dist/version.js +5 -2
  38. package/dist/wots.js +94 -64
  39. package/package.json +35 -6
  40. package/src/Streamable.d.ts +0 -265
  41. package/src/Streamable.js +0 -431
  42. package/src/Streamable.ts +0 -567
  43. package/src/__tests__/Streamable.parity.test.ts +0 -422
  44. package/src/__tests__/perAddressDerivation.parity.test.ts +0 -152
  45. package/src/__tests__/roottree-prepare.test.ts +0 -101
  46. package/src/__tests__/wots-parity.test.ts +0 -289
  47. package/src/adapters/index.d.ts +0 -190
  48. package/src/adapters/index.js +0 -117
  49. package/src/adapters/index.ts +0 -301
  50. package/src/adapters/types.ts +0 -235
  51. package/src/addr.oracle.test.ts +0 -25
  52. package/src/address.test.ts +0 -55
  53. package/src/binio.ts +0 -21
  54. package/src/bip39.d.ts +0 -91
  55. package/src/bip39.js +0 -427
  56. package/src/bip39.ts +0 -432
  57. package/src/derive.d.ts +0 -2
  58. package/src/derive.js +0 -13
  59. package/src/derive.ts +0 -11
  60. package/src/index.d.ts +0 -26
  61. package/src/index.js +0 -128
  62. package/src/index.test.ts +0 -5
  63. package/src/index.ts +0 -221
  64. package/src/javaStreamables.d.ts +0 -233
  65. package/src/javaStreamables.js +0 -328
  66. package/src/javaStreamables.ts +0 -403
  67. package/src/lease/LeaseMonitor.d.ts +0 -44
  68. package/src/lease/LeaseMonitor.js +0 -111
  69. package/src/lease/LeaseMonitor.ts +0 -157
  70. package/src/lease/LeaseStore.d.ts +0 -57
  71. package/src/lease/LeaseStore.js +0 -148
  72. package/src/lease/LeaseStore.ts +0 -203
  73. package/src/lease/WatermarkStore.d.ts +0 -61
  74. package/src/lease/WatermarkStore.js +0 -206
  75. package/src/lease/WatermarkStore.ts +0 -270
  76. package/src/lease/index.d.ts +0 -14
  77. package/src/lease/index.js +0 -22
  78. package/src/lease/index.ts +0 -41
  79. package/src/lease-client.d.ts +0 -31
  80. package/src/lease-client.js +0 -44
  81. package/src/lease-client.ts +0 -69
  82. package/src/minima32.d.ts +0 -10
  83. package/src/minima32.js +0 -113
  84. package/src/minima32.test.ts +0 -11
  85. package/src/minima32.ts +0 -127
  86. package/src/minimaWireSerializer.d.ts +0 -189
  87. package/src/minimaWireSerializer.js +0 -311
  88. package/src/minimaWireSerializer.test.ts +0 -466
  89. package/src/minimaWireSerializer.ts +0 -117
  90. package/src/mmr.d.ts +0 -159
  91. package/src/mmr.js +0 -352
  92. package/src/mmr.oracle.test.ts +0 -28
  93. package/src/mmr.ts +0 -429
  94. package/src/mx.test.ts +0 -25
  95. package/src/mx.ts +0 -1
  96. package/src/params.d.ts +0 -29
  97. package/src/params.d.ts.map +0 -1
  98. package/src/params.js +0 -20
  99. package/src/params.js.map +0 -1
  100. package/src/params.ts +0 -44
  101. package/src/script.d.ts +0 -7
  102. package/src/script.js +0 -27
  103. package/src/script.ts +0 -24
  104. package/src/scripts/contract-helpers.ts +0 -609
  105. package/src/scripts/dapp-types.ts +0 -240
  106. package/src/scripts/index.ts +0 -22
  107. package/src/scripts/types.ts +0 -247
  108. package/src/scripts/witness-serializer.ts +0 -384
  109. package/src/transaction.ts +0 -430
  110. package/src/treekey.d.ts +0 -383
  111. package/src/treekey.js +0 -774
  112. package/src/treekey.parity.test.ts +0 -459
  113. package/src/treekey.ts +0 -975
  114. package/src/tx/TransactionLifecycle.d.ts +0 -55
  115. package/src/tx/TransactionLifecycle.js +0 -188
  116. package/src/tx/TransactionLifecycle.ts +0 -280
  117. package/src/tx/TransactionReceiptStore.d.ts +0 -36
  118. package/src/tx/TransactionReceiptStore.js +0 -89
  119. package/src/tx/TransactionReceiptStore.ts +0 -112
  120. package/src/tx/TransactionService.d.ts +0 -31
  121. package/src/tx/TransactionService.js +0 -140
  122. package/src/tx/TransactionService.ts +0 -252
  123. package/src/tx/index.d.ts +0 -13
  124. package/src/tx/index.js +0 -20
  125. package/src/tx/index.ts +0 -44
  126. package/src/tx/types.d.ts +0 -80
  127. package/src/tx/types.js +0 -6
  128. package/src/tx/types.ts +0 -130
  129. package/src/util.d.ts +0 -1
  130. package/src/util.js +0 -5
  131. package/src/util.ts +0 -1
  132. package/src/utils.d.ts +0 -8
  133. package/src/utils.js +0 -42
  134. package/src/utils.ts +0 -38
  135. package/src/verify.ts +0 -210
  136. package/src/version.ts +0 -13
  137. package/src/wots.d.ts +0 -224
  138. package/src/wots.d.ts.map +0 -1
  139. package/src/wots.js +0 -565
  140. package/src/wots.js.map +0 -1
  141. package/src/wots.ts +0 -651
  142. package/test-vectors.json +0 -45
package/src/mmr.d.ts DELETED
@@ -1,159 +0,0 @@
1
- export declare function serializeMMRProof(proof: {
2
- chunks: Array<{
3
- isLeft: boolean;
4
- mmrData: {
5
- data: Bytes;
6
- value: bigint;
7
- };
8
- }>;
9
- }, blockTime?: bigint): Bytes;
10
- export type Bytes = Uint8Array;
11
- /**
12
- * Byte-exact one-leaf MMR leaf used by Minima Address.java path:
13
- * sha3( MiniNumber.ZERO || MiniString(script) || MiniNumber.ZERO )
14
- */
15
- export declare function mmrLeafExact(script: string): Bytes;
16
- /** In a single-leaf MMR the root equals the leaf commitment. */
17
- export declare function mmrRootFromSingleLeaf(script: string): Bytes;
18
- /**
19
- * MMRData structure matching Minima's MMRData.java
20
- * Contains hash and value (for sum tree functionality)
21
- */
22
- export interface MMRData {
23
- data: Bytes;
24
- value: bigint;
25
- }
26
- /**
27
- * MMREntry structure matching Minima's MMREntry.java
28
- * Represents a node in the MMR at a specific row and position
29
- */
30
- export interface MMREntry {
31
- row: number;
32
- entryNumber: bigint;
33
- mmrData: MMRData;
34
- }
35
- /**
36
- * MMRProofChunk - one step in the proof path
37
- * Matches Minima's MMRProof structure
38
- */
39
- export interface MMRProofChunk {
40
- isLeft: boolean;
41
- mmrData: MMRData;
42
- }
43
- /**
44
- * MMRProof structure matching Minima's MMRProof.java
45
- * Contains proof chunks to verify leaf membership in the tree
46
- */
47
- export interface MMRProof {
48
- chunks: MMRProofChunk[];
49
- }
50
- /**
51
- * Create MMRData leaf node matching Minima's MMRData.CreateMMRDataLeafNode
52
- *
53
- * From MMRData.java:
54
- * MiniData hash = Crypto.getInstance().hashAllObjects(MiniNumber.ZERO, zData, zSumValue);
55
- *
56
- * CRITICAL: Crypto.hashAllObjects uses writeDataStream for Streamables:
57
- * - MiniNumber: scale + len + data (see serializeMiniNumber)
58
- * - MiniData: 4-byte length + data (see serializeMiniData)
59
- *
60
- * For TreeKeyNode, zData is the Winternitz public key (MiniData) and zSumValue is ZERO
61
- *
62
- * Serialization order:
63
- * 1. MiniNumber.ZERO: [0x00, 0x01, 0x00]
64
- * 2. MiniData (pubkey): [4-byte length] + [bytes] (writeDataStream, NOT writeHashToStream)
65
- * 3. MiniNumber.ZERO: [0x00, 0x01, 0x00]
66
- */
67
- export declare function createMMRDataLeafNode(pubkey: Bytes, sumValue?: bigint): MMRData;
68
- /**
69
- * Create MMRData parent node matching Minima's MMRData.CreateMMRDataParentNode
70
- *
71
- * From MMRData.java:
72
- * MiniNumber sumvalue = zLeft.getValue().add(zRight.getValue());
73
- * MiniData combinedhash = Crypto.getInstance().hashAllObjects(
74
- * MiniNumber.ONE, zLeft.getData(), zRight.getData(), sumvalue);
75
- *
76
- * CRITICAL: The getData() returns MiniData (the hash), which is serialized
77
- * with writeDataStream (4-byte length) in hashAllObjects.
78
- *
79
- * Serialization order:
80
- * 1. MiniNumber.ONE: [0x00, 0x01, 0x01]
81
- * 2. MiniData (left.data): [4-byte length] + [bytes]
82
- * 3. MiniData (right.data): [4-byte length] + [bytes]
83
- * 4. MiniNumber (sumvalue): serialized MiniNumber
84
- */
85
- export declare function createMMRDataParentNode(left: MMRData, right: MMRData): MMRData;
86
- /**
87
- * Simple MMR Tree for TreeKeyNode
88
- * Builds a perfect binary tree from N entries (N must be power of 2 for simplicity)
89
- *
90
- * This matches TreeKeyNode.java which always uses 64 leaves (2^6)
91
- */
92
- export declare class MMRTree {
93
- private entries;
94
- private leafCount;
95
- private maxRow;
96
- private getKey;
97
- private setEntry;
98
- private getEntry;
99
- /**
100
- * Add a leaf entry to the MMR
101
- * Matches MMR.java addEntry() but simplified for power-of-2 trees
102
- */
103
- addLeaf(data: MMRData): MMREntry;
104
- /**
105
- * Build tree from array of Winternitz public keys
106
- * Used by TreeKeyNode to compute wallet public key
107
- */
108
- static fromPublicKeys(pubkeys: Bytes[]): MMRTree;
109
- /**
110
- * Get the root of the tree
111
- * For a perfect binary tree with N leaves, root is at row log2(N), entry 0
112
- */
113
- getRoot(): MMRData | null;
114
- /**
115
- * Get proof for a leaf at given index
116
- * Matches MMR.java getProofToPeak()
117
- */
118
- getProof(leafIndex: number): MMRProof;
119
- /**
120
- * Get the leaf MMRData at a specific index
121
- */
122
- getLeaf(index: number): MMRData | null;
123
- }
124
- /**
125
- * Calculate root from leaf data and proof
126
- * Matches SignatureProof.getRootPublicKey() in Java
127
- *
128
- * From SignatureProof.java:
129
- * MMRData pubentry = MMRData.CreateMMRDataLeafNode(mPublicKey, MiniNumber.ZERO);
130
- * return mProof.calculateProof(pubentry).getData();
131
- */
132
- export declare function calculateProofRoot(leafData: MMRData, proof: MMRProof): Bytes;
133
- /**
134
- * Verify a proof: check that leaf + proof computes to expected root
135
- */
136
- export declare function verifyMMRProof(leafPubkey: Bytes, proof: MMRProof, expectedRoot: Bytes): boolean;
137
- /**
138
- * Deserialize MMRProof from bytes matching Minima's MMRProof.readDataStream()
139
- *
140
- * Format:
141
- * 1. blockTime (MiniNumber)
142
- * 2. chain length (MiniNumber)
143
- * 3. Each chunk: isLeft (1 byte) + MMRData (hash with 4-byte length prefix + value MiniNumber)
144
- *
145
- * CRITICAL: Java MMRData.readDataStream uses mData.readHashFromStream() which reads
146
- * a 4-byte big-endian length prefix followed by the hash bytes.
147
- *
148
- * @returns { proof: MMRProof, blockTime: bigint }
149
- */
150
- export declare function deserializeMMRProof(data: Bytes): {
151
- proof: MMRProof;
152
- blockTime: bigint;
153
- bytesRead: number;
154
- };
155
- export declare function parseMMRProofFromHex(data: Bytes): {
156
- proof: MMRProof;
157
- blockTime: bigint;
158
- bytesRead: number;
159
- };
package/src/mmr.js DELETED
@@ -1,352 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MMRTree = void 0;
4
- exports.serializeMMRProof = serializeMMRProof;
5
- exports.mmrLeafExact = mmrLeafExact;
6
- exports.mmrRootFromSingleLeaf = mmrRootFromSingleLeaf;
7
- exports.createMMRDataLeafNode = createMMRDataLeafNode;
8
- exports.createMMRDataParentNode = createMMRDataParentNode;
9
- exports.calculateProofRoot = calculateProofRoot;
10
- exports.verifyMMRProof = verifyMMRProof;
11
- exports.deserializeMMRProof = deserializeMMRProof;
12
- exports.parseMMRProofFromHex = deserializeMMRProof;
13
- // packages/totem-sdk/packages/core/src/mmr.ts
14
- // Full MMR implementation matching Minima's MMR.java, MMRData.java, and TreeKeyNode.java
15
- const sha3_1 = require("@noble/hashes/sha3");
16
- const javaStreamables_1 = require("./javaStreamables");
17
- // Import canonical wire serialization from Streamable.ts (single source of truth)
18
- const Streamable_1 = require("./Streamable");
19
- // Re-export for API compatibility (existing code imports from mmr.ts)
20
- // Using a wrapper function for better compatibility with dynamic imports
21
- function serializeMMRProof(proof, blockTime = 0n) {
22
- // Convert to Streamable format and serialize
23
- const streamableProof = {
24
- blockTime: blockTime,
25
- chunks: proof.chunks.map(c => ({
26
- isLeft: c.isLeft,
27
- mmrData: { data: c.mmrData.data, value: c.mmrData.value }
28
- }))
29
- };
30
- return (0, Streamable_1.writeMMRProof)(streamableProof);
31
- }
32
- /** SHA3-256 helper returning 32 bytes */
33
- function sha3(data) {
34
- return sha3_1.sha3_256(data);
35
- }
36
- /** concat utility */
37
- function concat(...parts) {
38
- const total = parts.reduce((n, p) => n + p.length, 0);
39
- const out = new Uint8Array(total);
40
- let off = 0;
41
- for (const p of parts) {
42
- out.set(p, off);
43
- off += p.length;
44
- }
45
- return out;
46
- }
47
- /** big-endian u32 */
48
- const u32be = (n) => new Uint8Array([(n >>> 24) & 0xff, (n >>> 16) & 0xff, (n >>> 8) & 0xff, n & 0xff]);
49
- /**
50
- * EXACT MiniNumber.ZERO wire format from Java:
51
- * scale (1 byte) = 0x00
52
- * length (1 byte) = 0x01
53
- * unscaled bytes (length=1) = 0x00
54
- * => 00 01 00
55
- */
56
- function encodeMiniNumberZERO() {
57
- return new Uint8Array([0x00, 0x01, 0x00]);
58
- }
59
- /**
60
- * EXACT MiniString wire format (MiniData of UTF-8):
61
- * 4-byte big-endian length
62
- * raw UTF-8 bytes
63
- */
64
- function encodeMiniStringUTF8(text) {
65
- const utf8 = new TextEncoder().encode(text);
66
- const len = u32be(utf8.length);
67
- return concat(len, utf8);
68
- }
69
- /**
70
- * Byte-exact one-leaf MMR leaf used by Minima Address.java path:
71
- * sha3( MiniNumber.ZERO || MiniString(script) || MiniNumber.ZERO )
72
- */
73
- function mmrLeafExact(script) {
74
- const zero = encodeMiniNumberZERO();
75
- const mstr = encodeMiniStringUTF8(script);
76
- const all = concat(zero, mstr, zero);
77
- return sha3(all); // 32-byte leaf hash
78
- }
79
- /** In a single-leaf MMR the root equals the leaf commitment. */
80
- function mmrRootFromSingleLeaf(script) {
81
- return mmrLeafExact(script);
82
- }
83
- /**
84
- * Create MMRData leaf node matching Minima's MMRData.CreateMMRDataLeafNode
85
- *
86
- * From MMRData.java:
87
- * MiniData hash = Crypto.getInstance().hashAllObjects(MiniNumber.ZERO, zData, zSumValue);
88
- *
89
- * CRITICAL: Crypto.hashAllObjects uses writeDataStream for Streamables:
90
- * - MiniNumber: scale + len + data (see serializeMiniNumber)
91
- * - MiniData: 4-byte length + data (see serializeMiniData)
92
- *
93
- * For TreeKeyNode, zData is the Winternitz public key (MiniData) and zSumValue is ZERO
94
- *
95
- * Serialization order:
96
- * 1. MiniNumber.ZERO: [0x00, 0x01, 0x00]
97
- * 2. MiniData (pubkey): [4-byte length] + [bytes] (writeDataStream, NOT writeHashToStream)
98
- * 3. MiniNumber.ZERO: [0x00, 0x01, 0x00]
99
- */
100
- function createMMRDataLeafNode(pubkey, sumValue = 0n) {
101
- // Use cached ZERO serialization for efficiency
102
- const zero = new Uint8Array([0x00, 0x01, 0x00]); // MiniNumber.ZERO
103
- // IMPORTANT: hashAllObjects uses writeDataStream which is 4-byte length prefixed
104
- const pubkeySerialized = (0, javaStreamables_1.serializeMiniData)(pubkey);
105
- // For sumValue, serialize as MiniNumber
106
- let sumSerialized;
107
- if (sumValue === 0n) {
108
- sumSerialized = new Uint8Array([0x00, 0x01, 0x00]); // MiniNumber.ZERO
109
- }
110
- else {
111
- sumSerialized = (0, javaStreamables_1.serializeMiniNumber)(Number(sumValue));
112
- }
113
- const hash = (0, javaStreamables_1.javaHashAllObjects)(zero, pubkeySerialized, sumSerialized);
114
- return { data: hash, value: sumValue };
115
- }
116
- /**
117
- * Create MMRData parent node matching Minima's MMRData.CreateMMRDataParentNode
118
- *
119
- * From MMRData.java:
120
- * MiniNumber sumvalue = zLeft.getValue().add(zRight.getValue());
121
- * MiniData combinedhash = Crypto.getInstance().hashAllObjects(
122
- * MiniNumber.ONE, zLeft.getData(), zRight.getData(), sumvalue);
123
- *
124
- * CRITICAL: The getData() returns MiniData (the hash), which is serialized
125
- * with writeDataStream (4-byte length) in hashAllObjects.
126
- *
127
- * Serialization order:
128
- * 1. MiniNumber.ONE: [0x00, 0x01, 0x01]
129
- * 2. MiniData (left.data): [4-byte length] + [bytes]
130
- * 3. MiniData (right.data): [4-byte length] + [bytes]
131
- * 4. MiniNumber (sumvalue): serialized MiniNumber
132
- */
133
- function createMMRDataParentNode(left, right) {
134
- const sumValue = left.value + right.value;
135
- // MiniNumber.ONE: [0x00, 0x01, 0x01]
136
- const one = new Uint8Array([0x00, 0x01, 0x01]);
137
- // Serialize left and right data as MiniData (4-byte length-prefixed)
138
- const leftDataSerialized = (0, javaStreamables_1.serializeMiniData)(left.data);
139
- const rightDataSerialized = (0, javaStreamables_1.serializeMiniData)(right.data);
140
- // Serialize sum value
141
- let sumSerialized;
142
- if (sumValue === 0n) {
143
- sumSerialized = new Uint8Array([0x00, 0x01, 0x00]); // MiniNumber.ZERO
144
- }
145
- else {
146
- sumSerialized = (0, javaStreamables_1.serializeMiniNumber)(Number(sumValue));
147
- }
148
- const hash = (0, javaStreamables_1.javaHashAllObjects)(one, leftDataSerialized, rightDataSerialized, sumSerialized);
149
- return { data: hash, value: sumValue };
150
- }
151
- /**
152
- * Simple MMR Tree for TreeKeyNode
153
- * Builds a perfect binary tree from N entries (N must be power of 2 for simplicity)
154
- *
155
- * This matches TreeKeyNode.java which always uses 64 leaves (2^6)
156
- */
157
- class MMRTree {
158
- constructor() {
159
- this.entries = new Map();
160
- this.leafCount = 0;
161
- this.maxRow = 0;
162
- }
163
- getKey(row, entryNumber) {
164
- return `${row}:${entryNumber}`;
165
- }
166
- setEntry(row, entryNumber, data) {
167
- const entry = { row, entryNumber, mmrData: data };
168
- this.entries.set(this.getKey(row, entryNumber), entry);
169
- if (row > this.maxRow)
170
- this.maxRow = row;
171
- return entry;
172
- }
173
- getEntry(row, entryNumber) {
174
- return this.entries.get(this.getKey(row, entryNumber));
175
- }
176
- /**
177
- * Add a leaf entry to the MMR
178
- * Matches MMR.java addEntry() but simplified for power-of-2 trees
179
- */
180
- addLeaf(data) {
181
- const entryNumber = BigInt(this.leafCount);
182
- const entry = this.setEntry(0, entryNumber, data);
183
- this.leafCount++;
184
- // Propagate up the tree
185
- let current = entry;
186
- while (current.entryNumber % 2n === 1n) { // Is right child
187
- const siblingNumber = current.entryNumber - 1n;
188
- const sibling = this.getEntry(current.row, siblingNumber);
189
- if (!sibling)
190
- break;
191
- // Create parent node
192
- const parentData = createMMRDataParentNode(sibling.mmrData, current.mmrData);
193
- const parentRow = current.row + 1;
194
- const parentEntry = current.entryNumber / 2n;
195
- current = this.setEntry(parentRow, parentEntry, parentData);
196
- }
197
- return entry;
198
- }
199
- /**
200
- * Build tree from array of Winternitz public keys
201
- * Used by TreeKeyNode to compute wallet public key
202
- */
203
- static fromPublicKeys(pubkeys) {
204
- const tree = new MMRTree();
205
- for (const pk of pubkeys) {
206
- const leafData = createMMRDataLeafNode(pk, 0n);
207
- tree.addLeaf(leafData);
208
- }
209
- return tree;
210
- }
211
- /**
212
- * Get the root of the tree
213
- * For a perfect binary tree with N leaves, root is at row log2(N), entry 0
214
- */
215
- getRoot() {
216
- if (this.leafCount === 0)
217
- return null;
218
- // For power of 2 leaves, there's exactly one peak at the top
219
- const topRow = Math.floor(Math.log2(this.leafCount));
220
- const root = this.getEntry(topRow, 0n);
221
- return root?.mmrData || null;
222
- }
223
- /**
224
- * Get proof for a leaf at given index
225
- * Matches MMR.java getProofToPeak()
226
- */
227
- getProof(leafIndex) {
228
- const chunks = [];
229
- let row = 0;
230
- let entryNumber = BigInt(leafIndex);
231
- // Walk up the tree collecting siblings
232
- while (row < this.maxRow) {
233
- const siblingNumber = entryNumber % 2n === 0n
234
- ? entryNumber + 1n // Current is left, sibling is right
235
- : entryNumber - 1n; // Current is right, sibling is left
236
- const sibling = this.getEntry(row, siblingNumber);
237
- if (!sibling)
238
- break;
239
- const isLeft = siblingNumber < entryNumber;
240
- chunks.push({ isLeft, mmrData: sibling.mmrData });
241
- // Move to parent
242
- row++;
243
- entryNumber = entryNumber / 2n;
244
- }
245
- return { chunks };
246
- }
247
- /**
248
- * Get the leaf MMRData at a specific index
249
- */
250
- getLeaf(index) {
251
- const entry = this.getEntry(0, BigInt(index));
252
- return entry?.mmrData || null;
253
- }
254
- }
255
- exports.MMRTree = MMRTree;
256
- /**
257
- * Calculate root from leaf data and proof
258
- * Matches SignatureProof.getRootPublicKey() in Java
259
- *
260
- * From SignatureProof.java:
261
- * MMRData pubentry = MMRData.CreateMMRDataLeafNode(mPublicKey, MiniNumber.ZERO);
262
- * return mProof.calculateProof(pubentry).getData();
263
- */
264
- function calculateProofRoot(leafData, proof) {
265
- let current = leafData;
266
- for (const chunk of proof.chunks) {
267
- if (chunk.isLeft) {
268
- // Sibling is on the left, current is on the right
269
- current = createMMRDataParentNode(chunk.mmrData, current);
270
- }
271
- else {
272
- // Sibling is on the right, current is on the left
273
- current = createMMRDataParentNode(current, chunk.mmrData);
274
- }
275
- }
276
- return current.data;
277
- }
278
- /**
279
- * Verify a proof: check that leaf + proof computes to expected root
280
- */
281
- function verifyMMRProof(leafPubkey, proof, expectedRoot) {
282
- const leafData = createMMRDataLeafNode(leafPubkey, 0n);
283
- const computedRoot = calculateProofRoot(leafData, proof);
284
- if (computedRoot.length !== expectedRoot.length)
285
- return false;
286
- for (let i = 0; i < computedRoot.length; i++) {
287
- if (computedRoot[i] !== expectedRoot[i])
288
- return false;
289
- }
290
- return true;
291
- }
292
- // NOTE: serializeMMRProof is now imported from minimaWireSerializer.ts and re-exported above
293
- // This consolidates wire format serialization into a single source of truth.
294
- /**
295
- * Deserialize MMRProof from bytes matching Minima's MMRProof.readDataStream()
296
- *
297
- * Format:
298
- * 1. blockTime (MiniNumber)
299
- * 2. chain length (MiniNumber)
300
- * 3. Each chunk: isLeft (1 byte) + MMRData (hash with 4-byte length prefix + value MiniNumber)
301
- *
302
- * CRITICAL: Java MMRData.readDataStream uses mData.readHashFromStream() which reads
303
- * a 4-byte big-endian length prefix followed by the hash bytes.
304
- *
305
- * @returns { proof: MMRProof, blockTime: bigint }
306
- */
307
- function deserializeMMRProof(data) {
308
- let offset = 0;
309
- // Read blockTime as MiniNumber
310
- const { value: blockTime, bytesRead: btRead } = readMiniNumber(data, offset);
311
- offset += btRead;
312
- // Read chain length as MiniNumber
313
- const { value: numChunks, bytesRead: ncRead } = readMiniNumber(data, offset);
314
- offset += ncRead;
315
- const chunks = [];
316
- for (let i = 0; i < Number(numChunks); i++) {
317
- // isLeft flag (1 byte)
318
- const isLeft = data[offset] === 1;
319
- offset += 1;
320
- // MMRData: hash (4-byte length prefix + hash bytes) + value (MiniNumber)
321
- // Read 4-byte big-endian length
322
- const hashLength = (data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3];
323
- offset += 4;
324
- const hashData = data.slice(offset, offset + hashLength);
325
- offset += hashLength;
326
- const { value: chunkValue, bytesRead: cvRead } = readMiniNumber(data, offset);
327
- offset += cvRead;
328
- chunks.push({ isLeft, mmrData: { data: hashData, value: chunkValue } });
329
- }
330
- return { proof: { chunks }, blockTime, bytesRead: offset };
331
- }
332
- /**
333
- * Read a MiniNumber from bytes at the given offset
334
- * Format: [scale: 1 byte] [length: 1 byte] [data: N bytes]
335
- */
336
- function readMiniNumber(data, offset) {
337
- const scale = data[offset];
338
- const length = data[offset + 1];
339
- if (length === 0) {
340
- // Zero value (shouldn't happen with proper serialization)
341
- return { value: 0n, bytesRead: 2 };
342
- }
343
- const dataBytes = data.slice(offset + 2, offset + 2 + length);
344
- // Convert bytes to bigint
345
- let value = 0n;
346
- for (let i = 0; i < dataBytes.length; i++) {
347
- value = (value << 8n) | BigInt(dataBytes[i]);
348
- }
349
- // Apply scale if non-zero (for decimal numbers)
350
- // For TreeKey MMR, scale is always 0
351
- return { value, bytesRead: 2 + length };
352
- }
@@ -1,28 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { mmrRootFromSingleLeaf } from "./mmr";
3
- import { bytesToHex } from "@noble/hashes/utils.js";
4
-
5
- const enc = (s: string) => new TextEncoder().encode(s);
6
-
7
- describe("MMR roots (single-leaf) – Minima oracles", () => {
8
- it("RETURN TRUE", () => {
9
- const root = mmrRootFromSingleLeaf("RETURN TRUE");
10
- expect(bytesToHex(root).toUpperCase()).toBe(
11
- "582AA40EA996419A3D8A5D26039A4E9584B746C2C26F860DAC8372BEA4457AF6"
12
- );
13
- });
14
-
15
- it("LET x 1 RETURN x == 1", () => {
16
- const root = mmrRootFromSingleLeaf("LET x 1 RETURN x == 1");
17
- expect(bytesToHex(root).toUpperCase()).toBe(
18
- "B3FA26AEA3FFD4367C23DFFEB55C17BE75AE4A923E4A3A9E790CFEFC5A96FB93"
19
- );
20
- });
21
-
22
- it("RETURN SIGNEDBY(0xFFFF)", () => {
23
- const root = mmrRootFromSingleLeaf("RETURN SIGNEDBY(0xFFFF)");
24
- expect(bytesToHex(root).toUpperCase()).toBe(
25
- "65EC70E6DEF38CBC8E1556305F06637BF8D6B0EF5719C3CD9386981D250B9E95"
26
- );
27
- });
28
- });