@totemsdk/core 1.0.9 → 1.0.11

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 (145) 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.d.ts +2 -2
  39. package/dist/wots.js +94 -64
  40. package/package.json +50 -6
  41. package/src/Streamable.d.ts +0 -268
  42. package/src/Streamable.js +0 -416
  43. package/src/Streamable.ts +0 -567
  44. package/src/__tests__/Streamable.parity.test.ts +0 -422
  45. package/src/__tests__/perAddressDerivation.parity.test.ts +0 -152
  46. package/src/__tests__/roottree-prepare.test.ts +0 -101
  47. package/src/__tests__/wots-parity.test.ts +0 -289
  48. package/src/adapters/index.d.ts +0 -190
  49. package/src/adapters/index.js +0 -117
  50. package/src/adapters/index.ts +0 -301
  51. package/src/adapters/types.ts +0 -235
  52. package/src/addr.oracle.test.ts +0 -25
  53. package/src/address.test.ts +0 -55
  54. package/src/binio.ts +0 -21
  55. package/src/bip39.d.ts +0 -91
  56. package/src/bip39.js +0 -427
  57. package/src/bip39.ts +0 -432
  58. package/src/derive.d.ts +0 -2
  59. package/src/derive.js +0 -13
  60. package/src/derive.ts +0 -11
  61. package/src/index.d.ts +0 -26
  62. package/src/index.js +0 -128
  63. package/src/index.test.ts +0 -5
  64. package/src/index.ts +0 -221
  65. package/src/javaStreamables.d.ts +0 -233
  66. package/src/javaStreamables.js +0 -332
  67. package/src/javaStreamables.ts +0 -403
  68. package/src/lease/LeaseMonitor.d.ts +0 -44
  69. package/src/lease/LeaseMonitor.js +0 -111
  70. package/src/lease/LeaseMonitor.ts +0 -157
  71. package/src/lease/LeaseStore.d.ts +0 -57
  72. package/src/lease/LeaseStore.js +0 -148
  73. package/src/lease/LeaseStore.ts +0 -203
  74. package/src/lease/WatermarkStore.d.ts +0 -61
  75. package/src/lease/WatermarkStore.js +0 -206
  76. package/src/lease/WatermarkStore.ts +0 -270
  77. package/src/lease/index.d.ts +0 -14
  78. package/src/lease/index.js +0 -22
  79. package/src/lease/index.ts +0 -41
  80. package/src/lease-client.d.ts +0 -31
  81. package/src/lease-client.js +0 -44
  82. package/src/lease-client.ts +0 -69
  83. package/src/minima32.d.ts +0 -10
  84. package/src/minima32.js +0 -113
  85. package/src/minima32.test.ts +0 -11
  86. package/src/minima32.ts +0 -127
  87. package/src/minimaWireSerializer.d.ts +0 -189
  88. package/src/minimaWireSerializer.js +0 -311
  89. package/src/minimaWireSerializer.test.ts +0 -466
  90. package/src/minimaWireSerializer.ts +0 -117
  91. package/src/mmr.d.ts +0 -157
  92. package/src/mmr.js +0 -340
  93. package/src/mmr.oracle.test.ts +0 -28
  94. package/src/mmr.ts +0 -429
  95. package/src/mx.test.ts +0 -25
  96. package/src/mx.ts +0 -1
  97. package/src/params.d.ts +0 -29
  98. package/src/params.d.ts.map +0 -1
  99. package/src/params.js +0 -20
  100. package/src/params.js.map +0 -1
  101. package/src/params.ts +0 -44
  102. package/src/script.d.ts +0 -7
  103. package/src/script.js +0 -27
  104. package/src/script.ts +0 -24
  105. package/src/scripts/contract-helpers.ts +0 -609
  106. package/src/scripts/dapp-types.ts +0 -240
  107. package/src/scripts/index.ts +0 -22
  108. package/src/scripts/types.d.ts +0 -81
  109. package/src/scripts/types.js +0 -145
  110. package/src/scripts/types.ts +0 -247
  111. package/src/scripts/witness-serializer.ts +0 -384
  112. package/src/transaction.ts +0 -430
  113. package/src/treekey.d.ts +0 -383
  114. package/src/treekey.js +0 -774
  115. package/src/treekey.parity.test.ts +0 -459
  116. package/src/treekey.ts +0 -975
  117. package/src/tx/TransactionLifecycle.d.ts +0 -55
  118. package/src/tx/TransactionLifecycle.js +0 -188
  119. package/src/tx/TransactionLifecycle.ts +0 -280
  120. package/src/tx/TransactionReceiptStore.d.ts +0 -36
  121. package/src/tx/TransactionReceiptStore.js +0 -89
  122. package/src/tx/TransactionReceiptStore.ts +0 -112
  123. package/src/tx/TransactionService.d.ts +0 -31
  124. package/src/tx/TransactionService.js +0 -140
  125. package/src/tx/TransactionService.ts +0 -252
  126. package/src/tx/index.d.ts +0 -13
  127. package/src/tx/index.js +0 -20
  128. package/src/tx/index.ts +0 -44
  129. package/src/tx/types.d.ts +0 -80
  130. package/src/tx/types.js +0 -6
  131. package/src/tx/types.ts +0 -130
  132. package/src/util.d.ts +0 -1
  133. package/src/util.js +0 -5
  134. package/src/util.ts +0 -1
  135. package/src/utils.d.ts +0 -8
  136. package/src/utils.js +0 -42
  137. package/src/utils.ts +0 -38
  138. package/src/verify.ts +0 -210
  139. package/src/version.ts +0 -13
  140. package/src/wots.d.ts +0 -224
  141. package/src/wots.d.ts.map +0 -1
  142. package/src/wots.js +0 -565
  143. package/src/wots.js.map +0 -1
  144. package/src/wots.ts +0 -651
  145. package/test-vectors.json +0 -45
@@ -1,422 +0,0 @@
1
- /**
2
- * Streamable.parity.test.ts - Byte-for-Byte Java Parity Tests
3
- *
4
- * These tests validate that our TypeScript serialization produces
5
- * byte-exact output matching Minima's Java implementation.
6
- *
7
- * JAVA REFERENCE FILES (from attached_assets):
8
- * - MiniNumber_1767465037473.java: MiniNumber.writeDataStream()
9
- * - MiniData_1767465051037.java: MiniData.writeDataStream(), writeHashToStream()
10
- * - MMRData_1768742834148.java: MMRData.writeDataStream()
11
- * - MMRProof_1768740810861.java: MMRProof.writeDataStream(), MMRProofChunk.writeDataStream()
12
- * - SignatureProof_1768848582024.java: SignatureProof.writeDataStream()
13
- * - Signature_1767887681489.java: Signature.writeDataStream()
14
- * - Witness_1766887812428.java: Witness.writeDataStream()
15
- *
16
- * Created: 2026-01-26
17
- * Purpose: Gate all serialization changes with Java parity validation
18
- */
19
-
20
- // Jest test suite (SDK uses Jest, not Vitest)
21
- import {
22
- hexToBytes,
23
- bytesToHex,
24
- concat,
25
- writeMiniByte,
26
- writeMiniData,
27
- writeMiniNumber,
28
- writeHashToStream,
29
- writeMMREntryNumber,
30
- bigIntToByteArray,
31
- writeMMRData,
32
- writeMMRProofChunk,
33
- writeMMRProof,
34
- writeSignatureProof,
35
- writeSignature,
36
- writeWitness,
37
- writeHierarchicalWitness,
38
- type MMRData,
39
- type MMRProofChunk,
40
- type MMRProof,
41
- type SignatureProof,
42
- type Signature,
43
- } from '../Streamable';
44
-
45
- /**
46
- * Helper to compare bytes and show diff on failure
47
- */
48
- function expectBytesEqual(actual: Uint8Array, expected: Uint8Array, context: string = '') {
49
- const actualHex = bytesToHex(actual);
50
- const expectedHex = bytesToHex(expected);
51
- if (actualHex !== expectedHex) {
52
- console.error(`${context} Mismatch:`);
53
- console.error(` Expected: ${expectedHex} (${expected.length} bytes)`);
54
- console.error(` Actual: ${actualHex} (${actual.length} bytes)`);
55
- }
56
- expect(actualHex).toBe(expectedHex);
57
- }
58
-
59
- describe('MiniNumber Serialization (Java Parity)', () => {
60
- /**
61
- * Java MiniNumber.writeDataStream():
62
- * 1 byte: scale (signed)
63
- * 1 byte: length of unscaled BigInteger data
64
- * N bytes: unscaled BigInteger in two's complement
65
- */
66
-
67
- it('MiniNumber(0) → [0x00, 0x01, 0x00]', () => {
68
- const result = writeMiniNumber(0n, 0);
69
- expectBytesEqual(result, new Uint8Array([0x00, 0x01, 0x00]), 'MiniNumber(0)');
70
- });
71
-
72
- it('MiniNumber(1) → [0x00, 0x01, 0x01]', () => {
73
- const result = writeMiniNumber(1n, 0);
74
- expectBytesEqual(result, new Uint8Array([0x00, 0x01, 0x01]), 'MiniNumber(1)');
75
- });
76
-
77
- it('MiniNumber(127) → [0x00, 0x01, 0x7F]', () => {
78
- const result = writeMiniNumber(127n, 0);
79
- expectBytesEqual(result, new Uint8Array([0x00, 0x01, 0x7F]), 'MiniNumber(127)');
80
- });
81
-
82
- it('MiniNumber(128) → [0x00, 0x02, 0x00, 0x80] (needs leading zero)', () => {
83
- const result = writeMiniNumber(128n, 0);
84
- expectBytesEqual(result, new Uint8Array([0x00, 0x02, 0x00, 0x80]), 'MiniNumber(128)');
85
- });
86
-
87
- it('MiniNumber(255) → [0x00, 0x02, 0x00, 0xFF]', () => {
88
- const result = writeMiniNumber(255n, 0);
89
- expectBytesEqual(result, new Uint8Array([0x00, 0x02, 0x00, 0xFF]), 'MiniNumber(255)');
90
- });
91
-
92
- it('MiniNumber(256) → [0x00, 0x02, 0x01, 0x00]', () => {
93
- const result = writeMiniNumber(256n, 0);
94
- expectBytesEqual(result, new Uint8Array([0x00, 0x02, 0x01, 0x00]), 'MiniNumber(256)');
95
- });
96
-
97
- it('MiniNumber(65535) → [0x00, 0x03, 0x00, 0xFF, 0xFF]', () => {
98
- const result = writeMiniNumber(65535n, 0);
99
- expectBytesEqual(result, new Uint8Array([0x00, 0x03, 0x00, 0xFF, 0xFF]), 'MiniNumber(65535)');
100
- });
101
-
102
- it('MiniNumber with scale=2 (e.g., 123 with 2 decimal places)', () => {
103
- const result = writeMiniNumber(123n, 2);
104
- expectBytesEqual(result, new Uint8Array([0x02, 0x01, 0x7B]), 'MiniNumber(123, scale=2)');
105
- });
106
- });
107
-
108
- describe('MiniData Serialization (Java Parity)', () => {
109
- /**
110
- * Java MiniData.writeDataStream():
111
- * 4 bytes: big-endian int length
112
- * N bytes: raw data
113
- */
114
-
115
- it('Empty MiniData → [0x00, 0x00, 0x00, 0x00]', () => {
116
- const result = writeMiniData(new Uint8Array(0));
117
- expectBytesEqual(result, new Uint8Array([0x00, 0x00, 0x00, 0x00]), 'Empty MiniData');
118
- });
119
-
120
- it('MiniData([0xAB]) → [0x00, 0x00, 0x00, 0x01, 0xAB]', () => {
121
- const result = writeMiniData(new Uint8Array([0xAB]));
122
- expectBytesEqual(result, new Uint8Array([0x00, 0x00, 0x00, 0x01, 0xAB]), 'MiniData(1 byte)');
123
- });
124
-
125
- it('MiniData(32-byte hash) → 4-byte len + 32 bytes', () => {
126
- const hash = new Uint8Array(32).fill(0xAA);
127
- const result = writeMiniData(hash);
128
- expect(result.length).toBe(36);
129
- expect(result[0]).toBe(0x00);
130
- expect(result[1]).toBe(0x00);
131
- expect(result[2]).toBe(0x00);
132
- expect(result[3]).toBe(0x20); // 32 in hex
133
- expect(result[4]).toBe(0xAA);
134
- expect(result[35]).toBe(0xAA);
135
- });
136
- });
137
-
138
- describe('writeHashToStream (Java Crypto.writeHashToStream Parity)', () => {
139
- /**
140
- * Java Crypto.writeHashToStream() is same as MiniData.writeDataStream()
141
- */
142
-
143
- it('32-byte hash → 4-byte len + 32 bytes', () => {
144
- const hash = hexToBytes('0x' + 'AB'.repeat(32));
145
- const result = writeHashToStream(hash);
146
- expect(result.length).toBe(36);
147
- expect(result[3]).toBe(0x20); // length = 32
148
- });
149
- });
150
-
151
- describe('MiniByte Serialization (Java Parity)', () => {
152
- /**
153
- * Java MiniByte.writeDataStream(): single byte
154
- */
155
-
156
- it('MiniByte(false) → [0x00]', () => {
157
- const result = writeMiniByte(false);
158
- expectBytesEqual(result, new Uint8Array([0x00]), 'MiniByte(false)');
159
- });
160
-
161
- it('MiniByte(true) → [0x01]', () => {
162
- const result = writeMiniByte(true);
163
- expectBytesEqual(result, new Uint8Array([0x01]), 'MiniByte(true)');
164
- });
165
-
166
- it('MiniByte(0) → [0x00]', () => {
167
- const result = writeMiniByte(0);
168
- expectBytesEqual(result, new Uint8Array([0x00]), 'MiniByte(0)');
169
- });
170
-
171
- it('MiniByte(255) → [0xFF]', () => {
172
- const result = writeMiniByte(255);
173
- expectBytesEqual(result, new Uint8Array([0xFF]), 'MiniByte(255)');
174
- });
175
- });
176
-
177
- describe('BigInt to ByteArray (Java BigInteger.toByteArray Parity)', () => {
178
- /**
179
- * Java BigInteger.toByteArray() uses two's complement:
180
- * - Zero → [0x00]
181
- * - Positive with high bit set → leading 0x00 byte
182
- */
183
-
184
- it('0n → [0x00]', () => {
185
- const result = bigIntToByteArray(0n);
186
- expectBytesEqual(result, new Uint8Array([0x00]), 'BigInt(0)');
187
- });
188
-
189
- it('1n → [0x01]', () => {
190
- const result = bigIntToByteArray(1n);
191
- expectBytesEqual(result, new Uint8Array([0x01]), 'BigInt(1)');
192
- });
193
-
194
- it('127n → [0x7F]', () => {
195
- const result = bigIntToByteArray(127n);
196
- expectBytesEqual(result, new Uint8Array([0x7F]), 'BigInt(127)');
197
- });
198
-
199
- it('128n → [0x00, 0x80] (two\'s complement needs leading zero)', () => {
200
- const result = bigIntToByteArray(128n);
201
- expectBytesEqual(result, new Uint8Array([0x00, 0x80]), 'BigInt(128)');
202
- });
203
-
204
- it('255n → [0x00, 0xFF]', () => {
205
- const result = bigIntToByteArray(255n);
206
- expectBytesEqual(result, new Uint8Array([0x00, 0xFF]), 'BigInt(255)');
207
- });
208
-
209
- it('256n → [0x01, 0x00]', () => {
210
- const result = bigIntToByteArray(256n);
211
- expectBytesEqual(result, new Uint8Array([0x01, 0x00]), 'BigInt(256)');
212
- });
213
-
214
- it('32767n → [0x7F, 0xFF]', () => {
215
- const result = bigIntToByteArray(32767n);
216
- expectBytesEqual(result, new Uint8Array([0x7F, 0xFF]), 'BigInt(32767)');
217
- });
218
-
219
- it('32768n → [0x00, 0x80, 0x00] (needs leading zero)', () => {
220
- const result = bigIntToByteArray(32768n);
221
- expectBytesEqual(result, new Uint8Array([0x00, 0x80, 0x00]), 'BigInt(32768)');
222
- });
223
- });
224
-
225
- describe('MMREntryNumber Serialization (Java Parity)', () => {
226
- /**
227
- * Java MMREntryNumber.writeDataStream():
228
- * MiniNumber for scale (always 0 for integers)
229
- * MiniData for unscaled BigInteger value
230
- *
231
- * For value=0, scale=0:
232
- * [00 01 00] - MiniNumber: scale=0, len=1, data=0x00
233
- * [00 00 00 01 00] - MiniData: len=1, data=0x00
234
- */
235
-
236
- it('MMREntryNumber(0) → MiniNumber(0) + MiniData([0x00])', () => {
237
- const result = writeMMREntryNumber(0n, 0);
238
- const expected = concat(
239
- new Uint8Array([0x00, 0x01, 0x00]), // MiniNumber for scale=0
240
- new Uint8Array([0x00, 0x00, 0x00, 0x01, 0x00]) // MiniData for value=0
241
- );
242
- expectBytesEqual(result, expected, 'MMREntryNumber(0)');
243
- });
244
-
245
- it('MMREntryNumber(1) → MiniNumber(0) + MiniData([0x01])', () => {
246
- const result = writeMMREntryNumber(1n, 0);
247
- const expected = concat(
248
- new Uint8Array([0x00, 0x01, 0x00]), // MiniNumber for scale=0
249
- new Uint8Array([0x00, 0x00, 0x00, 0x01, 0x01]) // MiniData for value=1
250
- );
251
- expectBytesEqual(result, expected, 'MMREntryNumber(1)');
252
- });
253
- });
254
-
255
- // ============================================================
256
- // MMR STRUCTURE SERIALIZATION TESTS
257
- // ============================================================
258
-
259
- describe('MMRData Serialization (Java Parity)', () => {
260
- it('MMRData with 32-byte hash and value=0', () => {
261
- const hash = new Uint8Array(32).fill(0xAA);
262
- const mmrData: MMRData = { data: hash, value: 0n };
263
- const result = writeMMRData(mmrData);
264
-
265
- // Expected: writeHashToStream(32 bytes) + MiniNumber(0)
266
- // = [00 00 00 20] + <32 bytes> + [00 01 00]
267
- expect(result.length).toBe(4 + 32 + 3); // 39 bytes
268
- expect(result[0]).toBe(0x00); // length high byte
269
- expect(result[3]).toBe(0x20); // length = 32
270
- expect(result[4]).toBe(0xAA); // first hash byte
271
- expect(result[35]).toBe(0xAA); // last hash byte
272
- expect(result[36]).toBe(0x00); // MiniNumber scale
273
- expect(result[37]).toBe(0x01); // MiniNumber length
274
- expect(result[38]).toBe(0x00); // MiniNumber value = 0
275
- });
276
-
277
- it('MMRData with value=1', () => {
278
- const hash = new Uint8Array(32).fill(0x00);
279
- const mmrData: MMRData = { data: hash, value: 1n };
280
- const result = writeMMRData(mmrData);
281
-
282
- expect(result.length).toBe(39);
283
- expect(result[38]).toBe(0x01); // MiniNumber value = 1
284
- });
285
- });
286
-
287
- describe('MMRProofChunk Serialization (Java Parity)', () => {
288
- it('MMRProofChunk(isLeft=true)', () => {
289
- const hash = new Uint8Array(32).fill(0xBB);
290
- const chunk: MMRProofChunk = {
291
- isLeft: true,
292
- mmrData: { data: hash, value: 0n }
293
- };
294
- const result = writeMMRProofChunk(chunk);
295
-
296
- // Expected: MiniByte(1) + MMRData
297
- // = [01] + 39 bytes = 40 bytes
298
- expect(result.length).toBe(40);
299
- expect(result[0]).toBe(0x01); // isLeft = true
300
- expect(result[1]).toBe(0x00); // MMRData hash length high byte
301
- });
302
-
303
- it('MMRProofChunk(isLeft=false)', () => {
304
- const hash = new Uint8Array(32).fill(0xCC);
305
- const chunk: MMRProofChunk = {
306
- isLeft: false,
307
- mmrData: { data: hash, value: 0n }
308
- };
309
- const result = writeMMRProofChunk(chunk);
310
-
311
- expect(result[0]).toBe(0x00); // isLeft = false
312
- });
313
- });
314
-
315
- describe('MMRProof Serialization (Java Parity)', () => {
316
- it('Empty MMRProof with blockTime=0', () => {
317
- const proof: MMRProof = { blockTime: 0n, chunks: [] };
318
- const result = writeMMRProof(proof);
319
-
320
- // Expected: MiniNumber(0) + MiniNumber(0)
321
- // = [00 01 00] + [00 01 00] = 6 bytes
322
- expectBytesEqual(result, concat(
323
- new Uint8Array([0x00, 0x01, 0x00]), // blockTime = 0
324
- new Uint8Array([0x00, 0x01, 0x00]) // length = 0
325
- ), 'Empty MMRProof');
326
- });
327
-
328
- it('MMRProof with 1 chunk', () => {
329
- const hash = new Uint8Array(32).fill(0xDD);
330
- const proof: MMRProof = {
331
- blockTime: 0n,
332
- chunks: [{
333
- isLeft: true,
334
- mmrData: { data: hash, value: 0n }
335
- }]
336
- };
337
- const result = writeMMRProof(proof);
338
-
339
- // Expected: MiniNumber(0) + MiniNumber(1) + chunk(40 bytes)
340
- // = 3 + 3 + 40 = 46 bytes
341
- expect(result.length).toBe(46);
342
- expect(result[5]).toBe(0x01); // length = 1
343
- });
344
- });
345
-
346
- describe('SignatureProof Serialization (Java Parity)', () => {
347
- it('SignatureProof with 32-byte pubkey, empty proof', () => {
348
- const pubKey = new Uint8Array(32).fill(0x11);
349
- const signature = new Uint8Array(1088).fill(0x22);
350
- const sigProof: SignatureProof = {
351
- leafPubkey: pubKey,
352
- signature: signature,
353
- mmrProof: { blockTime: 0n, chunks: [] }
354
- };
355
- const result = writeSignatureProof(sigProof);
356
-
357
- // Expected: MiniData(32) + MiniData(1088) + MMRProof(6)
358
- // = (4+32) + (4+1088) + 6 = 36 + 1092 + 6 = 1134 bytes
359
- expect(result.length).toBe(1134);
360
- expect(result[3]).toBe(0x20); // pubkey length = 32
361
- // Signature length starts at byte 36 (after 4+32 pubkey bytes)
362
- // 1088 = 0x00000440 in big-endian
363
- expect(result[36]).toBe(0x00); // signature length byte 0
364
- expect(result[37]).toBe(0x00); // signature length byte 1
365
- expect(result[38]).toBe(0x04); // signature length byte 2 (1088 = 0x0440)
366
- expect(result[39]).toBe(0x40); // signature length byte 3
367
- });
368
- });
369
-
370
- describe('Signature Serialization (Java Parity)', () => {
371
- it('Empty Signature (no proofs)', () => {
372
- const sig: Signature = { proofs: [] };
373
- const result = writeSignature(sig);
374
-
375
- // Expected: MiniNumber(0) = [00 01 00]
376
- expectBytesEqual(result, new Uint8Array([0x00, 0x01, 0x00]), 'Empty Signature');
377
- });
378
-
379
- it('Signature with 1 proof', () => {
380
- const pubKey = new Uint8Array(32).fill(0x33);
381
- const signature = new Uint8Array(1088).fill(0x44);
382
- const sig: Signature = {
383
- proofs: [{
384
- leafPubkey: pubKey,
385
- signature: signature,
386
- mmrProof: { blockTime: 0n, chunks: [] }
387
- }]
388
- };
389
- const result = writeSignature(sig);
390
-
391
- // Expected: MiniNumber(1) + SignatureProof(1134)
392
- // = 3 + 1134 = 1137 bytes
393
- expect(result.length).toBe(1137);
394
- expect(result[2]).toBe(0x01); // length = 1
395
- });
396
- });
397
-
398
- describe('Witness/HierarchicalWitness Serialization (Java Parity)', () => {
399
- it('Empty Witness (no proofs)', () => {
400
- const witness = {
401
- signatures: [],
402
- coinProofs: [],
403
- scriptProofs: []
404
- };
405
- const result = writeWitness(witness);
406
-
407
- // Expected: 3x MiniNumber(0) = [00 01 00] [00 01 00] [00 01 00]
408
- expectBytesEqual(result, concat(
409
- new Uint8Array([0x00, 0x01, 0x00]),
410
- new Uint8Array([0x00, 0x01, 0x00]),
411
- new Uint8Array([0x00, 0x01, 0x00])
412
- ), 'Empty Witness');
413
- });
414
-
415
- it('Empty HierarchicalWitness', () => {
416
- const bundle = { signatures: [] };
417
- const result = writeHierarchicalWitness(bundle);
418
-
419
- // Expected: MiniNumber(0) = [00 01 00]
420
- expectBytesEqual(result, new Uint8Array([0x00, 0x01, 0x00]), 'Empty HierarchicalWitness');
421
- });
422
- });
@@ -1,152 +0,0 @@
1
- /**
2
- * Parity test: Per-address key derivation matching Minima Wallet.java
3
- *
4
- * Verifies that derivePerAddressSeed() matches Minima Wallet.createNewKey():
5
- * MiniData modifier = new MiniData(new BigInteger(Integer.toString(numkeys)));
6
- * MiniData privseed = Crypto.getInstance().hashObjects(baseSeed, modifier);
7
- * TreeKey treekey = TreeKey.createDefault(privseed);
8
- *
9
- * Created: 2026-02-05
10
- * Purpose: Validate per-address key derivation matches Minima Wallet.java
11
- */
12
-
13
- import { derivePerAddressSeed, indexToMiniDataBytes } from '../javaStreamables';
14
- import { TreeKey, createPerAddressTreeKey, deriveAddressPublicKey, getRootPublicKey, verifyTreeSignature } from '../treekey';
15
-
16
- // Test seed (same as Java test)
17
- const TEST_SEED = new Uint8Array([
18
- 0x51, 0xD9, 0xF4, 0x03, 0x27, 0x1E, 0x26, 0x72,
19
- 0x29, 0xB6, 0xC2, 0xA9, 0x5C, 0x5E, 0xAE, 0xD5,
20
- 0x27, 0x84, 0x6A, 0x1A, 0xF8, 0x9F, 0x8B, 0x1C,
21
- 0xF5, 0x57, 0x4B, 0x0E, 0x79, 0xA4, 0x9C, 0xF1
22
- ]);
23
-
24
- function toHex(bytes: Uint8Array): string {
25
- return '0x' + Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('').toUpperCase();
26
- }
27
-
28
- describe('Per-Address Key Derivation (Minima Wallet Parity)', () => {
29
- // Expected values from Java TestPerAddressKeyDerivation.java
30
- const javaExpected = [
31
- { index: 0, modifier: '0x00', privSeed: '0x6DD2281FD93037819358EA2DCC27C8DE4F358EB2DC17D9C5907B500184DAA172', pubKey: '0x75C8EE428AC72E1D7A4A7A7E02A6E7B8BEE4F7281B73C0199BBC0CDD59B05C88' },
32
- { index: 1, modifier: '0x01', privSeed: '0x3BAC5E60BA11049C1BAA2F065F9C21F736F3E30F37F7213EE9A37BF755AE83E5', pubKey: '0xD008FC735BC7A8FB4912584F61F7F8D9469E4146128985209B0EF5048BBEA215' },
33
- { index: 2, modifier: '0x02', privSeed: '0xF63171651D6110F9DD086EB3AC3D35CFE41DA8B504DD81C9575781C02F8EC6B0', pubKey: '0xBBC3D6F727CFD1D413CE152830F626EC89AC3435144A86BF932E6D5C0DB67BDF' },
34
- { index: 3, modifier: '0x03', privSeed: '0x65EFC1CC40BF30127B55F716860EDCB32A2C47F8434A44479A85CE0D2D2A07BA', pubKey: '0x75166F510C0457E3D1C94EA17A89D47EE4A90DBC71D94B06111C34E2AAC91D8C' },
35
- { index: 4, modifier: '0x04', privSeed: '0xF9A21A47941E47C4F98D212D98E8D8CC2A5D3AD03D473379F037CF5914433DB7', pubKey: '0xBFB7AD971C3A665F96E2A8BADDF14301DC8EBA2E45AEEA34AF85EC428F39F835' },
36
- ];
37
-
38
- describe('indexToMiniDataBytes', () => {
39
- it('converts index 0 to 0x00', () => {
40
- expect(toHex(indexToMiniDataBytes(0))).toBe('0x00');
41
- });
42
-
43
- it('converts index 1 to 0x01', () => {
44
- expect(toHex(indexToMiniDataBytes(1))).toBe('0x01');
45
- });
46
-
47
- it('converts index 63 to 0x3F', () => {
48
- expect(toHex(indexToMiniDataBytes(63))).toBe('0x3F');
49
- });
50
-
51
- it('converts index 64 to 0x40', () => {
52
- expect(toHex(indexToMiniDataBytes(64))).toBe('0x40');
53
- });
54
-
55
- it('converts index 255 to 0xFF', () => {
56
- expect(toHex(indexToMiniDataBytes(255))).toBe('0xFF');
57
- });
58
-
59
- it('converts index 256 to 0x0100 (2 bytes)', () => {
60
- expect(toHex(indexToMiniDataBytes(256))).toBe('0x0100');
61
- });
62
- });
63
-
64
- describe('derivePerAddressSeed', () => {
65
- javaExpected.forEach(({ index, modifier, privSeed }) => {
66
- it(`derives correct private seed for address ${index}`, () => {
67
- const modifierBytes = indexToMiniDataBytes(index);
68
- expect(toHex(modifierBytes)).toBe(modifier);
69
-
70
- const derivedSeed = derivePerAddressSeed(TEST_SEED, index);
71
- expect(toHex(derivedSeed)).toBe(privSeed);
72
- });
73
- });
74
- });
75
-
76
- describe('Full address public key derivation', () => {
77
- javaExpected.forEach(({ index, pubKey }) => {
78
- it(`derives correct public key for address ${index}`, () => {
79
- // Step 1: Derive private seed for this address
80
- const privSeed = derivePerAddressSeed(TEST_SEED, index);
81
-
82
- // Step 2: Create TreeKey from private seed (size=64, depth=3 matches TreeKey.createDefault)
83
- const treeKey = new TreeKey(privSeed, 64, 3);
84
-
85
- // Step 3: Get public key (MMR root)
86
- const derivedPubKey = treeKey.getPublicKey();
87
-
88
- expect(toHex(derivedPubKey)).toBe(pubKey);
89
- });
90
- });
91
- });
92
-
93
- describe('createPerAddressTreeKey factory', () => {
94
- javaExpected.forEach(({ index, pubKey }) => {
95
- test(`factory creates correct TreeKey for address ${index}`, () => {
96
- const treeKey = createPerAddressTreeKey(TEST_SEED, index);
97
-
98
- expect(toHex(treeKey.getPublicKey())).toBe(pubKey);
99
- expect(treeKey.getMaxUses()).toBe(64 * 64 * 64);
100
- });
101
- });
102
- });
103
-
104
- describe('deriveAddressPublicKey helper', () => {
105
- javaExpected.forEach(({ index, pubKey }) => {
106
- test(`derives correct address pubkey for index ${index}`, () => {
107
- const addressPubkey = deriveAddressPublicKey(TEST_SEED, index);
108
- expect(toHex(addressPubkey)).toBe(pubKey);
109
- });
110
- });
111
- });
112
-
113
- describe('setUses + sign signing flow', () => {
114
- test('setUses + sign produces 3 proofs with correct structure', () => {
115
- const treeKey = createPerAddressTreeKey(TEST_SEED, 0);
116
- const testData = new Uint8Array(32).fill(0xAB);
117
-
118
- treeKey.setUses(0 * 64 + 0);
119
- const signature = treeKey.sign(testData);
120
-
121
- expect(signature.proofs).toHaveLength(3);
122
- expect(signature.proofs[0].leafPubkey).toHaveLength(32);
123
- expect(signature.proofs[0].signature).toHaveLength(1088);
124
- expect(signature.proofs[1].leafPubkey).toHaveLength(32);
125
- expect(signature.proofs[1].signature).toHaveLength(1088);
126
- expect(signature.proofs[2].leafPubkey).toHaveLength(32);
127
- expect(signature.proofs[2].signature).toHaveLength(1088);
128
- });
129
-
130
- test('sign first proof root matches TreeKey root public key', () => {
131
- const treeKey = createPerAddressTreeKey(TEST_SEED, 0);
132
- const testData = new Uint8Array(32).fill(0xCD);
133
-
134
- treeKey.setUses(0 * 64 + 0);
135
- const signature = treeKey.sign(testData);
136
- const proof0Root = getRootPublicKey(signature.proofs[0]);
137
-
138
- expect(toHex(proof0Root)).toBe(toHex(treeKey.getPublicKey()));
139
- });
140
-
141
- test('sign signature verifies correctly', () => {
142
- const treeKey = createPerAddressTreeKey(TEST_SEED, 1);
143
- const testData = new Uint8Array(32).fill(0xEF);
144
-
145
- treeKey.setUses(1 * 64 + 1);
146
- const signature = treeKey.sign(testData);
147
- const isValid = verifyTreeSignature(treeKey.getPublicKey(), testData, signature);
148
-
149
- expect(isValid).toBe(true);
150
- });
151
- });
152
- });
@@ -1,101 +0,0 @@
1
- /**
2
- * RootTree prepare() propagation tests
3
- *
4
- * Verifies that TransactionService.prepare() correctly forwards walletMode
5
- * and perAddressPublicKey in the POST body so the /prepare endpoint can
6
- * apply RootTree-specific validation and return perAddressScript.
7
- */
8
-
9
- import { TransactionService } from '../tx/TransactionService.js';
10
- import type { TransactionServiceConfig } from '../tx/TransactionService.js';
11
- import type { HttpClient } from '../adapters/index.js';
12
-
13
- function makeMockHttp(capturedBodies: any[]): HttpClient {
14
- return {
15
- post: async <T>(_url: string, body: any): Promise<{ ok: boolean; status: number; data: T }> => {
16
- capturedBodies.push({ body });
17
- return {
18
- ok: true,
19
- status: 200,
20
- data: {
21
- addressIndex: 0,
22
- l1: 0,
23
- l2: 0,
24
- leaseToken: 'mock-lease-token',
25
- digestTx: '0x' + 'ab'.repeat(32),
26
- digestL2: null,
27
- digestL3: null,
28
- txId: 'tx-mock',
29
- rootPublicKey: '0x' + 'ff'.repeat(32),
30
- paramSet: 'v2-spec',
31
- leaseId: 'lease-mock',
32
- leaseTTL: 120000,
33
- perAddressScript: 'RETURN SIGNEDBY(0x' + 'ff'.repeat(32) + ')',
34
- } as T,
35
- };
36
- },
37
- get: async <T>(): Promise<{ ok: boolean; status: number; data: T }> => ({
38
- ok: true, status: 200, data: {} as T,
39
- }),
40
- };
41
- }
42
-
43
- const config: TransactionServiceConfig = {
44
- baseUrl: 'https://api.example.com',
45
- apiKey: 'test-api-key',
46
- paramSet: 'v2-spec',
47
- };
48
-
49
- const MOCK_ROOT_PK = '0x' + 'aa'.repeat(32);
50
- const MOCK_PER_ADDR_PK = '0x' + 'bb'.repeat(32);
51
-
52
- describe('TransactionService.prepare() — RootTree propagation', () => {
53
- it('sends walletMode=AnonTree by default', async () => {
54
- const bodies: any[] = [];
55
- const svc = new TransactionService(makeMockHttp(bodies), config);
56
-
57
- await svc.prepare(
58
- { to: 'MxABC', amount: '1', addressIndex: 0 },
59
- MOCK_ROOT_PK
60
- );
61
-
62
- expect(bodies).toHaveLength(1);
63
- expect(bodies[0].body.walletMode).toBe('AnonTree');
64
- expect(bodies[0].body.perAddressPublicKey).toBeNull();
65
- });
66
-
67
- it('forwards walletMode=RootTree and perAddressPublicKey in POST body', async () => {
68
- const bodies: any[] = [];
69
- const svc = new TransactionService(makeMockHttp(bodies), config);
70
-
71
- await svc.prepare(
72
- {
73
- to: 'MxABC',
74
- amount: '1',
75
- addressIndex: 0,
76
- walletMode: 'RootTree',
77
- perAddressPublicKey: MOCK_PER_ADDR_PK,
78
- },
79
- MOCK_ROOT_PK
80
- );
81
-
82
- expect(bodies).toHaveLength(1);
83
- const sent = bodies[0].body;
84
- expect(sent.walletMode).toBe('RootTree');
85
- expect(sent.perAddressPublicKey).toBe(MOCK_PER_ADDR_PK);
86
- expect(sent.rootPublicKey).toBe(MOCK_ROOT_PK);
87
- });
88
-
89
- it('PrepareResponse includes perAddressScript field from server', async () => {
90
- const bodies: any[] = [];
91
- const svc = new TransactionService(makeMockHttp(bodies), config);
92
-
93
- const result = await svc.prepare(
94
- { to: 'MxABC', amount: '1', addressIndex: 0, walletMode: 'RootTree', perAddressPublicKey: MOCK_PER_ADDR_PK },
95
- MOCK_ROOT_PK
96
- );
97
-
98
- expect(result.perAddressScript).toBeDefined();
99
- expect(typeof result.perAddressScript).toBe('string');
100
- });
101
- });