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