Repository navigation
[PQ-Accounts] SHAKE hint and direct variants - #1730
Conversation
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Essentials Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
WalkthroughThe change adds Falcon-512 SHAKE account variants, pure Cairo hashing, packing, modular arithmetic, generic and optimized NTT implementations, account interfaces, validation logic, comprehensive tests, and release-mode CI coverage. ChangesFalcon-512 account support
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant Account
participant Verifier
participant SHAKE256
participant NTT
Account->>Verifier: submit transaction signature
Verifier->>SHAKE256: derive message point from message and salt
Verifier->>NTT: transform and verify Falcon polynomial values
NTT-->>Verifier: return norm and product checks
Verifier-->>Account: return validation status
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
A rabbit hops through SHAKE’s bright stream, Comment |
🧪 Cairo Contract Size Benchmark DiffBYTECODE SIZE (felts) (limit: 81,920 felts)
SIERRA CONTRACT CLASS SIZE (bytes) (limit: 4,089,446 bytes)
This comment was generated automatically from benchmark diffs. |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (7)
packages/account/README.md (1)
13-22: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider listing the new Falcon interfaces in the sections below.
The new bullets describe the two Falcon accounts. The
Interfacessection still lists onlyISRC6andISRC9_V2. The tests useIFeltArrayPublicKeyandIFeltArrayDeployable, which are new public interfaces. Add them so readers can find the felt-array key and deploy entrypoints.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/account/README.md` around lines 13 - 22, Update the README’s Interfaces section to list the new public interfaces IFeltArrayPublicKey and IFeltArrayDeployable alongside ISRC6 and ISRC9_V2, reflecting the felt-array key and deploy entrypoints used by the Falcon accounts.packages/account/src/tests/test_falcon_512.cairo (1)
375-391: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winBare
#[should_panic]in four negative tests. These tests pass on any panic, including a panic from an unrelated cause such as calldata deserialization or a future assertion added earlier in the call path. The rest of both files already pins the panic reason with#[should_panic(expected: ...)], so these four sites are the inconsistent ones.
packages/account/src/tests/test_falcon_512.cairo#L375-L391: add the expected panic message totest_constructor_rejects_wrong_public_key_lengthandtest_constructor_rejects_noncanonical_public_key, so each test proves the length check and the canonicality check specifically.packages/account/src/tests/test_falcon_512_ntt.cairo#L143-L153: add the expected panic message totest_forward_roots_reject_unsupported_degreeandtest_inverse_roots_reject_unsupported_degree, using the real message emitted byget_even_roots_feltandget_scaled_inv_roots.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/account/src/tests/test_falcon_512.cairo` around lines 375 - 391, The four negative tests currently accept any panic; pin each to the specific expected panic message. In packages/account/src/tests/test_falcon_512.cairo:375-391, update test_constructor_rejects_wrong_public_key_length and test_constructor_rejects_noncanonical_public_key with the messages emitted by the public-key length and canonicality checks. In packages/account/src/tests/test_falcon_512_ntt.cairo:143-153, update test_forward_roots_reject_unsupported_degree and test_inverse_roots_reject_unsupported_degree with the actual messages from get_even_roots_felt and get_scaled_inv_roots.packages/account/src/falcon_512.cairo (1)
24-31: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDerive the slice offsets from named constants and share the decoding.
The literals
29and31in the slices repeat the layout thatPUBLIC_KEY_FELTS,SIGNATURE_FELTSandDIRECT_SIGNATURE_FELTSalready encode. The twoverifyimplementations also duplicate the public key,s1and salt decoding. If the polynomial slot count changes, the length gate and the slices can desynchronize.♻️ Proposed refactor
+/// Felts per packed Z_q polynomial (28 full slots + 1 partial slot). +pub(crate) const POLY_FELTS: u32 = packing::PACKED_SLOTS; +/// Felts holding the 40-byte salt. +const SALT_FELTS: u32 = 2; + /// Number of felts in a packed Falcon-512 public key. -pub(crate) const PUBLIC_KEY_FELTS: u32 = 29; +pub(crate) const PUBLIC_KEY_FELTS: u32 = POLY_FELTS; /// Number of felts in a Falcon-512 signature carrying a product hint. -pub(crate) const SIGNATURE_FELTS: u32 = 60; +pub(crate) const SIGNATURE_FELTS: u32 = DIRECT_SIGNATURE_FELTS + POLY_FELTS; /// Number of felts in a hint-free Falcon-512 signature. -pub(crate) const DIRECT_SIGNATURE_FELTS: u32 = 31; +pub(crate) const DIRECT_SIGNATURE_FELTS: u32 = POLY_FELTS + SALT_FELTS;Then reuse one helper for the shared prefix:
/// Decodes `h_ntt`, `s1` and the message point shared by both signature layouts. fn decode_common( message_hash: felt252, public_key: Span<felt252>, signature: Span<felt252>, ) -> Option<(Array<u16>, Array<u16>, Array<u16>)> { let h_ntt = packing::unpack_512_u16(public_key)?; let s1 = packing::unpack_512_u16(signature.slice(0, POLY_FELTS))?; let message_point = hash_to_point_shake_512( message_hash, *signature.at(POLY_FELTS), *signature.at(POLY_FELTS + 1), )?; Some((h_ntt, s1, message_point)) }and slice the hint with
signature.slice(DIRECT_SIGNATURE_FELTS, POLY_FELTS).Also applies to: 36-52, 76-88
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/account/src/falcon_512.cairo` around lines 24 - 31, Derive all signature and public-key slice offsets from the existing layout constants, including the hint slice, instead of hardcoded 29 and 31 values. Add a shared decode_common helper for public-key, s1, and message-point decoding, then update both verify implementations to reuse it while preserving their distinct signature-layout handling.packages/account/src/falcon_512/hashing/shake256.cairo (1)
156-157: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueGate
shake256behind#[cfg(test)]or add a non-test caller.
shake256has no non-test caller. Production code imports onlykeccak_f1600, and all calls are in the test module.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/account/src/falcon_512/hashing/shake256.cairo` around lines 156 - 157, Update the `shake256` function visibility so it is compiled only for tests using the project’s test configuration attribute, unless a real production caller is added. Keep `keccak_f1600` and the existing test calls unchanged.packages/account/src/falcon_512/ntt/engine.cairo (1)
357-360: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueReset
bitswithboundin the last-level reduction.The branch resets
boundbut leavesbitsstale.bitsis not read after this point, so behavior is correct today. A future change that readsbitsafter the last level would use a wrong value. Keep the two tracked variables consistent.♻️ Proposed change
if bits + growth_bits > SAFE_BITS { cur = reduce_pass(cur.span(), q_nz); + bits = qbits; bound = q_felt; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/account/src/falcon_512/ntt/engine.cairo` around lines 357 - 360, Update the last-level reduction branch in the NTT engine to reset bits consistently when bound is reset after reduce_pass. Preserve the existing reduction flow and ensure both tracked values reflect the new bound for any subsequent use.packages/account/src/falcon_512/ntt/falcon512.cairo (1)
34-50: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueDocument or guard the degree precondition.
config_for_degreeaccepts anyn. Ifnis not a power of two in[4, 512],config_with_permcallsget_even_roots_feltwith an unsupported size and panics with "no root table for degree". The failure message does not name the caller argument. Add an explicit assertion so misuse fails with a clear reason.♻️ Proposed guard
pub fn config_for_degree(n: u32, levels: u32) -> NttConfig { + assert!(n >= 4 && n <= 512, "config_for_degree: unsupported degree"); let mut perm: Array<u16> = array![];🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/account/src/falcon_512/ntt/falcon512.cairo` around lines 34 - 50, Add an explicit precondition at the start of config_for_degree validating that n is a power of two within the supported range [4, 512], and assert with a message that includes the supplied n when invalid. Keep the existing permutation construction and config_with_perm flow unchanged for valid degrees.packages/account/src/falcon_512/account.cairo (1)
155-178: 🚀 Performance & Scalability | 🔵 Trivial | ⚖️ Poor tradeoffRead the public key once per validation call.
validate_transactionandis_valid_signatureboth callread_public_key, which performs one storage read per stored felt. The Falcon-512 key is 29 felts, so each validation costs 29 storage reads plus the vector length read.The key is immutable after the constructor. Consider caching it in a single packed storage layout, or document the cost so integrators can budget for it. This is an observation about gas cost, not a correctness defect.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/account/src/falcon_512/account.cairo` around lines 155 - 178, Reduce repeated public-key storage reads across validate_transaction and is_valid_signature by caching the immutable Falcon-512 key in a single packed storage representation initialized by the constructor, then have read_public_key reuse that cached value. If the existing storage model prevents caching, document the 29-felt plus length-read cost for integrators instead.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/account/src/falcon_512/account.cairo`:
- Around line 141-152: Guard the public initializer method against repeated
calls by checking that self.public_key is empty before validating or appending
the key. Add and use a dedicated initialization error constant alongside the
existing Errors constants, ensuring a second call fails without mutating the
stored key.
In `@packages/account/src/tests/falcon_512_fixture.cairo`:
- Around line 8-11: Correct the documentation comment above msg() to describe
1222479111879746474823 as the encoded benchmark message “BENCH_MSG,” not its
hash; leave the function and returned value unchanged.
In `@packages/account/src/tests/test_falcon_512_ntt.cairo`:
- Around line 136-141: Update test_intt_reduces_before_last_level to pass the
nonzero input ntt([1, 2, 3, 4]) to intt, using input_bits = 111 and input_bound
= 12289 with the existing degree-4 configuration. Preserve the assertion that
the recovered values equal the original [1, 2, 3, 4] values.
---
Nitpick comments:
In `@packages/account/README.md`:
- Around line 13-22: Update the README’s Interfaces section to list the new
public interfaces IFeltArrayPublicKey and IFeltArrayDeployable alongside ISRC6
and ISRC9_V2, reflecting the felt-array key and deploy entrypoints used by the
Falcon accounts.
In `@packages/account/src/falcon_512.cairo`:
- Around line 24-31: Derive all signature and public-key slice offsets from the
existing layout constants, including the hint slice, instead of hardcoded 29 and
31 values. Add a shared decode_common helper for public-key, s1, and
message-point decoding, then update both verify implementations to reuse it
while preserving their distinct signature-layout handling.
In `@packages/account/src/falcon_512/account.cairo`:
- Around line 155-178: Reduce repeated public-key storage reads across
validate_transaction and is_valid_signature by caching the immutable Falcon-512
key in a single packed storage representation initialized by the constructor,
then have read_public_key reuse that cached value. If the existing storage model
prevents caching, document the 29-felt plus length-read cost for integrators
instead.
In `@packages/account/src/falcon_512/hashing/shake256.cairo`:
- Around line 156-157: Update the `shake256` function visibility so it is
compiled only for tests using the project’s test configuration attribute, unless
a real production caller is added. Keep `keccak_f1600` and the existing test
calls unchanged.
In `@packages/account/src/falcon_512/ntt/engine.cairo`:
- Around line 357-360: Update the last-level reduction branch in the NTT engine
to reset bits consistently when bound is reset after reduce_pass. Preserve the
existing reduction flow and ensure both tracked values reflect the new bound for
any subsequent use.
In `@packages/account/src/falcon_512/ntt/falcon512.cairo`:
- Around line 34-50: Add an explicit precondition at the start of
config_for_degree validating that n is a power of two within the supported range
[4, 512], and assert with a message that includes the supplied n when invalid.
Keep the existing permutation construction and config_with_perm flow unchanged
for valid degrees.
In `@packages/account/src/tests/test_falcon_512.cairo`:
- Around line 375-391: The four negative tests currently accept any panic; pin
each to the specific expected panic message. In
packages/account/src/tests/test_falcon_512.cairo:375-391, update
test_constructor_rejects_wrong_public_key_length and
test_constructor_rejects_noncanonical_public_key with the messages emitted by
the public-key length and canonicality checks. In
packages/account/src/tests/test_falcon_512_ntt.cairo:143-153, update
test_forward_roots_reject_unsupported_degree and
test_inverse_roots_reject_unsupported_degree with the actual messages from
get_even_roots_felt and get_scaled_inv_roots.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 2bca1632-f2eb-4d2d-9c6f-db954491b7bc
⛔ Files ignored due to path filters (1)
Scarb.lockis excluded by!**/*.lock
📒 Files selected for processing (29)
.github/workflows/test.ymlLICENSEScarb.tomlpackages/account/README.mdpackages/account/Scarb.tomlpackages/account/src/falcon_512.cairopackages/account/src/falcon_512/account.cairopackages/account/src/falcon_512/falcon.cairopackages/account/src/falcon_512/falcon_512_shake.cairopackages/account/src/falcon_512/falcon_512_shake_direct.cairopackages/account/src/falcon_512/hashing.cairopackages/account/src/falcon_512/hashing/hash_to_point.cairopackages/account/src/falcon_512/hashing/shake256.cairopackages/account/src/falcon_512/ntt.cairopackages/account/src/falcon_512/ntt/bitrev.cairopackages/account/src/falcon_512/ntt/engine.cairopackages/account/src/falcon_512/ntt/falcon512.cairopackages/account/src/falcon_512/ntt/falcon512_fast.cairopackages/account/src/falcon_512/ntt/roots_felt.cairopackages/account/src/falcon_512/ntt/roots_scaled.cairopackages/account/src/falcon_512/packing.cairopackages/account/src/falcon_512/zq.cairopackages/account/src/lib.cairopackages/account/src/tests.cairopackages/account/src/tests/falcon_512_fixture.cairopackages/account/src/tests/test_falcon_512.cairopackages/account/src/tests/test_falcon_512_ntt.cairopackages/interfaces/README.mdpackages/interfaces/src/account/accounts.cairo
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Review — falcon_512
|
immrsd
left a comment
There was a problem hiding this comment.
Left minor comments, apart from that LGTM
immrsd
left a comment
There was a problem hiding this comment.
Full review of the Falcon-512 PQ account addition — findings verified against the actual sources, with the crypto core independently re-derived and the gas/size numbers measured on this branch (scarb/cairo 2.18.0).
Measured baseline (release profile):
| CASM felts | class bytes | sierra gas / verify | |
|---|---|---|---|
Falcon512ShakeAccountUpgradeable |
57,120 (69.7% of 81,920 cap) | 2,159,881 | ~52.5M |
Falcon512ShakeDirectAccountUpgradeable |
57,048 | 2,039,421 | ~62.7M |
AccountUpgradeable (baseline) |
6,244 | 139,195 | — |
Cost split of one verification: SHAKE-256/hash_to_point ~36M (68%), generic intt ~15.5M (direct only), generated forward NTT ~1.6M, unpacking ~1.5M each.
Inline comments carry the individual findings (3 High, 8 Medium, 8 Low/Info). Two things that don't anchor to changed lines:
- SRC9 self-call cost (Low, pre-existing design):
SRC9Component::assert_valid_signaturedispatchesis_valid_signaturethroughcall_contract_syscallat the account's own address, re-entering the 57k-felt class and re-reading the whole 29-felt key (verified:CallContract: 2, StorageRead: 90vs 1/30 on the direct path). Account-agnostic by design and not introduced here, but far more visible with this key size — the presets could call the component impl directly. - Minor:
Errors::INVALID_PUBLIC_KEYreused for an unreachable stored-length invariant (account.cairo:397);SHIFTadded per NTT output instead of per butterfly pair (−512 CASM felts available, two-line generator change); duplicated cfg-gated module/forward_nttdeclarations inpresets/src/lib.cairoandfalcon.cairo;second_accept_ownership_hash()unused;DIRECT_SIGNATURE_FELTShardcoded in preset tests because the constant ispub(crate); theintt(…, 111, 12289, …)NTT test passes deliberately inconsistent bits/bound args with no explanatory comment.
Verified sound (checked, not assumed): norm bound 34034726 = reference l2bound[9] with correct inclusive comparison; centering arithmetic; hint soundness (the generator proves the 512 evaluation points are distinct roots of x^512+1, so the NTT is a bijection and mul_hint is uniquely pinned to s1·h); strict canonical-encoding bijection with [0,q)^512 (all Acc*/DivT constants verified); SHAKE-256 round constants, ρ/π/θ/χ/ι and pad10*1 layout against FIPS 202; REJECT_BOUND = 5q; all overflow bounds (norm accumulator < 2^36, NTT lazy-reduction schedule peaks at 2^122.3 with 6 bits of headroom — do not reuse the generator for n=1024 without re-running the bound check). The checked-in NTT tables regenerate byte-for-byte from the script; the fixtures were decoded in Python and the Falcon relation re-verified externally. Replay protection, deploy front-running (key in constructor calldata → address derivation), access control, and graceful rejection of malformed input all check out.
Overall: the cryptographic core is correct and carefully built, but the upgrade-bricking hazard needs closing, the generated-code and SHAKE efficiency work plus a CASM/gas CI guard are needed before these presets are safe to evolve at 70% of the bytecode cap — and the hint-vs-direct question deserves an explicit decision before both variants become public API.
…eat/add-post-quantum-accounts
immrsd
left a comment
There was a problem hiding this comment.
Re-reviewed after the updates — the responses are substantial and they verify cleanly on my side: the regenerated NTT sources match byte-for-byte, the resource and gas budgets actually fail when tightened, and check_fixtures.py independently reproduces all four signatures. Remaining items are in the inline comments; the one I'd still consider blocking before approval is the upgrade-compatibility warning (existing thread on the preset).
One request: could the lint-related fixes move to their own small PR? That's the ERC6909TokenSupplyMock hooks change with its new supply tests, the ERC721Consecutive DefaultConfig imports, the governor unwrap_or_else changes, and the SRC9 mock assert. They're all legitimate — each traces to a real scarb lint warning, and the ERC6909 one is a genuine mock fix prescribed by the new with_components diagnostic — but main currently carries the identical warnings, so a standalone PR would fix them where they live, and a behavioral change to a shared mock is easy to miss inside a Falcon feature PR.
Related follow-up worth considering: the CI "Cairo lint" step only runs scarb fmt --check, so these diagnostics (including the new ERC6909 hook-wiring one) aren't enforced anywhere. Promoting it to also run scarb lint would keep this from recurring.
|
|
||
| // Budgets include deployment and test setup as well as one validation call. | ||
| #[test] | ||
| #[available_gas(l2_gas: 75000000)] |
There was a problem hiding this comment.
Medium: the budgets don't assert the number that matters.
These bundle declare + deploy + setup + validate into one #[available_gas], so the headroom they demonstrate is against a repo-chosen number, not the protocol limit — validate_max_sierra_gas (~1e8) and validate_max_n_steps (1e6) are asserted nowhere in the repo. If a compiler or gas-schedule change pushes a single __validate__ past the cap, deployed accounts of that variant can no longer validate any transaction, and CI stays green.
Suggestion: one test per variant that isolates a single __validate__ (or subtracts the measured deploy baseline) and asserts it under the protocol cap with an explicit margin.
| MAX_BYTECODE_FELTS = 81_920 | ||
| MAX_CLASS_BYTES = 4_089_446 | ||
| # Repository regression budgets leave room below the protocol limits. | ||
| BUDGETS = {"sierra_felts": 60_000, "casm_felts": 50_000, "artifact_bytes": 2_000_000} |
There was a problem hiding this comment.
Three nits:
- The protocol-cap checks below can never fire — the repo budgets are all strictly tighter and raise first. Fine as a backstop, but worth a comment saying only the budgets are enforced.
- The "including debug info and whitespace makes this stricter" claim doesn't hold: stripping
sierra_program_debug_infofrom the release artifact changes the size by ~86 bytes. - The tightest gate is the least meaningful one: artifact bytes sit at ~89% of the 2MB budget while CASM is at ~43% of its cap, so the first alarm will likely be a false one. Consider rebalancing the byte budget.
|
|
||
| // Production inputs come from canonical base-Q unpacking; the test wrapper documents the same | ||
| // coefficient precondition. The generated unchecked NTT is sound for both call paths. | ||
| let s1_ntt = forward_ntt(s1); |
There was a problem hiding this comment.
Low: the norm check could run before these two transforms.
The norm accumulation depends only on msg_point, mul_hint, and s1 — none of the NTT outputs. Moving it ahead of the forward_ntt calls makes every norm-failing signature (wrong key, replayed/corrupted signature) reject before paying for both transforms. Same idea for the direct variant: Σ center_sq(s1) > β² can reject before its NTT + INTT.
Caveat: this only cheapens the honest-failure path — crafted inputs (e.g. s1 = 0, mul_hint = msg_point) still pass the norm gate and force the transforms — but it's a free win.
| } | ||
|
|
||
| /// Inverse-transform configuration without unused forward root tables. | ||
| pub fn inverse_config() -> NttConfig { |
There was a problem hiding this comment.
Info: inverse_config() returns a config with empty merge_roots; passing it to ntt() panics with a bare index-out-of-bounds. Internal-only, but a latent footgun — an assert with a clear message at the top of ntt() (or separate forward/inverse config types) would make the misuse obvious.
|
|
||
| N = 512 | ||
| PRIME = 2**251 + 17 * 2**192 + 1 | ||
| NORM_BOUND = 34_034_726 |
There was a problem hiding this comment.
NORM_BOUND, Q, and the felt layout are duplicated here with no cross-check against the Cairo constants (SIG_BOUND_512, PUBLIC_KEY_FELTS, ...) — if either side changes, the checker silently drifts. Cheap fix: read the constants out of the Cairo source and compare, the way the NTT generator check does.
Also worth one line in CONTRIBUTING: the fixtures are verifiable but not reproducible (no seeds or signer committed), so a layout change can only be re-checked, never re-derived. Committing the signer script or the seeds would close that.
| resource limits again. A successful local build does not verify a public network's supported | ||
| Sierra version or permitted libfuncs. | ||
|
|
||
| ### Validation resources |
There was a problem hiding this comment.
Three additions worth making in this section:
- The figures come from a single reference vector; ~63% of signatures need one extra Keccak permutation (rejection sampling), so label them typical rather than worst-case — direct sits fairly close to the validate cap.
- A transaction that fails
__validate__costs the sender nothing but costs the sequencer the full ~46-56M gas, roughly 100x a STARK-curve account. Worth stating that the mitigation is sequencer-side mempool policy, not the contract. - Since both variants ship, a sentence on when to pick hint vs direct (hint is currently ~10M gas cheaper; direct has 31-felt signatures) so the choice isn't guesswork.
Fixes #1725
Summary
Falcon512AccountComponentwith SHAKE-256 hint and direct verification strategies for canonical 29-felt Falcon-512 public keys.Falcon512ShakeAccountUpgradeableandFalcon512ShakeDirectAccountUpgradeablepresets with SRC9 outside execution and self-authorized class upgrades.The verifiers implement the SHAKE-256 verification relation from the FALCON submission selected by NIST using contract-specific felt encodings. They are not FN-DSA (FIPS 206) implementations.
PR Checklist