@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,605 @@
1
+ // Embedded MASM constants - content from masm/*.masm files
2
+ export const MULTISIG_MASM = `# Multi-Signature RPO Falcon 512 Authentication Component
3
+ #
4
+ # This component provides multi-signature authentication for accounts.
5
+ # It integrates with the PSM component for optional PSM signature verification.
6
+
7
+ use miden::active_account
8
+ use miden::native_account
9
+ use miden::auth
10
+ use openzeppelin::psm
11
+
12
+ # Type definitions for v0.12 syntax
13
+ type BeWord = struct @bigendian { a: felt, b: felt, c: felt, d: felt }
14
+
15
+ # CONSTANTS
16
+ # =================================================================================================
17
+
18
+ # Auth Request Constants
19
+
20
+ # The event emitted when a signature is not found for a required signer.
21
+ const AUTH_UNAUTHORIZED_EVENT = event("miden::auth::unauthorized")
22
+
23
+ # Storage Layout Constants
24
+ #
25
+ # +-------------------------------+----------+--------------+-------------------+
26
+ # | THRESHOLD & APPROVERS CONFIG | PUB KEYS | EXECUTED TXS | PROC THRESHOLDS |
27
+ # | (slot) | (map) | (map) | (map) |
28
+ # +-------------------------------+----------+--------------+-------------------+
29
+ # | 0 | 1 | 2 | 3 |
30
+ # +-------------------------------+----------+--------------+-------------------+
31
+
32
+ # The slot in this component's storage layout where the default signature threshold and
33
+ # number of approvers are stored as:
34
+ # [default_threshold, num_approvers, 0, 0].
35
+ # The threshold is guaranteed to be less than or equal to num_approvers.
36
+ const THRESHOLD_CONFIG_SLOT = 0
37
+
38
+ # The slot in this component's storage layout where the public keys map is stored.
39
+ # Map entries: [key_index, 0, 0, 0] => APPROVER_PUBLIC_KEY
40
+ const PUBLIC_KEYS_MAP_SLOT = 1
41
+
42
+ # The slot in this component's storage layout where executed transactions are stored.
43
+ # Map entries: transaction_message => [is_executed, 0, 0, 0]
44
+ const EXECUTED_TXS_SLOT = 2
45
+
46
+ # The slot in this component's storage layout where procedure thresholds are stored.
47
+ # Map entries: PROC_ROOT => [proc_threshold, 0, 0, 0]
48
+ const PROC_THRESHOLD_ROOTS_SLOT = 3
49
+
50
+ # Executed Transaction Flag Constant
51
+ const IS_EXECUTED_FLAG = [1, 0, 0, 0]
52
+
53
+ # ERRORS
54
+ const ERR_TX_ALREADY_EXECUTED = "failed to approve multisig transaction as it was already executed"
55
+
56
+ const ERR_MALFORMED_MULTISIG_CONFIG = "number of approvers must be equal to or greater than threshold"
57
+
58
+ const ERR_ZERO_IN_MULTISIG_CONFIG = "number of approvers or threshold must not be zero"
59
+
60
+ # MULTISIG PROCEDURES
61
+ # =================================================================================================
62
+
63
+ #! Check if transaction has already been executed and add it to executed transactions for replay protection.
64
+ #!
65
+ #! Inputs: [MSG]
66
+ #! Outputs: []
67
+ #!
68
+ #! Panics if:
69
+ #! - the same transaction has already been executed
70
+ proc assert_new_tx(msg: BeWord)
71
+ push.IS_EXECUTED_FLAG
72
+ # => [[0, 0, 0, is_executed], MSG]
73
+
74
+ swapw
75
+ # => [MSG, IS_EXECUTED_FLAG]
76
+
77
+ push.EXECUTED_TXS_SLOT
78
+ # => [index, MSG, IS_EXECUTED_FLAG]
79
+
80
+ # Set the key value pair in the map to mark transaction as executed
81
+ exec.native_account::set_map_item
82
+ # => [OLD_MAP_ROOT, [0, 0, 0, is_executed]]
83
+
84
+ dropw drop drop drop
85
+ # => [is_executed]
86
+
87
+ assertz.err=ERR_TX_ALREADY_EXECUTED
88
+ # => []
89
+ end
90
+
91
+ #! Remove old approver public keys from the approver public key mapping.
92
+ #!
93
+ #! This procedure cleans up the storage by removing public keys of approvers that are no longer
94
+ #! part of the multisig configuration. This procedure assumes that init_num_of_approvers and
95
+ #! new_num_of_approvers are u32 values.
96
+ #!
97
+ #! Inputs: [init_num_of_approvers, new_num_of_approvers]
98
+ #! Outputs: []
99
+ #!
100
+ #! Where:
101
+ #! - init_num_of_approvers is the original number of approvers before the update
102
+ #! - new_num_of_approvers is the new number of approvers after the update
103
+ proc cleanup_pubkey_mapping(init_num_of_approvers: u32, new_num_of_approvers: u32)
104
+ dup.1 dup.1
105
+ u32assert2 u32lt
106
+ # => [should_loop, i = init_num_of_approvers, new_num_of_approvers]
107
+
108
+ while.true
109
+ # => [i, new_num_of_approvers]
110
+
111
+ sub.1
112
+ # => [i-1, new_num_of_approvers]
113
+
114
+ dup
115
+ # => [i-1, i-1, new_num_of_approvers]
116
+
117
+ push.0.0.0
118
+ # => [[0, 0, 0, i-1], i-1, new_num_of_approvers]
119
+
120
+ padw swapw
121
+ # => [[0, 0, 0, i-1], EMPTY_WORD, i-1, new_num_of_approvers]
122
+
123
+ push.PUBLIC_KEYS_MAP_SLOT
124
+ # => [pub_key_slot_idx, [0, 0, 0, i-1], EMPTY_WORD, i-1, new_num_of_approvers]
125
+
126
+ exec.native_account::set_map_item
127
+ # => [OLD_MAP_ROOT, OLD_MAP_VALUE, i-1, new_num_of_approvers]
128
+
129
+ dropw dropw
130
+ # => [i-1, new_num_of_approvers]
131
+
132
+ dup.1 dup.1
133
+ u32lt
134
+ # => [should_loop, i-1, new_num_of_approvers]
135
+ end
136
+
137
+ drop drop
138
+ # => []
139
+ end
140
+
141
+ #! Update threshold config and add / remove approvers
142
+ #!
143
+ #! Inputs:
144
+ #! Operand stack: [MULTISIG_CONFIG_HASH, pad(12)]
145
+ #! Advice map: {
146
+ #! MULTISIG_CONFIG_HASH => [CONFIG, PUB_KEY_N, PUB_KEY_N-1, ..., PUB_KEY_0]
147
+ #! }
148
+ #! Outputs:
149
+ #! Operand stack: []
150
+ #!
151
+ #! Where:
152
+ #! - MULTISIG_CONFIG_HASH is the hash of the threshold and new public key vector
153
+ #! - MULTISIG_CONFIG is [threshold, num_approvers, 0, 0]
154
+ #! - PUB_KEY_i is the public key of the i-th signer
155
+ #!
156
+ #! Locals:
157
+ #! 0: new_num_of_approvers
158
+ #! 1: init_num_of_approvers
159
+ pub proc update_signers_and_threshold.2(multisig_config_hash: BeWord)
160
+ adv.push_mapval
161
+ # => [MULTISIG_CONFIG_HASH, pad(12)]
162
+
163
+ adv_loadw
164
+ # => [MULTISIG_CONFIG, pad(12)]
165
+
166
+ # store new_num_of_approvers for later
167
+ dup.2 loc_store.0
168
+ # => [MULTISIG_CONFIG, pad(12)]
169
+
170
+ dup.3 dup.3
171
+ # => [num_approvers, threshold, MULTISIG_CONFIG, pad(12)]
172
+
173
+ # make sure that the threshold is smaller than the number of approvers
174
+ u32assert2.err=ERR_MALFORMED_MULTISIG_CONFIG
175
+ u32gt assertz.err=ERR_MALFORMED_MULTISIG_CONFIG
176
+ # => [MULTISIG_CONFIG, pad(12)]
177
+
178
+ dup.3 dup.3
179
+ # => [num_approvers, threshold, MULTISIG_CONFIG, pad(12)]
180
+
181
+ # make sure that threshold or num_approvers are not zero
182
+ eq.0 assertz.err=ERR_ZERO_IN_MULTISIG_CONFIG
183
+ eq.0 assertz.err=ERR_ZERO_IN_MULTISIG_CONFIG
184
+ # => [MULTISIG_CONFIG, pad(12)]
185
+
186
+ push.THRESHOLD_CONFIG_SLOT
187
+ # => [slot, MULTISIG_CONFIG, pad(12)]
188
+
189
+ exec.native_account::set_item
190
+ # => [OLD_THRESHOLD_CONFIG, pad(12)]
191
+
192
+ # store init_num_of_approvers for later
193
+ drop drop loc_store.1 drop
194
+ # => [pad(12)]
195
+
196
+ loc_load.0
197
+ # => [num_approvers]
198
+
199
+ dup neq.0
200
+ while.true
201
+ sub.1
202
+ # => [i-1, pad(12)]
203
+
204
+ dup push.0.0.0
205
+ # => [[0, 0, 0, i-1], i-1, pad(12)]
206
+
207
+ padw adv_loadw
208
+ # => [PUB_KEY, [0, 0, 0, i-1], i-1, pad(12)]
209
+
210
+ swapw
211
+ # => [[0, 0, 0, i-1], PUB_KEY, i-1, pad(12)]
212
+
213
+ push.PUBLIC_KEYS_MAP_SLOT
214
+ # => [pub_key_slot_idx, [0, 0, 0, i-1], PUB_KEY, i-1, pad(12)]
215
+
216
+ exec.native_account::set_map_item
217
+ # => [OLD_MAP_ROOT, OLD_MAP_VALUE, i-1, pad(12)]
218
+
219
+ dropw dropw
220
+ # => [i-1, pad(12)]
221
+
222
+ dup neq.0
223
+ # => [is_non_zero, i-1, pad(12)]
224
+ end
225
+ # => [pad(13)]
226
+
227
+ drop
228
+ # => [pad(12)]
229
+
230
+ # compare initial vs current multisig config
231
+
232
+ # load init_num_of_approvers & new_num_of_approvers
233
+ loc_load.0 loc_load.1
234
+ # => [init_num_of_approvers, new_num_of_approvers, pad(12)]
235
+
236
+ exec.cleanup_pubkey_mapping
237
+ # => [pad(12)]
238
+ end
239
+
240
+ # Computes the effective transaction threshold based on called procedures and per-procedure
241
+ # overrides stored in PROC_THRESHOLD_ROOTS_SLOT. Falls back to default_threshold if no
242
+ # overrides apply.
243
+ #
244
+ #! Inputs: [default_threshold]
245
+ #! Outputs: [transaction_threshold]
246
+ proc compute_transaction_threshold.1(default_threshold: u32) -> u32
247
+ # 1. initialize transaction_threshold = 0
248
+ # 2. iterate through all account procedures
249
+ # a. check if the procedure was called during the transaction
250
+ # b. if called, get the override threshold of that procedure from the config map
251
+ # c. if proc_threshold > transaction_threshold, set transaction_threshold = proc_threshold
252
+ # 3. if transaction_threshold == 0 at the end, revert to using default_threshold
253
+
254
+ # store default_threshold for later
255
+ loc_store.0
256
+ # => []
257
+
258
+ # 1. initialize transaction_threshold = 0
259
+ push.0
260
+ # => [transaction_threshold]
261
+
262
+ # get the number of account procedures
263
+ exec.active_account::get_num_procedures
264
+ # => [num_procedures, transaction_threshold]
265
+
266
+ # 2. iterate through all account procedures
267
+ dup neq.0
268
+ # => [should_continue, num_procedures, transaction_threshold]
269
+ while.true
270
+ sub.1 dup
271
+ # => [num_procedures-1, num_procedures-1, transaction_threshold]
272
+
273
+ # get procedure root of the procedure with index i
274
+ exec.active_account::get_procedure_root dupw
275
+ # => [PROC_ROOT, PROC_ROOT, num_procedures-1, transaction_threshold]
276
+
277
+ # 2a. check if this procedure has been called in the transaction
278
+ exec.native_account::was_procedure_called
279
+ # => [was_called, PROC_ROOT, num_procedures-1, transaction_threshold]
280
+
281
+ # if it has been called, get the override threshold of that procedure
282
+ if.true
283
+ # => [PROC_ROOT, num_procedures-1, transaction_threshold]
284
+
285
+ push.PROC_THRESHOLD_ROOTS_SLOT
286
+ # => [PROC_THRESHOLD_ROOTS_SLOT, PROC_ROOT, num_procedures-1, transaction_threshold]
287
+
288
+ # 2b. get the override proc_threshold of that procedure
289
+ # if the procedure has no override threshold, the returned map item will be [0, 0, 0, 0]
290
+ exec.active_account::get_initial_map_item
291
+ # => [[0, 0, 0, proc_threshold], num_procedures-1, transaction_threshold]
292
+
293
+ drop drop drop dup dup.3
294
+ # => [transaction_threshold, proc_threshold, proc_threshold, num_procedures-1, transaction_threshold]
295
+
296
+ u32assert2.err="transaction threshold or procedure threshold are not u32"
297
+ u32gt
298
+ # => [is_gt, proc_threshold, num_procedures-1, transaction_threshold]
299
+ # 2c. if proc_threshold > transaction_threshold, update transaction_threshold
300
+ movup.2 movdn.3
301
+ # => [is_gt, proc_threshold, transaction_threshold, num_procedures-1]
302
+ cdrop
303
+ # => [updated_transaction_threshold, num_procedures-1]
304
+ swap
305
+ # => [num_procedures-1, updated_transaction_threshold]
306
+ # if it has not been called during this transaction, nothing to do, move to the next procedure
307
+ else
308
+ dropw
309
+ # => [num_procedures-1, transaction_threshold]
310
+ end
311
+
312
+ dup neq.0
313
+ # => [should_continue, num_procedures-1, transaction_threshold]
314
+ end
315
+
316
+ drop
317
+ # => [transaction_threshold]
318
+
319
+ loc_load.0
320
+ # => [default_threshold, transaction_threshold]
321
+
322
+ # 3. if transaction_threshold == 0 at the end, revert to using default_threshold
323
+ dup.1 eq.0
324
+ # => [is_zero, default_threshold, transaction_threshold]
325
+
326
+ cdrop
327
+ # => [effective_transaction_threshold]
328
+ end
329
+
330
+ #! Authenticate a transaction using the Falcon signature scheme with multi-signature support.
331
+ #!
332
+ #! This procedure implements multi-signature authentication by:
333
+ #! 1. Computing the transaction summary message that needs to be signed
334
+ #! 2. Verifying signatures from multiple required signers against their public keys
335
+ #! 3. Ensuring the minimum threshold of valid signatures is met
336
+ #! 4. Implementing replay protection by tracking executed transactions
337
+ #! 5. Verifying PSM signature if PSM selector is enabled (via PSM component)
338
+ #!
339
+ #! Inputs:
340
+ #! Operand stack: [SALT]
341
+ #! Advice map: {
342
+ #! h(SIG_0, MSG): SIG_0,
343
+ #! h(SIG_1, MSG): SIG_1,
344
+ #! h(SIG_n, MSG): SIG_n
345
+ #! }
346
+ #! Outputs:
347
+ #! Operand stack: []
348
+ #!
349
+ #! Where:
350
+ #! - SALT is a cryptographically random nonce that enables multiple concurrent
351
+ #! multisig transactions while maintaining replay protection. Each transaction
352
+ #! must use a unique SALT value to ensure transaction uniqueness.
353
+ #! - SIG_i is the signature from the i-th signer.
354
+ #! - MSG is the transaction message being signed.
355
+ #! - h(SIG_i, MSG) is the hash of the signature and message used as the advice map key.
356
+ #!
357
+ #! Panics if:
358
+ #! - insufficient number of valid signatures (below threshold).
359
+ #! - the same transaction has already been executed (replay protection).
360
+ #! - PSM signature verification fails (if PSM is enabled).
361
+ #!
362
+ #! Invocation: call
363
+ pub proc auth_tx_rpo_falcon512_multisig.1(salt: BeWord)
364
+ exec.native_account::incr_nonce drop
365
+ # => [SALT]
366
+
367
+ # ------ Computing transaction summary ------
368
+
369
+ exec.auth::create_tx_summary
370
+ # => [SALT, OUTPUT_NOTES_COMMITMENT, INPUT_NOTES_COMMITMENT, ACCOUNT_DELTA_COMMITMENT]
371
+
372
+ # to build a tx_summary in the host, we need these four words in the advice provider
373
+ exec.auth::adv_insert_hqword
374
+ # => [SALT, OUTPUT_NOTES_COMMITMENT, INPUT_NOTES_COMMITMENT, ACCOUNT_DELTA_COMMITMENT]
375
+
376
+ # the commitment to the tx summary is the message that is signed
377
+ exec.auth::hash_tx_summary
378
+ # => [TX_SUMMARY_COMMITMENT]
379
+
380
+ # ------ Verifying approver signatures ------
381
+
382
+ push.THRESHOLD_CONFIG_SLOT
383
+ # => [index, TX_SUMMARY_COMMITMENT]
384
+
385
+ exec.active_account::get_initial_item
386
+ # => [0, 0, num_of_approvers, default_threshold, TX_SUMMARY_COMMITMENT]
387
+
388
+ drop drop
389
+ # => [num_of_approvers, default_threshold, TX_SUMMARY_COMMITMENT]
390
+
391
+ swap movdn.5
392
+ # => [num_of_approvers, TX_SUMMARY_COMMITMENT, default_threshold]
393
+
394
+ push.PUBLIC_KEYS_MAP_SLOT
395
+ # => [pub_key_slot_idx, num_of_approvers, TX_SUMMARY_COMMITMENT, default_threshold]
396
+
397
+ exec.::miden::auth::rpo_falcon512::verify_signatures
398
+ # => [num_verified_signatures, TX_SUMMARY_COMMITMENT, default_threshold]
399
+
400
+ # ------ Checking threshold is >= num_verified_signatures ------
401
+
402
+ movup.5
403
+ # => [default_threshold, num_verified_signatures, TX_SUMMARY_COMMITMENT]
404
+
405
+ exec.compute_transaction_threshold
406
+ # => [transaction_threshold, num_verified_signatures, TX_SUMMARY_COMMITMENT]
407
+
408
+ u32assert2 u32lt
409
+ # => [is_unauthorized, TX_SUMMARY_COMMITMENT]
410
+
411
+ # If signatures are non-existent the tx will fail here.
412
+ if.true
413
+ emit.AUTH_UNAUTHORIZED_EVENT
414
+ push.0 assert.err="insufficient number of signatures"
415
+ end
416
+
417
+ # ------ Verifying PSM Signature ------
418
+ # => [TX_SUMMARY_COMMITMENT]
419
+ call.psm::verify_psm_signature
420
+
421
+ # ------ Writing executed transaction MSG to map ------
422
+ # => [TX_SUMMARY_COMMITMENT]
423
+ exec.assert_new_tx
424
+ end
425
+ `;
426
+ export const PSM_MASM = `# Private State Manager (PSM) Authentication Component
427
+ #
428
+ # This component provides PSM signature verification for accounts.
429
+ # It can be used standalone or in conjunction with other auth components like multisig.
430
+
431
+ use miden::active_account
432
+ use miden::native_account
433
+
434
+ # Type definitions for v0.12 syntax
435
+ type BeWord = struct @bigendian { a: felt, b: felt, c: felt, d: felt }
436
+
437
+ # IMPORTANT SECURITY NOTES
438
+ # --------------------------------------------------------------------------------
439
+ # - The selector in \`PSM_SELECTOR_SLOT\` controls whether the extra PSM signature
440
+ # is enforced:
441
+ # * PSM_ON => exactly one valid PSM signature is required.
442
+ # * PSM_OFF => PSM signature is skipped for that call.
443
+ #
444
+ # - \`verify_psm_signature\` reads the selector from initial storage state.
445
+ # This means changes made during the same transaction won't affect the check.
446
+ #
447
+ # - \`enable_psm\` / \`disable_psm\` procedures allow explicit control over PSM state.
448
+ #
449
+ # - \`update_psm_public_key\`:
450
+ # * Installs a new PSM public key in the map at \`PSM_PUBLIC_KEY_MAP_SLOT\`.
451
+ # * Does not itself perform any signature checks.
452
+ # * To update the key without requiring PSM signature, ensure selector is OFF.
453
+ #
454
+ # Storage Layout
455
+ # --------------------------------------------------------------------------------
456
+ #
457
+ # +---------------------+---------------+
458
+ # | DESCRIPTION | SLOT |
459
+ # +---------------------+---------------+
460
+ # | PSM SELECTOR (word) | 0 |
461
+ # | PSM PUBLIC KEY MAP | 1 |
462
+ # +---------------------+---------------+
463
+ #
464
+ # - PSM_SELECTOR_SLOT (0):
465
+ # * Stores a word that is compared against [1, 0, 0, 0] (PSM_ON).
466
+ # * Any value != PSM_ON is treated as PSM_OFF.
467
+ #
468
+ # - PSM_PUBLIC_KEY_MAP_SLOT (1):
469
+ # * A map from a fixed key [0, 0, 0, 0] to the single PSM public key:
470
+ # [0, 0, 0, 0] => PSM_PUBLIC_KEY
471
+ # * PSM_PUBLIC_KEY is a RPO Falcon 512 public key represented as a word.
472
+
473
+ # CONSTANTS
474
+ # =================================================================================================
475
+
476
+ # Slot where the PSM selector flag is stored:
477
+ # - PSM_ON => PSM signature required
478
+ # - PSM_OFF => PSM signature skipped
479
+ const PSM_SELECTOR_SLOT = 0
480
+
481
+ # Map slot for PSM public key
482
+ # Uses exactly one PSM public key at index [0, 0, 0, 0]
483
+ # [0, 0, 0, 0] => PSM_PUBLIC_KEY
484
+ const PSM_PUBLIC_KEY_MAP_SLOT = 1
485
+
486
+ # Selector flag values
487
+ const PSM_ON = [1, 0, 0, 0]
488
+ const PSM_OFF = [0, 0, 0, 0]
489
+
490
+ # The event emitted when a signature is not found for a required signer.
491
+ const AUTH_UNAUTHORIZED_EVENT = event("miden::auth::unauthorized")
492
+
493
+ # PSM PROCEDURES
494
+ # =================================================================================================
495
+
496
+ #! Enable PSM verification by setting the selector to ON.
497
+ #!
498
+ #! Operand stack inputs: []
499
+ #! Outputs: []
500
+ #!
501
+ #! Notes:
502
+ #! - Sets PSM_SELECTOR_SLOT to PSM_ON (1)
503
+ #! - After this, transactions will require PSM signature verification
504
+ proc.enable_psm
505
+ push.PSM_ON
506
+ # => [PSM_ON]
507
+
508
+ push.PSM_SELECTOR_SLOT
509
+ # => [PSM_SELECTOR_SLOT, PSM_ON]
510
+
511
+ exec.native_account::set_item
512
+ # => [OLD_ROOT]
513
+
514
+ dropw
515
+ # => []
516
+ end
517
+
518
+ #! Disable PSM verification by setting the selector to OFF.
519
+ #!
520
+ #! Operand stack inputs: []
521
+ #! Outputs: []
522
+ #!
523
+ #! Notes:
524
+ #! - Sets PSM_SELECTOR_SLOT to PSM_OFF (0)
525
+ #! - After this, transactions will NOT require PSM signature verification
526
+ proc.disable_psm
527
+ push.PSM_OFF
528
+ # => [PSM_OFF]
529
+
530
+ push.PSM_SELECTOR_SLOT
531
+ # => [PSM_SELECTOR_SLOT, PSM_OFF]
532
+
533
+ exec.native_account::set_item
534
+ # => [OLD_ROOT]
535
+
536
+ dropw
537
+ # => []
538
+ end
539
+
540
+ #! Update the PSM public key.
541
+ #!
542
+ #! Operand stack inputs: []
543
+ #! Advice stack inputs: [PUB_KEY]
544
+ #! - PUB_KEY is the new PSM RPO Falcon 512 public key
545
+ #!
546
+ #! Notes:
547
+ #! - Stores PUB_KEY into PSM_PUBLIC_KEY_MAP_SLOT:
548
+ #! [0, 0, 0, 0] => PSM_PUBLIC_KEY
549
+ #! - To update the key without requiring PSM signature, ensure
550
+ #! PSM_SELECTOR_SLOT = 0 (OFF) before calling this.
551
+ pub proc update_psm_public_key
552
+ exec.disable_psm
553
+ # ------ Update the PSM public key ------
554
+ adv_loadw
555
+ # => [PUB_KEY]
556
+
557
+ push.0.0.0.0
558
+ # => [MAP_KEY, PUB_KEY]
559
+ # Note that MAP_KEY is [0, 0, 0, 0] for a single PSM_KEY
560
+
561
+ push.PSM_PUBLIC_KEY_MAP_SLOT
562
+ # => [index, MAP_KEY, PUB_KEY]
563
+
564
+ exec.native_account::set_map_item
565
+ # => [OLD_MAP_ROOT, OLD_MAP_VALUE]
566
+
567
+ dropw dropw
568
+ # => []
569
+ end
570
+
571
+ #! Conditionally verify a "PSM" signature against a stored public key hash.
572
+ #! The condition is controlled by the selector at PSM_SELECTOR_SLOT.
573
+ #!
574
+ #! Inputs: [MSG]
575
+ #! Outputs: [MSG]
576
+ #!
577
+ #! Panics if:
578
+ #! - Selector is ON but the provided PSM signature is invalid or missing.
579
+ #!
580
+ #! Notes:
581
+ #! - MSG is TX_SUMMARY_COMMITMENT provided by auth procedure
582
+ #! - If selector is OFF (0), PSM verification is skipped
583
+ #! - Selector value is read from initial storage state
584
+ pub proc verify_psm_signature(msg: BeWord)
585
+ push.PSM_SELECTOR_SLOT
586
+ exec.active_account::get_item
587
+ drop drop drop
588
+ # => [selector, MSG]
589
+
590
+ push.1 eq
591
+ if.true
592
+ push.1
593
+ push.PSM_PUBLIC_KEY_MAP_SLOT
594
+ exec.::miden::auth::rpo_falcon512::verify_signatures
595
+ push.1 neq
596
+ if.true
597
+ emit.AUTH_UNAUTHORIZED_EVENT
598
+ push.0 assert.err="invalid PSM signature"
599
+ end
600
+ end
601
+ # => [MSG]
602
+ exec.enable_psm
603
+ end
604
+ `;
605
+ //# sourceMappingURL=masm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"masm.js","sourceRoot":"","sources":["../../src/account/masm.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAE3D,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAua5B,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkLvB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { MultisigConfig } from '../types.js';
2
+ import { StorageSlot } from '@demox-labs/miden-sdk';
3
+ export declare class StorageLayoutBuilder {
4
+ buildMultisigSlots(config: MultisigConfig): StorageSlot[];
5
+ buildPsmSlots(config: MultisigConfig): StorageSlot[];
6
+ }
7
+ export declare function buildMultisigStorageSlots(config: MultisigConfig): StorageSlot[];
8
+ export declare function buildPsmStorageSlots(config: MultisigConfig): StorageSlot[];
9
+ export declare const storageLayoutBuilder: StorageLayoutBuilder;
10
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/account/storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,WAAW,EAAoB,MAAM,uBAAuB,CAAC;AAItE,qBAAa,oBAAoB;IAC/B,kBAAkB,CAAC,MAAM,EAAE,cAAc,GAAG,WAAW,EAAE;IAsCzD,aAAa,CAAC,MAAM,EAAE,cAAc,GAAG,WAAW,EAAE;CAarD;AAID,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,cAAc,GAAG,WAAW,EAAE,CAE/E;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,cAAc,GAAG,WAAW,EAAE,CAE1E;AAED,eAAO,MAAM,oBAAoB,sBAAwB,CAAC"}
@@ -0,0 +1,56 @@
1
+ import { StorageSlot, StorageMap, Word } from '@demox-labs/miden-sdk';
2
+ import { ensureHexPrefix } from '../utils/encoding.js';
3
+ import { getProcedureRoot } from '../procedures.js';
4
+ export class StorageLayoutBuilder {
5
+ buildMultisigSlots(config) {
6
+ const numSigners = config.signerCommitments.length;
7
+ const slot0Word = new Word(new BigUint64Array([
8
+ BigInt(config.threshold),
9
+ BigInt(numSigners),
10
+ 0n,
11
+ 0n,
12
+ ]));
13
+ const slot0 = StorageSlot.fromValue(slot0Word);
14
+ const signersMap = new StorageMap();
15
+ config.signerCommitments.forEach((commitment, index) => {
16
+ const key = new Word(new BigUint64Array([BigInt(index), 0n, 0n, 0n]));
17
+ const value = Word.fromHex(ensureHexPrefix(commitment));
18
+ signersMap.insert(key, value);
19
+ });
20
+ const slot1 = StorageSlot.map(signersMap);
21
+ const slot2 = StorageSlot.map(new StorageMap());
22
+ // Map entries: PROC_ROOT => [proc_threshold, 0, 0, 0]
23
+ // Use SDK's Word.fromHex to match how account code procedure roots are represented
24
+ const procThresholdMap = new StorageMap();
25
+ if (config.procedureThresholds) {
26
+ for (const pt of config.procedureThresholds) {
27
+ const rootHex = getProcedureRoot(pt.procedure);
28
+ const key = Word.fromHex(rootHex);
29
+ const value = new Word(new BigUint64Array([BigInt(pt.threshold), 0n, 0n, 0n]));
30
+ procThresholdMap.insert(key, value);
31
+ }
32
+ }
33
+ const slot3 = StorageSlot.map(procThresholdMap);
34
+ return [slot0, slot1, slot2, slot3];
35
+ }
36
+ buildPsmSlots(config) {
37
+ const selector = config.psmEnabled !== false ? 1n : 0n;
38
+ const selectorWord = new Word(new BigUint64Array([selector, 0n, 0n, 0n]));
39
+ const slot0 = StorageSlot.fromValue(selectorWord);
40
+ const psmKeyMap = new StorageMap();
41
+ const zeroKey = new Word(new BigUint64Array([0n, 0n, 0n, 0n]));
42
+ const psmKey = Word.fromHex(ensureHexPrefix(config.psmCommitment));
43
+ psmKeyMap.insert(zeroKey, psmKey);
44
+ const slot1 = StorageSlot.map(psmKeyMap);
45
+ return [slot0, slot1];
46
+ }
47
+ }
48
+ const defaultStorageBuilder = new StorageLayoutBuilder();
49
+ export function buildMultisigStorageSlots(config) {
50
+ return defaultStorageBuilder.buildMultisigSlots(config);
51
+ }
52
+ export function buildPsmStorageSlots(config) {
53
+ return defaultStorageBuilder.buildPsmSlots(config);
54
+ }
55
+ export const storageLayoutBuilder = defaultStorageBuilder;
56
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/account/storage.ts"],"names":[],"mappings":"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"}