Add Spark V2 mobile spend support - #12
Conversation
Keep the deployed prefix-only s2 derivation, avoid writes through cleared vectors, and cleanse temporary seed buffers. Pin both derivations so future refactors cannot change wallet addresses.
Preserve the deployed V1 wire format while adding Spark V2's componentwise Chaum proof, context binding, canonical bounded serialization, and explicit historical verification. Cover the new proof and payload rules with tamper, bounds, and round-trip tests.
Require callers to select V1 or V2 explicitly, pass the extension commitment before proof generation, and account for V2 input size. Add Spark Name domain binding and wallet amount guards, then make the complete integration test path fail fast.
🤖 CodeAnt AI — Review Status
|
|
@CodeAnt-AI review |
User descriptionProblemSparkMobile only builds the deployed V1 type-9 spend payload. Firo #1913 restores multi-input Spark spending through the versioned type-11 V2 proof and payload, so mobile callers cannot construct restored spends. Changes
The library keeps its existing combined Downstream callers must select V2 by next-block activation height, set outer Validation
Known test gap: the suite checks V2 per-input response rejection, but does not yet port Core's full non-diagonal V1 forgery fixture or submit a transaction to an H2-enabled Related: firoorg/firo#1913 CodeAnt-AI DescriptionAdd versioned Spark V2 spends while preserving historical V1 transactions What Changed
Impact
💡 Usage GuideChecking Your Pull RequestEvery time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later. Talking to CodeAnt AIGot a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask: This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code. ExamplePreserve Org Learnings with CodeAntYou can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input: This helps CodeAnt AI learn and adapt to your team's coding style and standards. ExampleRetrigger reviewAsk CodeAnt AI to review the PR again, by typing: Check Your Repository HealthTo analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health. |
User descriptionProblemSparkMobile only builds the deployed V1 type-9 spend payload. Firo #1913 restores multi-input Spark spending through the versioned type-11 V2 proof and payload, so mobile callers cannot construct restored spends. Changes
The library keeps its existing combined Downstream callers must select V2 by next-block activation height, set outer Validation
Known test gap: the suite checks V2 per-input response rejection, but does not yet port Core's full non-diagonal V1 forgery fixture or submit a transaction to an H2-enabled Related: firoorg/firo#1913 CodeAnt-AI DescriptionAdd versioned Spark V2 mobile spends while preserving existing V1 transactions What Changed
Impact
💡 Usage GuideChecking Your Pull RequestEvery time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later. Talking to CodeAnt AIGot a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask: This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code. ExamplePreserve Org Learnings with CodeAntYou can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input: This helps CodeAnt AI learn and adapt to your team's coding style and standards. ExampleRetrigger reviewAsk CodeAnt AI to review the PR again, by typing: Check Your Repository HealthTo analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health. |
CodeAnt Nitpicks1 code suggestion1. V1 accepts extension commitments that are never serialized or cryptographically bound.Api mismatch · |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 195d354997
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Require recipient memo plaintext to match the fixed deployed shape before reading its length. Cover both mint and spend identification with authenticated short-payload regressions.
Sample the S/V equation-binding weight across the scalar field instead of restricting it to 16 bits. Keep the existing nonzero retry required by the verification equation.
Accept the ownership digest and spend version at the script boundary, then derive the proof scalar internally. This makes stale V1 scalar mapping fail at compile time for V2 callers while preserving both proof paths.
Reject non-null extension commitments in the direct V1 constructor because the V1 wire format and Chaum proof do not carry or bind them. Cover the low-level API alongside the existing wrapper guards.
Reject zero and IDs above INT32_MAX at the V2 serialization boundary, matching constructor and Core contextual validation. Cover wire payloads whose ID vectors and reference maps otherwise remain internally consistent.
Build internally consistent invalid-ID fixtures and assert the intended constructor error. Serialize a complete V2 dimension header so EOF cannot satisfy the bounds regression.
Convert every Scalar raw-string throw to std::runtime_error so Spark Name and FFI std::exception boundaries catch failures consistently. Cover the restored V1 ownership path with an overflowing digest.
Sparkmobile has no network or height context, so its fixed 10,000 FIRO rejection can conflict with Core policy. Preserve the public base constant, remove only the unconditional check, and construct and verify an 11,000 FIRO V2 spend.
Return status 1 when either script is missing its output directory or receives an existing file, so CI and callers cannot mistake rejected input for success.
Use otherwise-valid fixtures and exact error predicates for Chaum input caps, amount and fee checks, cover-set IDs, and extraneous hashes. Each regression now fails if its target guard is removed instead of passing on an unrelated later error.
Use separate function-local statics for production and test parameters. Copy the parameter pointer during SpendKey assignment so assigned scalars remain paired with their generators.
Require complete Bech32 conversion, canonical non-identity group keys, and the exact two-byte HRP before accepting an address. Recheck recipient keys at coin construction so programmatically created invalid addresses cannot create unspendable outputs.
Propagate coin-identification failures instead of returning partially initialized metadata. Preserve the coin type and serial context on round trip, and give fundamental metadata fields safe defaults.
Reject impossible cover-set sizes and mismatched generator/scalar vectors before indexing them. Delete unsafe implicit MultiExponent assignment and correct the tests to allocate serialized-root storage before writing.
Own OpenSSL contexts with RAII and check every allocation and operation before using its output. Reject truncated AEAD tags, preserve transcript state on copy failure, and throw standard exceptions when randomness or AES encryption fails.
Clean derived seed bytes before later construction can throw, wipe SpendKeyData and Scalar storage at destruction, and reject null key buffers before copying from the public pointer boundary.
Pass large cover-set data by reference, move owned coin and script results, reserve input storage, and verify transaction batches by reference. Remove the randomized default-key comparison because it cannot validate a caller's key and only adds RNG work.
Use a small local compatibility header when the platform does not provide endian.h. Keep the existing system header path on Unix-like platforms and avoid adding a dependency.
Quote caller paths, let make refresh changed secp256k1 sources, compile shared sources once, and drive every test from one explicit list. Add a least-privilege Ubuntu workflow and document the actual vendored build.
Run push-triggered CI only for main. Pull request branches remain covered by the pull_request event without launching the same job twice.
Problem
SparkMobile only constructs the deployed V1 type-9 spend payload. Firo #1913 restores multi-input Spark spending through the versioned type-11 V2 proof and payload, so mobile callers cannot construct restored spends.
Changes
The library keeps its existing combined
CoverSetData. No Core state, cache, mempool, RPC, Qt, or provider abstractions were copied. Low-level C++ consumers must rebuild for the versioned V2 API and const-reference signatures.Downstream callers must select V2 by next-block activation height, set outer
nVersion = 3and type11before computingtxHashSig, pass same-tip 32-byte cover-set references, emit transparent outputs before zero-valued private outputs, and recheck the tip before broadcast. The Flutter wrapper must also pass the Spark Name ownership digest and explicit spend version instead of constructing aScalarwithSetHex.Validation
make -C secp256k1 check, 2 tests passedbash -n build run_all_tests.github/workflows/test.ymland rangit diff --check origin/main...HEAD1d57c4f7efa7eea0819b7996c2f27f4515f51d444f0c771462b2f327e3a7ff7bf2532bc33c727713Known validation gap: no transaction was submitted to an H2-enabled
firodbecause no local Firo node binary was available. V1 proof behavior remains unchanged for historical compatibility; any stricter V1 consensus rule requires activation-aware handling in Firo Core.Related: firoorg/firo#1913