Skip to content

Full dex test with final halo2 instruction/circuit + check historical hashes instruction NODE-2737#232

Open
alinaT95 wants to merge 275 commits into
mainfrom
full_dex_test_with_final_halo2_circuit
Open

Full dex test with final halo2 instruction/circuit + check historical hashes instruction NODE-2737#232
alinaT95 wants to merge 275 commits into
mainfrom
full_dex_test_with_final_halo2_circuit

Conversation

@alinaT95
Copy link
Copy Markdown
Contributor

No description provided.

alinaT95 and others added 20 commits April 17, 2026 01:54
VerifyingKey::read internally constructs an EvaluationDomain (K=19)
that precomputes FFT twiddle factors for 2^19 elements — takes
several seconds, far too slow to repeat per ZKHALO2VERIFY call.

Use OnceLock to build VK and params once, reuse forever.
Spawn background warmup thread during handler registration so the
first transaction doesn't block.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New instruction (opcode 0xC7 0x51) verifies that a key block's common
section at a specified layer stores a particular layer hash value.
Takes 3 stack args: hash (256-bit), block_height (u64), layer_number (u8).
Returns boolean. Uses callback pattern for verification logic.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The opcode 0xC7 0x49 was registered in the VM handler but missing
from the assembler, causing the sold linker to fail on contracts
using gosh.zkhalo2verify.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The CHKHISTPROOF callback in consumers (e.g. acki-nacki) only indexes into
a (thread_id, layer_number, hash) tuple — block_height was popped from the
stack but never used for filtering. Dropping it from:

  - executor stack-pop count: fetch_stack(3) → fetch_stack(2)
  - callback type: Fn(u64, u8, [u8;32]) → Fn(u8, [u8;32])
  - 3 fields carrying the Arc (engine core, vmsetup, transaction_executor)
  - test helpers + 5 chk_hist_proof tests

Bytecode (0xC7, 0x51) is unchanged.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Existing VERGRTH16 (0xC7 0x31) is hardwired to the zkLogin verifying key
returned by global_pvk(), so it cannot be reused by other circuits. The new
VERGRTH16WITHVK opcode (0xC7 0x49) keeps the same BN254 / arkworks machinery
but takes the verifying key as a third stack operand, making the verifier
generic over any Groth16-on-BN254 setup.

Primary use case (NODE-3406): the Acki Nacki -> Ethereum bridge needs to
verify wrapped Halo2 deposit-event proofs produced on Ethereum. With this
opcode in place the AN-side TokenBridge.finalizeDeposit can replace its
current `proof; // ignored` stub with a real ZK check.

Stack layout for VERGRTH16WITHVK (top -> bottom):
  vk_cell             Cell with ark_groth16::VerifyingKey<Bn254>
                      in canonical-compressed form
  public_inputs_cell  Cell with concatenated compressed Fr elements
  proof_cell          Cell with ark_groth16::Proof<Bn254> compressed

Pushes a Boolean: true if the pairing check holds, false otherwise.
Malformed VK / proof / public-input bytes throw FatalError; a cryptographic
rejection is signalled as `false` on the stack.

Gas: 2600 (VERGRTH16 + small overhead for VK deserialization and the
gamma_abc_g1 MSM that scales with the number of public inputs).

Tests:
  * tvm_vm/src/tests/test_vergrth16_with_vk.rs - 6 unit tests covering the
    positive path, flipped-bit proof, wrong public input, swapped VK,
    mismatched input count, and BN254 pairing sanity. Proofs are produced
    in-process via ark-groth16 + a minimal a*b=c R1CS gadget, so the test
    is self-contained (no external fixture files).
  * tvm_assembler/src/lib.rs - round-trip check that the four gosh-feature
    ZK mnemonics (VERGRTH16, POSEIDONZKLOGIN, VERGRTH16WITHVK, POSEIDON)
    compile to their expected dispatch bytes.

Full tvm_vm --features gosh suite: 103/103 passing.

Co-authored-by: Cursor <cursoragent@cursor.com>
CI Lint step runs `cargo +nightly fmt --all -- --check` and rejected the
doc-comment line wrapping in zk.rs and test_vergrth16_with_vk.rs from the
previous commit. Pure formatting fixup — no semantic change.
Re-ran the 6 VERGRTH16WITHVK unit tests after the reflow: still all green.

Co-authored-by: Cursor <cursoragent@cursor.com>
Three review items from the customer:

1. (blocker) Gas-price docstring rewritten to make the cost model explicit.
   The previous wording said "~6 ms for VK preparation" but that pairing
   evaluation is already done by VERGRTH16 inside global_pvk() and thus
   already paid for by the 2380-gas baseline. The +220 delta covers only
   the strictly marginal work: VK deserialize, gamma_abc_g1 size check,
   and the IC-MSM increment over zkLogin's 2 IC points. Spelled out so a
   future reviewer can re-tune the price if the opcode is exposed to
   circuits with substantially more public inputs.

2. (blocker) "Throws" section reorganised so the input-count mismatch
   path is no longer buried in a trailing Note: the docstring now lists
   the exhaustive set of "pushes false" cases (pairing fail + gamma_abc_g1
   mismatch) and the exhaustive set of FatalError cases (malformed VK,
   malformed proof, non-32-byte-aligned public inputs) at the same
   visibility level. Behaviour is unchanged.

3. (nit) `#[cfg(test)]` on the test module replaced with
   `#[cfg(all(test, feature = "gosh"))]`. The 0xC7 0x49 handler is only
   registered under the `gosh` feature in handlers.rs, so without the
   feature the tests would have failed with "unknown opcode" — making
   the gate explicit prevents that surprise and matches the implicit
   convention of the rest of the gosh.* test suite.

Items #3 (boolean!(res?) unreachable) and #5 (unpack_data_from_cell
error text in utils) were noted as non-blockers; #3 stays as-is for
visual parity with execute_vergrth16, #5 is in a shared utility and
out of scope for this PR.

6/6 unit tests still green under `--features gosh`; `cargo check`
without features also clean.

Co-authored-by: Cursor <cursoragent@cursor.com>
@alinaT95 alinaT95 requested a review from SeHor05 May 14, 2026 05:26
alinaT95 and others added 3 commits May 14, 2026 09:33
The crate was declared as an optional dep but never activated by the gosh
feature, so building with default features failed with E0433 in
tvm_vm/src/executor/zk_halo2{,_utils}.rs. Add dep:gosh-zk-snark-halo2-utils
to the gosh feature alongside the other ZK deps, and add a TODO in
zk_halo2_utils.rs noting that a VK per historical window will be required
(currently 4 for tests, 128 in future).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The DarkDexCircuitNew circuit now exposes ephemeral_pubkey as a 5th
public instance, so the stored proof/instances .bin files (4 instances,
128 bytes) no longer matched the embedded DARK_DEX_W8_VK_BYTES. Regenerate
the L0/L1/L2 fixtures with 5 instances (160 bytes) and re-enable the
previously commented-out assertion for the L1 case. Drop the unused
dark_dex_w8_vk.bin file (verifier reads the embedded const, not the file).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@elasticLove1 elasticLove1 changed the title Full dex test with final halo2 instruction/circuit + check historical hashes instruction Full dex test with final halo2 instruction/circuit + check historical hashes instruction NODE-2737 May 14, 2026
alinaT95 and others added 5 commits May 14, 2026 12:35
Two related wasm-hygiene fixes that were missing on this branch:

* GasState::chkhistproof_price / consume_chkhistproof reference
  CHKHISTPROOF_GAS_PRICE, which is gated behind feature = "gosh". Gate
  the methods themselves to match (mirroring consume_vergrth16 above).
  Without this, any non-gosh build (wasm_web in particular) fails with
  unresolved name errors.

* The cached PoseidonSponge / GLOBAL_SPONGE infrastructure references
  halo2_Fr and pse_poseidon, which are not available on wasm32. The
  imports were already cfg-gated to native, but the struct, impls,
  static, and free functions using them were not. Gate the cached path
  to non-wasm32 and add wasm32 stubs of poseidon_bytes_axiom /
  poseidon_bytes_flat returning Err(UnsupportedPlatform), matching the
  pattern used on main before the caching refactor landed.

Native runtime behavior is unchanged (cached round constants still
active via GLOBAL_SPONGE). cargo build --release passes; cargo check
--target wasm32-unknown-unknown -p tvm_client --features wasm_web also
passes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PR #233 (vergrth16-with-vk) merged a dispatch entry .set(0x50,
execute_poseidon) into handlers.rs and a POSEIDON mnemonic into the
assembler, but the execute_poseidon function definition itself never
landed. Remove both the dispatch and the mnemonic and renumber the
two opcodes that followed to close the gap:

  CHKHISTPROOF     0xC7,0x51 -> 0xC7,0x50
  VERGRTH16WITHVK  0xC7,0x52 -> 0xC7,0x51

Also clean up two gas_state.rs merge artifacts from the same merge:

* Stray "full_dex_test_with_final_halo2_circuit" token inside
  consume_chkhistproof, left over from a conflict marker cleanup.
* Missing #[cfg(feature = "gosh")] gate on the VERGRTH16_WITH_VK_GAS_PRICE
  import; the executor::zk module is gosh-only, so wasm builds broke
  trying to resolve it.

cargo build --release passes; cargo check --target wasm32-unknown-unknown
-p tvm_client --features wasm_web also passes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The test hard-coded the opcode as 0xC7 0x49, which is ZKHALO2VERIFY's
encoding, not VERGRTH16WITHVK's. The accepts_valid_proof test failed
because the stack layout doesn't match the halo2 verifier; the three
reject_* tests passed for the wrong reason (mismatched stack also
returns false in the halo2 path). After the post-POSEIDON renumber,
VERGRTH16WITHVK is 0xC7 0x51 on this branch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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.