@openzeppelin/miden-multisig-client 0.13.1 → 0.13.2

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 (275) hide show
  1. package/README.md +98 -119
  2. package/dist/account/builder.d.ts +18 -0
  3. package/dist/account/builder.d.ts.map +1 -1
  4. package/dist/account/builder.js +59 -29
  5. package/dist/account/builder.js.map +1 -1
  6. package/dist/account/builder.test.js +108 -32
  7. package/dist/account/builder.test.js.map +1 -1
  8. package/dist/account/index.d.ts +1 -1
  9. package/dist/account/index.d.ts.map +1 -1
  10. package/dist/account/index.js +1 -1
  11. package/dist/account/index.js.map +1 -1
  12. package/dist/account/masm/account-components/auth.d.ts +5 -0
  13. package/dist/account/masm/account-components/auth.d.ts.map +1 -0
  14. package/dist/account/masm/account-components/auth.js +67 -0
  15. package/dist/account/masm/account-components/auth.js.map +1 -0
  16. package/dist/account/masm/auth.d.ts +5 -0
  17. package/dist/account/masm/auth.d.ts.map +1 -0
  18. package/dist/account/masm/auth.js +1395 -0
  19. package/dist/account/masm/auth.js.map +1 -0
  20. package/dist/account/masm/index.d.ts +3 -0
  21. package/dist/account/masm/index.d.ts.map +1 -0
  22. package/dist/account/masm/index.js +5 -0
  23. package/dist/account/masm/index.js.map +1 -0
  24. package/dist/account/masm.d.ts +1 -4
  25. package/dist/account/masm.d.ts.map +1 -1
  26. package/dist/account/masm.js +3 -1034
  27. package/dist/account/masm.js.map +1 -1
  28. package/dist/account/storage.d.ts +2 -2
  29. package/dist/account/storage.d.ts.map +1 -1
  30. package/dist/account/storage.js +18 -16
  31. package/dist/account/storage.js.map +1 -1
  32. package/dist/client.d.ts +67 -9
  33. package/dist/client.d.ts.map +1 -1
  34. package/dist/client.js +73 -22
  35. package/dist/client.js.map +1 -1
  36. package/dist/client.test.js +31 -32
  37. package/dist/client.test.js.map +1 -1
  38. package/dist/index.d.ts +54 -12
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +53 -9
  41. package/dist/index.js.map +1 -1
  42. package/dist/inspector.d.ts +32 -6
  43. package/dist/inspector.d.ts.map +1 -1
  44. package/dist/inspector.js +58 -23
  45. package/dist/inspector.js.map +1 -1
  46. package/dist/inspector.test.js +18 -18
  47. package/dist/inspector.test.js.map +1 -1
  48. package/dist/multisig/proposal/execution.d.ts +4 -4
  49. package/dist/multisig/proposal/execution.d.ts.map +1 -1
  50. package/dist/multisig/proposal/execution.js +42 -31
  51. package/dist/multisig/proposal/execution.js.map +1 -1
  52. package/dist/multisig/proposal/parser.d.ts +3 -3
  53. package/dist/multisig/proposal/parser.d.ts.map +1 -1
  54. package/dist/multisig/proposal/parser.js +23 -23
  55. package/dist/multisig/proposal/parser.js.map +1 -1
  56. package/dist/multisig/signing.d.ts +3 -3
  57. package/dist/multisig/signing.d.ts.map +1 -1
  58. package/dist/multisig/signing.js +3 -3
  59. package/dist/multisig/signing.js.map +1 -1
  60. package/dist/multisig.d.ts +188 -48
  61. package/dist/multisig.d.ts.map +1 -1
  62. package/dist/multisig.js +650 -308
  63. package/dist/multisig.js.map +1 -1
  64. package/dist/multisig.test.js +1680 -241
  65. package/dist/multisig.test.js.map +1 -1
  66. package/dist/procedures.d.ts +46 -24
  67. package/dist/procedures.d.ts.map +1 -1
  68. package/dist/procedures.js +46 -21
  69. package/dist/procedures.js.map +1 -1
  70. package/dist/proposal/factory.d.ts +18 -0
  71. package/dist/proposal/factory.d.ts.map +1 -0
  72. package/dist/proposal/factory.js +99 -0
  73. package/dist/proposal/factory.js.map +1 -0
  74. package/dist/proposal/metadata.d.ts +5 -12
  75. package/dist/proposal/metadata.d.ts.map +1 -1
  76. package/dist/proposal/metadata.js +118 -174
  77. package/dist/proposal/metadata.js.map +1 -1
  78. package/dist/proposal/signatures.d.ts +10 -0
  79. package/dist/proposal/signatures.d.ts.map +1 -0
  80. package/dist/proposal/signatures.js +54 -0
  81. package/dist/proposal/signatures.js.map +1 -0
  82. package/dist/signer.d.ts +2 -0
  83. package/dist/signer.d.ts.map +1 -1
  84. package/dist/signer.js +2 -0
  85. package/dist/signer.js.map +1 -1
  86. package/dist/signers/ecdsa.d.ts +3 -0
  87. package/dist/signers/ecdsa.d.ts.map +1 -1
  88. package/dist/signers/ecdsa.js +8 -4
  89. package/dist/signers/ecdsa.js.map +1 -1
  90. package/dist/signers/ecdsa.test.d.ts +2 -0
  91. package/dist/signers/ecdsa.test.d.ts.map +1 -0
  92. package/dist/signers/ecdsa.test.js +65 -0
  93. package/dist/signers/ecdsa.test.js.map +1 -0
  94. package/dist/signers/falcon.d.ts +3 -0
  95. package/dist/signers/falcon.d.ts.map +1 -1
  96. package/dist/signers/falcon.js +8 -4
  97. package/dist/signers/falcon.js.map +1 -1
  98. package/dist/signers/falcon.test.js +12 -0
  99. package/dist/signers/falcon.test.js.map +1 -1
  100. package/dist/signers/miden-wallet.d.ts +3 -1
  101. package/dist/signers/miden-wallet.d.ts.map +1 -1
  102. package/dist/signers/miden-wallet.js +11 -2
  103. package/dist/signers/miden-wallet.js.map +1 -1
  104. package/dist/signers/miden-wallet.test.js +26 -0
  105. package/dist/signers/miden-wallet.test.js.map +1 -1
  106. package/dist/signers/para.d.ts +3 -3
  107. package/dist/signers/para.d.ts.map +1 -1
  108. package/dist/signers/para.js +15 -6
  109. package/dist/signers/para.js.map +1 -1
  110. package/dist/signers/para.test.js +39 -0
  111. package/dist/signers/para.test.js.map +1 -1
  112. package/dist/transaction/consumeNotes.d.ts.map +1 -1
  113. package/dist/transaction/consumeNotes.js +1 -0
  114. package/dist/transaction/consumeNotes.js.map +1 -1
  115. package/dist/transaction/index.d.ts +2 -1
  116. package/dist/transaction/index.d.ts.map +1 -1
  117. package/dist/transaction/index.js +2 -1
  118. package/dist/transaction/index.js.map +1 -1
  119. package/dist/transaction/options.d.ts +1 -1
  120. package/dist/transaction/options.d.ts.map +1 -1
  121. package/dist/transaction/p2id.d.ts +1 -0
  122. package/dist/transaction/p2id.d.ts.map +1 -1
  123. package/dist/transaction/p2id.js +9 -3
  124. package/dist/transaction/p2id.js.map +1 -1
  125. package/dist/transaction/updateGuardian.d.ts +7 -0
  126. package/dist/transaction/updateGuardian.d.ts.map +1 -0
  127. package/dist/transaction/{updatePsm.js → updateGuardian.js} +15 -29
  128. package/dist/transaction/updateGuardian.js.map +1 -0
  129. package/dist/transaction/updateProcedureThreshold.d.ts +9 -0
  130. package/dist/transaction/updateProcedureThreshold.d.ts.map +1 -0
  131. package/dist/transaction/updateProcedureThreshold.js +55 -0
  132. package/dist/transaction/updateProcedureThreshold.js.map +1 -0
  133. package/dist/transaction/updateSigners.d.ts.map +1 -1
  134. package/dist/transaction/updateSigners.js +5 -23
  135. package/dist/transaction/updateSigners.js.map +1 -1
  136. package/dist/transaction.d.ts +2 -1
  137. package/dist/transaction.d.ts.map +1 -1
  138. package/dist/transaction.js +2 -1
  139. package/dist/transaction.js.map +1 -1
  140. package/dist/types/proposal.d.ts +32 -15
  141. package/dist/types/proposal.d.ts.map +1 -1
  142. package/dist/types.d.ts +24 -7
  143. package/dist/types.d.ts.map +1 -1
  144. package/dist/utils/digest.d.ts +5 -0
  145. package/dist/utils/digest.d.ts.map +1 -1
  146. package/dist/utils/digest.js +34 -1
  147. package/dist/utils/digest.js.map +1 -1
  148. package/dist/utils/digest.test.d.ts +2 -0
  149. package/dist/utils/digest.test.d.ts.map +1 -0
  150. package/dist/utils/digest.test.js +48 -0
  151. package/dist/utils/digest.test.js.map +1 -0
  152. package/dist/utils/signature.d.ts +3 -1
  153. package/dist/utils/signature.d.ts.map +1 -1
  154. package/dist/utils/signature.js +31 -6
  155. package/dist/utils/signature.js.map +1 -1
  156. package/dist/utils/word.test.js +1 -52
  157. package/dist/utils/word.test.js.map +1 -1
  158. package/masm/account_components/auth/multisig.masm +13 -0
  159. package/masm/account_components/auth/multisig_ecdsa.masm +13 -0
  160. package/masm/account_components/auth/multisig_guardian.masm +17 -0
  161. package/masm/account_components/auth/multisig_guardian_ecdsa.masm +17 -0
  162. package/masm/auth/guardian.masm +177 -0
  163. package/masm/auth/guardian_ecdsa.masm +178 -0
  164. package/masm/{multisig.masm → auth/multisig.masm} +149 -55
  165. package/masm/{multisig_ecdsa.masm → auth/multisig_ecdsa.masm} +148 -56
  166. package/package.json +11 -9
  167. package/src/account/builder.test.ts +165 -0
  168. package/src/account/builder.ts +71 -34
  169. package/src/account/index.ts +1 -1
  170. package/src/account/masm/account-components/auth.ts +70 -0
  171. package/src/account/masm/auth.ts +1398 -0
  172. package/src/account/masm/index.ts +5 -0
  173. package/src/account/masm.ts +3 -1040
  174. package/src/account/storage.ts +18 -16
  175. package/src/client.test.ts +31 -35
  176. package/src/client.ts +98 -26
  177. package/src/index.ts +84 -22
  178. package/src/inspector.test.ts +17 -17
  179. package/src/inspector.ts +63 -29
  180. package/src/multisig/proposal/execution.ts +66 -49
  181. package/src/multisig/proposal/parser.ts +26 -26
  182. package/src/multisig/signing.ts +4 -4
  183. package/src/multisig.test.ts +2097 -248
  184. package/src/multisig.ts +882 -388
  185. package/src/procedures.ts +50 -26
  186. package/src/proposal/factory.ts +171 -0
  187. package/src/proposal/metadata.ts +165 -0
  188. package/src/proposal/signatures.ts +68 -0
  189. package/src/signer.ts +2 -0
  190. package/src/signers/ecdsa.test.ts +80 -0
  191. package/src/signers/ecdsa.ts +15 -4
  192. package/src/signers/falcon.test.ts +19 -0
  193. package/src/signers/falcon.ts +16 -5
  194. package/src/signers/miden-wallet.test.ts +47 -0
  195. package/src/signers/miden-wallet.ts +18 -1
  196. package/src/signers/para.test.ts +57 -0
  197. package/src/signers/para.ts +26 -7
  198. package/src/transaction/consumeNotes.ts +1 -0
  199. package/src/transaction/index.ts +2 -2
  200. package/src/transaction/options.ts +1 -2
  201. package/src/transaction/p2id.test.ts +190 -0
  202. package/src/transaction/p2id.ts +11 -5
  203. package/src/transaction/rpoRandomCoin.test.ts +64 -0
  204. package/src/transaction/rpoRandomCoin.ts +24 -0
  205. package/src/transaction/{updatePsm.ts → updateGuardian.ts} +19 -32
  206. package/src/transaction/updateProcedureThreshold.ts +97 -0
  207. package/src/transaction/updateSigners.ts +12 -27
  208. package/src/transaction.ts +5 -3
  209. package/src/types/proposal.ts +43 -11
  210. package/src/types.ts +29 -11
  211. package/src/utils/digest.test.ts +55 -0
  212. package/src/utils/digest.ts +51 -1
  213. package/src/utils/signature.ts +47 -9
  214. package/src/utils/word.test.ts +1 -55
  215. package/dist/account.d.ts +0 -104
  216. package/dist/account.d.ts.map +0 -1
  217. package/dist/account.js +0 -136
  218. package/dist/account.js.map +0 -1
  219. package/dist/builder.d.ts +0 -54
  220. package/dist/builder.d.ts.map +0 -1
  221. package/dist/builder.js +0 -78
  222. package/dist/builder.js.map +0 -1
  223. package/dist/http.d.ts +0 -64
  224. package/dist/http.d.ts.map +0 -1
  225. package/dist/http.js +0 -162
  226. package/dist/http.js.map +0 -1
  227. package/dist/keystore.d.ts +0 -65
  228. package/dist/keystore.d.ts.map +0 -1
  229. package/dist/keystore.js +0 -121
  230. package/dist/keystore.js.map +0 -1
  231. package/dist/miden.d.ts +0 -9
  232. package/dist/miden.d.ts.map +0 -1
  233. package/dist/miden.js +0 -26
  234. package/dist/miden.js.map +0 -1
  235. package/dist/multisig/metadata.d.ts +0 -18
  236. package/dist/multisig/metadata.d.ts.map +0 -1
  237. package/dist/multisig/metadata.js +0 -100
  238. package/dist/multisig/metadata.js.map +0 -1
  239. package/dist/multisig/metadata.test.d.ts +0 -2
  240. package/dist/multisig/metadata.test.d.ts.map +0 -1
  241. package/dist/multisig/metadata.test.js +0 -323
  242. package/dist/multisig/metadata.test.js.map +0 -1
  243. package/dist/proposal/exported.d.ts +0 -12
  244. package/dist/proposal/exported.d.ts.map +0 -1
  245. package/dist/proposal/exported.js +0 -88
  246. package/dist/proposal/exported.js.map +0 -1
  247. package/dist/signer.test.d.ts +0 -2
  248. package/dist/signer.test.d.ts.map +0 -1
  249. package/dist/signer.test.js +0 -123
  250. package/dist/signer.test.js.map +0 -1
  251. package/dist/transaction/p2id.interop.test.d.ts +0 -2
  252. package/dist/transaction/p2id.interop.test.d.ts.map +0 -1
  253. package/dist/transaction/p2id.interop.test.js +0 -36
  254. package/dist/transaction/p2id.interop.test.js.map +0 -1
  255. package/dist/transaction/updatePsm.d.ts +0 -7
  256. package/dist/transaction/updatePsm.d.ts.map +0 -1
  257. package/dist/transaction/updatePsm.js.map +0 -1
  258. package/dist/transport/http.d.ts +0 -64
  259. package/dist/transport/http.d.ts.map +0 -1
  260. package/dist/transport/http.js +0 -162
  261. package/dist/transport/http.js.map +0 -1
  262. package/dist/transport/index.d.ts +0 -5
  263. package/dist/transport/index.d.ts.map +0 -1
  264. package/dist/transport/index.js +0 -5
  265. package/dist/transport/index.js.map +0 -1
  266. package/dist/utils/state-validation.d.ts +0 -5
  267. package/dist/utils/state-validation.d.ts.map +0 -1
  268. package/dist/utils/state-validation.js +0 -30
  269. package/dist/utils/state-validation.js.map +0 -1
  270. package/dist/utils/validation.d.ts +0 -6
  271. package/dist/utils/validation.d.ts.map +0 -1
  272. package/dist/utils/validation.js +0 -52
  273. package/dist/utils/validation.js.map +0 -1
  274. package/masm/psm.masm +0 -178
  275. package/masm/psm_ecdsa.masm +0 -179
@@ -1,1035 +1,4 @@
1
- export const MULTISIG_MASM = `# Multi-Signature RPO Falcon 512 Authentication Component
2
- #
3
- # This component provides multi-signature authentication for accounts.
4
- # It integrates with the PSM component for optional PSM signature verification.
5
-
6
- use miden::protocol::active_account
7
- use miden::protocol::native_account
8
- use miden::standards::auth
9
- use openzeppelin::psm
10
-
11
- type BeWord = struct @bigendian { a: felt, b: felt, c: felt, d: felt }
12
-
13
- # CONSTANTS
14
- # =================================================================================================
15
-
16
- # Auth Request Constants
17
-
18
- # The event emitted when a signature is not found for a required signer.
19
- const AUTH_UNAUTHORIZED_EVENT=event("miden::auth::unauthorized")
20
-
21
- # Storage Layout Constants
22
- #
23
- # +-------------------------------+----------+--------------+-------------------+
24
- # | THRESHOLD & APPROVERS CONFIG | PUB KEYS | EXECUTED TXS | PROC THRESHOLDS |
25
- # | (slot) | (map) | (map) | (map) |
26
- # +-------------------------------+----------+--------------+-------------------+
27
- # | 0 | 1 | 2 | 3 |
28
- # +-------------------------------+----------+--------------+-------------------+
29
-
30
- # The slot in this component's storage layout where the default signature threshold and
31
- # number of approvers are stored as:
32
- # [default_threshold, num_approvers, 0, 0].
33
- # The threshold is guaranteed to be less than or equal to num_approvers.
34
- const THRESHOLD_CONFIG_SLOT=word("openzeppelin::multisig::threshold_config")
35
-
36
- # The slot in this component's storage layout where the public keys map is stored.
37
- # Map entries: [key_index, 0, 0, 0] => APPROVER_PUBLIC_KEY
38
- const PUBLIC_KEYS_MAP_SLOT=word("openzeppelin::multisig::signer_public_keys")
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
-
51
- # ERRORS
52
- const ERR_TX_ALREADY_EXECUTED="failed to approve multisig transaction as it was already executed"
53
-
54
- const ERR_MALFORMED_MULTISIG_CONFIG="number of approvers must be equal to or greater than threshold"
55
-
56
- const ERR_ZERO_IN_MULTISIG_CONFIG="number of approvers or threshold must not be zero"
57
-
58
- # MULTISIG PROCEDURES
59
- # =================================================================================================
60
-
61
- #! Check if transaction has already been executed and add it to executed transactions for replay protection.
62
- #!
63
- #! Inputs: [MSG]
64
- #! Outputs: []
65
- #!
66
- #! Panics if:
67
- #! - the same transaction has already been executed
68
- proc assert_new_tx(msg: BeWord)
69
- push.IS_EXECUTED_FLAG
70
- # => [[0, 0, 0, is_executed], MSG]
71
-
72
- swapw
73
- # => [MSG, IS_EXECUTED_FLAG]
74
-
75
- push.EXECUTED_TXS_SLOT[0..2]
76
- # => [txs_slot_prefix, txs_slot_suffix, MSG, IS_EXECUTED_FLAG]
77
-
78
- # Set the key value pair in the map to mark transaction as executed
79
- exec.native_account::set_map_item
80
- # => [[0, 0, 0, is_executed]]
81
-
82
- drop drop drop
83
- # => [is_executed]
84
-
85
- assertz.err=ERR_TX_ALREADY_EXECUTED
86
- # => []
87
- end
88
-
89
- #! Remove old approver public keys from the approver public key mapping.
90
- #!
91
- #! This procedure cleans up the storage by removing public keys of approvers that are no longer
92
- #! part of the multisig configuration. This procedure assumes that init_num_of_approvers and
93
- #! new_num_of_approvers are u32 values.
94
- #!
95
- #! Inputs: [init_num_of_approvers, new_num_of_approvers]
96
- #! Outputs: []
97
- #!
98
- #! Where:
99
- #! - init_num_of_approvers is the original number of approvers before the update
100
- #! - new_num_of_approvers is the new number of approvers after the update
101
- proc cleanup_pubkey_mapping(init_num_of_approvers: u32, new_num_of_approvers: u32)
102
- dup.1 dup.1
103
- u32assert2 u32lt
104
- # => [should_loop, i = init_num_of_approvers, new_num_of_approvers]
105
-
106
- while.true
107
- # => [i, new_num_of_approvers]
108
-
109
- sub.1
110
- # => [i-1, new_num_of_approvers]
111
-
112
- dup
113
- # => [i-1, i-1, new_num_of_approvers]
114
-
115
- push.0.0.0
116
- # => [[0, 0, 0, i-1], i-1, new_num_of_approvers]
117
-
118
- padw swapw
119
- # => [[0, 0, 0, i-1], EMPTY_WORD, i-1, new_num_of_approvers]
120
-
121
- push.PUBLIC_KEYS_MAP_SLOT[0..2]
122
- # => [pub_key_slot_prefix, pub_key_slot_suffix, [0, 0, 0, i-1], EMPTY_WORD, i-1, new_num_of_approvers]
123
-
124
- exec.native_account::set_map_item
125
- # => [OLD_MAP_VALUE, i-1, new_num_of_approvers]
126
-
127
- dropw
128
- # => [i-1, new_num_of_approvers]
129
-
130
- dup.1 dup.1
131
- u32lt
132
- # => [should_loop, i-1, new_num_of_approvers]
133
- end
134
-
135
- drop drop
136
- # => []
137
- end
138
-
139
- #! Update threshold config and add / remove approvers
140
- #!
141
- #! Inputs:
142
- #! Operand stack: [MULTISIG_CONFIG_HASH, pad(12)]
143
- #! Advice map: {
144
- #! MULTISIG_CONFIG_HASH => [CONFIG, PUB_KEY_N, PUB_KEY_N-1, ..., PUB_KEY_0]
145
- #! }
146
- #! Outputs:
147
- #! Operand stack: []
148
- #!
149
- #! Where:
150
- #! - MULTISIG_CONFIG_HASH is the hash of the threshold and new public key vector
151
- #! - MULTISIG_CONFIG is [threshold, num_approvers, 0, 0]
152
- #! - PUB_KEY_i is the public key of the i-th signer
153
- #!
154
- #! Locals:
155
- #! 0: new_num_of_approvers
156
- #! 1: init_num_of_approvers
157
- @locals(2)
158
- pub proc update_signers_and_threshold(multisig_config_hash: BeWord)
159
- adv.push_mapval
160
- # => [MULTISIG_CONFIG_HASH, pad(12)]
161
-
162
- adv_loadw
163
- # => [MULTISIG_CONFIG, pad(12)]
164
-
165
- # store new_num_of_approvers for later
166
- dup.2 loc_store.0
167
- # => [MULTISIG_CONFIG, pad(12)]
168
-
169
- dup.3 dup.3
170
- # => [num_approvers, threshold, MULTISIG_CONFIG, pad(12)]
171
-
172
- # make sure that the threshold is smaller than the number of approvers
173
- u32assert2.err=ERR_MALFORMED_MULTISIG_CONFIG
174
- u32gt assertz.err=ERR_MALFORMED_MULTISIG_CONFIG
175
- # => [MULTISIG_CONFIG, pad(12)]
176
-
177
- dup.3 dup.3
178
- # => [num_approvers, threshold, MULTISIG_CONFIG, pad(12)]
179
-
180
- # make sure that threshold or num_approvers are not zero
181
- eq.0 assertz.err=ERR_ZERO_IN_MULTISIG_CONFIG
182
- eq.0 assertz.err=ERR_ZERO_IN_MULTISIG_CONFIG
183
- # => [MULTISIG_CONFIG, pad(12)]
184
-
185
- push.THRESHOLD_CONFIG_SLOT[0..2]
186
- # => [config_slot_prefix, config_slot_suffix, MULTISIG_CONFIG, pad(12)]
187
-
188
- exec.native_account::set_item
189
- # => [OLD_THRESHOLD_CONFIG, pad(12)]
190
-
191
- # store init_num_of_approvers for later
192
- drop drop loc_store.1 drop
193
- # => [pad(12)]
194
-
195
- loc_load.0
196
- # => [num_approvers]
197
-
198
- dup neq.0
199
- while.true
200
- sub.1
201
- # => [i-1, pad(12)]
202
-
203
- dup push.0.0.0
204
- # => [[0, 0, 0, i-1], i-1, pad(12)]
205
-
206
- padw adv_loadw
207
- # => [PUB_KEY, [0, 0, 0, i-1], i-1, pad(12)]
208
-
209
- swapw
210
- # => [[0, 0, 0, i-1], PUB_KEY, i-1, pad(12)]
211
-
212
- push.PUBLIC_KEYS_MAP_SLOT[0..2]
213
- # => [pub_key_slot_prefix, pub_key_slot_suffix, [0, 0, 0, i-1], PUB_KEY, i-1, pad(12)]
214
-
215
- exec.native_account::set_map_item
216
- # => [OLD_VALUE, i-1, pad(12)]
217
-
218
- dropw
219
- # => [i-1, pad(12)]
220
-
221
- dup neq.0
222
- # => [is_non_zero, i-1, pad(12)]
223
- end
224
- # => [pad(13)]
225
-
226
- drop
227
- # => [pad(12)]
228
-
229
- # compare initial vs current multisig config
230
-
231
- # load init_num_of_approvers & new_num_of_approvers
232
- loc_load.0 loc_load.1
233
- # => [init_num_of_approvers, new_num_of_approvers, pad(12)]
234
-
235
- exec.cleanup_pubkey_mapping
236
- # => [pad(12)]
237
- end
238
-
239
- # Computes the effective transaction threshold based on called procedures and per-procedure
240
- # overrides stored in PROC_THRESHOLD_ROOTS_SLOT. Falls back to default_threshold if no
241
- # overrides apply.
242
- #
243
- #! Inputs: [default_threshold]
244
- #! Outputs: [transaction_threshold]
245
- @locals(1)
246
- proc compute_transaction_threshold(default_threshold: u32) -> u32
247
- # 1. initialize transaction_threshold = 0
248
- # 2. iterate through all account procedures
249
- # a. check if the procedure was called during the transaction
250
- # b. if called, get the override threshold of that procedure from the config map
251
- # c. if proc_threshold > transaction_threshold, set transaction_threshold = proc_threshold
252
- # 3. if transaction_threshold == 0 at the end, revert to using default_threshold
253
-
254
- # store default_threshold for later
255
- loc_store.0
256
- # => []
257
-
258
- # 1. initialize transaction_threshold = 0
259
- push.0
260
- # => [transaction_threshold]
261
-
262
- # get the number of account procedures
263
- exec.active_account::get_num_procedures
264
- # => [num_procedures, transaction_threshold]
265
-
266
- # 2. iterate through all account procedures
267
- dup neq.0
268
- # => [should_continue, num_procedures, transaction_threshold]
269
- while.true
270
- sub.1 dup
271
- # => [num_procedures-1, num_procedures-1, transaction_threshold]
272
-
273
- # get procedure root of the procedure with index i
274
- exec.active_account::get_procedure_root dupw
275
- # => [PROC_ROOT, PROC_ROOT, num_procedures-1, transaction_threshold]
276
-
277
- # 2a. check if this procedure has been called in the transaction
278
- exec.native_account::was_procedure_called
279
- # => [was_called, PROC_ROOT, num_procedures-1, transaction_threshold]
280
-
281
- # if it has been called, get the override threshold of that procedure
282
- if.true
283
- # => [PROC_ROOT, num_procedures-1, transaction_threshold]
284
-
285
- push.PROC_THRESHOLD_ROOTS_SLOT[0..2]
286
- # => [PROC_THRESHOLD_ROOTS_SLOT_prefix, PROC_THRESHOLD_ROOTS_SLOT_suffix, PROC_ROOT, num_procedures-1, transaction_threshold]
287
-
288
- # 2b. get the override proc_threshold of that procedure
289
- # if the procedure has no override threshold, the returned map item will be [0, 0, 0, 0]
290
- exec.active_account::get_initial_map_item
291
- # => [[0, 0, 0, proc_threshold], num_procedures-1, transaction_threshold]
292
-
293
- drop drop drop dup dup.3
294
- # => [transaction_threshold, proc_threshold, proc_threshold, num_procedures-1, transaction_threshold]
295
-
296
- u32assert2.err="transaction threshold or procedure threshold are not u32"
297
- u32gt
298
- # => [is_gt, proc_threshold, num_procedures-1, transaction_threshold]
299
- # 2c. if proc_threshold > transaction_threshold, update transaction_threshold
300
- movup.2 movdn.3
301
- # => [is_gt, proc_threshold, transaction_threshold, num_procedures-1]
302
- cdrop
303
- # => [updated_transaction_threshold, num_procedures-1]
304
- swap
305
- # => [num_procedures-1, updated_transaction_threshold]
306
- # if it has not been called during this transaction, nothing to do, move to the next procedure
307
- else
308
- dropw
309
- # => [num_procedures-1, transaction_threshold]
310
- end
311
-
312
- dup neq.0
313
- # => [should_continue, num_procedures-1, transaction_threshold]
314
- end
315
-
316
- drop
317
- # => [transaction_threshold]
318
-
319
- loc_load.0
320
- # => [default_threshold, transaction_threshold]
321
-
322
- # 3. if transaction_threshold == 0 at the end, revert to using default_threshold
323
- dup.1 eq.0
324
- # => [is_zero, default_threshold, transaction_threshold]
325
-
326
- cdrop
327
- # => [effective_transaction_threshold]
328
- end
329
-
330
- #! Authenticate a transaction using the Falcon signature scheme with multi-signature support.
331
- #!
332
- #! This procedure implements multi-signature authentication by:
333
- #! 1. Computing the transaction summary message that needs to be signed
334
- #! 2. Verifying signatures from multiple required signers against their public keys
335
- #! 3. Ensuring the minimum threshold of valid signatures is met
336
- #! 4. Implementing replay protection by tracking executed transactions
337
- #! 5. Verifying PSM signature if PSM selector is enabled (via PSM component)
338
- #!
339
- #! Inputs:
340
- #! Operand stack: [SALT]
341
- #! Advice map: {
342
- #! h(SIG_0, MSG): SIG_0,
343
- #! h(SIG_1, MSG): SIG_1,
344
- #! h(SIG_n, MSG): SIG_n
345
- #! }
346
- #! Outputs:
347
- #! Operand stack: []
348
- #!
349
- #! Where:
350
- #! - SALT is a cryptographically random nonce that enables multiple concurrent
351
- #! multisig transactions while maintaining replay protection. Each transaction
352
- #! must use a unique SALT value to ensure transaction uniqueness.
353
- #! - SIG_i is the signature from the i-th signer.
354
- #! - MSG is the transaction message being signed.
355
- #! - h(SIG_i, MSG) is the hash of the signature and message used as the advice map key.
356
- #!
357
- #! Panics if:
358
- #! - insufficient number of valid signatures (below threshold).
359
- #! - the same transaction has already been executed (replay protection).
360
- #! - PSM signature verification fails (if PSM is enabled).
361
- #!
362
- #! Invocation: call
363
- @locals(1)
364
- pub proc auth_tx_rpo_falcon512_multisig(salt: BeWord)
365
- exec.native_account::incr_nonce drop
366
- # => [SALT]
367
-
368
- # ------ Computing transaction summary ------
369
-
370
- exec.auth::create_tx_summary
371
- # => [SALT, OUTPUT_NOTES_COMMITMENT, INPUT_NOTES_COMMITMENT, ACCOUNT_DELTA_COMMITMENT]
372
-
373
- # to build a tx_summary in the host, we need these four words in the advice provider
374
- exec.auth::adv_insert_hqword
375
- # => [SALT, OUTPUT_NOTES_COMMITMENT, INPUT_NOTES_COMMITMENT, ACCOUNT_DELTA_COMMITMENT]
376
-
377
- # the commitment to the tx summary is the message that is signed
378
- exec.auth::hash_tx_summary
379
- # => [TX_SUMMARY_COMMITMENT]
380
-
381
- # ------ Verifying approver signatures ------
382
-
383
- push.THRESHOLD_CONFIG_SLOT[0..2]
384
- # => [config_slot_prefix, config_slot_suffix, TX_SUMMARY_COMMITMENT]
385
-
386
- exec.active_account::get_initial_item
387
- # => [0, 0, num_of_approvers, default_threshold, TX_SUMMARY_COMMITMENT]
388
-
389
- drop drop
390
- # => [num_of_approvers, default_threshold, TX_SUMMARY_COMMITMENT]
391
-
392
- swap movdn.5
393
- # => [num_of_approvers, TX_SUMMARY_COMMITMENT, default_threshold]
394
-
395
- push.PUBLIC_KEYS_MAP_SLOT[0..2]
396
- # => [pub_key_slot_prefix, pub_key_slot_suffix, num_of_approvers, TX_SUMMARY_COMMITMENT, default_threshold]
397
-
398
- exec.::miden::standards::auth::falcon512_rpo::verify_signatures
399
- # => [num_verified_signatures, TX_SUMMARY_COMMITMENT, default_threshold]
400
-
401
- # ------ Checking threshold is >= num_verified_signatures ------
402
-
403
- movup.5
404
- # => [default_threshold, num_verified_signatures, TX_SUMMARY_COMMITMENT]
405
-
406
- exec.compute_transaction_threshold
407
- # => [transaction_threshold, num_verified_signatures, TX_SUMMARY_COMMITMENT]
408
-
409
- u32assert2 u32lt
410
- # => [is_unauthorized, TX_SUMMARY_COMMITMENT]
411
-
412
- # If signatures are non-existent the tx will fail here.
413
- if.true
414
- emit.AUTH_UNAUTHORIZED_EVENT
415
- push.0 assert.err="insufficient number of signatures"
416
- end
417
-
418
- # ------ Verifying PSM Signature ------
419
- # => [TX_SUMMARY_COMMITMENT]
420
- call.psm::verify_psm_signature
421
-
422
- # ------ Writing executed transaction MSG to map ------
423
- # => [TX_SUMMARY_COMMITMENT]
424
- exec.assert_new_tx
425
- end
426
- `;
427
- export const MULTISIG_ECDSA_MASM = `# Multi-Signature ECDSA secp256k1 Authentication Component
428
- #
429
- # This component provides multi-signature authentication for accounts using
430
- # ECDSA secp256k1 (k256/keccak) signatures instead of RPO Falcon 512.
431
- # It integrates with the PSM component for optional PSM signature verification.
432
-
433
- use miden::protocol::active_account
434
- use miden::protocol::native_account
435
- use miden::standards::auth
436
- use openzeppelin::psm_ecdsa
437
-
438
- type BeWord = struct @bigendian { a: felt, b: felt, c: felt, d: felt }
439
-
440
- # CONSTANTS
441
- # =================================================================================================
442
-
443
- # Auth Request Constants
444
-
445
- # The event emitted when a signature is not found for a required signer.
446
- const AUTH_UNAUTHORIZED_EVENT=event("miden::auth::unauthorized")
447
-
448
- # Storage Layout Constants
449
- #
450
- # +-------------------------------+----------+--------------+-------------------+
451
- # | THRESHOLD & APPROVERS CONFIG | PUB KEYS | EXECUTED TXS | PROC THRESHOLDS |
452
- # | (slot) | (map) | (map) | (map) |
453
- # +-------------------------------+----------+--------------+-------------------+
454
- # | 0 | 1 | 2 | 3 |
455
- # +-------------------------------+----------+--------------+-------------------+
456
-
457
- # The slot in this component's storage layout where the default signature threshold and
458
- # number of approvers are stored as:
459
- # [default_threshold, num_approvers, 0, 0].
460
- # The threshold is guaranteed to be less than or equal to num_approvers.
461
- const THRESHOLD_CONFIG_SLOT=word("openzeppelin::multisig::threshold_config")
462
-
463
- # The slot in this component's storage layout where the public keys map is stored.
464
- # Map entries: [key_index, 0, 0, 0] => APPROVER_PUBLIC_KEY
465
- const PUBLIC_KEYS_MAP_SLOT=word("openzeppelin::multisig::signer_public_keys")
466
-
467
- # The slot in this component's storage layout where executed transactions are stored.
468
- # Map entries: transaction_message => [is_executed, 0, 0, 0]
469
- const EXECUTED_TXS_SLOT=word("openzeppelin::multisig::executed_transactions")
470
-
471
- # The slot in this component's storage layout where procedure thresholds are stored.
472
- # Map entries: PROC_ROOT => [proc_threshold, 0, 0, 0]
473
- const PROC_THRESHOLD_ROOTS_SLOT=word("openzeppelin::multisig::procedure_thresholds")
474
-
475
- # Executed Transaction Flag Constant
476
- const IS_EXECUTED_FLAG=[1, 0, 0, 0]
477
-
478
- # ERRORS
479
- const ERR_TX_ALREADY_EXECUTED="failed to approve multisig transaction as it was already executed"
480
-
481
- const ERR_MALFORMED_MULTISIG_CONFIG="number of approvers must be equal to or greater than threshold"
482
-
483
- const ERR_ZERO_IN_MULTISIG_CONFIG="number of approvers or threshold must not be zero"
484
-
485
- # MULTISIG PROCEDURES
486
- # =================================================================================================
487
-
488
- #! Check if transaction has already been executed and add it to executed transactions for replay protection.
489
- #!
490
- #! Inputs: [MSG]
491
- #! Outputs: []
492
- #!
493
- #! Panics if:
494
- #! - the same transaction has already been executed
495
- proc assert_new_tx(msg: BeWord)
496
- push.IS_EXECUTED_FLAG
497
- # => [[0, 0, 0, is_executed], MSG]
498
-
499
- swapw
500
- # => [MSG, IS_EXECUTED_FLAG]
501
-
502
- push.EXECUTED_TXS_SLOT[0..2]
503
- # => [txs_slot_prefix, txs_slot_suffix, MSG, IS_EXECUTED_FLAG]
504
-
505
- # Set the key value pair in the map to mark transaction as executed
506
- exec.native_account::set_map_item
507
- # => [[0, 0, 0, is_executed]]
508
-
509
- drop drop drop
510
- # => [is_executed]
511
-
512
- assertz.err=ERR_TX_ALREADY_EXECUTED
513
- # => []
514
- end
515
-
516
- #! Remove old approver public keys from the approver public key mapping.
517
- #!
518
- #! This procedure cleans up the storage by removing public keys of approvers that are no longer
519
- #! part of the multisig configuration. This procedure assumes that init_num_of_approvers and
520
- #! new_num_of_approvers are u32 values.
521
- #!
522
- #! Inputs: [init_num_of_approvers, new_num_of_approvers]
523
- #! Outputs: []
524
- #!
525
- #! Where:
526
- #! - init_num_of_approvers is the original number of approvers before the update
527
- #! - new_num_of_approvers is the new number of approvers after the update
528
- proc cleanup_pubkey_mapping(init_num_of_approvers: u32, new_num_of_approvers: u32)
529
- dup.1 dup.1
530
- u32assert2 u32lt
531
- # => [should_loop, i = init_num_of_approvers, new_num_of_approvers]
532
-
533
- while.true
534
- # => [i, new_num_of_approvers]
535
-
536
- sub.1
537
- # => [i-1, new_num_of_approvers]
538
-
539
- dup
540
- # => [i-1, i-1, new_num_of_approvers]
541
-
542
- push.0.0.0
543
- # => [[0, 0, 0, i-1], i-1, new_num_of_approvers]
544
-
545
- padw swapw
546
- # => [[0, 0, 0, i-1], EMPTY_WORD, i-1, new_num_of_approvers]
547
-
548
- push.PUBLIC_KEYS_MAP_SLOT[0..2]
549
- # => [pub_key_slot_prefix, pub_key_slot_suffix, [0, 0, 0, i-1], EMPTY_WORD, i-1, new_num_of_approvers]
550
-
551
- exec.native_account::set_map_item
552
- # => [OLD_MAP_VALUE, i-1, new_num_of_approvers]
553
-
554
- dropw
555
- # => [i-1, new_num_of_approvers]
556
-
557
- dup.1 dup.1
558
- u32lt
559
- # => [should_loop, i-1, new_num_of_approvers]
560
- end
561
-
562
- drop drop
563
- # => []
564
- end
565
-
566
- #! Update threshold config and add / remove approvers
567
- #!
568
- #! Inputs:
569
- #! Operand stack: [MULTISIG_CONFIG_HASH, pad(12)]
570
- #! Advice map: {
571
- #! MULTISIG_CONFIG_HASH => [CONFIG, PUB_KEY_N, PUB_KEY_N-1, ..., PUB_KEY_0]
572
- #! }
573
- #! Outputs:
574
- #! Operand stack: []
575
- #!
576
- #! Where:
577
- #! - MULTISIG_CONFIG_HASH is the hash of the threshold and new public key vector
578
- #! - MULTISIG_CONFIG is [threshold, num_approvers, 0, 0]
579
- #! - PUB_KEY_i is the public key of the i-th signer
580
- #!
581
- #! Locals:
582
- #! 0: new_num_of_approvers
583
- #! 1: init_num_of_approvers
584
- @locals(2)
585
- pub proc update_signers_and_threshold(multisig_config_hash: BeWord)
586
- adv.push_mapval
587
- # => [MULTISIG_CONFIG_HASH, pad(12)]
588
-
589
- adv_loadw
590
- # => [MULTISIG_CONFIG, pad(12)]
591
-
592
- # store new_num_of_approvers for later
593
- dup.2 loc_store.0
594
- # => [MULTISIG_CONFIG, pad(12)]
595
-
596
- dup.3 dup.3
597
- # => [num_approvers, threshold, MULTISIG_CONFIG, pad(12)]
598
-
599
- # make sure that the threshold is smaller than the number of approvers
600
- u32assert2.err=ERR_MALFORMED_MULTISIG_CONFIG
601
- u32gt assertz.err=ERR_MALFORMED_MULTISIG_CONFIG
602
- # => [MULTISIG_CONFIG, pad(12)]
603
-
604
- dup.3 dup.3
605
- # => [num_approvers, threshold, MULTISIG_CONFIG, pad(12)]
606
-
607
- # make sure that threshold or num_approvers are not zero
608
- eq.0 assertz.err=ERR_ZERO_IN_MULTISIG_CONFIG
609
- eq.0 assertz.err=ERR_ZERO_IN_MULTISIG_CONFIG
610
- # => [MULTISIG_CONFIG, pad(12)]
611
-
612
- push.THRESHOLD_CONFIG_SLOT[0..2]
613
- # => [config_slot_prefix, config_slot_suffix, MULTISIG_CONFIG, pad(12)]
614
-
615
- exec.native_account::set_item
616
- # => [OLD_THRESHOLD_CONFIG, pad(12)]
617
-
618
- # store init_num_of_approvers for later
619
- drop drop loc_store.1 drop
620
- # => [pad(12)]
621
-
622
- loc_load.0
623
- # => [num_approvers]
624
-
625
- dup neq.0
626
- while.true
627
- sub.1
628
- # => [i-1, pad(12)]
629
-
630
- dup push.0.0.0
631
- # => [[0, 0, 0, i-1], i-1, pad(12)]
632
-
633
- padw adv_loadw
634
- # => [PUB_KEY, [0, 0, 0, i-1], i-1, pad(12)]
635
-
636
- swapw
637
- # => [[0, 0, 0, i-1], PUB_KEY, i-1, pad(12)]
638
-
639
- push.PUBLIC_KEYS_MAP_SLOT[0..2]
640
- # => [pub_key_slot_prefix, pub_key_slot_suffix, [0, 0, 0, i-1], PUB_KEY, i-1, pad(12)]
641
-
642
- exec.native_account::set_map_item
643
- # => [OLD_VALUE, i-1, pad(12)]
644
-
645
- dropw
646
- # => [i-1, pad(12)]
647
-
648
- dup neq.0
649
- # => [is_non_zero, i-1, pad(12)]
650
- end
651
- # => [pad(13)]
652
-
653
- drop
654
- # => [pad(12)]
655
-
656
- # compare initial vs current multisig config
657
-
658
- # load init_num_of_approvers & new_num_of_approvers
659
- loc_load.0 loc_load.1
660
- # => [init_num_of_approvers, new_num_of_approvers, pad(12)]
661
-
662
- exec.cleanup_pubkey_mapping
663
- # => [pad(12)]
664
- end
665
-
666
- # Computes the effective transaction threshold based on called procedures and per-procedure
667
- # overrides stored in PROC_THRESHOLD_ROOTS_SLOT. Falls back to default_threshold if no
668
- # overrides apply.
669
- #
670
- #! Inputs: [default_threshold]
671
- #! Outputs: [transaction_threshold]
672
- @locals(1)
673
- proc compute_transaction_threshold(default_threshold: u32) -> u32
674
- # 1. initialize transaction_threshold = 0
675
- # 2. iterate through all account procedures
676
- # a. check if the procedure was called during the transaction
677
- # b. if called, get the override threshold of that procedure from the config map
678
- # c. if proc_threshold > transaction_threshold, set transaction_threshold = proc_threshold
679
- # 3. if transaction_threshold == 0 at the end, revert to using default_threshold
680
-
681
- # store default_threshold for later
682
- loc_store.0
683
- # => []
684
-
685
- # 1. initialize transaction_threshold = 0
686
- push.0
687
- # => [transaction_threshold]
688
-
689
- # get the number of account procedures
690
- exec.active_account::get_num_procedures
691
- # => [num_procedures, transaction_threshold]
692
-
693
- # 2. iterate through all account procedures
694
- dup neq.0
695
- # => [should_continue, num_procedures, transaction_threshold]
696
- while.true
697
- sub.1 dup
698
- # => [num_procedures-1, num_procedures-1, transaction_threshold]
699
-
700
- # get procedure root of the procedure with index i
701
- exec.active_account::get_procedure_root dupw
702
- # => [PROC_ROOT, PROC_ROOT, num_procedures-1, transaction_threshold]
703
-
704
- # 2a. check if this procedure has been called in the transaction
705
- exec.native_account::was_procedure_called
706
- # => [was_called, PROC_ROOT, num_procedures-1, transaction_threshold]
707
-
708
- # if it has been called, get the override threshold of that procedure
709
- if.true
710
- # => [PROC_ROOT, num_procedures-1, transaction_threshold]
711
-
712
- push.PROC_THRESHOLD_ROOTS_SLOT[0..2]
713
- # => [PROC_THRESHOLD_ROOTS_SLOT_prefix, PROC_THRESHOLD_ROOTS_SLOT_suffix, PROC_ROOT, num_procedures-1, transaction_threshold]
714
-
715
- # 2b. get the override proc_threshold of that procedure
716
- # if the procedure has no override threshold, the returned map item will be [0, 0, 0, 0]
717
- exec.active_account::get_initial_map_item
718
- # => [[0, 0, 0, proc_threshold], num_procedures-1, transaction_threshold]
719
-
720
- drop drop drop dup dup.3
721
- # => [transaction_threshold, proc_threshold, proc_threshold, num_procedures-1, transaction_threshold]
722
-
723
- u32assert2.err="transaction threshold or procedure threshold are not u32"
724
- u32gt
725
- # => [is_gt, proc_threshold, num_procedures-1, transaction_threshold]
726
- # 2c. if proc_threshold > transaction_threshold, update transaction_threshold
727
- movup.2 movdn.3
728
- # => [is_gt, proc_threshold, transaction_threshold, num_procedures-1]
729
- cdrop
730
- # => [updated_transaction_threshold, num_procedures-1]
731
- swap
732
- # => [num_procedures-1, updated_transaction_threshold]
733
- # if it has not been called during this transaction, nothing to do, move to the next procedure
734
- else
735
- dropw
736
- # => [num_procedures-1, transaction_threshold]
737
- end
738
-
739
- dup neq.0
740
- # => [should_continue, num_procedures-1, transaction_threshold]
741
- end
742
-
743
- drop
744
- # => [transaction_threshold]
745
-
746
- loc_load.0
747
- # => [default_threshold, transaction_threshold]
748
-
749
- # 3. if transaction_threshold == 0 at the end, revert to using default_threshold
750
- dup.1 eq.0
751
- # => [is_zero, default_threshold, transaction_threshold]
752
-
753
- cdrop
754
- # => [effective_transaction_threshold]
755
- end
756
-
757
- #! Authenticate a transaction using ECDSA secp256k1 with multi-signature support.
758
- #!
759
- #! This procedure implements multi-signature authentication by:
760
- #! 1. Computing the transaction summary message that needs to be signed
761
- #! 2. Verifying ECDSA signatures from multiple required signers against their public keys
762
- #! 3. Ensuring the minimum threshold of valid signatures is met
763
- #! 4. Implementing replay protection by tracking executed transactions
764
- #! 5. Verifying PSM signature if PSM selector is enabled (via PSM component)
765
- #!
766
- #! Inputs:
767
- #! Operand stack: [SALT]
768
- #! Advice map: {
769
- #! h(PUB_KEY_0, MSG): SIG_0,
770
- #! h(PUB_KEY_1, MSG): SIG_1,
771
- #! h(PUB_KEY_n, MSG): SIG_n
772
- #! }
773
- #! Outputs:
774
- #! Operand stack: []
775
- #!
776
- #! Where:
777
- #! - SALT is a cryptographically random nonce that enables multiple concurrent
778
- #! multisig transactions while maintaining replay protection. Each transaction
779
- #! must use a unique SALT value to ensure transaction uniqueness.
780
- #! - SIG_i is the ECDSA signature from the i-th signer.
781
- #! - MSG is the transaction message being signed.
782
- #! - h(PUB_KEY_i, MSG) is the hash of the public key and message used as the advice map key.
783
- #!
784
- #! Panics if:
785
- #! - insufficient number of valid signatures (below threshold).
786
- #! - the same transaction has already been executed (replay protection).
787
- #! - PSM signature verification fails (if PSM is enabled).
788
- #!
789
- #! Invocation: call
790
- @locals(1)
791
- pub proc auth_tx_ecdsa_multisig(salt: BeWord)
792
- exec.native_account::incr_nonce drop
793
- # => [SALT]
794
-
795
- # ------ Computing transaction summary ------
796
-
797
- exec.auth::create_tx_summary
798
- # => [SALT, OUTPUT_NOTES_COMMITMENT, INPUT_NOTES_COMMITMENT, ACCOUNT_DELTA_COMMITMENT]
799
-
800
- # to build a tx_summary in the host, we need these four words in the advice provider
801
- exec.auth::adv_insert_hqword
802
- # => [SALT, OUTPUT_NOTES_COMMITMENT, INPUT_NOTES_COMMITMENT, ACCOUNT_DELTA_COMMITMENT]
803
-
804
- # the commitment to the tx summary is the message that is signed
805
- exec.auth::hash_tx_summary
806
- # => [TX_SUMMARY_COMMITMENT]
807
-
808
- # ------ Verifying approver signatures ------
809
-
810
- push.THRESHOLD_CONFIG_SLOT[0..2]
811
- # => [config_slot_prefix, config_slot_suffix, TX_SUMMARY_COMMITMENT]
812
-
813
- exec.active_account::get_initial_item
814
- # => [0, 0, num_of_approvers, default_threshold, TX_SUMMARY_COMMITMENT]
815
-
816
- drop drop
817
- # => [num_of_approvers, default_threshold, TX_SUMMARY_COMMITMENT]
818
-
819
- swap movdn.5
820
- # => [num_of_approvers, TX_SUMMARY_COMMITMENT, default_threshold]
821
-
822
- push.PUBLIC_KEYS_MAP_SLOT[0..2]
823
- # => [pub_key_slot_prefix, pub_key_slot_suffix, num_of_approvers, TX_SUMMARY_COMMITMENT, default_threshold]
824
-
825
- exec.::miden::standards::auth::ecdsa_k256_keccak::verify_signatures
826
- # => [num_verified_signatures, TX_SUMMARY_COMMITMENT, default_threshold]
827
-
828
- # ------ Checking threshold is >= num_verified_signatures ------
829
-
830
- movup.5
831
- # => [default_threshold, num_verified_signatures, TX_SUMMARY_COMMITMENT]
832
-
833
- exec.compute_transaction_threshold
834
- # => [transaction_threshold, num_verified_signatures, TX_SUMMARY_COMMITMENT]
835
-
836
- u32assert2 u32lt
837
- # => [is_unauthorized, TX_SUMMARY_COMMITMENT]
838
-
839
- # If signatures are non-existent the tx will fail here.
840
- if.true
841
- emit.AUTH_UNAUTHORIZED_EVENT
842
- push.0 assert.err="insufficient number of signatures"
843
- end
844
-
845
- # ------ Verifying PSM Signature ------
846
- # => [TX_SUMMARY_COMMITMENT]
847
- call.psm_ecdsa::verify_psm_signature
848
-
849
- # ------ Writing executed transaction MSG to map ------
850
- # => [TX_SUMMARY_COMMITMENT]
851
- exec.assert_new_tx
852
- end
853
- `;
854
- export const PSM_MASM = `# Private State Manager (PSM) Authentication Component
855
- #
856
- # This component provides PSM signature verification for accounts.
857
- # It can be used standalone or in conjunction with other auth components like multisig.
858
-
859
- use miden::protocol::active_account
860
- use miden::protocol::native_account
861
-
862
- type BeWord = struct @bigendian { a: felt, b: felt, c: felt, d: felt }
863
-
864
- # IMPORTANT SECURITY NOTES
865
- # --------------------------------------------------------------------------------
866
- # - The selector in \`PSM_SELECTOR_SLOT\` controls whether the extra PSM signature
867
- # is enforced:
868
- # * PSM_ON => exactly one valid PSM signature is required.
869
- # * PSM_OFF => PSM signature is skipped for that call.
870
- #
871
- # - \`verify_psm_signature\` reads the selector from initial storage state.
872
- # This means changes made during the same transaction won't affect the check.
873
- #
874
- # - \`enable_psm\` / \`disable_psm\` procedures allow explicit control over PSM state.
875
- #
876
- # - \`update_psm_public_key\`:
877
- # * Installs a new PSM public key in the map at \`PSM_PUBLIC_KEY_MAP_SLOT\`.
878
- # * Does not itself perform any signature checks.
879
- # * To update the key without requiring PSM signature, ensure selector is OFF.
880
- #
881
- # Storage Layout
882
- # --------------------------------------------------------------------------------
883
- #
884
- # +---------------------+---------------+
885
- # | DESCRIPTION | SLOT |
886
- # +---------------------+---------------+
887
- # | PSM SELECTOR (word) | 0 |
888
- # | PSM PUBLIC KEY MAP | 1 |
889
- # +---------------------+---------------+
890
- #
891
- # - PSM_SELECTOR_SLOT (0):
892
- # * Stores a word that is compared against [1, 0, 0, 0] (PSM_ON).
893
- # * Any value != PSM_ON is treated as PSM_OFF.
894
- #
895
- # - PSM_PUBLIC_KEY_MAP_SLOT (1):
896
- # * A map from a fixed key [0, 0, 0, 0] to the single PSM public key:
897
- # [0, 0, 0, 0] => PSM_PUBLIC_KEY
898
- # * PSM_PUBLIC_KEY is a RPO Falcon 512 public key represented as a word.
899
-
900
- # CONSTANTS
901
- # =================================================================================================
902
-
903
- # Slot where the PSM selector flag is stored (using word() for named slot access):
904
- # - PSM_ON => PSM signature required
905
- # - PSM_OFF => PSM signature skipped
906
- const PSM_SELECTOR_SLOT=word("openzeppelin::psm::selector")
907
-
908
- # Map slot for PSM public key
909
- # Uses exactly one PSM public key at index [0, 0, 0, 0]
910
- # [0, 0, 0, 0] => PSM_PUBLIC_KEY
911
- const PSM_PUBLIC_KEY_MAP_SLOT=word("openzeppelin::psm::public_key")
912
-
913
- # Selector flag values
914
- const PSM_ON=[1, 0, 0, 0]
915
- const PSM_OFF=[0, 0, 0, 0]
916
-
917
- # The event emitted when a signature is not found for a required signer.
918
- const AUTH_UNAUTHORIZED_EVENT=event("miden::auth::unauthorized")
919
-
920
- # PSM PROCEDURES
921
- # =================================================================================================
922
-
923
- #! Enable PSM verification by setting the selector to ON.
924
- #!
925
- #! Operand stack inputs: []
926
- #! Outputs: []
927
- #!
928
- #! Notes:
929
- #! - Sets PSM_SELECTOR_SLOT to PSM_ON (1)
930
- #! - After this, transactions will require PSM signature verification
931
- proc enable_psm
932
- push.PSM_ON
933
- # => [PSM_ON]
934
-
935
- push.PSM_SELECTOR_SLOT[0..2]
936
- # => [selector_slot_prefix, selector_slot_suffix, PSM_ON]
937
-
938
- exec.native_account::set_item
939
- # => [OLD_ROOT]
940
-
941
- dropw
942
- # => []
943
- end
944
-
945
- #! Disable PSM verification by setting the selector to OFF.
946
- #!
947
- #! Operand stack inputs: []
948
- #! Outputs: []
949
- #!
950
- #! Notes:
951
- #! - Sets PSM_SELECTOR_SLOT to PSM_OFF (0)
952
- #! - After this, transactions will NOT require PSM signature verification
953
- proc disable_psm
954
- push.PSM_OFF
955
- # => [PSM_OFF]
956
-
957
- push.PSM_SELECTOR_SLOT[0..2]
958
- # => [selector_slot_prefix, selector_slot_suffix, PSM_OFF]
959
-
960
- exec.native_account::set_item
961
- # => [OLD_ROOT]
962
-
963
- dropw
964
- # => []
965
- end
966
-
967
- #! Update the PSM public key.
968
- #!
969
- #! Operand stack inputs: []
970
- #! Advice stack inputs: [PUB_KEY]
971
- #! - PUB_KEY is the new PSM RPO Falcon 512 public key
972
- #!
973
- #! Notes:
974
- #! - Stores PUB_KEY into PSM_PUBLIC_KEY_MAP_SLOT:
975
- #! [0, 0, 0, 0] => PSM_PUBLIC_KEY
976
- #! - To update the key without requiring PSM signature, ensure
977
- #! PSM_SELECTOR_SLOT = 0 (OFF) before calling this.
978
- pub proc update_psm_public_key
979
- exec.disable_psm
980
- # ------ Update the PSM public key ------
981
- adv_loadw
982
- # => [PUB_KEY]
983
-
984
- push.0.0.0.0
985
- # => [MAP_KEY, PUB_KEY]
986
- # Note that MAP_KEY is [0, 0, 0, 0] for a single PSM_KEY
987
-
988
- push.PSM_PUBLIC_KEY_MAP_SLOT[0..2]
989
- # => [pub_key_slot_prefix, pub_key_slot_suffix, MAP_KEY, PUB_KEY]
990
-
991
- exec.native_account::set_map_item
992
- # => [OLD_MAP_VALUE]
993
-
994
- dropw
995
- # => []
996
- end
997
-
998
- #! Conditionally verify a "PSM" signature against a stored public key hash.
999
- #! The condition is controlled by the selector at PSM_SELECTOR_SLOT.
1000
- #!
1001
- #! Inputs: [MSG]
1002
- #! Outputs: [MSG]
1003
- #!
1004
- #! Panics if:
1005
- #! - Selector is ON but the provided PSM signature is invalid or missing.
1006
- #!
1007
- #! Notes:
1008
- #! - MSG is TX_SUMMARY_COMMITMENT provided by auth procedure
1009
- #! - If selector is OFF (0), PSM verification is skipped
1010
- #! - Selector value is read from initial storage state
1011
- pub proc verify_psm_signature(msg: BeWord) -> BeWord
1012
- push.PSM_SELECTOR_SLOT[0..2]
1013
- exec.active_account::get_item
1014
- drop drop drop
1015
- # => [selector, MSG]
1016
-
1017
- push.1 eq
1018
- if.true
1019
- push.1
1020
- push.PSM_PUBLIC_KEY_MAP_SLOT[0..2]
1021
- exec.::miden::standards::auth::falcon512_rpo::verify_signatures
1022
- push.1 neq
1023
- if.true
1024
- emit.AUTH_UNAUTHORIZED_EVENT
1025
- push.0 assert.err="invalid PSM signature"
1026
- end
1027
- end
1028
- # => [MSG]
1029
- exec.enable_psm
1030
- end
1031
- `;
1032
- export const PSM_ECDSA_MASM = PSM_MASM
1033
- .replaceAll('RPO Falcon 512', 'ECDSA secp256k1')
1034
- .replace('exec.::miden::standards::auth::falcon512_rpo::verify_signatures', 'exec.::miden::standards::auth::ecdsa_k256_keccak::verify_signatures');
1
+ // This file is generated by scripts/generate-masm.mjs from the MASM contract sources.
2
+ // Do not edit it by hand.
3
+ export * from './masm/index.js';
1035
4
  //# sourceMappingURL=masm.js.map