diff --git a/aptos-move/framework/aptos-framework/doc/account.md b/aptos-move/framework/aptos-framework/doc/account.md
index 9565d16e617ad..d17c58a984c9c 100644
--- a/aptos-move/framework/aptos-framework/doc/account.md
+++ b/aptos-move/framework/aptos-framework/doc/account.md
@@ -1143,8 +1143,11 @@ is returned. This way, the caller of this function can publish additional resour
## Function `rotate_authentication_key_internal`
-This function is used to rotate a resource account's authentication key to 0, so that no private key can control
-the resource account.
+This function is used to rotate a resource account's authentication key to new_auth_key
. This is done in
+many contexts:
+1. During normal key rotation via rotate_authentication_key
or rotate_authentication_key_call
+2. During resource account initialization so that no private key can control the resource account
+3. During multisig_v2 account creation
public(friend) fun rotate_authentication_key_internal(account: &signer, new_auth_key: vector<u8>)
@@ -1176,7 +1179,11 @@ the resource account.
## Function `rotate_authentication_key_call`
-Entry function-only rotation key function that allows the signer update their authentication_key.
+Private entry function for key rotation that allows the signer to update their authentication key.
+Note that this does not update the OriginatingAddress
table because the new_auth_key
is not "verified": it
+does not come with a proof-of-knowledge of the underlying SK. Nonetheless, we need this functionality due to
+the introduction of non-standard key algorithms, such as passkeys, which cannot produce proofs-of-knowledge in
+the format expected in rotate_authentication_key
.
entry fun rotate_authentication_key_call(account: &signer, new_auth_key: vector<u8>)
@@ -1188,15 +1195,8 @@ Entry function-only rotation key function that allows the signer update their au
Implementation
-entry fun rotate_authentication_key_call(account: &signer, new_auth_key: vector<u8>) acquires Account, OriginatingAddress {
- let addr = signer::address_of(account);
- assert!(exists_at(addr), error::not_found(EACCOUNT_DOES_NOT_EXIST));
- assert!(
- vector::length(&new_auth_key) == 32,
- error::invalid_argument(EMALFORMED_AUTHENTICATION_KEY)
- );
- let account_resource = borrow_global_mut<Account>(addr);
- update_auth_key_and_originating_address_table(addr, account_resource, new_auth_key);
+entry fun rotate_authentication_key_call(account: &signer, new_auth_key: vector<u8>) acquires Account {
+ rotate_authentication_key_internal(account, new_auth_key);
}
@@ -2526,29 +2526,15 @@ The length of new_auth_key is 32.
-The Account existed under the signer before the call.
-The length of new_auth_key is 32.
let addr = signer::address_of(account);
+// This enforces high-level requirement 10:
+let post account_resource = global<Account>(addr);
aborts_if !exists<Account>(addr);
aborts_if vector::length(new_auth_key) != 32;
-let account_resource = global<Account>(addr);
-let curr_auth_key = from_bcs::deserialize<address>(account_resource.authentication_key);
-let originating_addr = addr;
-let address_map = global<OriginatingAddress>(@aptos_framework).address_map;
-let new_auth_key_addr = from_bcs::deserialize<address>(new_auth_key);
-aborts_if !exists<OriginatingAddress>(@aptos_framework);
-aborts_if !from_bcs::deserializable<address>(account_resource.authentication_key);
-aborts_if table::spec_contains(address_map, curr_auth_key) &&
- table::spec_get(address_map, curr_auth_key) != originating_addr;
-aborts_if curr_auth_key != new_auth_key_addr && table::spec_contains(address_map, new_auth_key_addr);
-include UpdateAuthKeyAndOriginatingAddressTableAbortsIf {
- originating_addr: addr,
- new_auth_key_vector: new_auth_key,
-};
-let post auth_key = global<Account>(addr).authentication_key;
-ensures auth_key == new_auth_key;
+modifies global<Account>(addr);
+ensures account_resource.authentication_key == new_auth_key;
diff --git a/aptos-move/framework/aptos-framework/sources/account.move b/aptos-move/framework/aptos-framework/sources/account.move
index 76bea0e3132c5..807b09c9d4284 100644
--- a/aptos-move/framework/aptos-framework/sources/account.move
+++ b/aptos-move/framework/aptos-framework/sources/account.move
@@ -265,8 +265,11 @@ module aptos_framework::account {
borrow_global(addr).authentication_key
}
- /// This function is used to rotate a resource account's authentication key to 0, so that no private key can control
- /// the resource account.
+ /// This function is used to rotate a resource account's authentication key to `new_auth_key`. This is done in
+ /// many contexts:
+ /// 1. During normal key rotation via `rotate_authentication_key` or `rotate_authentication_key_call`
+ /// 2. During resource account initialization so that no private key can control the resource account
+ /// 3. During multisig_v2 account creation
public(friend) fun rotate_authentication_key_internal(account: &signer, new_auth_key: vector) acquires Account {
let addr = signer::address_of(account);
assert!(exists_at(addr), error::not_found(EACCOUNT_DOES_NOT_EXIST));
@@ -278,16 +281,13 @@ module aptos_framework::account {
account_resource.authentication_key = new_auth_key;
}
- /// Entry function-only rotation key function that allows the signer update their authentication_key.
- entry fun rotate_authentication_key_call(account: &signer, new_auth_key: vector) acquires Account, OriginatingAddress {
- let addr = signer::address_of(account);
- assert!(exists_at(addr), error::not_found(EACCOUNT_DOES_NOT_EXIST));
- assert!(
- vector::length(&new_auth_key) == 32,
- error::invalid_argument(EMALFORMED_AUTHENTICATION_KEY)
- );
- let account_resource = borrow_global_mut(addr);
- update_auth_key_and_originating_address_table(addr, account_resource, new_auth_key);
+ /// Private entry function for key rotation that allows the signer to update their authentication key.
+ /// Note that this does not update the `OriginatingAddress` table because the `new_auth_key` is not "verified": it
+ /// does not come with a proof-of-knowledge of the underlying SK. Nonetheless, we need this functionality due to
+ /// the introduction of non-standard key algorithms, such as passkeys, which cannot produce proofs-of-knowledge in
+ /// the format expected in `rotate_authentication_key`.
+ entry fun rotate_authentication_key_call(account: &signer, new_auth_key: vector) acquires Account {
+ rotate_authentication_key_internal(account, new_auth_key);
}
/// 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 {
#[test(account = @aptos_framework)]
- public entry fun test_simple_rotation(account: &signer) acquires Account, OriginatingAddress {
+ public entry fun test_simple_rotation(account: &signer) acquires Account {
initialize(account);
let alice_addr = @0x1234;
@@ -1349,10 +1349,6 @@ module aptos_framework::account {
let new_addr = from_bcs::to_address(new_auth_key);
rotate_authentication_key_call(&alice, new_auth_key);
-
- let address_map = &mut borrow_global_mut(@aptos_framework).address_map;
- let expected_originating_address = table::borrow(address_map, new_addr);
- assert!(*expected_originating_address == alice_addr, 0);
assert!(borrow_global(alice_addr).authentication_key == new_auth_key, 0);
}
diff --git a/aptos-move/framework/aptos-framework/sources/account.spec.move b/aptos-move/framework/aptos-framework/sources/account.spec.move
index 91e1aca7751ce..2b80dbdce527d 100644
--- a/aptos-move/framework/aptos-framework/sources/account.spec.move
+++ b/aptos-move/framework/aptos-framework/sources/account.spec.move
@@ -203,35 +203,14 @@ spec aptos_framework::account {
ensures account_resource.authentication_key == new_auth_key;
}
- /// The Account existed under the signer before the call.
- /// The length of new_auth_key is 32.
spec rotate_authentication_key_call(account: &signer, new_auth_key: vector) {
let addr = signer::address_of(account);
+ /// [high-level-req-10]
+ let post account_resource = global(addr);
aborts_if !exists(addr);
aborts_if vector::length(new_auth_key) != 32;
- let account_resource = global(addr);
- let curr_auth_key = from_bcs::deserialize(account_resource.authentication_key);
-
- // Verify all properties in update_auth_key_and_originating_address_table
- let originating_addr = addr;
-
- let address_map = global(@aptos_framework).address_map;
- let new_auth_key_addr = from_bcs::deserialize(new_auth_key);
-
- aborts_if !exists(@aptos_framework);
- aborts_if !from_bcs::deserializable(account_resource.authentication_key);
- aborts_if table::spec_contains(address_map, curr_auth_key) &&
- table::spec_get(address_map, curr_auth_key) != originating_addr;
-
- aborts_if curr_auth_key != new_auth_key_addr && table::spec_contains(address_map, new_auth_key_addr);
-
- include UpdateAuthKeyAndOriginatingAddressTableAbortsIf {
- originating_addr: addr,
- new_auth_key_vector: new_auth_key,
- };
-
- let post auth_key = global(addr).authentication_key;
- ensures auth_key == new_auth_key;
+ modifies global(addr);
+ ensures account_resource.authentication_key == new_auth_key;
}
spec fun spec_assert_valid_rotation_proof_signature_and_get_auth_key(scheme: u8, public_key_bytes: vector, signature: vector, challenge: RotationProofChallenge): vector;
diff --git a/aptos-move/framework/cached-packages/src/aptos_framework_sdk_builder.rs b/aptos-move/framework/cached-packages/src/aptos_framework_sdk_builder.rs
index 27a318e48603d..045a27c1a664a 100644
--- a/aptos-move/framework/cached-packages/src/aptos_framework_sdk_builder.rs
+++ b/aptos-move/framework/cached-packages/src/aptos_framework_sdk_builder.rs
@@ -131,7 +131,11 @@ pub enum EntryFunctionCall {
cap_update_table: Vec,
},
- /// Entry function-only rotation key function that allows the signer update their authentication_key.
+ /// Private entry function for key rotation that allows the signer to update their authentication key.
+ /// Note that this does not update the `OriginatingAddress` table because the `new_auth_key` is not "verified": it
+ /// does not come with a proof-of-knowledge of the underlying SK. Nonetheless, we need this functionality due to
+ /// the introduction of non-standard key algorithms, such as passkeys, which cannot produce proofs-of-knowledge in
+ /// the format expected in `rotate_authentication_key`.
AccountRotateAuthenticationKeyCall {
new_auth_key: Vec,
},
@@ -1676,7 +1680,11 @@ pub fn account_rotate_authentication_key(
))
}
-/// Entry function-only rotation key function that allows the signer update their authentication_key.
+/// Private entry function for key rotation that allows the signer to update their authentication key.
+/// Note that this does not update the `OriginatingAddress` table because the `new_auth_key` is not "verified": it
+/// does not come with a proof-of-knowledge of the underlying SK. Nonetheless, we need this functionality due to
+/// the introduction of non-standard key algorithms, such as passkeys, which cannot produce proofs-of-knowledge in
+/// the format expected in `rotate_authentication_key`.
pub fn account_rotate_authentication_key_call(new_auth_key: Vec) -> TransactionPayload {
TransactionPayload::EntryFunction(EntryFunction::new(
ModuleId::new(