-
Notifications
You must be signed in to change notification settings - Fork 166
Expand file tree
/
Copy pathsinglesig_acl.masm
More file actions
149 lines (118 loc) · 5.23 KB
/
Copy pathsinglesig_acl.masm
File metadata and controls
149 lines (118 loc) · 5.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# The MASM code of the signature-based authentication Account Component with an exempt-list ACL.
#
# See the `AuthSingleSigAcl` Rust type's documentation for more details.
use miden::protocol::active_account
use miden::protocol::native_account
use miden::standards::auth::signature
use miden::core::word
# CONSTANTS
# ================================================================================================
# The slot in this component's storage layout where the public key is stored.
const PUBLIC_KEY_SLOT = word("miden::standards::auth::singlesig_acl::pub_key")
# The slot in this component's storage layout where the corresponding signature scheme id is stored.
const SCHEME_ID_SLOT = word("miden::standards::auth::singlesig_acl::scheme")
# The slot where the map of procedure roots exempt from requiring a signature is stored.
# Map entries: `PROC_ROOT => [1, 0, 0, 0]`
const EXEMPT_PROCEDURE_ROOTS_SLOT = word("miden::standards::auth::singlesig_acl::exempt_procedure_roots")
#! Authenticate a transaction using the signature scheme specified by scheme_id.
#!
#! Supported schemes:
#! - 1 => ecdsa_k256_keccak
#! - 2 => falcon512_poseidon2
#!
#! Authentication is required if a non-auth kernel-detected procedure not on the exempt list
#! was called.
#!
#! Notice that asset removal from the account vault uses a kernel-tracked procedure, so any
#! transaction which moves assets out of the account will be authenticated unless all the
#! procedures required for that are explicitly added to the exempt list.
#!
#! If authentication is required, the configured signature is verified. Otherwise, the nonce
#! is conditionally incremented when the account state changed or the account is new.
#!
#! Inputs: [AUTH_ARGS, pad(12)]
#! Outputs: [pad(16)]
#!
#! Invocation: call
@auth_script
pub proc auth_tx_acl(auth_args: word)
dropw
# => [pad(16)]
# ------ Iterate procedures to determine whether any non-exempt proc was called ------
# By default we assume no authentication required, look for conditions to change that
push.0
# => [auth_required, pad(16)]
exec.active_account::get_num_procedures
# => [num_procedures, auth_required, pad(16)]
# Iterate indices from `num_procedures-1` down to `1`. That way we can skip the
# authentication procedure itself located at index `0`.
dup neq.1
# => [should_continue, num_procedures, auth_required, pad(16)]
while.true
sub.1
# => [i, auth_required, pad(16)]
# Get the procedure root at index i.
dup exec.active_account::get_procedure_root dupw
# => [PROC_ROOT, PROC_ROOT, i, auth_required, pad(16)]
exec.native_account::was_procedure_called
# => [was_called, PROC_ROOT, i, auth_required, pad(16)]
if.true
# Look up the proc root in the exempt map. Exempt procedure entries have
# `[1, 0, 0, 0]` as their values.
push.EXEMPT_PROCEDURE_ROOTS_SLOT[0..2]
# => [slot_suffix, slot_prefix, PROC_ROOT, i, auth_required, pad(16)]
exec.active_account::get_initial_map_item
# => [[is_exempt, 0, 0, 0], i, auth_required, pad(16)]
movdn.3 drop drop drop
# => [is_exempt, i, auth_required, pad(16)]
# If the called procedure is not exempt, auth is required.
not
# => [is_not_exempt, i, auth_required, pad(16)]
movup.2 or
# => [auth_required', i, pad(16)]
swap
# => [i, auth_required', pad(16)]
else
# Procedure was not called; discard the duplicated root.
dropw
# => [i, auth_required, pad(16)]
end
dup neq.1
# => [should_continue, i, auth_required, pad(16)]
end
# => [i = 1, auth_required, pad(16)]
drop
# => [auth_required, pad(16)]
# If authentication is required, perform signature verification
if.true
# Fetch public key from storage.
push.PUBLIC_KEY_SLOT[0..2] exec.active_account::get_initial_item
# => [PUB_KEY, pad(16)]
# Fetch scheme_id from storage
push.SCHEME_ID_SLOT[0..2] exec.active_account::get_initial_item
# => [[scheme_id, 0, 0, 0], PUB_KEY, pad(16)]
movdn.7 drop drop drop
# => [PUB_KEY, scheme_id, pad(16)]
exec.signature::authenticate_transaction
else
# ------ Check if initial account commitment differs from current commitment ------
exec.active_account::get_initial_commitment
# => [INITIAL_COMMITMENT, pad(16)]
exec.active_account::compute_commitment
# => [CURRENT_COMMITMENT, INITIAL_COMMITMENT, pad(16)]
exec.word::eq not
# => [has_account_state_changed, pad(16)]
# check if this is a new account (i.e., nonce == 0); this check is needed because new
# accounts are initialized with a non-empty state, and thus, unless the account was
# modified during the transaction, the initial and current state commitments will be
# the same
exec.active_account::get_nonce eq.0
# => [is_new_account, has_account_state_changed, pad(16)]
or
# => [should_increment_nonce, pad(16)]
if.true
exec.native_account::incr_nonce drop
end
end
# => [pad(16)]
end