Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
d6c5964
Add MULTITHREAD_CIRCUIT_SPEC.md — DEX circuit multi-thread design
alinaT95 Jun 26, 2026
c74b9e1
Spec: note anonymity as the primary purpose of layer-N anchoring
alinaT95 Jun 26, 2026
7ff4742
Spec: fix proposal doc filename reference
alinaT95 Jun 26, 2026
0be4fe3
Spec: relocate hash-family notes out of Terminology
alinaT95 Jun 26, 2026
f85887f
Spec: complete multi-proof multi-thread design
alinaT95 Jun 26, 2026
0594a23
Spec: lock MAX_PROOF_BLOCK_REFS = 256 (depth-8 L7 inner tree)
alinaT95 Jun 27, 2026
35b19f1
Phase 3: expose salt_commitment + event_salted_block_id publics in Da…
alinaT95 Jun 28, 2026
06be9b1
Phase 4 Stage 1: bundle_verifier (pure-Rust RootPN.sol mock) + bindin…
alinaT95 Jun 28, 2026
7fb2135
Phase 4 Stage 2a: multi_hop_witness — GQL-shaped witness + native hel…
alinaT95 Jun 28, 2026
85c5c43
Phase 4 Stage 2b: synth_chain + split_into_bundle_snarks helpers
alinaT95 Jun 28, 2026
b297763
Phase 4 Stage 2c: MultiHopProofCircuit{,B,C} — three sibling halo2 ci…
alinaT95 Jun 28, 2026
ef04074
Phase 4 Stage 2d: bundle E2E happy path (4 real KZG snarks + DexFinal)
alinaT95 Jun 28, 2026
7db99ee
Phase 4 Stage 2e: bundle negative tests — 5 failure scenarios
alinaT95 Jun 28, 2026
79ea68c
Phase 4 Stage 2f: bundle stress at L = L_MAX = 20 (worst-case spec ta…
alinaT95 Jun 28, 2026
bb03da3
Phase 4 Stage 2g: variable-N_BUNDLE stress tests at L = 50 / 100 / 300
alinaT95 Jun 28, 2026
fdf72c8
Spec: rename chain-length K → L to disambiguate from halo2 circuit K
alinaT95 Jun 28, 2026
7a28dda
Spec: branch-precise GlobalHistoryData / history_proofs semantics
alinaT95 Jun 29, 2026
67d3b67
rename
alinaT95 Jun 29, 2026
72e673b
Spec §6.11: measured Phase 4 bundle-test performance (dev hardware)
alinaT95 Jun 29, 2026
8b121a5
Remove dead code: unused circuit_helper, boc parsers, trivial test
alinaT95 Jun 29, 2026
39a3893
poseidon/salt: single source of truth in gosh-dense-balanced-tree
alinaT95 Jun 29, 2026
cc6f8db
Delete dex-halo2-circuit::poseidon shim; consume gosh-dense-balanced-…
alinaT95 Jun 29, 2026
65d5a75
bundle_verifier: drop Phase 4 scaffolding, rename to DEX_FINAL_LEN
alinaT95 Jun 29, 2026
0882bb2
Rename salted_start/salted_end → salted_start_block_id/salted_end_blo…
alinaT95 Jun 29, 2026
34aacef
multi_hop_witness: drop stage/phase references from comments
alinaT95 Jun 29, 2026
c9b2fb7
multi_hop_proof: drop stage references, link circuit variants
alinaT95 Jun 30, 2026
3e66559
multi_hop_witness: derive MAX_PROOF_BLOCK_REFS_DEPTH, clarify HopWitn…
alinaT95 Jun 30, 2026
b3f379e
Phase 1 byte-flat poseidon (native): drop Fr-vector helpers
alinaT95 Jun 30, 2026
dec07c9
Phase 2 byte-flat poseidon (in-circuit Phase A)
alinaT95 Jun 30, 2026
c549650
Phase 3 byte-flat poseidon (in-circuit Phase B + Phase C)
alinaT95 Jun 30, 2026
94f7628
dark_dex: sibling poseidon_hash_96_circuit_bytes (sound byte-flat)
alinaT95 Jun 30, 2026
0745e6e
Phase 4 byte-flat poseidon (dark_dex_circuit_new + spec)
alinaT95 Jun 30, 2026
5c56444
Phase 4 cleanup: drop dead Fr-input poseidon_hash_96_circuit, refresh…
alinaT95 Jun 30, 2026
2d6aa1c
Split MultiHopProof into hop_proof + multi_hop_proof; drop phase framing
alinaT95 Jun 30, 2026
54fdfbd
hop circuits: thread private ref_index witness through both layouts
alinaT95 Jun 30, 2026
5d02b35
Rename parent_id witness field to ref_block_id
alinaT95 Jun 30, 2026
477fc91
docs: clarify HopProofCircuit is a standalone example, not used by Mu…
alinaT95 Jun 30, 2026
044ae58
Rename ref_leaf_tag_chunk*_fr to ref_leaf_parent_tag_chunk*_fr
alinaT95 Jun 30, 2026
db90e55
Expand cryptic _p/_r suffixes on ref-leaf chunk locals
alinaT95 Jun 30, 2026
b012cb4
Rename salted_endpoint closure param other to endpoint_id_bytes
alinaT95 Jun 30, 2026
4207040
Hoist powers_le_32 table; slice at call sites
alinaT95 Jun 30, 2026
baeb673
Bring MultiHopProof MockProver into smartphone budget (K=17)
alinaT95 Jun 30, 2026
bf86671
Real-prover tests: bring MultiHopProof into smartphone budget (K=17)
alinaT95 Jun 30, 2026
467cf7f
Spec update: no-C variant with depth-4 block-id + L8 event binding
alinaT95 Jul 1, 2026
9c54bd5
Rewrite spec as single-protocol description (no history / no C)
alinaT95 Jul 1, 2026
3f70f30
Spec: correct anchor model — RootPN not thread-0-pinned
alinaT95 Jul 1, 2026
4a6eca0
spec fix
alinaT95 Jul 1, 2026
ca42f29
docs fix
alinaT95 Jul 1, 2026
9cc5e8d
docs fix
alinaT95 Jul 1, 2026
b9aaf01
Spec §1.4: drop premature salted_endpoint reference
alinaT95 Jul 1, 2026
d4b35c9
Spec §0: define X-side / Y-side jargon
alinaT95 Jul 1, 2026
e7a6458
Spec §0: add Poseidon 31-byte chunking reminder
alinaT95 Jul 1, 2026
125dae7
Spec §5: drop L7 slot-0 (parent_block_id) from hop primitive
alinaT95 Jul 1, 2026
f1cb089
Spec §5.2: clarify hop is a building block; no publics, is_active bel…
alinaT95 Jul 1, 2026
e1900a6
Spec §5.3: hop is 4 SHA compressions, not 6 (h8..15 opaque in hops)
alinaT95 Jul 1, 2026
7e69043
docs fix
alinaT95 Jul 1, 2026
340b98b
Spec: record production L_MAX = 300 (node-team spec) alongside L_MAX …
alinaT95 Jul 1, 2026
2766a40
Spec §7.3: drop stale reference to gosh-referenced-block-hop
alinaT95 Jul 1, 2026
49301cf
Spec §7.4: reorder RootPN to fail-fast on public-input consistency be…
alinaT95 Jul 1, 2026
35f7fdb
Spec §7.7: fix DexFinalProof L8-opening — 4 SHA compressions, not 3
alinaT95 Jul 1, 2026
db01583
Spec §7.7: highlight DexFinalProof as two disjoint sub-proofs (X-side…
alinaT95 Jul 1, 2026
fe12040
Spec §12: rewrite Circuit implementation plan to reflect all prior §§…
alinaT95 Jul 1, 2026
e406761
Spec §12: drop recap preamble; keep short up-to-date plan intro
alinaT95 Jul 1, 2026
1a68671
Spec §12.2: clarify ext-out gadget opens event_hash -> L8 (X-side); L…
alinaT95 Jul 1, 2026
fb679c2
Spec §12.3 + §7.7: X-side witnesses the raw event BOC and reconstruct…
alinaT95 Jul 1, 2026
d48cc56
Circuits: drop parent-slot branch from hop / multi_hop_proof
alinaT95 Jul 1, 2026
ee57e68
DarkDexCircuitNew: refactor to §7.7 V2 semantics (X/Y split, depth-4 …
alinaT95 Jul 2, 2026
802a946
Rename DarkDexCircuitNew → DarkDexCircuit (module dark_dex_circuit)
alinaT95 Jul 2, 2026
04985f2
halo2-proover: migrate to DarkDexCircuit V2 (§7.3 8-instance layout)
alinaT95 Jul 2, 2026
f07c620
Rename event_data_helper -> voucher_event_helper; move extract_event_…
alinaT95 Jul 2, 2026
edadfdf
DarkDexCircuit: rename entries -> voucher_event_entries; dedup SHA256…
alinaT95 Jul 2, 2026
c4d96df
DarkDexCircuit: prefix event-BOC and Y-side locals for readability
alinaT95 Jul 2, 2026
a0a24d0
DarkDexCircuit: rename root_1 -> y_history_window_root
alinaT95 Jul 2, 2026
8cb5fee
DarkDexCircuit: rename final_root -> y_final_root
alinaT95 Jul 2, 2026
9cb1983
Extract salted_block_id_poseidon_circuit into salt.rs
alinaT95 Jul 2, 2026
bfcbe2f
DarkDexCircuit: expose x_account_dapp_id / x_account_id as publics [8…
alinaT95 Jul 2, 2026
546077c
Move voucher parsing helpers into voucher_event_helper
alinaT95 Jul 2, 2026
99e7c15
Drop V2/v2_ naming — no versioning left to disambiguate
alinaT95 Jul 2, 2026
a9c8d89
Unify TwoLevelWitnesses + CrossThreadWitness into DexFinalWitness
alinaT95 Jul 2, 2026
e1e38d4
Fix slot-0 hop-edge comment + rename y_blocks_root_level_0 -> _layer_1
alinaT95 Jul 2, 2026
cb2bc80
Merge build_dex_final_witness_{uniform,cross_thread} into single fn
alinaT95 Jul 2, 2026
ff571d9
add poseidon dex helper
alinaT95 Jul 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 6 additions & 15 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

859 changes: 859 additions & 0 deletions MULTITHREAD_CIRCUIT_SPEC.md

Large diffs are not rendered by default.

122 changes: 0 additions & 122 deletions README.md

This file was deleted.

2 changes: 1 addition & 1 deletion dex-halo2-circuit/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ Input arguments:
}


cargo test --release --package gosh-dark-dex-halo2-new-circuit --lib -- dark_dex_circuit_new::tests::test_dark_dex_circuit_real_proof --exact --nocapture --include-ignored
cargo test --release --package gosh-dark-dex-halo2-new-circuit --lib -- dark_dex_circuit::tests::test_dark_dex_circuit_real_proof --exact --nocapture --include-ignored
155 changes: 155 additions & 0 deletions dex-halo2-circuit/src/block_id_tree.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
//! Depth-4 SHA-256 block_id tree constants and helpers used by
//! [`crate::dark_dex_circuit::DarkDexCircuit`].
//!
//! `block_id` is defined as the SHA-256 root of a depth-4
//! binary tree over 16 fixed-position 32-byte leaves. Leaf 8 is the
//! `l8_tracked_ext_out_messages_root` (a Poseidon image); leaves 9..15 are
//! reserved / zero for now. Leaves 0..=7 are aggregated into an opaque
//! sibling `H07` that the prover supplies as a witness — the circuit does
//! not need to open its structure to bind `x_l8` into `x_block_id`.
//!
//! The depth-4 opening path from leaf-8 to root is:
//! H8_9 = SHA(x_l8 || ZERO_LEAF)
//! H8_11 = SHA(H8_9 || H10_11_CONST)
//! H8_15 = SHA(H8_11 || H12_15_CONST)
//! root = SHA(H07 || H8_15)
//!
//! Only the two constants `H10_11_CONST = SHA(0x00 · 32 || 0x00 · 32)` and
//! `H12_15_CONST = SHA(H10_11_CONST || H10_11_CONST)` need to be shared
//! between prover and verifier — the circuit hard-codes them.

use sha2::{Digest, Sha256};
use std::sync::OnceLock;

/// All-zero 32-byte leaf used to pad the depth-4 block_id SHA-tree.
pub const ZERO_LEAF: [u8; 32] = [0u8; 32];

fn sha256_of_two(a: &[u8; 32], b: &[u8; 32]) -> [u8; 32] {
let mut h = Sha256::new();
h.update(a);
h.update(b);
let out = h.finalize();
let mut r = [0u8; 32];
r.copy_from_slice(&out);
r
}

/// SHA-256(ZERO_LEAF || ZERO_LEAF) — leaves 10..=11 aggregate.
pub fn h10_11_const() -> &'static [u8; 32] {
static ONCE: OnceLock<[u8; 32]> = OnceLock::new();
ONCE.get_or_init(|| sha256_of_two(&ZERO_LEAF, &ZERO_LEAF))
}

/// SHA-256(H10_11_CONST || H10_11_CONST) — leaves 12..=15 aggregate.
pub fn h12_15_const() -> &'static [u8; 32] {
static ONCE: OnceLock<[u8; 32]> = OnceLock::new();
ONCE.get_or_init(|| {
let mid = *h10_11_const();
sha256_of_two(&mid, &mid)
})
}

/// Native helper: derive `block_id` from `x_l8` (leaf-8) and the opaque
/// aggregated left sibling `h07_sibling` (SHA-root of leaves 0..=7).
///
/// This is exactly what the in-circuit `assert_depth4_l8_opening_circuit`
/// gadget enforces bit-for-bit.
pub fn compute_block_id_from_l8_native(x_l8: &[u8; 32], h07_sibling: &[u8; 32]) -> [u8; 32] {
let h8_9 = sha256_of_two(x_l8, &ZERO_LEAF);
let h8_11 = sha256_of_two(&h8_9, h10_11_const());
let h8_15 = sha256_of_two(&h8_11, h12_15_const());
sha256_of_two(h07_sibling, &h8_15)
}

// ---------------------------------------------------------------------------
// In-circuit gadget
// ---------------------------------------------------------------------------

use gosh_sha256_chip::Sha256Chip;
use halo2_base::{
gates::RangeInstructions,
halo2_proofs::halo2curves::bn256::Fr,
AssignedValue, Context,
};

/// Assert that `x_block_id_bytes = depth-4 SHA opening of (leaf=8, sibling_0..=7 = h07)`.
///
/// The four SHA compressions are performed with `sha_chip`. Byte cells are
/// assumed already range-checked to 8 bits by their creators (this gadget
/// re-range-checks the two sibling inputs it loads as witnesses).
pub fn assert_depth4_l8_opening_circuit<'a>(
ctx: &mut Context<Fr>,
range: &impl RangeInstructions<Fr>,
sha_chip: &Sha256Chip<'a, Fr>,
x_l8_bytes: &[AssignedValue<Fr>; 32],
h07_sibling_bytes: &[AssignedValue<Fr>; 32],
x_block_id_bytes: &[AssignedValue<Fr>; 32],
) {
// Load the two known-constant intermediate nodes as constant byte cells.
let h10_11 = *h10_11_const();
let h12_15 = *h12_15_const();
let h10_11_cells: Vec<AssignedValue<Fr>> =
h10_11.iter().map(|&b| ctx.load_constant(Fr::from(b as u64))).collect();
let h12_15_cells: Vec<AssignedValue<Fr>> =
h12_15.iter().map(|&b| ctx.load_constant(Fr::from(b as u64))).collect();

// Range-check the sibling witness bytes (defensive; the caller should
// already have witnessed these but we guarantee 8-bit constraints here).
for &b in h07_sibling_bytes {
range.range_check(ctx, b, 8);
}

// ZERO_LEAF as 32 constant zero cells.
let zero_leaf_cells: Vec<AssignedValue<Fr>> =
(0..32).map(|_| ctx.load_constant(Fr::zero())).collect();

// H8_9 = SHA(x_l8 || ZERO_LEAF)
let mut buf: Vec<AssignedValue<Fr>> = Vec::with_capacity(64);
buf.extend_from_slice(x_l8_bytes);
buf.extend_from_slice(&zero_leaf_cells);
let h8_9 = sha_chip.digest_bytes(ctx, &buf);
assert_eq!(h8_9.len(), 32);

// H8_11 = SHA(H8_9 || H10_11_CONST)
let mut buf: Vec<AssignedValue<Fr>> = Vec::with_capacity(64);
buf.extend_from_slice(&h8_9);
buf.extend_from_slice(&h10_11_cells);
let h8_11 = sha_chip.digest_bytes(ctx, &buf);

// H8_15 = SHA(H8_11 || H12_15_CONST)
let mut buf: Vec<AssignedValue<Fr>> = Vec::with_capacity(64);
buf.extend_from_slice(&h8_11);
buf.extend_from_slice(&h12_15_cells);
let h8_15 = sha_chip.digest_bytes(ctx, &buf);

// root = SHA(h07_sibling || H8_15)
let mut buf: Vec<AssignedValue<Fr>> = Vec::with_capacity(64);
buf.extend_from_slice(h07_sibling_bytes);
buf.extend_from_slice(&h8_15);
let root_bytes = sha_chip.digest_bytes(ctx, &buf);

// Constrain root_bytes == x_block_id_bytes.
for i in 0..32 {
ctx.constrain_equal(&root_bytes[i], &x_block_id_bytes[i]);
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn compute_block_id_deterministic() {
let l8 = [7u8; 32];
let sib = [0xABu8; 32];
let a = compute_block_id_from_l8_native(&l8, &sib);
let b = compute_block_id_from_l8_native(&l8, &sib);
assert_eq!(a, b);
}

#[test]
fn h10_11_matches_direct_sha() {
let expected = sha256_of_two(&[0u8; 32], &[0u8; 32]);
assert_eq!(*h10_11_const(), expected);
}
}
Loading