Skip to content

Commit d771cec

Browse files
davidiwalinush
andauthored
[move] rotate_authentication_key_call should not modify OriginatingAddress (aptos-labs#12108)
Co-authored-by: Alin Tomescu <[email protected]>
1 parent 67f372a commit d771cec

File tree

4 files changed

+43
-74
lines changed

4 files changed

+43
-74
lines changed

aptos-move/framework/aptos-framework/doc/account.md

Lines changed: 16 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,8 +1143,11 @@ is returned. This way, the caller of this function can publish additional resour
11431143

11441144
## Function `rotate_authentication_key_internal`
11451145

1146-
This function is used to rotate a resource account's authentication key to 0, so that no private key can control
1147-
the resource account.
1146+
This function is used to rotate a resource account's authentication key to <code>new_auth_key</code>. This is done in
1147+
many contexts:
1148+
1. During normal key rotation via <code>rotate_authentication_key</code> or <code>rotate_authentication_key_call</code>
1149+
2. During resource account initialization so that no private key can control the resource account
1150+
3. During multisig_v2 account creation
11481151

11491152

11501153
<pre><code><b>public</b>(<b>friend</b>) <b>fun</b> <a href="account.md#0x1_account_rotate_authentication_key_internal">rotate_authentication_key_internal</a>(<a href="account.md#0x1_account">account</a>: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>, new_auth_key: <a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector">vector</a>&lt;u8&gt;)
@@ -1176,7 +1179,11 @@ the resource account.
11761179

11771180
## Function `rotate_authentication_key_call`
11781181

1179-
Entry function-only rotation key function that allows the signer update their authentication_key.
1182+
Private entry function for key rotation that allows the signer to update their authentication key.
1183+
Note that this does not update the <code><a href="account.md#0x1_account_OriginatingAddress">OriginatingAddress</a></code> table because the <code>new_auth_key</code> is not "verified": it
1184+
does not come with a proof-of-knowledge of the underlying SK. Nonetheless, we need this functionality due to
1185+
the introduction of non-standard key algorithms, such as passkeys, which cannot produce proofs-of-knowledge in
1186+
the format expected in <code>rotate_authentication_key</code>.
11801187

11811188

11821189
<pre><code>entry <b>fun</b> <a href="account.md#0x1_account_rotate_authentication_key_call">rotate_authentication_key_call</a>(<a href="account.md#0x1_account">account</a>: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>, new_auth_key: <a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector">vector</a>&lt;u8&gt;)
@@ -1188,15 +1195,8 @@ Entry function-only rotation key function that allows the signer update their au
11881195
<summary>Implementation</summary>
11891196

11901197

1191-
<pre><code>entry <b>fun</b> <a href="account.md#0x1_account_rotate_authentication_key_call">rotate_authentication_key_call</a>(<a href="account.md#0x1_account">account</a>: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>, new_auth_key: <a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector">vector</a>&lt;u8&gt;) <b>acquires</b> <a href="account.md#0x1_account_Account">Account</a>, <a href="account.md#0x1_account_OriginatingAddress">OriginatingAddress</a> {
1192-
<b>let</b> addr = <a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer_address_of">signer::address_of</a>(<a href="account.md#0x1_account">account</a>);
1193-
<b>assert</b>!(<a href="account.md#0x1_account_exists_at">exists_at</a>(addr), <a href="../../aptos-stdlib/../move-stdlib/doc/error.md#0x1_error_not_found">error::not_found</a>(<a href="account.md#0x1_account_EACCOUNT_DOES_NOT_EXIST">EACCOUNT_DOES_NOT_EXIST</a>));
1194-
<b>assert</b>!(
1195-
<a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector_length">vector::length</a>(&new_auth_key) == 32,
1196-
<a href="../../aptos-stdlib/../move-stdlib/doc/error.md#0x1_error_invalid_argument">error::invalid_argument</a>(<a href="account.md#0x1_account_EMALFORMED_AUTHENTICATION_KEY">EMALFORMED_AUTHENTICATION_KEY</a>)
1197-
);
1198-
<b>let</b> account_resource = <b>borrow_global_mut</b>&lt;<a href="account.md#0x1_account_Account">Account</a>&gt;(addr);
1199-
<a href="account.md#0x1_account_update_auth_key_and_originating_address_table">update_auth_key_and_originating_address_table</a>(addr, account_resource, new_auth_key);
1198+
<pre><code>entry <b>fun</b> <a href="account.md#0x1_account_rotate_authentication_key_call">rotate_authentication_key_call</a>(<a href="account.md#0x1_account">account</a>: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>, new_auth_key: <a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector">vector</a>&lt;u8&gt;) <b>acquires</b> <a href="account.md#0x1_account_Account">Account</a> {
1199+
<a href="account.md#0x1_account_rotate_authentication_key_internal">rotate_authentication_key_internal</a>(<a href="account.md#0x1_account">account</a>, new_auth_key);
12001200
}
12011201
</code></pre>
12021202

@@ -2526,29 +2526,15 @@ The length of new_auth_key is 32.
25262526
</code></pre>
25272527

25282528

2529-
The Account existed under the signer before the call.
2530-
The length of new_auth_key is 32.
25312529

25322530

25332531
<pre><code><b>let</b> addr = <a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer_address_of">signer::address_of</a>(<a href="account.md#0x1_account">account</a>);
2532+
// This enforces <a id="high-level-req-10" href="#high-level-req">high-level requirement 10</a>:
2533+
<b>let</b> <b>post</b> account_resource = <b>global</b>&lt;<a href="account.md#0x1_account_Account">Account</a>&gt;(addr);
25342534
<b>aborts_if</b> !<b>exists</b>&lt;<a href="account.md#0x1_account_Account">Account</a>&gt;(addr);
25352535
<b>aborts_if</b> <a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector_length">vector::length</a>(new_auth_key) != 32;
2536-
<b>let</b> account_resource = <b>global</b>&lt;<a href="account.md#0x1_account_Account">Account</a>&gt;(addr);
2537-
<b>let</b> curr_auth_key = <a href="../../aptos-stdlib/doc/from_bcs.md#0x1_from_bcs_deserialize">from_bcs::deserialize</a>&lt;<b>address</b>&gt;(account_resource.authentication_key);
2538-
<b>let</b> originating_addr = addr;
2539-
<b>let</b> address_map = <b>global</b>&lt;<a href="account.md#0x1_account_OriginatingAddress">OriginatingAddress</a>&gt;(@aptos_framework).address_map;
2540-
<b>let</b> new_auth_key_addr = <a href="../../aptos-stdlib/doc/from_bcs.md#0x1_from_bcs_deserialize">from_bcs::deserialize</a>&lt;<b>address</b>&gt;(new_auth_key);
2541-
<b>aborts_if</b> !<b>exists</b>&lt;<a href="account.md#0x1_account_OriginatingAddress">OriginatingAddress</a>&gt;(@aptos_framework);
2542-
<b>aborts_if</b> !<a href="../../aptos-stdlib/doc/from_bcs.md#0x1_from_bcs_deserializable">from_bcs::deserializable</a>&lt;<b>address</b>&gt;(account_resource.authentication_key);
2543-
<b>aborts_if</b> <a href="../../aptos-stdlib/doc/table.md#0x1_table_spec_contains">table::spec_contains</a>(address_map, curr_auth_key) &&
2544-
<a href="../../aptos-stdlib/doc/table.md#0x1_table_spec_get">table::spec_get</a>(address_map, curr_auth_key) != originating_addr;
2545-
<b>aborts_if</b> curr_auth_key != new_auth_key_addr && <a href="../../aptos-stdlib/doc/table.md#0x1_table_spec_contains">table::spec_contains</a>(address_map, new_auth_key_addr);
2546-
<b>include</b> <a href="account.md#0x1_account_UpdateAuthKeyAndOriginatingAddressTableAbortsIf">UpdateAuthKeyAndOriginatingAddressTableAbortsIf</a> {
2547-
originating_addr: addr,
2548-
new_auth_key_vector: new_auth_key,
2549-
};
2550-
<b>let</b> <b>post</b> auth_key = <b>global</b>&lt;<a href="account.md#0x1_account_Account">Account</a>&gt;(addr).authentication_key;
2551-
<b>ensures</b> auth_key == new_auth_key;
2536+
<b>modifies</b> <b>global</b>&lt;<a href="account.md#0x1_account_Account">Account</a>&gt;(addr);
2537+
<b>ensures</b> account_resource.authentication_key == new_auth_key;
25522538
</code></pre>
25532539

25542540

aptos-move/framework/aptos-framework/sources/account.move

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -265,8 +265,11 @@ module aptos_framework::account {
265265
borrow_global<Account>(addr).authentication_key
266266
}
267267

268-
/// This function is used to rotate a resource account's authentication key to 0, so that no private key can control
269-
/// the resource account.
268+
/// This function is used to rotate a resource account's authentication key to `new_auth_key`. This is done in
269+
/// many contexts:
270+
/// 1. During normal key rotation via `rotate_authentication_key` or `rotate_authentication_key_call`
271+
/// 2. During resource account initialization so that no private key can control the resource account
272+
/// 3. During multisig_v2 account creation
270273
public(friend) fun rotate_authentication_key_internal(account: &signer, new_auth_key: vector<u8>) acquires Account {
271274
let addr = signer::address_of(account);
272275
assert!(exists_at(addr), error::not_found(EACCOUNT_DOES_NOT_EXIST));
@@ -278,16 +281,13 @@ module aptos_framework::account {
278281
account_resource.authentication_key = new_auth_key;
279282
}
280283

281-
/// Entry function-only rotation key function that allows the signer update their authentication_key.
282-
entry fun rotate_authentication_key_call(account: &signer, new_auth_key: vector<u8>) acquires Account, OriginatingAddress {
283-
let addr = signer::address_of(account);
284-
assert!(exists_at(addr), error::not_found(EACCOUNT_DOES_NOT_EXIST));
285-
assert!(
286-
vector::length(&new_auth_key) == 32,
287-
error::invalid_argument(EMALFORMED_AUTHENTICATION_KEY)
288-
);
289-
let account_resource = borrow_global_mut<Account>(addr);
290-
update_auth_key_and_originating_address_table(addr, account_resource, new_auth_key);
284+
/// Private entry function for key rotation that allows the signer to update their authentication key.
285+
/// Note that this does not update the `OriginatingAddress` table because the `new_auth_key` is not "verified": it
286+
/// does not come with a proof-of-knowledge of the underlying SK. Nonetheless, we need this functionality due to
287+
/// the introduction of non-standard key algorithms, such as passkeys, which cannot produce proofs-of-knowledge in
288+
/// the format expected in `rotate_authentication_key`.
289+
entry fun rotate_authentication_key_call(account: &signer, new_auth_key: vector<u8>) acquires Account {
290+
rotate_authentication_key_internal(account, new_auth_key);
291291
}
292292

293293
/// Generic authentication key rotation function that allows the user to rotate their authentication key from any scheme to any scheme.
@@ -1337,7 +1337,7 @@ module aptos_framework::account {
13371337

13381338

13391339
#[test(account = @aptos_framework)]
1340-
public entry fun test_simple_rotation(account: &signer) acquires Account, OriginatingAddress {
1340+
public entry fun test_simple_rotation(account: &signer) acquires Account {
13411341
initialize(account);
13421342

13431343
let alice_addr = @0x1234;
@@ -1349,10 +1349,6 @@ module aptos_framework::account {
13491349
let new_addr = from_bcs::to_address(new_auth_key);
13501350

13511351
rotate_authentication_key_call(&alice, new_auth_key);
1352-
1353-
let address_map = &mut borrow_global_mut<OriginatingAddress>(@aptos_framework).address_map;
1354-
let expected_originating_address = table::borrow(address_map, new_addr);
1355-
assert!(*expected_originating_address == alice_addr, 0);
13561352
assert!(borrow_global<Account>(alice_addr).authentication_key == new_auth_key, 0);
13571353
}
13581354

aptos-move/framework/aptos-framework/sources/account.spec.move

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -203,35 +203,14 @@ spec aptos_framework::account {
203203
ensures account_resource.authentication_key == new_auth_key;
204204
}
205205

206-
/// The Account existed under the signer before the call.
207-
/// The length of new_auth_key is 32.
208206
spec rotate_authentication_key_call(account: &signer, new_auth_key: vector<u8>) {
209207
let addr = signer::address_of(account);
208+
/// [high-level-req-10]
209+
let post account_resource = global<Account>(addr);
210210
aborts_if !exists<Account>(addr);
211211
aborts_if vector::length(new_auth_key) != 32;
212-
let account_resource = global<Account>(addr);
213-
let curr_auth_key = from_bcs::deserialize<address>(account_resource.authentication_key);
214-
215-
// Verify all properties in update_auth_key_and_originating_address_table
216-
let originating_addr = addr;
217-
218-
let address_map = global<OriginatingAddress>(@aptos_framework).address_map;
219-
let new_auth_key_addr = from_bcs::deserialize<address>(new_auth_key);
220-
221-
aborts_if !exists<OriginatingAddress>(@aptos_framework);
222-
aborts_if !from_bcs::deserializable<address>(account_resource.authentication_key);
223-
aborts_if table::spec_contains(address_map, curr_auth_key) &&
224-
table::spec_get(address_map, curr_auth_key) != originating_addr;
225-
226-
aborts_if curr_auth_key != new_auth_key_addr && table::spec_contains(address_map, new_auth_key_addr);
227-
228-
include UpdateAuthKeyAndOriginatingAddressTableAbortsIf {
229-
originating_addr: addr,
230-
new_auth_key_vector: new_auth_key,
231-
};
232-
233-
let post auth_key = global<Account>(addr).authentication_key;
234-
ensures auth_key == new_auth_key;
212+
modifies global<Account>(addr);
213+
ensures account_resource.authentication_key == new_auth_key;
235214
}
236215

237216
spec fun spec_assert_valid_rotation_proof_signature_and_get_auth_key(scheme: u8, public_key_bytes: vector<u8>, signature: vector<u8>, challenge: RotationProofChallenge): vector<u8>;

aptos-move/framework/cached-packages/src/aptos_framework_sdk_builder.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,11 @@ pub enum EntryFunctionCall {
131131
cap_update_table: Vec<u8>,
132132
},
133133

134-
/// Entry function-only rotation key function that allows the signer update their authentication_key.
134+
/// Private entry function for key rotation that allows the signer to update their authentication key.
135+
/// Note that this does not update the `OriginatingAddress` table because the `new_auth_key` is not "verified": it
136+
/// does not come with a proof-of-knowledge of the underlying SK. Nonetheless, we need this functionality due to
137+
/// the introduction of non-standard key algorithms, such as passkeys, which cannot produce proofs-of-knowledge in
138+
/// the format expected in `rotate_authentication_key`.
135139
AccountRotateAuthenticationKeyCall {
136140
new_auth_key: Vec<u8>,
137141
},
@@ -1676,7 +1680,11 @@ pub fn account_rotate_authentication_key(
16761680
))
16771681
}
16781682

1679-
/// Entry function-only rotation key function that allows the signer update their authentication_key.
1683+
/// Private entry function for key rotation that allows the signer to update their authentication key.
1684+
/// Note that this does not update the `OriginatingAddress` table because the `new_auth_key` is not "verified": it
1685+
/// does not come with a proof-of-knowledge of the underlying SK. Nonetheless, we need this functionality due to
1686+
/// the introduction of non-standard key algorithms, such as passkeys, which cannot produce proofs-of-knowledge in
1687+
/// the format expected in `rotate_authentication_key`.
16801688
pub fn account_rotate_authentication_key_call(new_auth_key: Vec<u8>) -> TransactionPayload {
16811689
TransactionPayload::EntryFunction(EntryFunction::new(
16821690
ModuleId::new(

0 commit comments

Comments
 (0)