@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
@@ -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
- });