@openzeppelin/miden-multisig-client 0.16.1 → 0.17.0-rc.1

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 (207) hide show
  1. package/README.md +192 -11
  2. package/dist/account/builder.d.ts.map +1 -1
  3. package/dist/account/builder.js +32 -25
  4. package/dist/account/builder.js.map +1 -1
  5. package/dist/account/builder.test.js +73 -21
  6. package/dist/account/builder.test.js.map +1 -1
  7. package/dist/account/layout.d.ts +31 -0
  8. package/dist/account/layout.d.ts.map +1 -0
  9. package/dist/account/layout.js +31 -0
  10. package/dist/account/layout.js.map +1 -0
  11. package/dist/account/masm/account-components/auth.d.ts +1 -4
  12. package/dist/account/masm/account-components/auth.d.ts.map +1 -1
  13. package/dist/account/masm/account-components/auth.js +36 -53
  14. package/dist/account/masm/account-components/auth.js.map +1 -1
  15. package/dist/account/masm/index.d.ts +0 -1
  16. package/dist/account/masm/index.d.ts.map +1 -1
  17. package/dist/account/masm/index.js +0 -1
  18. package/dist/account/masm/index.js.map +1 -1
  19. package/dist/account/storage.d.ts +4 -0
  20. package/dist/account/storage.d.ts.map +1 -1
  21. package/dist/account/storage.js +9 -20
  22. package/dist/account/storage.js.map +1 -1
  23. package/dist/client.d.ts +4 -0
  24. package/dist/client.d.ts.map +1 -1
  25. package/dist/client.js +10 -5
  26. package/dist/client.js.map +1 -1
  27. package/dist/client.test.js +74 -16
  28. package/dist/client.test.js.map +1 -1
  29. package/dist/index.d.ts +5 -3
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +3 -3
  32. package/dist/index.js.map +1 -1
  33. package/dist/inspector.d.ts +59 -1
  34. package/dist/inspector.d.ts.map +1 -1
  35. package/dist/inspector.js +157 -29
  36. package/dist/inspector.js.map +1 -1
  37. package/dist/inspector.test.js +246 -37
  38. package/dist/inspector.test.js.map +1 -1
  39. package/dist/multisig.d.ts +109 -33
  40. package/dist/multisig.d.ts.map +1 -1
  41. package/dist/multisig.js +307 -104
  42. package/dist/multisig.js.map +1 -1
  43. package/dist/multisig.test.js +582 -58
  44. package/dist/multisig.test.js.map +1 -1
  45. package/dist/procedures.d.ts +6 -7
  46. package/dist/procedures.d.ts.map +1 -1
  47. package/dist/procedures.js +6 -7
  48. package/dist/procedures.js.map +1 -1
  49. package/dist/proposal/metadata.d.ts.map +1 -1
  50. package/dist/proposal/metadata.js +13 -2
  51. package/dist/proposal/metadata.js.map +1 -1
  52. package/dist/proposal/metadata.test.js +57 -0
  53. package/dist/proposal/metadata.test.js.map +1 -1
  54. package/dist/prover/errors.d.ts +5 -0
  55. package/dist/prover/errors.d.ts.map +1 -1
  56. package/dist/prover/errors.js +7 -155
  57. package/dist/prover/errors.js.map +1 -1
  58. package/dist/prover/errors.test.js +5 -0
  59. package/dist/prover/errors.test.js.map +1 -1
  60. package/dist/prover/retry.d.ts +1 -6
  61. package/dist/prover/retry.d.ts.map +1 -1
  62. package/dist/prover/retry.js +5 -28
  63. package/dist/prover/retry.js.map +1 -1
  64. package/dist/prover/retry.test.js +1 -1
  65. package/dist/prover/retry.test.js.map +1 -1
  66. package/dist/prover/workflow.d.ts +4 -3
  67. package/dist/prover/workflow.d.ts.map +1 -1
  68. package/dist/prover/workflow.js +5 -2
  69. package/dist/prover/workflow.js.map +1 -1
  70. package/dist/prover/workflow.test.js +28 -3
  71. package/dist/prover/workflow.test.js.map +1 -1
  72. package/dist/retry/classify.d.ts +16 -0
  73. package/dist/retry/classify.d.ts.map +1 -0
  74. package/dist/retry/classify.js +187 -0
  75. package/dist/retry/classify.js.map +1 -0
  76. package/dist/retry/runtime.d.ts +13 -0
  77. package/dist/retry/runtime.d.ts.map +1 -0
  78. package/dist/retry/runtime.js +33 -0
  79. package/dist/retry/runtime.js.map +1 -0
  80. package/dist/rpc/config.d.ts +11 -0
  81. package/dist/rpc/config.d.ts.map +1 -0
  82. package/dist/rpc/config.js +17 -0
  83. package/dist/rpc/config.js.map +1 -0
  84. package/dist/rpc/config.test.d.ts +2 -0
  85. package/dist/rpc/config.test.d.ts.map +1 -0
  86. package/dist/rpc/config.test.js +24 -0
  87. package/dist/rpc/config.test.js.map +1 -0
  88. package/dist/rpc/errors.d.ts +2 -0
  89. package/dist/rpc/errors.d.ts.map +1 -0
  90. package/dist/rpc/errors.js +11 -0
  91. package/dist/rpc/errors.js.map +1 -0
  92. package/dist/rpc/errors.test.d.ts +2 -0
  93. package/dist/rpc/errors.test.d.ts.map +1 -0
  94. package/dist/rpc/errors.test.js +34 -0
  95. package/dist/rpc/errors.test.js.map +1 -0
  96. package/dist/rpc/retry.d.ts +4 -0
  97. package/dist/rpc/retry.d.ts.map +1 -0
  98. package/dist/rpc/retry.js +6 -0
  99. package/dist/rpc/retry.js.map +1 -0
  100. package/dist/rpc/retry.test.d.ts +2 -0
  101. package/dist/rpc/retry.test.d.ts.map +1 -0
  102. package/dist/rpc/retry.test.js +98 -0
  103. package/dist/rpc/retry.test.js.map +1 -0
  104. package/dist/transaction/index.d.ts +1 -1
  105. package/dist/transaction/index.d.ts.map +1 -1
  106. package/dist/transaction/index.js +1 -1
  107. package/dist/transaction/index.js.map +1 -1
  108. package/dist/transaction/p2id.d.ts +17 -6
  109. package/dist/transaction/p2id.d.ts.map +1 -1
  110. package/dist/transaction/p2id.js +22 -31
  111. package/dist/transaction/p2id.js.map +1 -1
  112. package/dist/transaction/p2id.test.js +62 -24
  113. package/dist/transaction/p2id.test.js.map +1 -1
  114. package/dist/transaction/summary.d.ts +45 -2
  115. package/dist/transaction/summary.d.ts.map +1 -1
  116. package/dist/transaction/summary.js +42 -2
  117. package/dist/transaction/summary.js.map +1 -1
  118. package/dist/transaction/summary.test.d.ts +2 -0
  119. package/dist/transaction/summary.test.d.ts.map +1 -0
  120. package/dist/transaction/summary.test.js +26 -0
  121. package/dist/transaction/summary.test.js.map +1 -0
  122. package/dist/transaction/updateGuardian.d.ts.map +1 -1
  123. package/dist/transaction/updateGuardian.js +16 -18
  124. package/dist/transaction/updateGuardian.js.map +1 -1
  125. package/dist/transaction/updateProcedureThreshold.d.ts.map +1 -1
  126. package/dist/transaction/updateProcedureThreshold.js +15 -17
  127. package/dist/transaction/updateProcedureThreshold.js.map +1 -1
  128. package/dist/transaction/updateSigners.d.ts +6 -1
  129. package/dist/transaction/updateSigners.d.ts.map +1 -1
  130. package/dist/transaction/updateSigners.js +20 -17
  131. package/dist/transaction/updateSigners.js.map +1 -1
  132. package/dist/transaction.d.ts +2 -2
  133. package/dist/transaction.d.ts.map +1 -1
  134. package/dist/transaction.js +1 -1
  135. package/dist/transaction.js.map +1 -1
  136. package/dist/types/proposal.d.ts +28 -4
  137. package/dist/types/proposal.d.ts.map +1 -1
  138. package/dist/types/proposal.js +18 -0
  139. package/dist/types/proposal.js.map +1 -1
  140. package/dist/types.d.ts +0 -1
  141. package/dist/types.d.ts.map +1 -1
  142. package/dist/utils/signature.d.ts +11 -7
  143. package/dist/utils/signature.d.ts.map +1 -1
  144. package/dist/utils/signature.js +24 -58
  145. package/dist/utils/signature.js.map +1 -1
  146. package/dist/utils/word.d.ts +7 -0
  147. package/dist/utils/word.d.ts.map +1 -1
  148. package/dist/utils/word.js +15 -0
  149. package/dist/utils/word.js.map +1 -1
  150. package/masm/account_components/auth/guarded_multisig.masm +42 -0
  151. package/package.json +7 -4
  152. package/src/account/builder.test.ts +111 -45
  153. package/src/account/builder.ts +45 -33
  154. package/src/account/layout.ts +33 -0
  155. package/src/account/masm/account-components/auth.ts +36 -56
  156. package/src/account/masm/index.ts +0 -1
  157. package/src/account/storage.ts +9 -22
  158. package/src/client.test.ts +87 -16
  159. package/src/client.ts +16 -3
  160. package/src/index.ts +27 -1
  161. package/src/inspector.test.ts +330 -38
  162. package/src/inspector.ts +196 -33
  163. package/src/multisig.test.ts +680 -63
  164. package/src/multisig.ts +400 -115
  165. package/src/procedures.ts +6 -7
  166. package/src/proposal/metadata.test.ts +76 -0
  167. package/src/proposal/metadata.ts +13 -2
  168. package/src/prover/errors.test.ts +8 -0
  169. package/src/prover/errors.ts +7 -175
  170. package/src/prover/retry.test.ts +1 -1
  171. package/src/prover/retry.ts +10 -35
  172. package/src/prover/workflow.test.ts +40 -4
  173. package/src/prover/workflow.ts +16 -4
  174. package/src/retry/classify.ts +220 -0
  175. package/src/retry/runtime.ts +45 -0
  176. package/src/rpc/config.test.ts +45 -0
  177. package/src/rpc/config.ts +30 -0
  178. package/src/rpc/errors.test.ts +69 -0
  179. package/src/rpc/errors.ts +12 -0
  180. package/src/rpc/retry.test.ts +144 -0
  181. package/src/rpc/retry.ts +12 -0
  182. package/src/transaction/index.ts +7 -1
  183. package/src/transaction/p2id.test.ts +112 -31
  184. package/src/transaction/p2id.ts +39 -38
  185. package/src/transaction/summary.test.ts +32 -0
  186. package/src/transaction/summary.ts +83 -4
  187. package/src/transaction/updateGuardian.ts +15 -25
  188. package/src/transaction/updateProcedureThreshold.ts +13 -29
  189. package/src/transaction/updateSigners.ts +38 -30
  190. package/src/transaction.ts +8 -1
  191. package/src/types/proposal.ts +43 -4
  192. package/src/types.ts +0 -1
  193. package/src/utils/signature.ts +32 -65
  194. package/src/utils/word.ts +17 -0
  195. package/dist/account/masm/auth.d.ts +0 -5
  196. package/dist/account/masm/auth.d.ts.map +0 -1
  197. package/dist/account/masm/auth.js +0 -1509
  198. package/dist/account/masm/auth.js.map +0 -1
  199. package/masm/account_components/auth/multisig.masm +0 -12
  200. package/masm/account_components/auth/multisig_ecdsa.masm +0 -12
  201. package/masm/account_components/auth/multisig_guardian.masm +0 -16
  202. package/masm/account_components/auth/multisig_guardian_ecdsa.masm +0 -16
  203. package/masm/auth/guardian.masm +0 -199
  204. package/masm/auth/guardian_ecdsa.masm +0 -195
  205. package/masm/auth/multisig.masm +0 -554
  206. package/masm/auth/multisig_ecdsa.masm +0 -554
  207. package/src/account/masm/auth.ts +0 -1512
@@ -1,1509 +0,0 @@
1
- // This file is generated by scripts/generate-masm.mjs from the MASM contract sources.
2
- // Do not edit it by hand.
3
- export const MULTISIG_MASM = `# Multi-Signature RPO Falcon 512 Authentication Core Library
4
- #
5
- # This library provides the reusable multisig procedures used by account wrappers.
6
-
7
- use miden::protocol::active_account
8
- use miden::protocol::auth::AUTH_UNAUTHORIZED_EVENT
9
- use miden::protocol::native_account
10
- use miden::standards::auth
11
-
12
- # CONSTANTS
13
- # =================================================================================================
14
-
15
- # Auth Request Constants
16
-
17
- # Storage Layout Constants
18
- #
19
- # +-------------------------------+----------+------------+--------------+-------------------+
20
- # | THRESHOLD & APPROVERS CONFIG | PUB KEYS | SCHEME IDS | EXECUTED TXS | PROC THRESHOLDS |
21
- # | (slot) | (map) | (map) | (map) | (map) |
22
- # +-------------------------------+----------+------------+--------------+-------------------+
23
- # | 0 | 1 | 2 | 3 | 4 |
24
- # +-------------------------------+----------+------------+--------------+-------------------+
25
-
26
- # The slot in this component's storage layout where the default signature threshold and
27
- # number of approvers are stored as:
28
- # [default_threshold, num_approvers, 0, 0].
29
- # The threshold is guaranteed to be less than or equal to num_approvers.
30
- const THRESHOLD_CONFIG_SLOT=word("openzeppelin::multisig::threshold_config")
31
-
32
- # The slot in this component's storage layout where the public keys map is stored.
33
- # Map entries: [key_index, 0, 0, 0] => APPROVER_PUBLIC_KEY
34
- const PUBLIC_KEYS_MAP_SLOT=word("openzeppelin::multisig::signer_public_keys")
35
-
36
- # The slot in this component's storage layout where signer scheme IDs are stored.
37
- # Map entries: [key_index, 0, 0, 0] => [scheme_id, 0, 0, 0]
38
- const APPROVER_SCHEME_ID_SLOT=word("openzeppelin::multisig::signer_scheme_ids")
39
-
40
- # The slot in this component's storage layout where executed transactions are stored.
41
- # Map entries: transaction_message => [is_executed, 0, 0, 0]
42
- const EXECUTED_TXS_SLOT=word("openzeppelin::multisig::executed_transactions")
43
-
44
- # The slot in this component's storage layout where procedure thresholds are stored.
45
- # Map entries: PROC_ROOT => [proc_threshold, 0, 0, 0]
46
- const PROC_THRESHOLD_ROOTS_SLOT=word("openzeppelin::multisig::procedure_thresholds")
47
-
48
- # Executed Transaction Flag Constant
49
- const IS_EXECUTED_FLAG=[1, 0, 0, 0]
50
- const FALCON_512_POSEIDON2_SCHEME_WORD=[2, 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
- const ERR_PROC_THRESHOLD_NOT_U32="procedure threshold must be a u32 value"
60
-
61
- const ERR_NUM_APPROVERS_OR_PROC_THRESHOLD_NOT_U32="number of approvers and procedure threshold must be u32"
62
-
63
- const ERR_PROC_THRESHOLD_EXCEEDS_NUM_APPROVERS="procedure threshold exceeds number of approvers"
64
-
65
- # MULTISIG PROCEDURES
66
- # =================================================================================================
67
-
68
- #! Check if transaction has already been executed and add it to executed transactions for replay protection.
69
- #!
70
- #! Inputs: [MSG]
71
- #! Outputs: []
72
- #!
73
- #! Panics if:
74
- #! - the same transaction has already been executed
75
- pub proc assert_new_tx(msg: word)
76
- push.IS_EXECUTED_FLAG
77
- # => [[0, 0, 0, is_executed], MSG]
78
-
79
- swapw
80
- # => [MSG, IS_EXECUTED_FLAG]
81
-
82
- push.EXECUTED_TXS_SLOT[0..2]
83
- # => [txs_slot_prefix, txs_slot_suffix, MSG, IS_EXECUTED_FLAG]
84
-
85
- # Set the key value pair in the map to mark transaction as executed
86
- exec.native_account::set_map_item
87
- # => [[0, 0, 0, is_executed]]
88
-
89
- drop drop drop
90
- # => [is_executed]
91
-
92
- assertz.err=ERR_TX_ALREADY_EXECUTED
93
- # => []
94
- end
95
-
96
- #! Remove old approver public keys from the approver public key mapping.
97
- #!
98
- #! This procedure cleans up the storage by removing public keys of approvers that are no longer
99
- #! part of the multisig configuration. This procedure assumes that init_num_of_approvers and
100
- #! new_num_of_approvers are u32 values.
101
- #!
102
- #! Inputs: [init_num_of_approvers, new_num_of_approvers]
103
- #! Outputs: []
104
- #!
105
- #! Where:
106
- #! - init_num_of_approvers is the original number of approvers before the update
107
- #! - new_num_of_approvers is the new number of approvers after the update
108
- proc cleanup_pubkey_mapping(init_num_of_approvers: u32, new_num_of_approvers: u32)
109
- dup.1 dup.1
110
- u32assert2 u32lt
111
- # => [should_loop, i = init_num_of_approvers, new_num_of_approvers]
112
-
113
- while.true
114
- # => [i, new_num_of_approvers]
115
-
116
- sub.1
117
- # => [i-1, new_num_of_approvers]
118
-
119
- dup exec.create_approver_map_key
120
- # => [APPROVER_MAP_KEY, i-1, new_num_of_approvers]
121
-
122
- padw swapw
123
- # => [APPROVER_MAP_KEY, EMPTY_WORD, i-1, new_num_of_approvers]
124
-
125
- push.PUBLIC_KEYS_MAP_SLOT[0..2]
126
- # => [pub_key_slot_prefix, pub_key_slot_suffix, APPROVER_MAP_KEY, EMPTY_WORD, i-1, new_num_of_approvers]
127
-
128
- exec.native_account::set_map_item
129
- # => [OLD_MAP_VALUE, i-1, new_num_of_approvers]
130
-
131
- dropw
132
- # => [i-1, new_num_of_approvers]
133
-
134
- dup exec.create_approver_map_key
135
- # => [APPROVER_MAP_KEY, i-1, new_num_of_approvers]
136
-
137
- padw swapw
138
- # => [APPROVER_MAP_KEY, EMPTY_WORD, i-1, new_num_of_approvers]
139
-
140
- push.APPROVER_SCHEME_ID_SLOT[0..2]
141
- # => [scheme_slot_prefix, scheme_slot_suffix, APPROVER_MAP_KEY, EMPTY_WORD, i-1, new_num_of_approvers]
142
-
143
- exec.native_account::set_map_item
144
- # => [OLD_MAP_VALUE, i-1, new_num_of_approvers]
145
-
146
- dropw
147
- # => [i-1, new_num_of_approvers]
148
-
149
- dup.1 dup.1
150
- u32lt
151
- # => [should_loop, i-1, new_num_of_approvers]
152
- end
153
-
154
- drop drop
155
- # => []
156
- end
157
-
158
- proc create_approver_map_key
159
- push.0.0.0 movup.3
160
- # => [APPROVER_MAP_KEY]
161
- end
162
-
163
- proc get_threshold_and_num_approvers
164
- push.THRESHOLD_CONFIG_SLOT[0..2]
165
- exec.active_account::get_initial_item
166
- # => [threshold, num_approvers]
167
-
168
- movup.2 drop movup.2 drop
169
- # => [threshold, num_approvers]
170
- end
171
-
172
- proc assert_proc_thresholds_lte_num_approvers(num_approvers: u32)
173
- exec.active_account::get_num_procedures
174
- # => [num_procedures, num_approvers]
175
-
176
- dup neq.0
177
- # => [should_continue, num_procedures, num_approvers]
178
- while.true
179
- sub.1 dup
180
- # => [proc_index, proc_index, num_approvers]
181
-
182
- exec.active_account::get_procedure_root
183
- # => [PROC_ROOT, proc_index, num_approvers]
184
-
185
- push.PROC_THRESHOLD_ROOTS_SLOT[0..2]
186
- # => [proc_roots_slot_prefix, proc_roots_slot_suffix, PROC_ROOT, proc_index, num_approvers]
187
-
188
- exec.active_account::get_map_item
189
- # => [[proc_threshold, 0, 0, 0], proc_index, num_approvers]
190
-
191
- movdn.3 drop drop drop
192
- # => [proc_threshold, proc_index, num_approvers]
193
-
194
- dup.2
195
- # => [num_approvers, proc_threshold, proc_index, num_approvers]
196
-
197
- u32assert2.err=ERR_PROC_THRESHOLD_NOT_U32
198
- u32gt assertz.err=ERR_PROC_THRESHOLD_EXCEEDS_NUM_APPROVERS
199
- # => [proc_index, num_approvers]
200
-
201
- dup neq.0
202
- # => [should_continue, proc_index, num_approvers]
203
- end
204
-
205
- drop drop
206
- # => []
207
- end
208
-
209
- # Internal storage helper used by the public \`update_procedure_threshold\`
210
- # entrypoint after it receives direct stack arguments.
211
- proc set_procedure_threshold(proc_threshold: u32, proc_root: word)
212
- exec.get_threshold_and_num_approvers
213
- # => [threshold, num_approvers, proc_threshold, PROC_ROOT]
214
-
215
- drop
216
- # => [num_approvers, proc_threshold, PROC_ROOT]
217
-
218
- dup.1 swap
219
- # => [num_approvers, proc_threshold, proc_threshold, PROC_ROOT]
220
-
221
- u32assert2.err=ERR_NUM_APPROVERS_OR_PROC_THRESHOLD_NOT_U32
222
- u32gt assertz.err=ERR_PROC_THRESHOLD_EXCEEDS_NUM_APPROVERS
223
- # => [proc_threshold, PROC_ROOT]
224
-
225
- push.0.0.0
226
- movup.3
227
- swapw
228
- # => [PROC_ROOT, PROC_THRESHOLD_WORD]
229
-
230
- push.PROC_THRESHOLD_ROOTS_SLOT[0..2]
231
- # => [proc_roots_slot_prefix, proc_roots_slot_suffix, PROC_ROOT, PROC_THRESHOLD_WORD]
232
-
233
- exec.native_account::set_map_item
234
- # => [OLD_VALUE]
235
-
236
- dropw
237
- # => []
238
- end
239
-
240
- #! Update threshold config and add / remove approvers
241
- #!
242
- #! Inputs:
243
- #! Operand stack: [MULTISIG_CONFIG_HASH, pad(12)]
244
- #! Advice map: {
245
- #! MULTISIG_CONFIG_HASH => [CONFIG, PUB_KEY_N, PUB_KEY_N-1, ..., PUB_KEY_0]
246
- #! }
247
- #! Outputs:
248
- #! Operand stack: [TX_SUMMARY_COMMITMENT]
249
- #!
250
- #! Where:
251
- #! - MULTISIG_CONFIG_HASH is the hash of the threshold and new public key vector
252
- #! - MULTISIG_CONFIG is [threshold, num_approvers, 0, 0]
253
- #! - PUB_KEY_i is the public key of the i-th signer
254
- #!
255
- #! Locals:
256
- #! 0: new_num_of_approvers
257
- #! 1: init_num_of_approvers
258
- @locals(2)
259
- pub proc update_signers_and_threshold(multisig_config_hash: word)
260
- adv.push_mapval
261
- # => [MULTISIG_CONFIG_HASH, pad(12)]
262
-
263
- adv_loadw
264
- # => [MULTISIG_CONFIG, pad(12)]
265
-
266
- # store new_num_of_approvers for later
267
- dup.1 loc_store.0
268
- # => [MULTISIG_CONFIG, pad(12)]
269
-
270
- dup dup.2
271
- # => [num_approvers, threshold, MULTISIG_CONFIG, pad(12)]
272
-
273
- # make sure that the threshold is smaller than the number of approvers
274
- u32assert2.err=ERR_MALFORMED_MULTISIG_CONFIG
275
- u32gt assertz.err=ERR_MALFORMED_MULTISIG_CONFIG
276
- # => [MULTISIG_CONFIG, pad(12)]
277
-
278
- dup dup.2
279
- # => [num_approvers, threshold, MULTISIG_CONFIG, pad(12)]
280
-
281
- # make sure that threshold or num_approvers are not zero
282
- eq.0 assertz.err=ERR_ZERO_IN_MULTISIG_CONFIG
283
- eq.0 assertz.err=ERR_ZERO_IN_MULTISIG_CONFIG
284
- # => [MULTISIG_CONFIG, pad(12)]
285
-
286
- loc_load.0
287
- # => [num_approvers, MULTISIG_CONFIG, pad(12)]
288
-
289
- exec.assert_proc_thresholds_lte_num_approvers
290
- # => [MULTISIG_CONFIG, pad(12)]
291
-
292
- push.THRESHOLD_CONFIG_SLOT[0..2]
293
- # => [config_slot_prefix, config_slot_suffix, MULTISIG_CONFIG, pad(12)]
294
-
295
- exec.native_account::set_item
296
- # => [OLD_THRESHOLD_CONFIG, pad(12)]
297
-
298
- # store init_num_of_approvers for later
299
- drop loc_store.1 drop drop
300
- # => [pad(12)]
301
-
302
- loc_load.0
303
- # => [num_approvers]
304
-
305
- dup neq.0
306
- while.true
307
- sub.1
308
- # => [i-1, pad(12)]
309
-
310
- dup exec.create_approver_map_key
311
- # => [APPROVER_MAP_KEY, i-1, pad(12)]
312
-
313
- padw adv_loadw
314
- # => [PUB_KEY, APPROVER_MAP_KEY, i-1, pad(12)]
315
-
316
- swapw
317
- # => [APPROVER_MAP_KEY, PUB_KEY, i-1, pad(12)]
318
-
319
- push.PUBLIC_KEYS_MAP_SLOT[0..2]
320
- # => [pub_key_slot_prefix, pub_key_slot_suffix, APPROVER_MAP_KEY, PUB_KEY, i-1, pad(12)]
321
-
322
- exec.native_account::set_map_item
323
- # => [OLD_VALUE, i-1, pad(12)]
324
-
325
- dropw
326
- # => [i-1, pad(12)]
327
-
328
- dup exec.create_approver_map_key
329
- # => [APPROVER_MAP_KEY, i-1, pad(12)]
330
-
331
- push.FALCON_512_POSEIDON2_SCHEME_WORD
332
- # => [SCHEME_ID_WORD, APPROVER_MAP_KEY, i-1, pad(12)]
333
-
334
- swapw
335
- # => [APPROVER_MAP_KEY, [2, 0, 0, 0], i-1, pad(12)]
336
-
337
- push.APPROVER_SCHEME_ID_SLOT[0..2]
338
- # => [scheme_slot_prefix, scheme_slot_suffix, APPROVER_MAP_KEY, [2, 0, 0, 0], i-1, pad(12)]
339
-
340
- exec.native_account::set_map_item
341
- # => [OLD_VALUE, i-1, pad(12)]
342
-
343
- dropw
344
- # => [i-1, pad(12)]
345
-
346
- dup neq.0
347
- # => [is_non_zero, i-1, pad(12)]
348
- end
349
- # => [pad(13)]
350
-
351
- drop
352
- # => [pad(12)]
353
-
354
- loc_load.0 loc_load.1
355
- # => [init_num_of_approvers, new_num_of_approvers, pad(12)]
356
-
357
- dup.1 dup.1
358
- u32assert2 u32lt
359
- # => [should_cleanup, init_num_of_approvers, new_num_of_approvers, pad(12)]
360
-
361
- if.true
362
- exec.cleanup_pubkey_mapping
363
- # => [pad(12)]
364
- else
365
- drop drop
366
- # => [pad(12)]
367
- end
368
- end
369
-
370
- #! Update or clear the threshold override for a specific procedure.
371
- #!
372
- #! Inputs:
373
- #! Operand stack: [proc_threshold, PROC_ROOT]
374
- #! Outputs:
375
- #! Operand stack: []
376
- #! Invocation: call
377
- pub proc update_procedure_threshold(proc_threshold: u32, proc_root: word)
378
- exec.set_procedure_threshold
379
- end
380
-
381
- # Computes the effective transaction threshold based on called procedures and per-procedure
382
- # overrides stored in PROC_THRESHOLD_ROOTS_SLOT. Falls back to default_threshold if no
383
- # overrides apply.
384
- #
385
- #! Inputs: [default_threshold]
386
- #! Outputs: [transaction_threshold]
387
- @locals(1)
388
- proc compute_transaction_threshold(default_threshold: u32) -> u32
389
- # 1. initialize transaction_threshold = 0
390
- # 2. iterate through all account procedures
391
- # a. check if the procedure was called during the transaction
392
- # b. if called, get the override threshold of that procedure from the config map
393
- # c. if proc_threshold > transaction_threshold, set transaction_threshold = proc_threshold
394
- # 3. if transaction_threshold == 0 at the end, revert to using default_threshold
395
-
396
- # store default_threshold for later
397
- loc_store.0
398
- # => []
399
-
400
- # 1. initialize transaction_threshold = 0
401
- push.0
402
- # => [transaction_threshold]
403
-
404
- # get the number of account procedures
405
- exec.active_account::get_num_procedures
406
- # => [num_procedures, transaction_threshold]
407
-
408
- # 2. iterate through all account procedures
409
- dup neq.0
410
- # => [should_continue, num_procedures, transaction_threshold]
411
- while.true
412
- sub.1 dup
413
- # => [num_procedures-1, num_procedures-1, transaction_threshold]
414
-
415
- # get procedure root of the procedure with index i
416
- exec.active_account::get_procedure_root dupw
417
- # => [PROC_ROOT, PROC_ROOT, num_procedures-1, transaction_threshold]
418
-
419
- # 2a. check if this procedure has been called in the transaction
420
- exec.native_account::was_procedure_called
421
- # => [was_called, PROC_ROOT, num_procedures-1, transaction_threshold]
422
-
423
- # if it has been called, get the override threshold of that procedure
424
- if.true
425
- # => [PROC_ROOT, num_procedures-1, transaction_threshold]
426
-
427
- push.PROC_THRESHOLD_ROOTS_SLOT[0..2]
428
- # => [PROC_THRESHOLD_ROOTS_SLOT_prefix, PROC_THRESHOLD_ROOTS_SLOT_suffix, PROC_ROOT, num_procedures-1, transaction_threshold]
429
-
430
- # 2b. get the override proc_threshold of that procedure
431
- # if the procedure has no override threshold, the returned map item will be [0, 0, 0, 0]
432
- exec.active_account::get_initial_map_item
433
- # => [[proc_threshold, 0, 0, 0], num_procedures-1, transaction_threshold]
434
-
435
- movdn.3 drop drop drop dup dup.3
436
- # => [transaction_threshold, proc_threshold, proc_threshold, num_procedures-1, transaction_threshold]
437
-
438
- u32assert2.err="transaction threshold or procedure threshold are not u32"
439
- u32gt
440
- # => [is_gt, proc_threshold, num_procedures-1, transaction_threshold]
441
- # 2c. if proc_threshold > transaction_threshold, update transaction_threshold
442
- movup.2 movdn.3
443
- # => [is_gt, proc_threshold, transaction_threshold, num_procedures-1]
444
- cdrop
445
- # => [updated_transaction_threshold, num_procedures-1]
446
- swap
447
- # => [num_procedures-1, updated_transaction_threshold]
448
- # if it has not been called during this transaction, nothing to do, move to the next procedure
449
- else
450
- dropw
451
- # => [num_procedures-1, transaction_threshold]
452
- end
453
-
454
- dup neq.0
455
- # => [should_continue, num_procedures-1, transaction_threshold]
456
- end
457
-
458
- drop
459
- # => [transaction_threshold]
460
-
461
- loc_load.0
462
- # => [default_threshold, transaction_threshold]
463
-
464
- # 3. if transaction_threshold == 0 at the end, revert to using default_threshold
465
- dup.1 eq.0
466
- # => [is_zero, default_threshold, transaction_threshold]
467
-
468
- cdrop
469
- # => [effective_transaction_threshold]
470
- end
471
-
472
- #! Authenticate a transaction using the Falcon signature scheme with multi-signature support.
473
- #!
474
- #! This procedure implements multi-signature authentication by:
475
- #! 1. Computing the transaction summary message that needs to be signed
476
- #! 2. Verifying signatures from multiple required signers against their public keys
477
- #! 3. Ensuring the minimum threshold of valid signatures is met
478
- #! 4. Returning the transaction summary commitment for higher-level wrappers.
479
- #!
480
- #! Inputs:
481
- #! Operand stack: [SALT]
482
- #! Advice map: {
483
- #! h(SIG_0, MSG): SIG_0,
484
- #! h(SIG_1, MSG): SIG_1,
485
- #! h(SIG_n, MSG): SIG_n
486
- #! }
487
- #! Outputs:
488
- #! Operand stack: []
489
- #!
490
- #! Where:
491
- #! - SALT is a cryptographically random nonce that enables multiple concurrent
492
- #! multisig transactions while maintaining replay protection. Each transaction
493
- #! must use a unique SALT value to ensure transaction uniqueness.
494
- #! - SIG_i is the signature from the i-th signer.
495
- #! - MSG is the transaction message being signed.
496
- #! - h(SIG_i, MSG) is the hash of the signature and message used as the advice map key.
497
- #!
498
- #! Panics if:
499
- #! - insufficient number of valid signatures (below threshold).
500
- #! - insufficient number of valid signatures (below threshold).
501
- #!
502
- #! Invocation: exec
503
- @locals(1)
504
- pub proc auth_tx(salt: word)
505
- exec.native_account::incr_nonce drop
506
- # => [SALT]
507
-
508
- # ------ Computing transaction summary ------
509
-
510
- exec.auth::create_tx_summary
511
- # => [ACCOUNT_DELTA_COMMITMENT, INPUT_NOTES_COMMITMENT, OUTPUT_NOTES_COMMITMENT, SALT]
512
-
513
- # to build a tx_summary in the host, we need these four words in the advice provider
514
- adv.insert_hqword
515
- # => [ACCOUNT_DELTA_COMMITMENT, INPUT_NOTES_COMMITMENT, OUTPUT_NOTES_COMMITMENT, SALT]
516
-
517
- # the commitment to the tx summary is the message that is signed
518
- exec.auth::hash_tx_summary
519
- # => [TX_SUMMARY_COMMITMENT]
520
-
521
- # ------ Verifying approver signatures ------
522
-
523
- exec.get_threshold_and_num_approvers
524
- # => [default_threshold, num_of_approvers, TX_SUMMARY_COMMITMENT]
525
-
526
- movdn.5
527
- # => [num_of_approvers, TX_SUMMARY_COMMITMENT, default_threshold]
528
-
529
- push.PUBLIC_KEYS_MAP_SLOT[0..2]
530
- # => [pub_key_slot_prefix, pub_key_slot_suffix, num_of_approvers, TX_SUMMARY_COMMITMENT, default_threshold]
531
-
532
- push.APPROVER_SCHEME_ID_SLOT[0..2]
533
- # => [scheme_id_slot_prefix, scheme_id_slot_suffix, pub_key_slot_prefix, pub_key_slot_suffix, num_of_approvers, TX_SUMMARY_COMMITMENT, default_threshold]
534
-
535
- exec.::miden::standards::auth::signature::verify_signatures
536
- # => [num_verified_signatures, TX_SUMMARY_COMMITMENT, default_threshold]
537
-
538
- # ------ Checking threshold is >= num_verified_signatures ------
539
-
540
- movup.5
541
- # => [default_threshold, num_verified_signatures, TX_SUMMARY_COMMITMENT]
542
-
543
- exec.compute_transaction_threshold
544
- # => [transaction_threshold, num_verified_signatures, TX_SUMMARY_COMMITMENT]
545
-
546
- u32assert2 u32lt
547
- # => [is_unauthorized, TX_SUMMARY_COMMITMENT]
548
-
549
- # If signatures are non-existent the tx will fail here.
550
- if.true
551
- emit.AUTH_UNAUTHORIZED_EVENT
552
- push.0 assert.err="insufficient number of signatures"
553
- end
554
-
555
- # => [TX_SUMMARY_COMMITMENT]
556
- end
557
- `;
558
- export const MULTISIG_ECDSA_MASM = `# Multi-Signature ECDSA secp256k1 Authentication Core Library
559
- #
560
- # This library provides the reusable multisig procedures used by account wrappers.
561
-
562
- use miden::protocol::active_account
563
- use miden::protocol::auth::AUTH_UNAUTHORIZED_EVENT
564
- use miden::protocol::native_account
565
- use miden::standards::auth
566
-
567
- # CONSTANTS
568
- # =================================================================================================
569
-
570
- # Auth Request Constants
571
-
572
- # Storage Layout Constants
573
- #
574
- # +-------------------------------+----------+------------+--------------+-------------------+
575
- # | THRESHOLD & APPROVERS CONFIG | PUB KEYS | SCHEME IDS | EXECUTED TXS | PROC THRESHOLDS |
576
- # | (slot) | (map) | (map) | (map) | (map) |
577
- # +-------------------------------+----------+------------+--------------+-------------------+
578
- # | 0 | 1 | 2 | 3 | 4 |
579
- # +-------------------------------+----------+------------+--------------+-------------------+
580
-
581
- # The slot in this component's storage layout where the default signature threshold and
582
- # number of approvers are stored as:
583
- # [default_threshold, num_approvers, 0, 0].
584
- # The threshold is guaranteed to be less than or equal to num_approvers.
585
- const THRESHOLD_CONFIG_SLOT=word("openzeppelin::multisig::threshold_config")
586
-
587
- # The slot in this component's storage layout where the public keys map is stored.
588
- # Map entries: [key_index, 0, 0, 0] => APPROVER_PUBLIC_KEY
589
- const PUBLIC_KEYS_MAP_SLOT=word("openzeppelin::multisig::signer_public_keys")
590
-
591
- # The slot in this component's storage layout where signer scheme IDs are stored.
592
- # Map entries: [key_index, 0, 0, 0] => [scheme_id, 0, 0, 0]
593
- const APPROVER_SCHEME_ID_SLOT=word("openzeppelin::multisig::signer_scheme_ids")
594
-
595
- # The slot in this component's storage layout where executed transactions are stored.
596
- # Map entries: transaction_message => [is_executed, 0, 0, 0]
597
- const EXECUTED_TXS_SLOT=word("openzeppelin::multisig::executed_transactions")
598
-
599
- # The slot in this component's storage layout where procedure thresholds are stored.
600
- # Map entries: PROC_ROOT => [proc_threshold, 0, 0, 0]
601
- const PROC_THRESHOLD_ROOTS_SLOT=word("openzeppelin::multisig::procedure_thresholds")
602
-
603
- # Executed Transaction Flag Constant
604
- const IS_EXECUTED_FLAG=[1, 0, 0, 0]
605
- const ECDSA_K256_KECCAK_SCHEME_WORD=[1, 0, 0, 0]
606
-
607
- # ERRORS
608
- const ERR_TX_ALREADY_EXECUTED="failed to approve multisig transaction as it was already executed"
609
-
610
- const ERR_MALFORMED_MULTISIG_CONFIG="number of approvers must be equal to or greater than threshold"
611
-
612
- const ERR_ZERO_IN_MULTISIG_CONFIG="number of approvers or threshold must not be zero"
613
-
614
- const ERR_PROC_THRESHOLD_NOT_U32="procedure threshold must be a u32 value"
615
-
616
- const ERR_NUM_APPROVERS_OR_PROC_THRESHOLD_NOT_U32="number of approvers and procedure threshold must be u32"
617
-
618
- const ERR_PROC_THRESHOLD_EXCEEDS_NUM_APPROVERS="procedure threshold exceeds number of approvers"
619
-
620
- # MULTISIG PROCEDURES
621
- # =================================================================================================
622
-
623
- #! Check if transaction has already been executed and add it to executed transactions for replay protection.
624
- #!
625
- #! Inputs: [MSG]
626
- #! Outputs: []
627
- #!
628
- #! Panics if:
629
- #! - the same transaction has already been executed
630
- pub proc assert_new_tx(msg: word)
631
- push.IS_EXECUTED_FLAG
632
- # => [[0, 0, 0, is_executed], MSG]
633
-
634
- swapw
635
- # => [MSG, IS_EXECUTED_FLAG]
636
-
637
- push.EXECUTED_TXS_SLOT[0..2]
638
- # => [txs_slot_prefix, txs_slot_suffix, MSG, IS_EXECUTED_FLAG]
639
-
640
- # Set the key value pair in the map to mark transaction as executed
641
- exec.native_account::set_map_item
642
- # => [[0, 0, 0, is_executed]]
643
-
644
- drop drop drop
645
- # => [is_executed]
646
-
647
- assertz.err=ERR_TX_ALREADY_EXECUTED
648
- # => []
649
- end
650
-
651
- #! Remove old approver public keys from the approver public key mapping.
652
- #!
653
- #! This procedure cleans up the storage by removing public keys of approvers that are no longer
654
- #! part of the multisig configuration. This procedure assumes that init_num_of_approvers and
655
- #! new_num_of_approvers are u32 values.
656
- #!
657
- #! Inputs: [init_num_of_approvers, new_num_of_approvers]
658
- #! Outputs: []
659
- #!
660
- #! Where:
661
- #! - init_num_of_approvers is the original number of approvers before the update
662
- #! - new_num_of_approvers is the new number of approvers after the update
663
- proc cleanup_pubkey_mapping(init_num_of_approvers: u32, new_num_of_approvers: u32)
664
- dup.1 dup.1
665
- u32assert2 u32lt
666
- # => [should_loop, i = init_num_of_approvers, new_num_of_approvers]
667
-
668
- while.true
669
- # => [i, new_num_of_approvers]
670
-
671
- sub.1
672
- # => [i-1, new_num_of_approvers]
673
-
674
- dup exec.create_approver_map_key
675
- # => [APPROVER_MAP_KEY, i-1, new_num_of_approvers]
676
-
677
- padw swapw
678
- # => [APPROVER_MAP_KEY, EMPTY_WORD, i-1, new_num_of_approvers]
679
-
680
- push.PUBLIC_KEYS_MAP_SLOT[0..2]
681
- # => [pub_key_slot_prefix, pub_key_slot_suffix, APPROVER_MAP_KEY, EMPTY_WORD, i-1, new_num_of_approvers]
682
-
683
- exec.native_account::set_map_item
684
- # => [OLD_MAP_VALUE, i-1, new_num_of_approvers]
685
-
686
- dropw
687
- # => [i-1, new_num_of_approvers]
688
-
689
- dup exec.create_approver_map_key
690
- # => [APPROVER_MAP_KEY, i-1, new_num_of_approvers]
691
-
692
- padw swapw
693
- # => [APPROVER_MAP_KEY, EMPTY_WORD, i-1, new_num_of_approvers]
694
-
695
- push.APPROVER_SCHEME_ID_SLOT[0..2]
696
- # => [scheme_slot_prefix, scheme_slot_suffix, APPROVER_MAP_KEY, EMPTY_WORD, i-1, new_num_of_approvers]
697
-
698
- exec.native_account::set_map_item
699
- # => [OLD_MAP_VALUE, i-1, new_num_of_approvers]
700
-
701
- dropw
702
- # => [i-1, new_num_of_approvers]
703
-
704
- dup.1 dup.1
705
- u32lt
706
- # => [should_loop, i-1, new_num_of_approvers]
707
- end
708
-
709
- drop drop
710
- # => []
711
- end
712
-
713
- proc create_approver_map_key
714
- push.0.0.0 movup.3
715
- # => [APPROVER_MAP_KEY]
716
- end
717
-
718
- proc get_threshold_and_num_approvers
719
- push.THRESHOLD_CONFIG_SLOT[0..2]
720
- exec.active_account::get_initial_item
721
- # => [threshold, num_approvers]
722
-
723
- movup.2 drop movup.2 drop
724
- # => [threshold, num_approvers]
725
- end
726
-
727
- proc assert_proc_thresholds_lte_num_approvers(num_approvers: u32)
728
- exec.active_account::get_num_procedures
729
- # => [num_procedures, num_approvers]
730
-
731
- dup neq.0
732
- # => [should_continue, num_procedures, num_approvers]
733
- while.true
734
- sub.1 dup
735
- # => [proc_index, proc_index, num_approvers]
736
-
737
- exec.active_account::get_procedure_root
738
- # => [PROC_ROOT, proc_index, num_approvers]
739
-
740
- push.PROC_THRESHOLD_ROOTS_SLOT[0..2]
741
- # => [proc_roots_slot_prefix, proc_roots_slot_suffix, PROC_ROOT, proc_index, num_approvers]
742
-
743
- exec.active_account::get_map_item
744
- # => [[proc_threshold, 0, 0, 0], proc_index, num_approvers]
745
-
746
- movdn.3 drop drop drop
747
- # => [proc_threshold, proc_index, num_approvers]
748
-
749
- dup.2
750
- # => [num_approvers, proc_threshold, proc_index, num_approvers]
751
-
752
- u32assert2.err=ERR_PROC_THRESHOLD_NOT_U32
753
- u32gt assertz.err=ERR_PROC_THRESHOLD_EXCEEDS_NUM_APPROVERS
754
- # => [proc_index, num_approvers]
755
-
756
- dup neq.0
757
- # => [should_continue, proc_index, num_approvers]
758
- end
759
-
760
- drop drop
761
- # => []
762
- end
763
-
764
- # Internal storage helper used by the public \`update_procedure_threshold\`
765
- # entrypoint after it receives direct stack arguments.
766
- proc set_procedure_threshold(proc_threshold: u32, proc_root: word)
767
- exec.get_threshold_and_num_approvers
768
- # => [threshold, num_approvers, proc_threshold, PROC_ROOT]
769
-
770
- drop
771
- # => [num_approvers, proc_threshold, PROC_ROOT]
772
-
773
- dup.1 swap
774
- # => [num_approvers, proc_threshold, proc_threshold, PROC_ROOT]
775
-
776
- u32assert2.err=ERR_NUM_APPROVERS_OR_PROC_THRESHOLD_NOT_U32
777
- u32gt assertz.err=ERR_PROC_THRESHOLD_EXCEEDS_NUM_APPROVERS
778
- # => [proc_threshold, PROC_ROOT]
779
-
780
- push.0.0.0
781
- movup.3
782
- swapw
783
- # => [PROC_ROOT, PROC_THRESHOLD_WORD]
784
-
785
- push.PROC_THRESHOLD_ROOTS_SLOT[0..2]
786
- # => [proc_roots_slot_prefix, proc_roots_slot_suffix, PROC_ROOT, PROC_THRESHOLD_WORD]
787
-
788
- exec.native_account::set_map_item
789
- # => [OLD_VALUE]
790
-
791
- dropw
792
- # => []
793
- end
794
-
795
- #! Update threshold config and add / remove approvers
796
- #!
797
- #! Inputs:
798
- #! Operand stack: [MULTISIG_CONFIG_HASH, pad(12)]
799
- #! Advice map: {
800
- #! MULTISIG_CONFIG_HASH => [CONFIG, PUB_KEY_N, PUB_KEY_N-1, ..., PUB_KEY_0]
801
- #! }
802
- #! Outputs:
803
- #! Operand stack: []
804
- #!
805
- #! Where:
806
- #! - MULTISIG_CONFIG_HASH is the hash of the threshold and new public key vector
807
- #! - MULTISIG_CONFIG is [threshold, num_approvers, 0, 0]
808
- #! - PUB_KEY_i is the public key of the i-th signer
809
- #!
810
- #! Locals:
811
- #! 0: new_num_of_approvers
812
- #! 1: init_num_of_approvers
813
- @locals(2)
814
- pub proc update_signers_and_threshold(multisig_config_hash: word)
815
- adv.push_mapval
816
- # => [MULTISIG_CONFIG_HASH, pad(12)]
817
-
818
- adv_loadw
819
- # => [MULTISIG_CONFIG, pad(12)]
820
-
821
- # store new_num_of_approvers for later
822
- dup.1 loc_store.0
823
- # => [MULTISIG_CONFIG, pad(12)]
824
-
825
- dup dup.2
826
- # => [num_approvers, threshold, MULTISIG_CONFIG, pad(12)]
827
-
828
- # make sure that the threshold is smaller than the number of approvers
829
- u32assert2.err=ERR_MALFORMED_MULTISIG_CONFIG
830
- u32gt assertz.err=ERR_MALFORMED_MULTISIG_CONFIG
831
- # => [MULTISIG_CONFIG, pad(12)]
832
-
833
- dup dup.2
834
- # => [num_approvers, threshold, MULTISIG_CONFIG, pad(12)]
835
-
836
- # make sure that threshold or num_approvers are not zero
837
- eq.0 assertz.err=ERR_ZERO_IN_MULTISIG_CONFIG
838
- eq.0 assertz.err=ERR_ZERO_IN_MULTISIG_CONFIG
839
- # => [MULTISIG_CONFIG, pad(12)]
840
-
841
- loc_load.0
842
- # => [num_approvers, MULTISIG_CONFIG, pad(12)]
843
-
844
- exec.assert_proc_thresholds_lte_num_approvers
845
- # => [MULTISIG_CONFIG, pad(12)]
846
-
847
- push.THRESHOLD_CONFIG_SLOT[0..2]
848
- # => [config_slot_prefix, config_slot_suffix, MULTISIG_CONFIG, pad(12)]
849
-
850
- exec.native_account::set_item
851
- # => [OLD_THRESHOLD_CONFIG, pad(12)]
852
-
853
- # store init_num_of_approvers for later
854
- drop loc_store.1 drop drop
855
- # => [pad(12)]
856
-
857
- loc_load.0
858
- # => [num_approvers]
859
-
860
- dup neq.0
861
- while.true
862
- sub.1
863
- # => [i-1, pad(12)]
864
-
865
- dup exec.create_approver_map_key
866
- # => [APPROVER_MAP_KEY, i-1, pad(12)]
867
-
868
- padw adv_loadw
869
- # => [PUB_KEY, APPROVER_MAP_KEY, i-1, pad(12)]
870
-
871
- swapw
872
- # => [APPROVER_MAP_KEY, PUB_KEY, i-1, pad(12)]
873
-
874
- push.PUBLIC_KEYS_MAP_SLOT[0..2]
875
- # => [pub_key_slot_prefix, pub_key_slot_suffix, APPROVER_MAP_KEY, PUB_KEY, i-1, pad(12)]
876
-
877
- exec.native_account::set_map_item
878
- # => [OLD_VALUE, i-1, pad(12)]
879
-
880
- dropw
881
- # => [i-1, pad(12)]
882
-
883
- dup exec.create_approver_map_key
884
- # => [APPROVER_MAP_KEY, i-1, pad(12)]
885
-
886
- push.ECDSA_K256_KECCAK_SCHEME_WORD
887
- # => [SCHEME_ID_WORD, APPROVER_MAP_KEY, i-1, pad(12)]
888
-
889
- swapw
890
- # => [APPROVER_MAP_KEY, [1, 0, 0, 0], i-1, pad(12)]
891
-
892
- push.APPROVER_SCHEME_ID_SLOT[0..2]
893
- # => [scheme_slot_prefix, scheme_slot_suffix, APPROVER_MAP_KEY, [1, 0, 0, 0], i-1, pad(12)]
894
-
895
- exec.native_account::set_map_item
896
- # => [OLD_VALUE, i-1, pad(12)]
897
-
898
- dropw
899
- # => [i-1, pad(12)]
900
-
901
- dup neq.0
902
- # => [is_non_zero, i-1, pad(12)]
903
- end
904
- # => [pad(13)]
905
-
906
- drop
907
- # => [pad(12)]
908
-
909
- loc_load.0 loc_load.1
910
- # => [init_num_of_approvers, new_num_of_approvers, pad(12)]
911
-
912
- dup.1 dup.1
913
- u32assert2 u32lt
914
- # => [should_cleanup, init_num_of_approvers, new_num_of_approvers, pad(12)]
915
-
916
- if.true
917
- exec.cleanup_pubkey_mapping
918
- # => [pad(12)]
919
- else
920
- drop drop
921
- # => [pad(12)]
922
- end
923
- end
924
-
925
- #! Update or clear the threshold override for a specific procedure.
926
- #!
927
- #! Inputs:
928
- #! Operand stack: [proc_threshold, PROC_ROOT]
929
- #! Outputs:
930
- #! Operand stack: []
931
- #! Invocation: call
932
- pub proc update_procedure_threshold(proc_threshold: u32, proc_root: word)
933
- exec.set_procedure_threshold
934
- end
935
-
936
- # Computes the effective transaction threshold based on called procedures and per-procedure
937
- # overrides stored in PROC_THRESHOLD_ROOTS_SLOT. Falls back to default_threshold if no
938
- # overrides apply.
939
- #
940
- #! Inputs: [default_threshold]
941
- #! Outputs: [transaction_threshold]
942
- @locals(1)
943
- proc compute_transaction_threshold(default_threshold: u32) -> u32
944
- # 1. initialize transaction_threshold = 0
945
- # 2. iterate through all account procedures
946
- # a. check if the procedure was called during the transaction
947
- # b. if called, get the override threshold of that procedure from the config map
948
- # c. if proc_threshold > transaction_threshold, set transaction_threshold = proc_threshold
949
- # 3. if transaction_threshold == 0 at the end, revert to using default_threshold
950
-
951
- # store default_threshold for later
952
- loc_store.0
953
- # => []
954
-
955
- # 1. initialize transaction_threshold = 0
956
- push.0
957
- # => [transaction_threshold]
958
-
959
- # get the number of account procedures
960
- exec.active_account::get_num_procedures
961
- # => [num_procedures, transaction_threshold]
962
-
963
- # 2. iterate through all account procedures
964
- dup neq.0
965
- # => [should_continue, num_procedures, transaction_threshold]
966
- while.true
967
- sub.1 dup
968
- # => [num_procedures-1, num_procedures-1, transaction_threshold]
969
-
970
- # get procedure root of the procedure with index i
971
- exec.active_account::get_procedure_root dupw
972
- # => [PROC_ROOT, PROC_ROOT, num_procedures-1, transaction_threshold]
973
-
974
- # 2a. check if this procedure has been called in the transaction
975
- exec.native_account::was_procedure_called
976
- # => [was_called, PROC_ROOT, num_procedures-1, transaction_threshold]
977
-
978
- # if it has been called, get the override threshold of that procedure
979
- if.true
980
- # => [PROC_ROOT, num_procedures-1, transaction_threshold]
981
-
982
- push.PROC_THRESHOLD_ROOTS_SLOT[0..2]
983
- # => [PROC_THRESHOLD_ROOTS_SLOT_prefix, PROC_THRESHOLD_ROOTS_SLOT_suffix, PROC_ROOT, num_procedures-1, transaction_threshold]
984
-
985
- # 2b. get the override proc_threshold of that procedure
986
- # if the procedure has no override threshold, the returned map item will be [0, 0, 0, 0]
987
- exec.active_account::get_initial_map_item
988
- # => [[proc_threshold, 0, 0, 0], num_procedures-1, transaction_threshold]
989
-
990
- movdn.3 drop drop drop dup dup.3
991
- # => [transaction_threshold, proc_threshold, proc_threshold, num_procedures-1, transaction_threshold]
992
-
993
- u32assert2.err="transaction threshold or procedure threshold are not u32"
994
- u32gt
995
- # => [is_gt, proc_threshold, num_procedures-1, transaction_threshold]
996
- # 2c. if proc_threshold > transaction_threshold, update transaction_threshold
997
- movup.2 movdn.3
998
- # => [is_gt, proc_threshold, transaction_threshold, num_procedures-1]
999
- cdrop
1000
- # => [updated_transaction_threshold, num_procedures-1]
1001
- swap
1002
- # => [num_procedures-1, updated_transaction_threshold]
1003
- # if it has not been called during this transaction, nothing to do, move to the next procedure
1004
- else
1005
- dropw
1006
- # => [num_procedures-1, transaction_threshold]
1007
- end
1008
-
1009
- dup neq.0
1010
- # => [should_continue, num_procedures-1, transaction_threshold]
1011
- end
1012
-
1013
- drop
1014
- # => [transaction_threshold]
1015
-
1016
- loc_load.0
1017
- # => [default_threshold, transaction_threshold]
1018
-
1019
- # 3. if transaction_threshold == 0 at the end, revert to using default_threshold
1020
- dup.1 eq.0
1021
- # => [is_zero, default_threshold, transaction_threshold]
1022
-
1023
- cdrop
1024
- # => [effective_transaction_threshold]
1025
- end
1026
-
1027
- #! Authenticate a transaction using ECDSA secp256k1 with multi-signature support.
1028
- #!
1029
- #! This procedure implements multi-signature authentication by:
1030
- #! 1. Computing the transaction summary message that needs to be signed
1031
- #! 2. Verifying ECDSA signatures from multiple required signers against their public keys
1032
- #! 3. Ensuring the minimum threshold of valid signatures is met
1033
- #! 4. Returning the transaction summary commitment for higher-level wrappers.
1034
- #!
1035
- #! Inputs:
1036
- #! Operand stack: [SALT]
1037
- #! Advice map: {
1038
- #! h(PUB_KEY_0, MSG): SIG_0,
1039
- #! h(PUB_KEY_1, MSG): SIG_1,
1040
- #! h(PUB_KEY_n, MSG): SIG_n
1041
- #! }
1042
- #! Outputs:
1043
- #! Operand stack: [TX_SUMMARY_COMMITMENT]
1044
- #!
1045
- #! Where:
1046
- #! - SALT is a cryptographically random nonce that enables multiple concurrent
1047
- #! multisig transactions while maintaining replay protection. Each transaction
1048
- #! must use a unique SALT value to ensure transaction uniqueness.
1049
- #! - SIG_i is the ECDSA signature from the i-th signer.
1050
- #! - MSG is the transaction message being signed.
1051
- #! - h(PUB_KEY_i, MSG) is the hash of the public key and message used as the advice map key.
1052
- #!
1053
- #! Panics if:
1054
- #! - insufficient number of valid signatures (below threshold).
1055
- #! - insufficient number of valid signatures (below threshold).
1056
- #!
1057
- #! Invocation: exec
1058
- @locals(1)
1059
- pub proc auth_tx(salt: word)
1060
- exec.native_account::incr_nonce drop
1061
- # => [SALT]
1062
-
1063
- # ------ Computing transaction summary ------
1064
-
1065
- exec.auth::create_tx_summary
1066
- # => [ACCOUNT_DELTA_COMMITMENT, INPUT_NOTES_COMMITMENT, OUTPUT_NOTES_COMMITMENT, SALT]
1067
-
1068
- # to build a tx_summary in the host, we need these four words in the advice provider
1069
- adv.insert_hqword
1070
- # => [ACCOUNT_DELTA_COMMITMENT, INPUT_NOTES_COMMITMENT, OUTPUT_NOTES_COMMITMENT, SALT]
1071
-
1072
- # the commitment to the tx summary is the message that is signed
1073
- exec.auth::hash_tx_summary
1074
- # => [TX_SUMMARY_COMMITMENT]
1075
-
1076
- # ------ Verifying approver signatures ------
1077
-
1078
- exec.get_threshold_and_num_approvers
1079
- # => [default_threshold, num_of_approvers, TX_SUMMARY_COMMITMENT]
1080
-
1081
- movdn.5
1082
- # => [num_of_approvers, TX_SUMMARY_COMMITMENT, default_threshold]
1083
-
1084
- push.PUBLIC_KEYS_MAP_SLOT[0..2]
1085
- # => [pub_key_slot_prefix, pub_key_slot_suffix, num_of_approvers, TX_SUMMARY_COMMITMENT, default_threshold]
1086
-
1087
- push.APPROVER_SCHEME_ID_SLOT[0..2]
1088
- # => [scheme_id_slot_prefix, scheme_id_slot_suffix, pub_key_slot_prefix, pub_key_slot_suffix, num_of_approvers, TX_SUMMARY_COMMITMENT, default_threshold]
1089
-
1090
- exec.::miden::standards::auth::signature::verify_signatures
1091
- # => [num_verified_signatures, TX_SUMMARY_COMMITMENT, default_threshold]
1092
-
1093
- # ------ Checking threshold is >= num_verified_signatures ------
1094
-
1095
- movup.5
1096
- # => [default_threshold, num_verified_signatures, TX_SUMMARY_COMMITMENT]
1097
-
1098
- exec.compute_transaction_threshold
1099
- # => [transaction_threshold, num_verified_signatures, TX_SUMMARY_COMMITMENT]
1100
-
1101
- u32assert2 u32lt
1102
- # => [is_unauthorized, TX_SUMMARY_COMMITMENT]
1103
-
1104
- # If signatures are non-existent the tx will fail here.
1105
- if.true
1106
- emit.AUTH_UNAUTHORIZED_EVENT
1107
- push.0 assert.err="insufficient number of signatures"
1108
- end
1109
-
1110
- # => [TX_SUMMARY_COMMITMENT]
1111
- end
1112
- `;
1113
- export const GUARDIAN_MASM = `# Guardian Authentication Component
1114
- #
1115
- # This component provides GUARDIAN signature verification for accounts.
1116
- # It can be used standalone or in conjunction with other auth components like multisig.
1117
-
1118
- use miden::protocol::active_account
1119
- use miden::protocol::auth::AUTH_UNAUTHORIZED_EVENT
1120
- use miden::protocol::native_account
1121
-
1122
- # IMPORTANT SECURITY NOTES
1123
- # --------------------------------------------------------------------------------
1124
- # - The selector in \`GUARDIAN_SELECTOR_SLOT\` controls whether the extra GUARDIAN signature
1125
- # is enforced:
1126
- # * GUARDIAN_ON => exactly one valid GUARDIAN signature is required.
1127
- # * GUARDIAN_OFF => GUARDIAN signature is skipped for that call.
1128
- #
1129
- # - \`verify_guardian_signature\` reads the selector from initial storage state.
1130
- # This means changes made during the same transaction won't affect the check.
1131
- #
1132
- # - \`enable_guardian\` / \`disable_guardian\` procedures allow explicit control over GUARDIAN state.
1133
- #
1134
- # - \`update_guardian_public_key\`:
1135
- # * Installs a new GUARDIAN public key in the map at \`GUARDIAN_PUBLIC_KEY_MAP_SLOT\`.
1136
- # * Does not itself perform any signature checks.
1137
- # * To update the key without requiring GUARDIAN signature, ensure selector is OFF.
1138
- #
1139
- # Storage Layout
1140
- # --------------------------------------------------------------------------------
1141
- #
1142
- # +---------------------+---------------+
1143
- # | DESCRIPTION | SLOT |
1144
- # +---------------------+---------------+
1145
- # | GUARDIAN SELECTOR (word) | 0 |
1146
- # | GUARDIAN PUBLIC KEY MAP | 1 |
1147
- # | GUARDIAN SCHEME ID MAP | 2 |
1148
- # +---------------------+---------------+
1149
- #
1150
- # - GUARDIAN_SELECTOR_SLOT (0):
1151
- # * Stores a word that is compared against [1, 0, 0, 0] (GUARDIAN_ON).
1152
- # * Any value != GUARDIAN_ON is treated as GUARDIAN_OFF.
1153
- #
1154
- # - GUARDIAN_PUBLIC_KEY_MAP_SLOT (1):
1155
- # * A map from a fixed key [0, 0, 0, 0] to the single GUARDIAN public key:
1156
- # [0, 0, 0, 0] => GUARDIAN_PUBLIC_KEY
1157
- # * GUARDIAN_PUBLIC_KEY is a Falcon Poseidon2 public key represented as a word.
1158
-
1159
- # CONSTANTS
1160
- # =================================================================================================
1161
-
1162
- # Slot where the GUARDIAN selector flag is stored (using word() for named slot access):
1163
- # - GUARDIAN_ON => GUARDIAN signature required
1164
- # - GUARDIAN_OFF => GUARDIAN signature skipped
1165
- const GUARDIAN_SELECTOR_SLOT=word("openzeppelin::guardian::selector")
1166
-
1167
- # Map slot for GUARDIAN public key
1168
- # Uses exactly one GUARDIAN public key at index [0, 0, 0, 0]
1169
- # [0, 0, 0, 0] => GUARDIAN_PUBLIC_KEY
1170
- const GUARDIAN_PUBLIC_KEY_MAP_SLOT=word("openzeppelin::guardian::public_key")
1171
-
1172
- # Map slot for GUARDIAN signature scheme IDs
1173
- # Uses exactly one scheme ID entry at index [0, 0, 0, 0]
1174
- # [0, 0, 0, 0] => [scheme_id, 0, 0, 0]
1175
- const GUARDIAN_SCHEME_ID_MAP_SLOT=word("openzeppelin::guardian::scheme_id")
1176
-
1177
- # Selector flag values
1178
- const GUARDIAN_ON=[1, 0, 0, 0]
1179
- const GUARDIAN_OFF=[0, 0, 0, 0]
1180
- const FALCON_512_POSEIDON2_SCHEME_WORD=[2, 0, 0, 0]
1181
-
1182
- # GUARDIAN PROCEDURES
1183
- # =================================================================================================
1184
-
1185
- #! Enable GUARDIAN verification by setting the selector to ON.
1186
- #!
1187
- #! Operand stack inputs: []
1188
- #! Outputs: []
1189
- #!
1190
- #! Notes:
1191
- #! - Sets GUARDIAN_SELECTOR_SLOT to GUARDIAN_ON (1)
1192
- #! - After this, transactions will require GUARDIAN signature verification
1193
- proc enable_guardian
1194
- push.GUARDIAN_ON
1195
- # => [GUARDIAN_ON]
1196
-
1197
- push.GUARDIAN_SELECTOR_SLOT[0..2]
1198
- # => [selector_slot_prefix, selector_slot_suffix, GUARDIAN_ON]
1199
-
1200
- exec.native_account::set_item
1201
- # => [OLD_ROOT]
1202
-
1203
- dropw
1204
- # => []
1205
- end
1206
-
1207
- #! Disable GUARDIAN verification by setting the selector to OFF.
1208
- #!
1209
- #! Operand stack inputs: []
1210
- #! Outputs: []
1211
- #!
1212
- #! Notes:
1213
- #! - Sets GUARDIAN_SELECTOR_SLOT to GUARDIAN_OFF (0)
1214
- #! - After this, transactions will NOT require GUARDIAN signature verification
1215
- proc disable_guardian
1216
- push.GUARDIAN_OFF
1217
- # => [GUARDIAN_OFF]
1218
-
1219
- push.GUARDIAN_SELECTOR_SLOT[0..2]
1220
- # => [selector_slot_prefix, selector_slot_suffix, GUARDIAN_OFF]
1221
-
1222
- exec.native_account::set_item
1223
- # => [OLD_ROOT]
1224
-
1225
- dropw
1226
- # => []
1227
- end
1228
-
1229
- #! Update the GUARDIAN public key.
1230
- #!
1231
- #! Operand stack inputs: []
1232
- #! Advice stack inputs: [PUB_KEY]
1233
- #! - PUB_KEY is the new GUARDIAN RPO Falcon 512 public key
1234
- #!
1235
- #! Notes:
1236
- #! - Stores PUB_KEY into GUARDIAN_PUBLIC_KEY_MAP_SLOT:
1237
- #! [0, 0, 0, 0] => GUARDIAN_PUBLIC_KEY
1238
- #! - To update the key without requiring GUARDIAN signature, ensure
1239
- #! GUARDIAN_SELECTOR_SLOT = 0 (OFF) before calling this.
1240
- pub proc update_guardian_public_key
1241
- exec.disable_guardian
1242
- # ------ Update the GUARDIAN public key ------
1243
- adv_loadw
1244
- # => [PUB_KEY]
1245
-
1246
- push.0.0.0.0
1247
- # => [MAP_KEY, PUB_KEY]
1248
- # Note that MAP_KEY is [0, 0, 0, 0] for a single GUARDIAN_KEY
1249
-
1250
- push.GUARDIAN_PUBLIC_KEY_MAP_SLOT[0..2]
1251
- # => [pub_key_slot_prefix, pub_key_slot_suffix, MAP_KEY, PUB_KEY]
1252
-
1253
- exec.native_account::set_map_item
1254
- # => [OLD_MAP_VALUE]
1255
-
1256
- dropw
1257
- # => []
1258
-
1259
- push.0.0.0.0
1260
- # => [MAP_KEY]
1261
-
1262
- push.FALCON_512_POSEIDON2_SCHEME_WORD
1263
- # => [SCHEME_ID_WORD, MAP_KEY]
1264
-
1265
- swapw
1266
- # => [MAP_KEY, SCHEME_ID_WORD]
1267
-
1268
- push.GUARDIAN_SCHEME_ID_MAP_SLOT[0..2]
1269
- # => [scheme_id_slot_prefix, scheme_id_slot_suffix, MAP_KEY, SCHEME_ID_WORD]
1270
-
1271
- exec.native_account::set_map_item
1272
- # => [OLD_MAP_VALUE]
1273
-
1274
- dropw
1275
- # => []
1276
- end
1277
-
1278
- #! Conditionally verify a "GUARDIAN" signature against a stored public key hash.
1279
- #! The condition is controlled by the selector at GUARDIAN_SELECTOR_SLOT.
1280
- #!
1281
- #! Inputs: [MSG]
1282
- #! Outputs: [MSG]
1283
- #!
1284
- #! Panics if:
1285
- #! - Selector is ON but the provided GUARDIAN signature is invalid or missing.
1286
- #!
1287
- #! Notes:
1288
- #! - MSG is TX_SUMMARY_COMMITMENT provided by auth procedure
1289
- #! - If selector is OFF (0), GUARDIAN verification is skipped
1290
- #! - Selector value is read from initial storage state
1291
- pub proc verify_guardian_signature(msg: word)
1292
- push.GUARDIAN_SELECTOR_SLOT[0..2]
1293
- exec.active_account::get_item
1294
- drop drop drop
1295
- # => [selector, MSG]
1296
-
1297
- push.1 eq
1298
- if.true
1299
- push.1
1300
- push.GUARDIAN_PUBLIC_KEY_MAP_SLOT[0..2]
1301
- push.GUARDIAN_SCHEME_ID_MAP_SLOT[0..2]
1302
- exec.::miden::standards::auth::signature::verify_signatures
1303
- push.1 neq
1304
- if.true
1305
- emit.AUTH_UNAUTHORIZED_EVENT
1306
- push.0 assert.err="invalid GUARDIAN signature"
1307
- end
1308
- end
1309
- # => [MSG]
1310
- exec.enable_guardian
1311
- end
1312
- `;
1313
- export const GUARDIAN_ECDSA_MASM = `# Guardian Authentication Component (ECDSA)
1314
- #
1315
- # This component provides GUARDIAN signature verification for accounts using
1316
- # ECDSA secp256k1 (k256/keccak) signatures.
1317
- # It can be used standalone or in conjunction with other auth components like multisig.
1318
-
1319
- use miden::protocol::active_account
1320
- use miden::protocol::auth::AUTH_UNAUTHORIZED_EVENT
1321
- use miden::protocol::native_account
1322
-
1323
- # IMPORTANT SECURITY NOTES
1324
- # --------------------------------------------------------------------------------
1325
- # - The selector in \`GUARDIAN_SELECTOR_SLOT\` controls whether the extra GUARDIAN signature
1326
- # is enforced:
1327
- # * GUARDIAN_ON => exactly one valid GUARDIAN signature is required.
1328
- # * GUARDIAN_OFF => GUARDIAN signature is skipped for that call.
1329
- #
1330
- # - \`verify_guardian_signature\` reads the selector from initial storage state.
1331
- # This means changes made during the same transaction won't affect the check.
1332
- #
1333
- # - \`enable_guardian\` / \`disable_guardian\` procedures allow explicit control over GUARDIAN state.
1334
- #
1335
- # - \`update_guardian_public_key\`:
1336
- # * Installs a new GUARDIAN public key in the map at \`GUARDIAN_PUBLIC_KEY_MAP_SLOT\`.
1337
- # * Does not itself perform any signature checks.
1338
- # * To update the key without requiring GUARDIAN signature, ensure selector is OFF.
1339
- #
1340
- # Storage Layout
1341
- # --------------------------------------------------------------------------------
1342
- #
1343
- # +---------------------+---------------+
1344
- # | DESCRIPTION | SLOT |
1345
- # +---------------------+---------------+
1346
- # | GUARDIAN SELECTOR (word) | 0 |
1347
- # | GUARDIAN PUBLIC KEY MAP | 1 |
1348
- # +---------------------+---------------+
1349
- #
1350
- # - GUARDIAN_SELECTOR_SLOT (0):
1351
- # * Stores a word that is compared against [1, 0, 0, 0] (GUARDIAN_ON).
1352
- # * Any value != GUARDIAN_ON is treated as GUARDIAN_OFF.
1353
- #
1354
- # - GUARDIAN_PUBLIC_KEY_MAP_SLOT (1):
1355
- # * A map from a fixed key [0, 0, 0, 0] to the single GUARDIAN public key:
1356
- # [0, 0, 0, 0] => GUARDIAN_PUBLIC_KEY
1357
- # * GUARDIAN_PUBLIC_KEY is an ECDSA secp256k1 public key represented as a word.
1358
-
1359
- # CONSTANTS
1360
- # =================================================================================================
1361
-
1362
- # Slot where the GUARDIAN selector flag is stored (using word() for named slot access):
1363
- # - GUARDIAN_ON => GUARDIAN signature required
1364
- # - GUARDIAN_OFF => GUARDIAN signature skipped
1365
- const GUARDIAN_SELECTOR_SLOT=word("openzeppelin::guardian::selector")
1366
-
1367
- # Map slot for GUARDIAN public key
1368
- # Uses exactly one GUARDIAN public key at index [0, 0, 0, 0]
1369
- # [0, 0, 0, 0] => GUARDIAN_PUBLIC_KEY
1370
- const GUARDIAN_PUBLIC_KEY_MAP_SLOT=word("openzeppelin::guardian::public_key")
1371
- const GUARDIAN_SCHEME_ID_MAP_SLOT=word("openzeppelin::guardian::scheme_id")
1372
-
1373
- # Selector flag values
1374
- const GUARDIAN_ON=[1, 0, 0, 0]
1375
- const GUARDIAN_OFF=[0, 0, 0, 0]
1376
- const ECDSA_K256_KECCAK_SCHEME_WORD=[1, 0, 0, 0]
1377
-
1378
- # GUARDIAN PROCEDURES
1379
- # =================================================================================================
1380
-
1381
- #! Enable GUARDIAN verification by setting the selector to ON.
1382
- #!
1383
- #! Operand stack inputs: []
1384
- #! Outputs: []
1385
- #!
1386
- #! Notes:
1387
- #! - Sets GUARDIAN_SELECTOR_SLOT to GUARDIAN_ON (1)
1388
- #! - After this, transactions will require GUARDIAN signature verification
1389
- proc enable_guardian
1390
- push.GUARDIAN_ON
1391
- # => [GUARDIAN_ON]
1392
-
1393
- push.GUARDIAN_SELECTOR_SLOT[0..2]
1394
- # => [selector_slot_prefix, selector_slot_suffix, GUARDIAN_ON]
1395
-
1396
- exec.native_account::set_item
1397
- # => [OLD_ROOT]
1398
-
1399
- dropw
1400
- # => []
1401
- end
1402
-
1403
- #! Disable GUARDIAN verification by setting the selector to OFF.
1404
- #!
1405
- #! Operand stack inputs: []
1406
- #! Outputs: []
1407
- #!
1408
- #! Notes:
1409
- #! - Sets GUARDIAN_SELECTOR_SLOT to GUARDIAN_OFF (0)
1410
- #! - After this, transactions will NOT require GUARDIAN signature verification
1411
- proc disable_guardian
1412
- push.GUARDIAN_OFF
1413
- # => [GUARDIAN_OFF]
1414
-
1415
- push.GUARDIAN_SELECTOR_SLOT[0..2]
1416
- # => [selector_slot_prefix, selector_slot_suffix, GUARDIAN_OFF]
1417
-
1418
- exec.native_account::set_item
1419
- # => [OLD_ROOT]
1420
-
1421
- dropw
1422
- # => []
1423
- end
1424
-
1425
- #! Update the GUARDIAN public key.
1426
- #!
1427
- #! Operand stack inputs: []
1428
- #! Advice stack inputs: [PUB_KEY]
1429
- #! - PUB_KEY is the new GUARDIAN ECDSA secp256k1 public key
1430
- #!
1431
- #! Notes:
1432
- #! - Stores PUB_KEY into GUARDIAN_PUBLIC_KEY_MAP_SLOT:
1433
- #! [0, 0, 0, 0] => GUARDIAN_PUBLIC_KEY
1434
- #! - To update the key without requiring GUARDIAN signature, ensure
1435
- #! GUARDIAN_SELECTOR_SLOT = 0 (OFF) before calling this.
1436
- pub proc update_guardian_public_key
1437
- exec.disable_guardian
1438
- # ------ Update the GUARDIAN public key ------
1439
- adv_loadw
1440
- # => [PUB_KEY]
1441
-
1442
- push.0.0.0.0
1443
- # => [MAP_KEY, PUB_KEY]
1444
- # Note that MAP_KEY is [0, 0, 0, 0] for a single GUARDIAN_KEY
1445
-
1446
- push.GUARDIAN_PUBLIC_KEY_MAP_SLOT[0..2]
1447
- # => [pub_key_slot_prefix, pub_key_slot_suffix, MAP_KEY, PUB_KEY]
1448
-
1449
- exec.native_account::set_map_item
1450
- # => [OLD_MAP_VALUE]
1451
-
1452
- dropw
1453
- # => []
1454
-
1455
- push.0.0.0.0
1456
- # => [MAP_KEY]
1457
-
1458
- push.ECDSA_K256_KECCAK_SCHEME_WORD
1459
- # => [SCHEME_ID_WORD, MAP_KEY]
1460
-
1461
- swapw
1462
- # => [MAP_KEY, SCHEME_ID_WORD]
1463
-
1464
- push.GUARDIAN_SCHEME_ID_MAP_SLOT[0..2]
1465
- # => [scheme_id_slot_prefix, scheme_id_slot_suffix, MAP_KEY, SCHEME_ID_WORD]
1466
-
1467
- exec.native_account::set_map_item
1468
- # => [OLD_MAP_VALUE]
1469
-
1470
- dropw
1471
- # => []
1472
- end
1473
-
1474
- #! Conditionally verify a "GUARDIAN" signature against a stored public key hash.
1475
- #! The condition is controlled by the selector at GUARDIAN_SELECTOR_SLOT.
1476
- #!
1477
- #! Inputs: [MSG]
1478
- #! Outputs: [MSG]
1479
- #!
1480
- #! Panics if:
1481
- #! - Selector is ON but the provided GUARDIAN signature is invalid or missing.
1482
- #!
1483
- #! Notes:
1484
- #! - MSG is TX_SUMMARY_COMMITMENT provided by auth procedure
1485
- #! - If selector is OFF (0), GUARDIAN verification is skipped
1486
- #! - Selector value is read from initial storage state
1487
- pub proc verify_guardian_signature(msg: word)
1488
- push.GUARDIAN_SELECTOR_SLOT[0..2]
1489
- exec.active_account::get_item
1490
- drop drop drop
1491
- # => [selector, MSG]
1492
-
1493
- push.1 eq
1494
- if.true
1495
- push.1
1496
- push.GUARDIAN_PUBLIC_KEY_MAP_SLOT[0..2]
1497
- push.GUARDIAN_SCHEME_ID_MAP_SLOT[0..2]
1498
- exec.::miden::standards::auth::signature::verify_signatures
1499
- push.1 neq
1500
- if.true
1501
- emit.AUTH_UNAUTHORIZED_EVENT
1502
- push.0 assert.err="invalid GUARDIAN signature"
1503
- end
1504
- end
1505
- # => [MSG]
1506
- exec.enable_guardian
1507
- end
1508
- `;
1509
- //# sourceMappingURL=auth.js.map