Skip to content

fix(standards): use initial storage state in auth components#2740

Open
partylikeits1983 wants to merge 7 commits intonextfrom
ajl-init-pub-key-auth-fix
Open

fix(standards): use initial storage state in auth components#2740
partylikeits1983 wants to merge 7 commits intonextfrom
ajl-init-pub-key-auth-fix

Conversation

@partylikeits1983
Copy link
Copy Markdown
Contributor

Closes #2677

Auth components (singlesig, singlesig_acl, multisig) were using get_item/ get_map_item to read public keys, scheme IDs, and configuration during authentication. These procedures return the current storage state, which may have been modified during the transaction. During a key rotation, the old key must sign off on the change; using get_item would incorrectly authenticate against the new (rotated) key.

Changes:

Replaced all auth-time storage reads with their initial-state counterparts:

singlesig.masm: get_item -> get_initial_item for public key and scheme ID slots
singlesig_acl.masm: get_item -> get_initial_item for public key, scheme ID, and config slots; get_map_item → get_initial_map_item for trigger procedure roots
multisig.masm: get_map_item -> get_initial_map_item in assert_proc_thresholds_lte_num_approvers

Regression Tests

Added key rotation regression tests for singlesig and singlesig_acl that overwrite the public key slot mid-transaction and verify the auth procedure still succeeds using the initial key. If the bug were reintroduced, these tests would fail because signature verification would use the new (bogus) key.

@partylikeits1983 partylikeits1983 force-pushed the ajl-init-pub-key-auth-fix branch from af47f5a to 9b6a3d5 Compare April 6, 2026 21:28
@partylikeits1983 partylikeits1983 marked this pull request as ready for review April 6, 2026 21:29
@partylikeits1983 partylikeits1983 added standards Related to standard note scripts or account components pr-from-maintainers PRs that come from internal contributors or integration partners. They should be given priority labels Apr 6, 2026
@partylikeits1983 partylikeits1983 self-assigned this Apr 6, 2026
Comment thread crates/miden-testing/tests/auth/singlesig.rs
Copy link
Copy Markdown
Contributor

@PhilippGackstatter PhilippGackstatter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me!

I think using get_initial* on scheme ID, public key and proc thresholds should be everything we need.

I think it's important to assert the exact error code in the tests, the other comments are optional.

Comment on lines +72 to +75
let (account, mock_chain, note) = setup_singlesig_with_mock_component(auth_scheme)?;

// Build the authenticator separately (same seed as Auth::BasicAuth uses)
let (_, authenticator) = Auth::BasicAuth { auth_scheme }.build_component();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make maintenance easier, can we return the authenticator from the setup function so these cannot get out of sync?

.await
.expect("singlesig auth should use initial public key, not the rotated one");

prove_and_verify_transaction(executed_tx).await?;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd only execute the transaction but not prove and verify, because our tests are already long-running and the additional proving and verification probably doesn't validate anything essential about this test.

Comment on lines +176 to +182
// This should FAIL because the auth procedure reads the initial key (A) but the
// authenticator signs with key B. The signature verification will not match.
let result = tx_context.execute().await;
assert!(
result.is_err(),
"transaction should fail when signed with the rotated key instead of the initial key"
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we assert the exact error code we expect using assert_transaction_executor_error!? Transactions can fail for many different reasons and in the current state, it doesn't serve as an actual regression test because signature verification could succeed, but the tx could still fail for some other benign reason, but the test won't alert us to that.

Comment on lines +437 to +443
// This should FAIL because the auth procedure reads the initial key (A) but the
// authenticator signs with key B. The signature verification will not match.
let result = tx_context.execute().await;
assert!(
result.is_err(),
"transaction should fail when signed with the rotated key instead of the initial key"
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

Copy link
Copy Markdown
Contributor

@bobbinth bobbinth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Thank you! (though, I only focused on the non-test code)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-from-maintainers PRs that come from internal contributors or integration partners. They should be given priority standards Related to standard note scripts or account components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Auth components should use initial public key for authentication

4 participants