Skip to content

EIP-712 multisig review fixes: tests and docs - #15

Open
WiktorStarczewski wants to merge 34 commits into
inicio-labs:vaibhav/eip712-multisig-v0.16from
0xMiden:wiktor/eip712-multisig-review-fixes
Open

WiktorStarczewski wants to merge 34 commits into
inicio-labs:vaibhav/eip712-multisig-v0.16from
0xMiden:wiktor/eip712-multisig-review-fixes

Conversation

@WiktorStarczewski

Copy link
Copy Markdown

Review fixes on top of #3856: tests that now fail when the behaviour they name breaks, and MASM docs that match the code. Only tests, comments and one local constant name change; no MASM instruction changes.

  • Rejection tests assert the ECDSA verifier's own failure, so they fail if the EIP-712 branch is disabled
  • New test pins raw-signature precedence over a malformed EIP-712 entry, for ECDSA and Falcon approvers
  • Every fee cycle-bound guard (regular, guarded and smart multisig) also measures an EIP-712 signer
  • The generic EIP-712 vector test uses distinct input bytes, so limb and byte order are pinned
  • Docs and names: the verify_bytes stack comment, PUBLIC_KEY_COMMITMENT_LOC, the auth_tx advice-map note, the guardian's EIP-712 option, the preimage packing comment

One commit per fix, based on 0xMiden#3856 at 54b5cfac5. Please merge this into the 0xMiden#3856 branch before 0xMiden#3856 lands: deleting that branch would close this PR.

Verification
  • Gates on the tip: make format-check, typos-check, toml-check, shear, clippy, clippy-no-std, doc, test-docs and test-release (1,875 tests), all green.
  • Each test change has a mutation proof. With the EIP-712 branch forced off, the rewritten rejection cases, the double-count control and the three new fee-guard cases fail. With the raw branch forced off, both precedence cases fail on the EIP-712 checks. With the generic test's limb push order reversed, the old symmetric inputs pass and the new inputs fail. Every case passes on the real code.
Commits
  • d43e6a10c fix(rev): round 1 - C-02 F-002 EIP-712 rejection tests prove the branch ran
  • 4b13cf714 fix(rev): round 1 - C-03 F-005 verify_bytes stack comment order
  • 7b1d74b6d fix(rev): round 1 - C-03 F-006 name the adapter local after PK_COMM
  • 997e112b0 fix(rev): round 1 - C-03 F-007 both signature formats come from the advice map
  • cde91f4dd fix(rev): round 1 - C-03 F-008 guardian doc names the EIP-712 option
  • 74244c978 fix(rev): round 2 - C-06 F-009 pin raw-signature precedence over EIP-712 entries
  • 851edc91a fix(rev): round 3 - C-03 F-012 preimage packing comment sits on its loop
  • 1ec00dffb fix(rev): round 4 - C-08 F-014 cycle-bound guards measure an EIP-712 signer
  • 805957f63 fix(rev): round 4 - C-09 F-015 generic EIP-712 test uses asymmetric inputs

Reviewers: 1ec00df is the largest change - it threads one SignatureFormat helper through the three fee-payment test harnesses; everything else is local to one test or one comment.

mmagician and others added 30 commits August 31, 2026 12:31
Co-authored-by: Claude (Opus) <noreply@anthropic.com>
Co-authored-by: Claude (Opus) <noreply@anthropic.com>
* let user fungible faucets hold the native fee asset

* unit-test the user fungible faucet factories

* prove a user faucet pays its own fee end to end

* scope the network-faucet wallet note to steady state

* drop the fee-asset tests and inline commentary

* Apply suggestion from @mmagician

---------

Co-authored-by: Marti <marti@miden.team>
* chore: bump Cargo version to 1.97

* chore: bump to 1.98 rather than 1.97

1.98 is the current stable (released 2026-08-20) and, like 1.97, carries
the `cargo publish --workspace` deadlock fix from rust-lang/cargo#17071
that the release job needs.

Going one release further adds the `chunks_exact_to_as_chunks` lint on
top of the ones 1.97 reports, so `AccountStorageHeader::try_from_elements`
and the attachment parser move to `as_chunks`. Both call sites already
guard the length, so the behaviour is unchanged - and the array chunks
make the fixed-width indexing that follows statically checked.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015bLUPBgD8T6Edt2141yrvQ

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
* refactor: split fee estimation out of pay_fee into estimate_fee

* refactor: split fee estimation out of fee payment

* fixup! refactor: split fee estimation out of fee payment

* docs(standards): say estimate_fee estimates the fee

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KkQzFtRjyDwQ7iVtRbsHsn

* docs(standards): drop the foreign account note from estimate_fee

The FPI requirement is documented on fees::create_network_note_sponsorships,
which the paragraph already points at.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KkQzFtRjyDwQ7iVtRbsHsn

* refactor(standards): share the per-note sponsorship logic behind a create flag

Replace the create_network_note_sponsorship / estimate_network_note_sponsorship
twins with a single handle_network_note_sponsorship that prices the note and,
when is_create is set, also creates its FEE_SPONSORSHIP note.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KkQzFtRjyDwQ7iVtRbsHsn

* test(standards): cover a network note priced to zero by its target

pay_fee must create no FEE_SPONSORSHIP note for it while still paying its
own fee. Shares the transaction setup with the sponsoring case.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KkQzFtRjyDwQ7iVtRbsHsn

* refactor(standards): share the sponsorship walk behind a create flag

create_network_note_sponsorships and estimate_network_note_sponsorships
become thin wrappers over a private handle_network_note_sponsorships that
walks the output notes once and passes is_create down to the per-note
procedure.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KkQzFtRjyDwQ7iVtRbsHsn

* test(standards): reject two sponsorships whose sum exceeds the one collected fee

Pins that the sponsorship cap compares the summed sponsored amount: a total
that collapsed to the number of sponsorship notes (as a stack slip in
create_network_note_sponsorships did during this refactor) passes the
single-note cases but fails this one.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KkQzFtRjyDwQ7iVtRbsHsn

* chore: regenerate the note cost tables for the fee estimation split

Output of make update-note-costs. Consuming a note now also runs the
estimation walk, and a note that creates network notes prices each of them
twice (estimate, then create), which pushed the agglayer CLAIM cost more
than 5% past its checked-in value.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KkQzFtRjyDwQ7iVtRbsHsn

* address review nits: rename sponsorship handlers and the create flag

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
* chore: bump version to v0.16.0-rc.9

rc.7 and rc.8 both aborted partway through `cargo publish --workspace`,
so each is half-published on crates.io: miden-protocol landed at both
versions while miden-tx and miden-testing are still at rc.6. Published
versions cannot be reused, so the next release attempt needs a fresh
number.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015bLUPBgD8T6Edt2141yrvQ

* fix: restore the workspace version to v0.16.0-rc.9

The conflict resolution in a3b4f17 set `[workspace.package] version` to
`0.16.0-rc.0` while leaving all eight `[workspace.dependencies]` pins at
`0.16.0-rc.9`, so no workspace crate could resolve:

    error: failed to select a version for the requirement
    `miden-protocol = "^0.16.0-rc.9"`
    candidate versions found which didn't match: 0.16.0-rc.0

That is what took out every cargo job on this PR. Cargo.lock already
carries rc.9 throughout and needs no change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015bLUPBgD8T6Edt2141yrvQ

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
* feat: add fee::assert_fee_bound for callers to bound a fee payment

* docs: trim assert_fee_bound docs to present behaviour

* Update crates/miden-standards/asm/standards/fee/mod.masm

* import account_id in fee module so assert_fee_bound assembles

---------

Co-authored-by: Marti <marti@miden.team>
…g auth (#3786)

* refactor: split fee estimation out of pay_fee into estimate_fee

* refactor: split fee estimation out of fee payment

* fixup! refactor: split fee estimation out of fee payment

* feat: add fee::assert_fee_bound for callers to bound a fee payment

* docs: trim assert_fee_bound docs to present behaviour

* feat: pay the fee in guarded and smart multisig auth, bounded

* test: pin the sponsorship step of the bounded fee flow

* Update crates/miden-standards/asm/standards/auth/guardian.masm

Co-authored-by: Marti <marti@miden.team>

* Update crates/miden-standards/asm/standards/auth/tx_policy.masm

Co-authored-by: Marti <marti@miden.team>

* address review nits: rename resolve_payment_info, drop 'sample' wording

* Apply suggestion from @mmagician

* Update docs/src/fees.md

Co-authored-by: zeapoz <zeapo@pm.me>

---------

Co-authored-by: Marti <marti@miden.team>
Co-authored-by: zeapoz <zeapo@pm.me>
…ch ran

F-002 P2  three rejection cases asserted only is_err and the double-count test had no
          control, so all of them passed with the EIP-712 branch disabled

The rejection cases now assert the ECDSA verifier's failure, and the double-count test first
authorizes with approver 0's EIP-712 witness alone. With the EIP-712 branch forced off, four of
the five cases fail; the raw-key case still passes because it exercises the raw verifier.
F-005 P3  the comment read [PK_COMM, 66, DIGEST_PREIMAGE_LOC]; the stack is
          [PK_COMM, digest_preimage_ptr, preimage_num_bytes]
F-006 P3  TX_SUMMARY_HASH_LOC stored the public-key commitment; renamed to
          PUBLIC_KEY_COMMITMENT_LOC, the name eip712.masm already uses
…dvice map

F-007 P3  the auth_tx doc said EIP-712 signatures, unlike raw ones, must be in the advice map
          before execution; verify_signatures also skips an approver whose raw key is absent
F-008 P3  an ECDSA guardian can acknowledge with an EIP-712 transaction-summary signature,
          and the verify_signature doc did not say so
…712 entries

F-009 P2  no test failed if an approver's EIP-712 entry were checked before, or alongside, its
          raw signature, and the auth_tx Panics bullet omitted the no-raw-signature condition

The new test gives one approver a valid raw signature plus a malformed EIP-712 entry (31 felts
for ECDSA, 32 zeros for Falcon) and expects the transaction to execute. With the raw branch
forced off, both cases abort on the EIP-712 checks.
F-012 P3  the explanation of the limb carry loop sat above the PROCEDURES banner, away from the
          loop in eip712::verify it describes
…signer

F-014 P2  no regression guard for estimate_multisig_authentication_cycles measured the costlier
          EIP-712 verification path, so it could outgrow the estimate unnoticed

Adds an EIP-712 case to the regular, guarded and smart multisig guards through a shared
signature-format helper. With the EIP-712 branch forced off, the new cases fail and the raw
cases still pass.
…nputs

F-015 P2  the test signed [0x11; 32] and [0x22; 32], which pack into identical u32 limbs, so it
          still passed with the pushed limb order reversed

With the limb order reversed, the test passes on the old inputs and fails on the new ones.
@coderabbitai

coderabbitai Bot commented Sep 15, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 9a0e1a5d-84af-4121-9512-27e1bc69ebc0

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants