@openzeppelin/miden-multisig-client 0.12.6

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 (215) hide show
  1. package/README.md +189 -0
  2. package/dist/account/builder.d.ts +23 -0
  3. package/dist/account/builder.d.ts.map +1 -0
  4. package/dist/account/builder.js +85 -0
  5. package/dist/account/builder.js.map +1 -0
  6. package/dist/account/index.d.ts +6 -0
  7. package/dist/account/index.d.ts.map +1 -0
  8. package/dist/account/index.js +6 -0
  9. package/dist/account/index.js.map +1 -0
  10. package/dist/account/masm.d.ts +3 -0
  11. package/dist/account/masm.d.ts.map +1 -0
  12. package/dist/account/masm.js +605 -0
  13. package/dist/account/masm.js.map +1 -0
  14. package/dist/account/storage.d.ts +10 -0
  15. package/dist/account/storage.d.ts.map +1 -0
  16. package/dist/account/storage.js +56 -0
  17. package/dist/account/storage.js.map +1 -0
  18. package/dist/account.d.ts +104 -0
  19. package/dist/account.d.ts.map +1 -0
  20. package/dist/account.js +136 -0
  21. package/dist/account.js.map +1 -0
  22. package/dist/builder.d.ts +54 -0
  23. package/dist/builder.d.ts.map +1 -0
  24. package/dist/builder.js +78 -0
  25. package/dist/builder.js.map +1 -0
  26. package/dist/client.d.ts +73 -0
  27. package/dist/client.d.ts.map +1 -0
  28. package/dist/client.js +104 -0
  29. package/dist/client.js.map +1 -0
  30. package/dist/client.test.d.ts +2 -0
  31. package/dist/client.test.d.ts.map +1 -0
  32. package/dist/client.test.js +150 -0
  33. package/dist/client.test.js.map +1 -0
  34. package/dist/http.d.ts +64 -0
  35. package/dist/http.d.ts.map +1 -0
  36. package/dist/http.js +162 -0
  37. package/dist/http.js.map +1 -0
  38. package/dist/index.d.ts +53 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +52 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/inspector.d.ts +49 -0
  43. package/dist/inspector.d.ts.map +1 -0
  44. package/dist/inspector.js +120 -0
  45. package/dist/inspector.js.map +1 -0
  46. package/dist/inspector.test.d.ts +2 -0
  47. package/dist/inspector.test.d.ts.map +1 -0
  48. package/dist/inspector.test.js +205 -0
  49. package/dist/inspector.test.js.map +1 -0
  50. package/dist/keystore.d.ts +65 -0
  51. package/dist/keystore.d.ts.map +1 -0
  52. package/dist/keystore.js +121 -0
  53. package/dist/keystore.js.map +1 -0
  54. package/dist/miden.d.ts +9 -0
  55. package/dist/miden.d.ts.map +1 -0
  56. package/dist/miden.js +26 -0
  57. package/dist/miden.js.map +1 -0
  58. package/dist/multisig/helpers.d.ts +4 -0
  59. package/dist/multisig/helpers.d.ts.map +1 -0
  60. package/dist/multisig/helpers.js +21 -0
  61. package/dist/multisig/helpers.js.map +1 -0
  62. package/dist/multisig/helpers.test.d.ts +2 -0
  63. package/dist/multisig/helpers.test.d.ts.map +1 -0
  64. package/dist/multisig/helpers.test.js +94 -0
  65. package/dist/multisig/helpers.test.js.map +1 -0
  66. package/dist/multisig/metadata.d.ts +18 -0
  67. package/dist/multisig/metadata.d.ts.map +1 -0
  68. package/dist/multisig/metadata.js +100 -0
  69. package/dist/multisig/metadata.js.map +1 -0
  70. package/dist/multisig/metadata.test.d.ts +2 -0
  71. package/dist/multisig/metadata.test.d.ts.map +1 -0
  72. package/dist/multisig/metadata.test.js +323 -0
  73. package/dist/multisig/metadata.test.js.map +1 -0
  74. package/dist/multisig.d.ts +199 -0
  75. package/dist/multisig.d.ts.map +1 -0
  76. package/dist/multisig.js +821 -0
  77. package/dist/multisig.js.map +1 -0
  78. package/dist/multisig.test.d.ts +2 -0
  79. package/dist/multisig.test.d.ts.map +1 -0
  80. package/dist/multisig.test.js +1121 -0
  81. package/dist/multisig.test.js.map +1 -0
  82. package/dist/procedures.d.ts +57 -0
  83. package/dist/procedures.d.ts.map +1 -0
  84. package/dist/procedures.js +62 -0
  85. package/dist/procedures.js.map +1 -0
  86. package/dist/signer.d.ts +36 -0
  87. package/dist/signer.d.ts.map +1 -0
  88. package/dist/signer.js +68 -0
  89. package/dist/signer.js.map +1 -0
  90. package/dist/signer.test.d.ts +2 -0
  91. package/dist/signer.test.d.ts.map +1 -0
  92. package/dist/signer.test.js +117 -0
  93. package/dist/signer.test.js.map +1 -0
  94. package/dist/transaction/consumeNotes.d.ts +7 -0
  95. package/dist/transaction/consumeNotes.d.ts.map +1 -0
  96. package/dist/transaction/consumeNotes.js +28 -0
  97. package/dist/transaction/consumeNotes.js.map +1 -0
  98. package/dist/transaction/index.d.ts +7 -0
  99. package/dist/transaction/index.d.ts.map +1 -0
  100. package/dist/transaction/index.js +6 -0
  101. package/dist/transaction/index.js.map +1 -0
  102. package/dist/transaction/options.d.ts +6 -0
  103. package/dist/transaction/options.d.ts.map +1 -0
  104. package/dist/transaction/options.js +2 -0
  105. package/dist/transaction/options.js.map +1 -0
  106. package/dist/transaction/p2id.d.ts +7 -0
  107. package/dist/transaction/p2id.d.ts.map +1 -0
  108. package/dist/transaction/p2id.js +43 -0
  109. package/dist/transaction/p2id.js.map +1 -0
  110. package/dist/transaction/summary.d.ts +3 -0
  111. package/dist/transaction/summary.d.ts.map +1 -0
  112. package/dist/transaction/summary.js +6 -0
  113. package/dist/transaction/summary.js.map +1 -0
  114. package/dist/transaction/updatePsm.d.ts +7 -0
  115. package/dist/transaction/updatePsm.d.ts.map +1 -0
  116. package/dist/transaction/updatePsm.js +43 -0
  117. package/dist/transaction/updatePsm.js.map +1 -0
  118. package/dist/transaction/updateSigners.d.ts +8 -0
  119. package/dist/transaction/updateSigners.d.ts.map +1 -0
  120. package/dist/transaction/updateSigners.js +60 -0
  121. package/dist/transaction/updateSigners.js.map +1 -0
  122. package/dist/transaction.d.ts +6 -0
  123. package/dist/transaction.d.ts.map +1 -0
  124. package/dist/transaction.js +8 -0
  125. package/dist/transaction.js.map +1 -0
  126. package/dist/transaction.test.d.ts +2 -0
  127. package/dist/transaction.test.d.ts.map +1 -0
  128. package/dist/transaction.test.js +117 -0
  129. package/dist/transaction.test.js.map +1 -0
  130. package/dist/transport/http.d.ts +64 -0
  131. package/dist/transport/http.d.ts.map +1 -0
  132. package/dist/transport/http.js +162 -0
  133. package/dist/transport/http.js.map +1 -0
  134. package/dist/transport/index.d.ts +5 -0
  135. package/dist/transport/index.d.ts.map +1 -0
  136. package/dist/transport/index.js +5 -0
  137. package/dist/transport/index.js.map +1 -0
  138. package/dist/types/proposal.d.ts +74 -0
  139. package/dist/types/proposal.d.ts.map +1 -0
  140. package/dist/types/proposal.js +2 -0
  141. package/dist/types/proposal.js.map +1 -0
  142. package/dist/types.d.ts +60 -0
  143. package/dist/types.d.ts.map +1 -0
  144. package/dist/types.js +2 -0
  145. package/dist/types.js.map +1 -0
  146. package/dist/utils/encoding.d.ts +7 -0
  147. package/dist/utils/encoding.d.ts.map +1 -0
  148. package/dist/utils/encoding.js +54 -0
  149. package/dist/utils/encoding.js.map +1 -0
  150. package/dist/utils/encoding.test.d.ts +2 -0
  151. package/dist/utils/encoding.test.d.ts.map +1 -0
  152. package/dist/utils/encoding.test.js +185 -0
  153. package/dist/utils/encoding.test.js.map +1 -0
  154. package/dist/utils/index.d.ts +5 -0
  155. package/dist/utils/index.d.ts.map +1 -0
  156. package/dist/utils/index.js +5 -0
  157. package/dist/utils/index.js.map +1 -0
  158. package/dist/utils/random.d.ts +3 -0
  159. package/dist/utils/random.d.ts.map +1 -0
  160. package/dist/utils/random.js +14 -0
  161. package/dist/utils/random.js.map +1 -0
  162. package/dist/utils/signature.d.ts +12 -0
  163. package/dist/utils/signature.d.ts.map +1 -0
  164. package/dist/utils/signature.js +28 -0
  165. package/dist/utils/signature.js.map +1 -0
  166. package/dist/utils/signature.test.d.ts +2 -0
  167. package/dist/utils/signature.test.d.ts.map +1 -0
  168. package/dist/utils/signature.test.js +149 -0
  169. package/dist/utils/signature.test.js.map +1 -0
  170. package/dist/utils/word.d.ts +4 -0
  171. package/dist/utils/word.d.ts.map +1 -0
  172. package/dist/utils/word.js +8 -0
  173. package/dist/utils/word.js.map +1 -0
  174. package/dist/utils/word.test.d.ts +2 -0
  175. package/dist/utils/word.test.d.ts.map +1 -0
  176. package/dist/utils/word.test.js +54 -0
  177. package/dist/utils/word.test.js.map +1 -0
  178. package/masm/multisig.masm +423 -0
  179. package/masm/psm.masm +178 -0
  180. package/package.json +42 -0
  181. package/src/account/builder.ts +112 -0
  182. package/src/account/index.ts +15 -0
  183. package/src/account/masm.ts +606 -0
  184. package/src/account/storage.ts +70 -0
  185. package/src/client.test.ts +177 -0
  186. package/src/client.ts +129 -0
  187. package/src/index.ts +118 -0
  188. package/src/inspector.test.ts +237 -0
  189. package/src/inspector.ts +142 -0
  190. package/src/multisig/helpers.test.ts +114 -0
  191. package/src/multisig/helpers.ts +23 -0
  192. package/src/multisig.test.ts +1294 -0
  193. package/src/multisig.ts +1097 -0
  194. package/src/procedures.ts +72 -0
  195. package/src/signer.test.ts +135 -0
  196. package/src/signer.ts +75 -0
  197. package/src/transaction/consumeNotes.ts +41 -0
  198. package/src/transaction/index.ts +7 -0
  199. package/src/transaction/options.ts +7 -0
  200. package/src/transaction/p2id.ts +105 -0
  201. package/src/transaction/summary.ts +12 -0
  202. package/src/transaction/updatePsm.ts +69 -0
  203. package/src/transaction/updateSigners.ts +96 -0
  204. package/src/transaction.test.ts +136 -0
  205. package/src/transaction.ts +16 -0
  206. package/src/types/proposal.ts +80 -0
  207. package/src/types.ts +81 -0
  208. package/src/utils/encoding.test.ts +233 -0
  209. package/src/utils/encoding.ts +60 -0
  210. package/src/utils/index.ts +5 -0
  211. package/src/utils/random.ts +15 -0
  212. package/src/utils/signature.test.ts +187 -0
  213. package/src/utils/signature.ts +36 -0
  214. package/src/utils/word.test.ts +64 -0
  215. package/src/utils/word.ts +11 -0
@@ -0,0 +1,149 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { signatureHexToBytes, buildSignatureAdviceEntry, mergeSignatureAdviceMaps, toWord } from './signature.js';
3
+ // Mock the Miden SDK
4
+ vi.mock('@demox-labs/miden-sdk', () => ({
5
+ AdviceMap: vi.fn().mockImplementation(() => ({
6
+ insert: vi.fn(),
7
+ })),
8
+ Felt: vi.fn().mockImplementation((v) => ({ value: v })),
9
+ FeltArray: vi.fn().mockImplementation((arr) => arr),
10
+ Rpo256: {
11
+ hashElements: vi.fn().mockReturnValue({
12
+ toHex: () => '0x' + 'h'.repeat(64),
13
+ }),
14
+ },
15
+ Signature: {
16
+ deserialize: vi.fn().mockReturnValue({
17
+ toPreparedSignature: vi.fn().mockReturnValue([1, 2, 3, 4]),
18
+ }),
19
+ },
20
+ Word: {
21
+ fromHex: vi.fn((hex) => ({
22
+ toHex: () => hex,
23
+ toFelts: () => [
24
+ { value: 1n },
25
+ { value: 2n },
26
+ { value: 3n },
27
+ { value: 4n },
28
+ ],
29
+ })),
30
+ },
31
+ }));
32
+ describe('signature utilities', () => {
33
+ beforeEach(() => {
34
+ vi.clearAllMocks();
35
+ });
36
+ describe('signatureHexToBytes', () => {
37
+ it('prepends auth scheme byte (0 = RpoFalcon512)', () => {
38
+ const result = signatureHexToBytes('deadbeef');
39
+ expect(result[0]).toBe(0); // RpoFalcon512 scheme byte
40
+ });
41
+ it('converts hex to bytes after prefix', () => {
42
+ const result = signatureHexToBytes('deadbeef');
43
+ expect(result.slice(1)).toEqual(new Uint8Array([0xde, 0xad, 0xbe, 0xef]));
44
+ });
45
+ it('handles 0x prefix', () => {
46
+ const result = signatureHexToBytes('0xaabbccdd');
47
+ expect(result[0]).toBe(0);
48
+ expect(result.slice(1)).toEqual(new Uint8Array([0xaa, 0xbb, 0xcc, 0xdd]));
49
+ });
50
+ it('returns correct length (input bytes + 1)', () => {
51
+ const sigHex = 'a'.repeat(128); // 64 bytes
52
+ const result = signatureHexToBytes(sigHex);
53
+ expect(result.length).toBe(65); // 64 bytes + 1 prefix byte
54
+ });
55
+ it('handles empty signature', () => {
56
+ const result = signatureHexToBytes('');
57
+ expect(result).toEqual(new Uint8Array([0])); // Just the prefix
58
+ });
59
+ it('handles empty with 0x prefix', () => {
60
+ const result = signatureHexToBytes('0x');
61
+ expect(result).toEqual(new Uint8Array([0]));
62
+ });
63
+ });
64
+ describe('buildSignatureAdviceEntry', () => {
65
+ it('returns key and values', async () => {
66
+ const { Word, Signature } = await import('@demox-labs/miden-sdk');
67
+ const pubkeyCommitment = Word.fromHex('0x' + 'a'.repeat(64));
68
+ const message = Word.fromHex('0x' + 'b'.repeat(64));
69
+ const signature = Signature.deserialize(new Uint8Array([0, 1, 2, 3]));
70
+ const { key, values } = buildSignatureAdviceEntry(pubkeyCommitment, message, signature);
71
+ expect(key).toBeDefined();
72
+ expect(values).toBeDefined();
73
+ });
74
+ it('hashes pubkey commitment and message to produce key', async () => {
75
+ const { Word, Signature, Rpo256 } = await import('@demox-labs/miden-sdk');
76
+ const pubkeyCommitment = Word.fromHex('0x' + 'a'.repeat(64));
77
+ const message = Word.fromHex('0x' + 'b'.repeat(64));
78
+ const signature = Signature.deserialize(new Uint8Array([0, 1, 2, 3]));
79
+ buildSignatureAdviceEntry(pubkeyCommitment, message, signature);
80
+ expect(Rpo256.hashElements).toHaveBeenCalled();
81
+ });
82
+ it('uses toPreparedSignature to get values', async () => {
83
+ const { Word, Signature } = await import('@demox-labs/miden-sdk');
84
+ const pubkeyCommitment = Word.fromHex('0x' + 'a'.repeat(64));
85
+ const message = Word.fromHex('0x' + 'b'.repeat(64));
86
+ const signature = Signature.deserialize(new Uint8Array([0, 1, 2, 3]));
87
+ const { values } = buildSignatureAdviceEntry(pubkeyCommitment, message, signature);
88
+ expect(signature.toPreparedSignature).toHaveBeenCalledWith(message);
89
+ expect(values).toEqual([1, 2, 3, 4]);
90
+ });
91
+ });
92
+ describe('mergeSignatureAdviceMaps', () => {
93
+ it('inserts all entries into advice map', async () => {
94
+ const { AdviceMap, Word, Signature } = await import('@demox-labs/miden-sdk');
95
+ const advice = new AdviceMap();
96
+ const entries = [
97
+ {
98
+ key: Word.fromHex('0x' + 'a'.repeat(64)),
99
+ values: [{ value: 1n }, { value: 2n }],
100
+ },
101
+ {
102
+ key: Word.fromHex('0x' + 'b'.repeat(64)),
103
+ values: [{ value: 3n }, { value: 4n }],
104
+ },
105
+ ];
106
+ const result = mergeSignatureAdviceMaps(advice, entries);
107
+ expect(advice.insert).toHaveBeenCalledTimes(2);
108
+ expect(result).toBe(advice);
109
+ });
110
+ it('returns the same advice map', async () => {
111
+ const { AdviceMap } = await import('@demox-labs/miden-sdk');
112
+ const advice = new AdviceMap();
113
+ const result = mergeSignatureAdviceMaps(advice, []);
114
+ expect(result).toBe(advice);
115
+ });
116
+ it('handles empty entries array', async () => {
117
+ const { AdviceMap } = await import('@demox-labs/miden-sdk');
118
+ const advice = new AdviceMap();
119
+ mergeSignatureAdviceMaps(advice, []);
120
+ expect(advice.insert).not.toHaveBeenCalled();
121
+ });
122
+ });
123
+ describe('toWord', () => {
124
+ it('creates Word from hex string', async () => {
125
+ const { Word } = await import('@demox-labs/miden-sdk');
126
+ const word = toWord('abc123');
127
+ expect(Word.fromHex).toHaveBeenCalled();
128
+ expect(word).toBeDefined();
129
+ });
130
+ it('normalizes hex before creating Word', async () => {
131
+ const { Word } = await import('@demox-labs/miden-sdk');
132
+ toWord('abc');
133
+ // Should be called with normalized hex (0x + padded to 64 chars)
134
+ expect(Word.fromHex).toHaveBeenCalledWith('0x' + '0'.repeat(61) + 'abc');
135
+ });
136
+ it('handles 0x prefix', async () => {
137
+ const { Word } = await import('@demox-labs/miden-sdk');
138
+ toWord('0xdef');
139
+ expect(Word.fromHex).toHaveBeenCalledWith('0x' + '0'.repeat(61) + 'def');
140
+ });
141
+ it('handles full 64-char hex', async () => {
142
+ const { Word } = await import('@demox-labs/miden-sdk');
143
+ const fullHex = 'f'.repeat(64);
144
+ toWord(fullHex);
145
+ expect(Word.fromHex).toHaveBeenCalledWith('0x' + fullHex);
146
+ });
147
+ });
148
+ });
149
+ //# sourceMappingURL=signature.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signature.test.js","sourceRoot":"","sources":["../../src/utils/signature.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { Word } from '@demox-labs/miden-sdk';
2
+ export declare function wordToHex(word: Word): string;
3
+ export declare function wordElementToBigInt(word: Word, index: number): bigint;
4
+ //# sourceMappingURL=word.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"word.d.ts","sourceRoot":"","sources":["../../src/utils/word.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAE7C,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAE5C;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAGrE"}
@@ -0,0 +1,8 @@
1
+ export function wordToHex(word) {
2
+ return word.toHex();
3
+ }
4
+ export function wordElementToBigInt(word, index) {
5
+ const elements = word.toU64s();
6
+ return index >= 0 && index < elements.length ? elements[index] : 0n;
7
+ }
8
+ //# sourceMappingURL=word.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"word.js","sourceRoot":"","sources":["../../src/utils/word.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,SAAS,CAAC,IAAU;IAClC,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,IAAU,EAAE,KAAa;IAC3D,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;IAC/B,OAAO,KAAK,IAAI,CAAC,IAAI,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACtE,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=word.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"word.test.d.ts","sourceRoot":"","sources":["../../src/utils/word.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,54 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { wordElementToBigInt, wordToHex } from './word.js';
3
+ import { Word } from '@demox-labs/miden-sdk';
4
+ // Mock the Miden SDK Word class
5
+ vi.mock('@demox-labs/miden-sdk', () => ({
6
+ Word: {
7
+ fromHex: (hex) => {
8
+ // Parse hex string (remove 0x prefix if present)
9
+ const cleanHex = hex.startsWith('0x') ? hex.slice(2) : hex;
10
+ if (cleanHex.length !== 64) {
11
+ throw new Error('Hex string must be 64 characters');
12
+ }
13
+ // Parse as big-endian: [e3_bytes][e2_bytes][e1_bytes][e0_bytes]
14
+ const e3 = BigInt('0x' + cleanHex.slice(0, 16));
15
+ const e2 = BigInt('0x' + cleanHex.slice(16, 32));
16
+ const e1 = BigInt('0x' + cleanHex.slice(32, 48));
17
+ const e0 = BigInt('0x' + cleanHex.slice(48, 64));
18
+ const elements = new BigUint64Array([e0, e1, e2, e3]);
19
+ return {
20
+ toU64s: () => elements,
21
+ toHex: () => {
22
+ const h3 = elements[3].toString(16).padStart(16, '0');
23
+ const h2 = elements[2].toString(16).padStart(16, '0');
24
+ const h1 = elements[1].toString(16).padStart(16, '0');
25
+ const h0 = elements[0].toString(16).padStart(16, '0');
26
+ return '0x' + h3 + h2 + h1 + h0;
27
+ },
28
+ };
29
+ },
30
+ },
31
+ }));
32
+ describe('word utilities', () => {
33
+ describe('wordElementToBigInt', () => {
34
+ it('should return element at valid index', () => {
35
+ const word = Word.fromHex('0x016ab79593165e5b849776919e0c0298fb9dac880d593d93edd7134bdcdb4b6f');
36
+ expect(wordElementToBigInt(word, 0)).toBe(BigInt('0xedd7134bdcdb4b6f'));
37
+ expect(wordElementToBigInt(word, 3)).toBe(BigInt('0x016ab79593165e5b'));
38
+ });
39
+ it('should return 0n for invalid index', () => {
40
+ const word = Word.fromHex('0x016ab79593165e5b849776919e0c0298fb9dac880d593d93edd7134bdcdb4b6f');
41
+ expect(wordElementToBigInt(word, -1)).toBe(0n);
42
+ expect(wordElementToBigInt(word, 4)).toBe(0n);
43
+ });
44
+ });
45
+ describe('wordToHex', () => {
46
+ it('should convert word back to hex string', () => {
47
+ const originalHex = '0xd6c130dba13c67ac4733915f24bea9d19f517f51a65c74ded7bcd27e066b400e';
48
+ const word = Word.fromHex(originalHex);
49
+ const hex = wordToHex(word);
50
+ expect(hex).toBe(originalHex);
51
+ });
52
+ });
53
+ });
54
+ //# sourceMappingURL=word.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"word.test.js","sourceRoot":"","sources":["../../src/utils/word.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,423 @@
1
+ # Multi-Signature RPO Falcon 512 Authentication Component
2
+ #
3
+ # This component provides multi-signature authentication for accounts.
4
+ # It integrates with the PSM component for optional PSM signature verification.
5
+
6
+ use miden::active_account
7
+ use miden::native_account
8
+ use miden::auth
9
+ use openzeppelin::psm
10
+
11
+ # Type definitions for v0.12 syntax
12
+ type BeWord = struct @bigendian { a: felt, b: felt, c: felt, d: felt }
13
+
14
+ # CONSTANTS
15
+ # =================================================================================================
16
+
17
+ # Auth Request Constants
18
+
19
+ # The event emitted when a signature is not found for a required signer.
20
+ const AUTH_UNAUTHORIZED_EVENT = event("miden::auth::unauthorized")
21
+
22
+ # Storage Layout Constants
23
+ #
24
+ # +-------------------------------+----------+--------------+-------------------+
25
+ # | THRESHOLD & APPROVERS CONFIG | PUB KEYS | EXECUTED TXS | PROC THRESHOLDS |
26
+ # | (slot) | (map) | (map) | (map) |
27
+ # +-------------------------------+----------+--------------+-------------------+
28
+ # | 0 | 1 | 2 | 3 |
29
+ # +-------------------------------+----------+--------------+-------------------+
30
+
31
+ # The slot in this component's storage layout where the default signature threshold and
32
+ # number of approvers are stored as:
33
+ # [default_threshold, num_approvers, 0, 0].
34
+ # The threshold is guaranteed to be less than or equal to num_approvers.
35
+ const THRESHOLD_CONFIG_SLOT = 0
36
+
37
+ # The slot in this component's storage layout where the public keys map is stored.
38
+ # Map entries: [key_index, 0, 0, 0] => APPROVER_PUBLIC_KEY
39
+ const PUBLIC_KEYS_MAP_SLOT = 1
40
+
41
+ # The slot in this component's storage layout where executed transactions are stored.
42
+ # Map entries: transaction_message => [is_executed, 0, 0, 0]
43
+ const EXECUTED_TXS_SLOT = 2
44
+
45
+ # The slot in this component's storage layout where procedure thresholds are stored.
46
+ # Map entries: PROC_ROOT => [proc_threshold, 0, 0, 0]
47
+ const PROC_THRESHOLD_ROOTS_SLOT = 3
48
+
49
+ # Executed Transaction Flag Constant
50
+ const IS_EXECUTED_FLAG = [1, 0, 0, 0]
51
+
52
+ # ERRORS
53
+ const ERR_TX_ALREADY_EXECUTED = "failed to approve multisig transaction as it was already executed"
54
+
55
+ const ERR_MALFORMED_MULTISIG_CONFIG = "number of approvers must be equal to or greater than threshold"
56
+
57
+ const ERR_ZERO_IN_MULTISIG_CONFIG = "number of approvers or threshold must not be zero"
58
+
59
+ # MULTISIG PROCEDURES
60
+ # =================================================================================================
61
+
62
+ #! Check if transaction has already been executed and add it to executed transactions for replay protection.
63
+ #!
64
+ #! Inputs: [MSG]
65
+ #! Outputs: []
66
+ #!
67
+ #! Panics if:
68
+ #! - the same transaction has already been executed
69
+ proc assert_new_tx(msg: BeWord)
70
+ push.IS_EXECUTED_FLAG
71
+ # => [[0, 0, 0, is_executed], MSG]
72
+
73
+ swapw
74
+ # => [MSG, IS_EXECUTED_FLAG]
75
+
76
+ push.EXECUTED_TXS_SLOT
77
+ # => [index, MSG, IS_EXECUTED_FLAG]
78
+
79
+ # Set the key value pair in the map to mark transaction as executed
80
+ exec.native_account::set_map_item
81
+ # => [OLD_MAP_ROOT, [0, 0, 0, is_executed]]
82
+
83
+ dropw drop drop drop
84
+ # => [is_executed]
85
+
86
+ assertz.err=ERR_TX_ALREADY_EXECUTED
87
+ # => []
88
+ end
89
+
90
+ #! Remove old approver public keys from the approver public key mapping.
91
+ #!
92
+ #! This procedure cleans up the storage by removing public keys of approvers that are no longer
93
+ #! part of the multisig configuration. This procedure assumes that init_num_of_approvers and
94
+ #! new_num_of_approvers are u32 values.
95
+ #!
96
+ #! Inputs: [init_num_of_approvers, new_num_of_approvers]
97
+ #! Outputs: []
98
+ #!
99
+ #! Where:
100
+ #! - init_num_of_approvers is the original number of approvers before the update
101
+ #! - new_num_of_approvers is the new number of approvers after the update
102
+ proc cleanup_pubkey_mapping(init_num_of_approvers: u32, new_num_of_approvers: u32)
103
+ dup.1 dup.1
104
+ u32assert2 u32lt
105
+ # => [should_loop, i = init_num_of_approvers, new_num_of_approvers]
106
+
107
+ while.true
108
+ # => [i, new_num_of_approvers]
109
+
110
+ sub.1
111
+ # => [i-1, new_num_of_approvers]
112
+
113
+ dup
114
+ # => [i-1, i-1, new_num_of_approvers]
115
+
116
+ push.0.0.0
117
+ # => [[0, 0, 0, i-1], i-1, new_num_of_approvers]
118
+
119
+ padw swapw
120
+ # => [[0, 0, 0, i-1], EMPTY_WORD, i-1, new_num_of_approvers]
121
+
122
+ push.PUBLIC_KEYS_MAP_SLOT
123
+ # => [pub_key_slot_idx, [0, 0, 0, i-1], EMPTY_WORD, i-1, new_num_of_approvers]
124
+
125
+ exec.native_account::set_map_item
126
+ # => [OLD_MAP_ROOT, OLD_MAP_VALUE, i-1, new_num_of_approvers]
127
+
128
+ dropw dropw
129
+ # => [i-1, new_num_of_approvers]
130
+
131
+ dup.1 dup.1
132
+ u32lt
133
+ # => [should_loop, i-1, new_num_of_approvers]
134
+ end
135
+
136
+ drop drop
137
+ # => []
138
+ end
139
+
140
+ #! Update threshold config and add / remove approvers
141
+ #!
142
+ #! Inputs:
143
+ #! Operand stack: [MULTISIG_CONFIG_HASH, pad(12)]
144
+ #! Advice map: {
145
+ #! MULTISIG_CONFIG_HASH => [CONFIG, PUB_KEY_N, PUB_KEY_N-1, ..., PUB_KEY_0]
146
+ #! }
147
+ #! Outputs:
148
+ #! Operand stack: []
149
+ #!
150
+ #! Where:
151
+ #! - MULTISIG_CONFIG_HASH is the hash of the threshold and new public key vector
152
+ #! - MULTISIG_CONFIG is [threshold, num_approvers, 0, 0]
153
+ #! - PUB_KEY_i is the public key of the i-th signer
154
+ #!
155
+ #! Locals:
156
+ #! 0: new_num_of_approvers
157
+ #! 1: init_num_of_approvers
158
+ pub proc update_signers_and_threshold.2(multisig_config_hash: BeWord)
159
+ adv.push_mapval
160
+ # => [MULTISIG_CONFIG_HASH, pad(12)]
161
+
162
+ adv_loadw
163
+ # => [MULTISIG_CONFIG, pad(12)]
164
+
165
+ # store new_num_of_approvers for later
166
+ dup.2 loc_store.0
167
+ # => [MULTISIG_CONFIG, pad(12)]
168
+
169
+ dup.3 dup.3
170
+ # => [num_approvers, threshold, MULTISIG_CONFIG, pad(12)]
171
+
172
+ # make sure that the threshold is smaller than the number of approvers
173
+ u32assert2.err=ERR_MALFORMED_MULTISIG_CONFIG
174
+ u32gt assertz.err=ERR_MALFORMED_MULTISIG_CONFIG
175
+ # => [MULTISIG_CONFIG, pad(12)]
176
+
177
+ dup.3 dup.3
178
+ # => [num_approvers, threshold, MULTISIG_CONFIG, pad(12)]
179
+
180
+ # make sure that threshold or num_approvers are not zero
181
+ eq.0 assertz.err=ERR_ZERO_IN_MULTISIG_CONFIG
182
+ eq.0 assertz.err=ERR_ZERO_IN_MULTISIG_CONFIG
183
+ # => [MULTISIG_CONFIG, pad(12)]
184
+
185
+ push.THRESHOLD_CONFIG_SLOT
186
+ # => [slot, MULTISIG_CONFIG, pad(12)]
187
+
188
+ exec.native_account::set_item
189
+ # => [OLD_THRESHOLD_CONFIG, pad(12)]
190
+
191
+ # store init_num_of_approvers for later
192
+ drop drop loc_store.1 drop
193
+ # => [pad(12)]
194
+
195
+ loc_load.0
196
+ # => [num_approvers]
197
+
198
+ dup neq.0
199
+ while.true
200
+ sub.1
201
+ # => [i-1, pad(12)]
202
+
203
+ dup push.0.0.0
204
+ # => [[0, 0, 0, i-1], i-1, pad(12)]
205
+
206
+ padw adv_loadw
207
+ # => [PUB_KEY, [0, 0, 0, i-1], i-1, pad(12)]
208
+
209
+ swapw
210
+ # => [[0, 0, 0, i-1], PUB_KEY, i-1, pad(12)]
211
+
212
+ push.PUBLIC_KEYS_MAP_SLOT
213
+ # => [pub_key_slot_idx, [0, 0, 0, i-1], PUB_KEY, i-1, pad(12)]
214
+
215
+ exec.native_account::set_map_item
216
+ # => [OLD_MAP_ROOT, OLD_MAP_VALUE, i-1, pad(12)]
217
+
218
+ dropw dropw
219
+ # => [i-1, pad(12)]
220
+
221
+ dup neq.0
222
+ # => [is_non_zero, i-1, pad(12)]
223
+ end
224
+ # => [pad(13)]
225
+
226
+ drop
227
+ # => [pad(12)]
228
+
229
+ # compare initial vs current multisig config
230
+
231
+ # load init_num_of_approvers & new_num_of_approvers
232
+ loc_load.0 loc_load.1
233
+ # => [init_num_of_approvers, new_num_of_approvers, pad(12)]
234
+
235
+ exec.cleanup_pubkey_mapping
236
+ # => [pad(12)]
237
+ end
238
+
239
+ # Computes the effective transaction threshold based on called procedures and per-procedure
240
+ # overrides stored in PROC_THRESHOLD_ROOTS_SLOT. Falls back to default_threshold if no
241
+ # overrides apply.
242
+ #
243
+ #! Inputs: [default_threshold]
244
+ #! Outputs: [transaction_threshold]
245
+ proc compute_transaction_threshold.1(default_threshold: u32) -> u32
246
+ # 1. initialize transaction_threshold = 0
247
+ # 2. iterate through all account procedures
248
+ # a. check if the procedure was called during the transaction
249
+ # b. if called, get the override threshold of that procedure from the config map
250
+ # c. if proc_threshold > transaction_threshold, set transaction_threshold = proc_threshold
251
+ # 3. if transaction_threshold == 0 at the end, revert to using default_threshold
252
+
253
+ # store default_threshold for later
254
+ loc_store.0
255
+ # => []
256
+
257
+ # 1. initialize transaction_threshold = 0
258
+ push.0
259
+ # => [transaction_threshold]
260
+
261
+ # get the number of account procedures
262
+ exec.active_account::get_num_procedures
263
+ # => [num_procedures, transaction_threshold]
264
+
265
+ # 2. iterate through all account procedures
266
+ dup neq.0
267
+ # => [should_continue, num_procedures, transaction_threshold]
268
+ while.true
269
+ sub.1 dup
270
+ # => [num_procedures-1, num_procedures-1, transaction_threshold]
271
+
272
+ # get procedure root of the procedure with index i
273
+ exec.active_account::get_procedure_root dupw
274
+ # => [PROC_ROOT, PROC_ROOT, num_procedures-1, transaction_threshold]
275
+
276
+ # 2a. check if this procedure has been called in the transaction
277
+ exec.native_account::was_procedure_called
278
+ # => [was_called, PROC_ROOT, num_procedures-1, transaction_threshold]
279
+
280
+ # if it has been called, get the override threshold of that procedure
281
+ if.true
282
+ # => [PROC_ROOT, num_procedures-1, transaction_threshold]
283
+
284
+ push.PROC_THRESHOLD_ROOTS_SLOT
285
+ # => [PROC_THRESHOLD_ROOTS_SLOT, PROC_ROOT, num_procedures-1, transaction_threshold]
286
+
287
+ # 2b. get the override proc_threshold of that procedure
288
+ # if the procedure has no override threshold, the returned map item will be [0, 0, 0, 0]
289
+ exec.active_account::get_initial_map_item
290
+ # => [[0, 0, 0, proc_threshold], num_procedures-1, transaction_threshold]
291
+
292
+ drop drop drop dup dup.3
293
+ # => [transaction_threshold, proc_threshold, proc_threshold, num_procedures-1, transaction_threshold]
294
+
295
+ u32assert2.err="transaction threshold or procedure threshold are not u32"
296
+ u32gt
297
+ # => [is_gt, proc_threshold, num_procedures-1, transaction_threshold]
298
+ # 2c. if proc_threshold > transaction_threshold, update transaction_threshold
299
+ movup.2 movdn.3
300
+ # => [is_gt, proc_threshold, transaction_threshold, num_procedures-1]
301
+ cdrop
302
+ # => [updated_transaction_threshold, num_procedures-1]
303
+ swap
304
+ # => [num_procedures-1, updated_transaction_threshold]
305
+ # if it has not been called during this transaction, nothing to do, move to the next procedure
306
+ else
307
+ dropw
308
+ # => [num_procedures-1, transaction_threshold]
309
+ end
310
+
311
+ dup neq.0
312
+ # => [should_continue, num_procedures-1, transaction_threshold]
313
+ end
314
+
315
+ drop
316
+ # => [transaction_threshold]
317
+
318
+ loc_load.0
319
+ # => [default_threshold, transaction_threshold]
320
+
321
+ # 3. if transaction_threshold == 0 at the end, revert to using default_threshold
322
+ dup.1 eq.0
323
+ # => [is_zero, default_threshold, transaction_threshold]
324
+
325
+ cdrop
326
+ # => [effective_transaction_threshold]
327
+ end
328
+
329
+ #! Authenticate a transaction using the Falcon signature scheme with multi-signature support.
330
+ #!
331
+ #! This procedure implements multi-signature authentication by:
332
+ #! 1. Computing the transaction summary message that needs to be signed
333
+ #! 2. Verifying signatures from multiple required signers against their public keys
334
+ #! 3. Ensuring the minimum threshold of valid signatures is met
335
+ #! 4. Implementing replay protection by tracking executed transactions
336
+ #! 5. Verifying PSM signature if PSM selector is enabled (via PSM component)
337
+ #!
338
+ #! Inputs:
339
+ #! Operand stack: [SALT]
340
+ #! Advice map: {
341
+ #! h(SIG_0, MSG): SIG_0,
342
+ #! h(SIG_1, MSG): SIG_1,
343
+ #! h(SIG_n, MSG): SIG_n
344
+ #! }
345
+ #! Outputs:
346
+ #! Operand stack: []
347
+ #!
348
+ #! Where:
349
+ #! - SALT is a cryptographically random nonce that enables multiple concurrent
350
+ #! multisig transactions while maintaining replay protection. Each transaction
351
+ #! must use a unique SALT value to ensure transaction uniqueness.
352
+ #! - SIG_i is the signature from the i-th signer.
353
+ #! - MSG is the transaction message being signed.
354
+ #! - h(SIG_i, MSG) is the hash of the signature and message used as the advice map key.
355
+ #!
356
+ #! Panics if:
357
+ #! - insufficient number of valid signatures (below threshold).
358
+ #! - the same transaction has already been executed (replay protection).
359
+ #! - PSM signature verification fails (if PSM is enabled).
360
+ #!
361
+ #! Invocation: call
362
+ pub proc auth_tx_rpo_falcon512_multisig.1(salt: BeWord)
363
+ exec.native_account::incr_nonce drop
364
+ # => [SALT]
365
+
366
+ # ------ Computing transaction summary ------
367
+
368
+ exec.auth::create_tx_summary
369
+ # => [SALT, OUTPUT_NOTES_COMMITMENT, INPUT_NOTES_COMMITMENT, ACCOUNT_DELTA_COMMITMENT]
370
+
371
+ # to build a tx_summary in the host, we need these four words in the advice provider
372
+ exec.auth::adv_insert_hqword
373
+ # => [SALT, OUTPUT_NOTES_COMMITMENT, INPUT_NOTES_COMMITMENT, ACCOUNT_DELTA_COMMITMENT]
374
+
375
+ # the commitment to the tx summary is the message that is signed
376
+ exec.auth::hash_tx_summary
377
+ # => [TX_SUMMARY_COMMITMENT]
378
+
379
+ # ------ Verifying approver signatures ------
380
+
381
+ push.THRESHOLD_CONFIG_SLOT
382
+ # => [index, TX_SUMMARY_COMMITMENT]
383
+
384
+ exec.active_account::get_initial_item
385
+ # => [0, 0, num_of_approvers, default_threshold, TX_SUMMARY_COMMITMENT]
386
+
387
+ drop drop
388
+ # => [num_of_approvers, default_threshold, TX_SUMMARY_COMMITMENT]
389
+
390
+ swap movdn.5
391
+ # => [num_of_approvers, TX_SUMMARY_COMMITMENT, default_threshold]
392
+
393
+ push.PUBLIC_KEYS_MAP_SLOT
394
+ # => [pub_key_slot_idx, num_of_approvers, TX_SUMMARY_COMMITMENT, default_threshold]
395
+
396
+ exec.::miden::auth::rpo_falcon512::verify_signatures
397
+ # => [num_verified_signatures, TX_SUMMARY_COMMITMENT, default_threshold]
398
+
399
+ # ------ Checking threshold is >= num_verified_signatures ------
400
+
401
+ movup.5
402
+ # => [default_threshold, num_verified_signatures, TX_SUMMARY_COMMITMENT]
403
+
404
+ exec.compute_transaction_threshold
405
+ # => [transaction_threshold, num_verified_signatures, TX_SUMMARY_COMMITMENT]
406
+
407
+ u32assert2 u32lt
408
+ # => [is_unauthorized, TX_SUMMARY_COMMITMENT]
409
+
410
+ # If signatures are non-existent the tx will fail here.
411
+ if.true
412
+ emit.AUTH_UNAUTHORIZED_EVENT
413
+ push.0 assert.err="insufficient number of signatures"
414
+ end
415
+
416
+ # ------ Verifying PSM Signature ------
417
+ # => [TX_SUMMARY_COMMITMENT]
418
+ call.psm::verify_psm_signature
419
+
420
+ # ------ Writing executed transaction MSG to map ------
421
+ # => [TX_SUMMARY_COMMITMENT]
422
+ exec.assert_new_tx
423
+ end