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