@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,459 +0,0 @@
1
- /**
2
- * Java Parity Tests for TreeKey/MMR Implementation
3
- *
4
- * These tests verify byte-exact compatibility with Minima's Java implementation.
5
- * Test vectors are generated from Minima's TreeKeyNode.java, MMR.java, and related classes.
6
- *
7
- * To generate new test vectors from Java:
8
- * 1. Create a Minima node
9
- * 2. Generate TreeKey with known seed
10
- * 3. Export public keys, signatures, and MMR proofs as hex strings
11
- */
12
-
13
- // Jest globals (describe, it, expect) are available in test environment
14
- import { sha3_256 } from '@noble/hashes/sha3.js';
15
- import {
16
- serializeMiniNumber,
17
- serializeMiniData,
18
- hashAllObjects,
19
- deriveChainSeedJava,
20
- hashObject,
21
- writeHashToStream,
22
- javaHashAllObjects,
23
- } from './javaStreamables';
24
- import {
25
- MMRTree,
26
- createMMRDataLeafNode,
27
- createMMRDataParentNode,
28
- calculateProofRoot,
29
- } from './mmr';
30
- import {
31
- TreeKeyNode,
32
- TreeKey,
33
- SignatureProof,
34
- getRootPublicKey,
35
- DEFAULT_KEYS_PER_LEVEL,
36
- } from './treekey';
37
- import { derivePKdigest, deriveFullPublicKey, wotsSign, wotsVerify } from './wots';
38
- import { getParamSet } from './params';
39
-
40
- function toHex(bytes: Uint8Array): string {
41
- return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');
42
- }
43
-
44
- function fromHex(hex: string): Uint8Array {
45
- const bytes = new Uint8Array(hex.length / 2);
46
- for (let i = 0; i < bytes.length; i++) {
47
- bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
48
- }
49
- return bytes;
50
- }
51
-
52
- describe('Java Serialization Parity', () => {
53
- describe('MiniNumber serialization', () => {
54
- it('serializes ZERO correctly', () => {
55
- const zero = serializeMiniNumber(0);
56
- expect(toHex(zero)).toBe('000100');
57
- });
58
-
59
- it('serializes ONE correctly', () => {
60
- const one = serializeMiniNumber(1);
61
- expect(toHex(one)).toBe('000101');
62
- });
63
-
64
- it('serializes 63 correctly', () => {
65
- const n = serializeMiniNumber(63);
66
- expect(toHex(n)).toBe('00013f');
67
- });
68
-
69
- it('serializes 64 correctly', () => {
70
- const n = serializeMiniNumber(64);
71
- expect(toHex(n)).toBe('000140');
72
- });
73
-
74
- it('serializes 127 correctly (no sign extension needed)', () => {
75
- const n = serializeMiniNumber(127);
76
- expect(toHex(n)).toBe('00017f');
77
- });
78
-
79
- it('serializes 128 correctly (requires sign extension)', () => {
80
- const n = serializeMiniNumber(128);
81
- expect(toHex(n)).toBe('00020080');
82
- });
83
-
84
- it('serializes 255 correctly', () => {
85
- const n = serializeMiniNumber(255);
86
- expect(toHex(n)).toBe('000200ff');
87
- });
88
-
89
- it('serializes 256 correctly', () => {
90
- const n = serializeMiniNumber(256);
91
- expect(toHex(n)).toBe('00020100');
92
- });
93
- });
94
-
95
- describe('MiniData serialization', () => {
96
- it('serializes empty data correctly', () => {
97
- const data = serializeMiniData(new Uint8Array(0));
98
- expect(toHex(data)).toBe('00000000');
99
- });
100
-
101
- it('serializes 32-byte hash correctly', () => {
102
- const hash = new Uint8Array(32).fill(0xab);
103
- const serialized = serializeMiniData(hash);
104
- expect(serialized.length).toBe(36);
105
- expect(toHex(serialized.slice(0, 4))).toBe('00000020');
106
- expect(serialized.slice(4)).toEqual(hash);
107
- });
108
- });
109
-
110
- describe('writeHashToStream (4-byte length)', () => {
111
- it('serializes 32-byte hash with 4-byte length prefix', () => {
112
- const hash = new Uint8Array(32).fill(0xcd);
113
- const serialized = writeHashToStream(hash);
114
- expect(serialized.length).toBe(36); // 4-byte prefix + 32 bytes
115
- // 4-byte big-endian length: 0x00000020 = 32
116
- expect(serialized[0]).toBe(0);
117
- expect(serialized[1]).toBe(0);
118
- expect(serialized[2]).toBe(0);
119
- expect(serialized[3]).toBe(32);
120
- expect(serialized.slice(4)).toEqual(hash);
121
- });
122
- });
123
-
124
- describe('hashObject (Crypto.hashObject)', () => {
125
- it('hashes MiniData correctly', () => {
126
- const seed = new Uint8Array(32).fill(0x42);
127
- const hashed = hashObject(seed);
128
- expect(hashed.length).toBe(32);
129
- const serialized = serializeMiniData(seed);
130
- const expected = sha3_256(serialized);
131
- expect(toHex(hashed)).toBe(toHex(expected));
132
- });
133
- });
134
-
135
- describe('deriveChainSeedJava (hashAllObjects)', () => {
136
- it('derives chain seed for index 0', () => {
137
- const seed = new Uint8Array(32).fill(0x11);
138
- const derived = deriveChainSeedJava(seed, 0);
139
- expect(derived.length).toBe(32);
140
- const indexSerialized = serializeMiniNumber(0);
141
- const seedSerialized = serializeMiniData(seed);
142
- const expected = javaHashAllObjects(indexSerialized, seedSerialized);
143
- expect(toHex(derived)).toBe(toHex(expected));
144
- });
145
-
146
- it('derives different seeds for different indices', () => {
147
- const seed = new Uint8Array(32).fill(0x22);
148
- const derived0 = deriveChainSeedJava(seed, 0);
149
- const derived1 = deriveChainSeedJava(seed, 1);
150
- const derived63 = deriveChainSeedJava(seed, 63);
151
- expect(toHex(derived0)).not.toBe(toHex(derived1));
152
- expect(toHex(derived1)).not.toBe(toHex(derived63));
153
- });
154
- });
155
- });
156
-
157
- describe('MMRData Parity', () => {
158
- describe('createMMRDataLeafNode', () => {
159
- it('creates leaf node with correct hash', () => {
160
- const pubkey = new Uint8Array(32).fill(0xaa);
161
- const leaf = createMMRDataLeafNode(pubkey, 0n);
162
- expect(leaf.data.length).toBe(32);
163
- expect(leaf.value).toBe(0n);
164
- });
165
-
166
- it('different pubkeys produce different leaf hashes', () => {
167
- const pk1 = new Uint8Array(32).fill(0x01);
168
- const pk2 = new Uint8Array(32).fill(0x02);
169
- const leaf1 = createMMRDataLeafNode(pk1, 0n);
170
- const leaf2 = createMMRDataLeafNode(pk2, 0n);
171
- expect(toHex(leaf1.data)).not.toBe(toHex(leaf2.data));
172
- });
173
- });
174
-
175
- describe('createMMRDataParentNode', () => {
176
- it('creates parent node from two children', () => {
177
- const pk1 = new Uint8Array(32).fill(0x01);
178
- const pk2 = new Uint8Array(32).fill(0x02);
179
- const left = createMMRDataLeafNode(pk1, 0n);
180
- const right = createMMRDataLeafNode(pk2, 0n);
181
- const parent = createMMRDataParentNode(left, right);
182
- expect(parent.data.length).toBe(32);
183
- expect(parent.value).toBe(0n);
184
- });
185
-
186
- it('parent hash is deterministic', () => {
187
- const pk1 = new Uint8Array(32).fill(0xaa);
188
- const pk2 = new Uint8Array(32).fill(0xbb);
189
- const left = createMMRDataLeafNode(pk1, 0n);
190
- const right = createMMRDataLeafNode(pk2, 0n);
191
- const parent1 = createMMRDataParentNode(left, right);
192
- const parent2 = createMMRDataParentNode(left, right);
193
- expect(toHex(parent1.data)).toBe(toHex(parent2.data));
194
- });
195
-
196
- it('order matters (left vs right)', () => {
197
- const pk1 = new Uint8Array(32).fill(0xcc);
198
- const pk2 = new Uint8Array(32).fill(0xdd);
199
- const leaf1 = createMMRDataLeafNode(pk1, 0n);
200
- const leaf2 = createMMRDataLeafNode(pk2, 0n);
201
- const parentLR = createMMRDataParentNode(leaf1, leaf2);
202
- const parentRL = createMMRDataParentNode(leaf2, leaf1);
203
- expect(toHex(parentLR.data)).not.toBe(toHex(parentRL.data));
204
- });
205
- });
206
- });
207
-
208
- describe('MMRTree Parity', () => {
209
- it('builds tree with 2 entries', () => {
210
- const pk1 = new Uint8Array(32).fill(0x01);
211
- const pk2 = new Uint8Array(32).fill(0x02);
212
- const tree = MMRTree.fromPublicKeys([pk1, pk2]);
213
- const root = tree.getRoot();
214
- expect(root).toBeDefined();
215
- expect(root!.data.length).toBe(32);
216
- });
217
-
218
- it('builds tree with 64 entries', () => {
219
- const pubkeys: Uint8Array[] = [];
220
- for (let i = 0; i < 64; i++) {
221
- pubkeys.push(new Uint8Array(32).fill(i));
222
- }
223
- const tree = MMRTree.fromPublicKeys(pubkeys);
224
- const root = tree.getRoot();
225
- expect(root).toBeDefined();
226
- expect(root!.data.length).toBe(32);
227
- });
228
-
229
- it('proof verifies back to root', () => {
230
- const pubkeys: Uint8Array[] = [];
231
- for (let i = 0; i < 64; i++) {
232
- pubkeys.push(new Uint8Array(32).fill(i));
233
- }
234
- const tree = MMRTree.fromPublicKeys(pubkeys);
235
- const root = tree.getRoot();
236
- for (let i = 0; i < 64; i++) {
237
- const proof = tree.getProof(i);
238
- const leaf = createMMRDataLeafNode(pubkeys[i], 0n);
239
- const computedRoot = calculateProofRoot(leaf, proof);
240
- expect(toHex(computedRoot)).toBe(toHex(root!.data));
241
- }
242
- });
243
- });
244
-
245
- describe('TreeKeyNode Parity', () => {
246
- const testSeed = new Uint8Array(32);
247
- for (let i = 0; i < 32; i++) testSeed[i] = i;
248
-
249
- it('creates node with deterministic public key', () => {
250
- const node1 = new TreeKeyNode(testSeed, 4);
251
- const node2 = new TreeKeyNode(testSeed, 4);
252
- expect(toHex(node1.getPublicKey())).toBe(toHex(node2.getPublicKey()));
253
- }, 30000);
254
-
255
- it('different seeds produce different public keys', () => {
256
- const seed1 = new Uint8Array(32).fill(0x11);
257
- const seed2 = new Uint8Array(32).fill(0x22);
258
- const node1 = new TreeKeyNode(seed1, 4);
259
- const node2 = new TreeKeyNode(seed2, 4);
260
- expect(toHex(node1.getPublicKey())).not.toBe(toHex(node2.getPublicKey()));
261
- }, 30000);
262
-
263
- it('public key is 32 bytes (MMR root hash)', () => {
264
- const node = new TreeKeyNode(testSeed, 4);
265
- expect(node.getPublicKey().length).toBe(32);
266
- }, 30000);
267
-
268
- it('child nodes have deterministic public keys', () => {
269
- const node = new TreeKeyNode(testSeed, 4);
270
- const child0a = node.getChild(0);
271
- const child0b = node.getChild(0);
272
- expect(toHex(child0a.getPublicKey())).toBe(toHex(child0b.getPublicKey()));
273
- }, 30000);
274
-
275
- it('different child indices produce different public keys', () => {
276
- const node = new TreeKeyNode(testSeed, 4);
277
- const child0 = node.getChild(0);
278
- const child1 = node.getChild(1);
279
- expect(toHex(child0.getPublicKey())).not.toBe(toHex(child1.getPublicKey()));
280
- }, 30000);
281
-
282
- it('signing produces valid SignatureProof with 32-byte pubkey DIGEST', () => {
283
- const node = new TreeKeyNode(testSeed, 4);
284
- const data = sha3_256(new TextEncoder().encode('test message'));
285
- const proof = node.sign(0, data);
286
- // CRITICAL FIX (January 2026): Java's Winternitz.getPublicKey() returns 32-byte DIGEST!
287
- // BouncyCastle hashes full 1088-byte key: SHA3-256(full_key) = 32 bytes
288
- expect(proof.leafPubkey.length).toBe(32); // 32-byte SHA3-256 digest
289
- expect(proof.signature.length).toBe(1088); // Signature is still 1088 bytes
290
- expect(proof.mmrProof.chunks.length).toBeGreaterThan(0);
291
- }, 30000);
292
-
293
- it('SignatureProof.getRootPublicKey matches node public key', () => {
294
- const node = new TreeKeyNode(testSeed, 4);
295
- const data = sha3_256(new TextEncoder().encode('test data'));
296
- const proof = node.sign(0, data);
297
- const recoveredRoot = getRootPublicKey(proof);
298
- expect(toHex(recoveredRoot)).toBe(toHex(node.getPublicKey()));
299
- }, 30000);
300
-
301
- it('all keys produce valid proofs to same root', () => {
302
- const node = new TreeKeyNode(testSeed, 4);
303
- const rootPubkey = node.getPublicKey();
304
- const data = sha3_256(new TextEncoder().encode('uniform test'));
305
- for (let i = 0; i < 4; i++) {
306
- const proof = node.sign(i, data);
307
- const recoveredRoot = getRootPublicKey(proof);
308
- expect(toHex(recoveredRoot)).toBe(toHex(rootPubkey));
309
- }
310
- }, 30000);
311
- });
312
-
313
- describe('TreeKey 3-Level Hierarchy', () => {
314
- const testSeed = new Uint8Array(32);
315
- for (let i = 0; i < 32; i++) testSeed[i] = (i * 7) % 256;
316
- const KEYS = 4;
317
-
318
- it('creates TreeKey with deterministic root public key', () => {
319
- const tk1 = new TreeKey(testSeed, KEYS, 3);
320
- const tk2 = new TreeKey(testSeed, KEYS, 3);
321
- expect(toHex(tk1.getPublicKey())).toBe(toHex(tk2.getPublicKey()));
322
- }, 60000);
323
-
324
- it('reports correct max uses (4^3 = 64 in test mode)', () => {
325
- const tk = new TreeKey(testSeed, KEYS, 3);
326
- expect(tk.getMaxUses()).toBe(64);
327
- }, 60000);
328
-
329
- it('sign() produces 3-level TreeSignature', () => {
330
- const tk = new TreeKey(testSeed, KEYS, 3);
331
- const data = sha3_256(new TextEncoder().encode('transaction data'));
332
- const sig = tk.sign(data);
333
- expect(sig.proofs.length).toBe(3);
334
- }, 60000);
335
-
336
- it('setUses(0) + sign() produces same signature as sequential sign()', () => {
337
- const tk1 = new TreeKey(testSeed, KEYS, 3);
338
- const tk2 = new TreeKey(testSeed, KEYS, 3);
339
- const data = sha3_256(new TextEncoder().encode('test'));
340
- const sigSeq = tk1.sign(data);
341
- tk2.setUses(0);
342
- const sigIdx = tk2.sign(data);
343
- expect(sigSeq.proofs.length).toBe(sigIdx.proofs.length);
344
- for (let i = 0; i < 3; i++) {
345
- expect(toHex(sigSeq.proofs[i].leafPubkey)).toBe(toHex(sigIdx.proofs[i].leafPubkey));
346
- expect(toHex(sigSeq.proofs[i].signature)).toBe(toHex(sigIdx.proofs[i].signature));
347
- }
348
- }, 60000);
349
-
350
- it('increments usage counter after signing', () => {
351
- const tk = new TreeKey(testSeed, KEYS, 3);
352
- expect(tk.getUses()).toBe(0);
353
- const data = sha3_256(new TextEncoder().encode('msg'));
354
- tk.sign(data);
355
- expect(tk.getUses()).toBe(1);
356
- tk.sign(data);
357
- expect(tk.getUses()).toBe(2);
358
- }, 60000);
359
-
360
- it('setUses at (0,0,1) differs from (0,0,0)', () => {
361
- const tk = new TreeKey(testSeed, KEYS, 3);
362
- const data = sha3_256(new TextEncoder().encode('test'));
363
- tk.setUses(0);
364
- const sig000 = tk.sign(data);
365
- tk.setUses(1);
366
- const sig001 = tk.sign(data);
367
- expect(toHex(sig000.proofs[2].leafPubkey)).not.toBe(toHex(sig001.proofs[2].leafPubkey));
368
- }, 60000);
369
-
370
- it('setUses at (0,1,0) uses different L2 node', () => {
371
- const tk = new TreeKey(testSeed, KEYS, 3);
372
- const data = sha3_256(new TextEncoder().encode('test'));
373
- tk.setUses(0);
374
- const sig000 = tk.sign(data);
375
- tk.setUses(1 * KEYS);
376
- const sig010 = tk.sign(data);
377
- expect(toHex(sig000.proofs[1].leafPubkey)).not.toBe(toHex(sig010.proofs[1].leafPubkey));
378
- }, 60000);
379
-
380
- it('setUses at (1,0,0) uses different L1 node', () => {
381
- const tk = new TreeKey(testSeed, KEYS, 3);
382
- const data = sha3_256(new TextEncoder().encode('test'));
383
- tk.setUses(0);
384
- const sig000 = tk.sign(data);
385
- tk.setUses(1 * KEYS * KEYS);
386
- const sig100 = tk.sign(data);
387
- expect(toHex(sig000.proofs[0].leafPubkey)).not.toBe(toHex(sig100.proofs[0].leafPubkey));
388
- }, 60000);
389
- });
390
-
391
- describe('Lease System Integration', () => {
392
- const KEYS = 4;
393
-
394
- it('lease indices map to TreeKey.setUses + sign correctly', () => {
395
- const tk = new TreeKey(new Uint8Array(32).fill(0x55), KEYS, 3);
396
- const leaseIndices = [
397
- { addressIndex: 0, l1: 0, l2: 0 },
398
- { addressIndex: 0, l1: 0, l2: 1 },
399
- { addressIndex: 0, l1: 1, l2: 0 },
400
- { addressIndex: 1, l1: 0, l2: 0 },
401
- { addressIndex: 3, l1: 3, l2: 3 },
402
- ];
403
- const data = sha3_256(new TextEncoder().encode('lease test'));
404
- for (const { addressIndex, l1, l2 } of leaseIndices) {
405
- tk.setUses(addressIndex * KEYS * KEYS + l1 * KEYS + l2);
406
- const sig = tk.sign(data);
407
- expect(sig.proofs.length).toBe(3);
408
- expect(sig.proofs[0].leafPubkey.length).toBe(32);
409
- expect(sig.proofs[1].leafPubkey.length).toBe(32);
410
- expect(sig.proofs[2].leafPubkey.length).toBe(32);
411
- }
412
- }, 60000);
413
-
414
- it('bump() order matches baseConversion()', () => {
415
- const tk = new TreeKey(new Uint8Array(32).fill(0x66), KEYS, 3);
416
- for (let i = 0; i < 10; i++) {
417
- const data = sha3_256(new Uint8Array([i]));
418
- const sig = tk.sign(data);
419
- expect(sig.proofs.length).toBe(3);
420
- }
421
- expect(tk.getUses()).toBe(10);
422
- }, 60000);
423
- });
424
-
425
- describe('WOTS Signature Verification', () => {
426
- const testSeed = new Uint8Array(32).fill(0x77);
427
-
428
- it('WOTS signature verifies correctly with FULL 1088-byte pubkey', () => {
429
- // CRITICAL: Both wotsSign and wotsVerify hash internally to match Java/BouncyCastle
430
- // Pass the SAME raw 32-byte data to both functions (not pre-hashed!)
431
- const rawMessage = new Uint8Array(32).fill(0xab); // 32-byte raw message (e.g., tx digest)
432
-
433
- // CRITICAL: Java's wotsVerify uses FULL 1088-byte public key, not 32-byte digest
434
- const pubkeyFull = deriveFullPublicKey(testSeed, 0, getParamSet());
435
- const signature = wotsSign(testSeed, 0, rawMessage, getParamSet()); // raw message - hashed internally
436
- const isValid = wotsVerify(signature, rawMessage, pubkeyFull, getParamSet()); // same raw message - hashed internally
437
- expect(isValid).toBe(true);
438
- });
439
-
440
- it('WOTS signature fails for wrong data', () => {
441
- const rawMessage1 = new Uint8Array(32).fill(0x11);
442
- const rawMessage2 = new Uint8Array(32).fill(0x22);
443
-
444
- const pubkeyFull = deriveFullPublicKey(testSeed, 0, getParamSet());
445
- const signature = wotsSign(testSeed, 0, rawMessage1, getParamSet());
446
- const isValid = wotsVerify(signature, rawMessage2, pubkeyFull, getParamSet());
447
- expect(isValid).toBe(false);
448
- });
449
-
450
- it('WOTS signature fails for wrong pubkey', () => {
451
- const rawMessage = new Uint8Array(32).fill(0x33);
452
-
453
- const pubkeyFull1 = deriveFullPublicKey(testSeed, 0, getParamSet());
454
- const pubkeyFull2 = deriveFullPublicKey(testSeed, 1, getParamSet());
455
- const signature = wotsSign(testSeed, 0, rawMessage, getParamSet());
456
- const isValid = wotsVerify(signature, rawMessage, pubkeyFull2, getParamSet());
457
- expect(isValid).toBe(false);
458
- });
459
- });