feat: offline verification and revocation helpers, client digest fix#8
Open
L0STE wants to merge 3 commits into
Open
feat: offline verification and revocation helpers, client digest fix#8L0STE wants to merge 3 commits into
L0STE wants to merge 3 commits into
Conversation
cbd689d to
59272cc
Compare
Two divergences between vector_core::advance_vector_digest and the buffer the on-chain program actually hashes: - The trailing 2-byte current_instruction_index footer was left zeroed by construct_instructions_data, so any advance not at index 0 (e.g. with a timeout pre-instruction) produced a digest whose signature fails on-chain. The footer is now patched to the advance's index before hashing, matching the TS SDK (digest.ts) and the runtime. - Per-instruction account flags were serialized verbatim, but the live sysvar reflects message-level flag promotion (signer/writable ORed per account across all instructions, fee payer included). Added promote_to_message_flags and advance_vector_digest_with_fee_payer mirroring the TS implementation. The 5-arg advance_vector_digest keeps its signature (footer patch only, no promotion) for verbatim harnesses like mollusk; see doc comments.
Per-scheme verify functions mirroring the signers, flat in vector-core and the TS SDK (vector-sdk/verify): recompute the exact digest the on-chain program hashes and verify the signature against it, returning the digest (the next nonce) on success. Covers ed25519, secp256k1 ECDSA (high-S normalized to match on-chain acceptance), EIP-191 (legacy v=27/28 rejected with guidance), Falcon-512, and Hawk-512. A deterministic digest constant is pinned in both the Rust and TS test suites — with the advance at index 1 — locking cross-language digest compatibility and the sysvar index-footer fix against regression. Readme: adds an Operational Patterns section (offline verification, lanes, revocation via inert advance, ordered pre-signing, expiry) and corrects stale content: Passthrough missing from the instruction table, Hawk-512 registration is three-step not two, SDK listings with nonexistent signatures.
59272cc to
1eaf141
Compare
Revocation is an inert advance: signing the advance digest with no
pre/post instructions at the outstanding nonce bumps the nonce and
orphans whatever was pre-signed against it. Adds the thin helpers —
revocation_digest / sign_revocation_instruction_{ed25519,
secp256k1_ecdsa, secp256k1_eip191} and their TS mirrors — next to the
advance signers, plus a mollusk test proving the semantics end to end
(revocation lands, the orphaned pre-signed advance fails, replay
fails) and a cross-language pinned revocation digest constant.
The digest commits to the broadcasting transaction's instruction
sysvar, so a pre-signed revocation is broadcast as a transaction
containing only the advance instruction; Falcon/Hawk sign via the
advance path with a compute-budget pre-instruction (Hawk exceeds the
default budget). Documented in the Readme revocation pattern.
1eaf141 to
d9830df
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three focused, client-side changes — flat in the existing crates/SDK, no new crates, no on-chain changes.
1. Client digest fix (
crates/core/src/digest.rs)advance_vector_digestdiverged from the buffer the on-chain program actually hashes, in two ways:current_instruction_indexfooter was left zeroed, so any advance not at index 0 (e.g. preceded by a timeout or compute-budget instruction) produced a digest whose signature fails on-chain. The footer is now patched to the advance's index before hashing, matching the TS SDK and the runtime.advance_vector_digest_with_fee_payermirrorsdigest.tsexactly; the 5-arg function keeps verbatim flags for harnesses (mollusk) that serialize per-instruction flags.2. Offline verification (
vector-core::verify,vector-sdk/verify)Per-scheme
verify_advance_signature_*/verifyAdvanceSignature*functions mirroring the signers: recompute the exact digest the program will hash and verify the signature, returning the digest (= the next nonce) on success. Sign-time validation instead of broadcast-time failure discovery — relevant for cold-key flows where a re-sign is expensive.v=27/28rejected with guidance (normalizeEip191RecoveryByte) sincesol_secp256k1_recoverrequires 0–33. Revocation helpers
Revocation falls out of the protocol: an inert advance (no pre/post instructions) signed at the outstanding nonce bumps the nonce and orphans whatever was pre-signed against it. This adds the thin helpers —
revocation_digestandsign_revocation_instruction_{ed25519, secp256k1_ecdsa, secp256k1_eip191}with TS mirrors — next to the advance signers, so a revocation can be pre-signed in the same session as the transaction it guards and held as a kill-switch.Docs
Readme gains an Operational Patterns section (offline verification, concurrency via one-identity-one-lane, unilateral revocation, ordered pre-signing via digest-as-next-nonce, expiry via in-buffer timeout) and corrects stale content: Passthrough was missing from the instruction table, Hawk-512 registration is three-step (not two), and several SDK listings had nonexistent signatures.
Test results
cargo test -p vector-tests(mollusk)cargo test -p vector-corecargo check --workspacebun x tscbun vitest run sdk/ts/test/verify.test.tsNote: bare
cargo build-sbfat the workspace root fails on a pre-existinggetrandomSBF issue (unrelated); per-programcargo build-sbf --manifest-path programs/<scheme>/Cargo.tomlworks as documented.