Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
998199b
improv
nicarq Jan 31, 2026
7ae6d12
regfile-as-Twist (REG_ID) + constraint reductions
nicarq Feb 1, 2026
4e290db
update
nicarq Feb 2, 2026
4c7888c
cp
nicarq Feb 3, 2026
406e6a5
neo-fold: add RV32 redteam suite tests
nicarq Feb 3, 2026
7b09829
ci: run workflow on PRs to any branch
nicarq Feb 3, 2026
7c819d4
neo-fold: rustfmt + RV32 redteam suite fixes
nicarq Feb 3, 2026
e8abd3d
cp
nicarq Feb 3, 2026
df07b84
Merge pull request #77 from LFDT-Nightstream/codex/redteam-riscv-tests
nicarq Feb 3, 2026
87951e3
Merge branch 'nico/constraint_bench_improv' of github.com:LFDT-Nights…
nicarq Feb 3, 2026
22bda6f
cp
nicarq Feb 4, 2026
df7c2fa
cp
nicarq Feb 13, 2026
a728cfa
perf(reductions): speed up RLC mix and row-phase oracle hot paths
nicarq Feb 13, 2026
f31e514
test(neo-fold): reorganize tests into suite-based layout
nicarq Feb 13, 2026
d1281f3
test(neo-fold): dedupe test suites, enforce real mixers, and remove r…
nicarq Feb 13, 2026
bdd67de
remove identity-first default and optimize split-NC oracle
nicarq Feb 13, 2026
016660c
feat(trace): enable chunked IVC in Rv32TraceWiring and fix mixed-opco…
nicarq Feb 13, 2026
6e46082
bug fix
nicarq Feb 14, 2026
4cc0f65
cp before big refactor
nicarq Feb 14, 2026
74d1f3f
tier-2.1 track A: W1 + WB + WP sidecar stages, 425 -> 156 constraints…
nicarq Feb 15, 2026
1da15ad
test fixes: use optimized
nicarq Feb 15, 2026
c10c290
W2/W3: close branch lookup binding gap and harden sidecar claim cutov
nicarq Feb 16, 2026
588388d
intermediate work
nicarq Feb 17, 2026
6111544
perf(trace): batch decode/width shout claims and ...
nicarq Feb 17, 2026
65c5b0c
test fixes and memory file split
nicarq Feb 17, 2026
7f81ae0
remove b1 (column based approach)
nicarq Feb 18, 2026
4d0f008
utils
nicarq Feb 18, 2026
c209edc
Merge pull request #81 from LFDT-Nightstream/nico/lookup_refactor
nicarq Feb 18, 2026
fb201ab
cargo fmt
nicarq Feb 18, 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
19 changes: 19 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,34 @@
- We don't care about backwards compatibility because we are still in development. Keep the code simple and lean.
- Avoid adding new Rust features or ENVs unless it is explicitly approved.
- Never modify this file without explicit approval.
- No single file should ever exceed 1,500 lines of code unless explicitly confirmed by the user.

## Testing
- Never add tests in the same implementation file, always prefer to add them to a file inside tests/ (current or new)
- If you add a test to catch a problem, the test should fail if aims to confirm a problem.
- Always use `FoldingMode::Optimized` in tests. Never use `FoldingMode::PaperExact` unless the user explicitly approves it. PaperExact is an O(2^ell) brute-force reference engine meant only for correctness cross-checking, not general test usage.

## Build & Test Commands
- When running tests use --release eg cargo test --workspace --release
- For extra debugs use debug-logs eg --features paper-exact,debug-logs

## Perf & Constraint Debugging

Perf tests live in `crates/neo-fold/tests/suites/perf/single_addi_metrics_nightstream.rs`. All use `--ignored`.

Full constraint architecture report (main CCS, bus, Route-A claims, openings, timing):
```bash
NS_DEBUG_N=10 cargo test -p neo-fold --release --test perf -- --ignored --nocapture report_track_a_w0_w1_snapshot
```
N: number of riscv instructions + 1 (halt).

Other useful tests (all accept `NS_DEBUG_N`):
- `debug_trace_single_n_mixed_ops` — trace-wiring prove/verify + openings
- `debug_chunked_single_n_mixed_ops` — same in chunked trace mode
- `debug_trace_vs_chunked_single_n_mixed_ops` — side-by-side comparison
- `report_trace_vs_chunked_medians` — 5-run median timing
- `debug_trace_core_rows_per_cycle_equiv` — CCS rows/cycle (no prove, fast; uses `NS_DEBUG_T`)

## Profiling

| Tool | Use Case | Output |
Expand Down
2 changes: 2 additions & 0 deletions Cargo.lock

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

16 changes: 3 additions & 13 deletions crates/neo-ccs/src/r1cs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
};

/// Minimal **R1CS → CCS** helper: given A, B, C ∈ F^{n×m}, produce CCS with
/// M_1=A, M_2=B, M_3=C and f(X1,X2,X3) = X1·X2X3 (elementwise).
/// M_0=A, M_1=B, M_2=C and f(X0,X1,X2) = X0·X1X2 (elementwise).
///
/// This is the standard embedding: row-wise, `A z ∘ B z = C z`, i.e., `f=0`.
pub fn r1cs_to_ccs<F: Field>(a: Mat<F>, b: Mat<F>, c: Mat<F>) -> CcsStructure<F> {
Expand All @@ -16,10 +16,7 @@ pub fn r1cs_to_ccs<F: Field>(a: Mat<F>, b: Mat<F>, c: Mat<F>) -> CcsStructure<F>
assert_eq!(a.cols(), b.cols());
assert_eq!(a.cols(), c.cols());

let n = a.rows();
let m = a.cols();

// Base polynomial f(X1,X2,X3) = X1 * X2 - X3
// Base polynomial f(X0,X1,X2) = X0 * X1 - X2
let base_terms = vec![
Term {
coeff: F::ONE,
Expand All @@ -32,12 +29,5 @@ pub fn r1cs_to_ccs<F: Field>(a: Mat<F>, b: Mat<F>, c: Mat<F>) -> CcsStructure<F>
];
let f_base = SparsePoly::new(3, base_terms);

// Insert identity-first only when square; otherwise keep legacy 3-matrix CCS.
if n == m {
let i_n = Mat::<F>::identity(n);
let f = f_base.insert_var_at_front();
CcsStructure::new(vec![i_n, a, b, c], f).expect("valid identity-first CCS structure")
} else {
CcsStructure::new(vec![a, b, c], f_base).expect("valid R1CS→CCS structure")
}
CcsStructure::new(vec![a, b, c], f_base).expect("valid R1CS→CCS structure")
}
25 changes: 14 additions & 11 deletions crates/neo-ccs/tests/identity_validation_tests.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Tests for M₀ = I_n validation required by Ajtai/NC pipeline.
//! Tests for legacy identity-first validation helpers used by Ajtai/NC-specific paths.

#![allow(non_snake_case)]

Expand All @@ -7,7 +7,7 @@ use neo_ccs::{r1cs_to_ccs, CcsStructure, Mat};
use neo_math::F;
use p3_field::PrimeCharacteristicRing;

/// Test that a valid square CCS with M₀ = I passes validation
/// Test that square R1CS output can be normalized to identity-first when needed.
#[test]
fn test_identity_validation_valid_square_ccs() {
// Create a simple square R1CS (4x4)
Expand All @@ -23,11 +23,13 @@ fn test_identity_validation_valid_square_ccs() {
B[(0, 1)] = F::ONE;
C[(0, 2)] = F::ONE;

// r1cs_to_ccs should produce identity-first CCS for square input
// r1cs_to_ccs always produces 3-matrix embedding now.
let ccs = r1cs_to_ccs(A, B, C);
assert_eq!(ccs.matrices.len(), 3);

// Should pass validation
assert!(ccs.assert_m0_is_identity_for_nc().is_ok());
// Explicit identity-first normalization still supports legacy validation paths.
let ccs_normalized = ccs.ensure_identity_first().expect("normalize");
assert!(ccs_normalized.assert_m0_is_identity_for_nc().is_ok());
}

/// Test that a non-square CCS fails validation with clear error
Expand Down Expand Up @@ -157,20 +159,21 @@ fn test_happy_path_square_r1cs_to_validated_ccs() {
B[(4, 2)] = F::ONE;
C[(4, 2)] = F::ONE;

// Convert to CCS (should be identity-first for square)
// Convert to CCS (3-matrix embedding, no auto identity insertion).
let ccs = r1cs_to_ccs(A, B, C);

// Verify it's square
assert_eq!(ccs.n, ccs.m);
assert_eq!(ccs.n, n);

// Verify M₀ is identity
assert!(ccs.matrices[0].is_identity());
// By default the first matrix is A, not identity.
assert!(!ccs.matrices[0].is_identity());
assert_eq!(ccs.matrices.len(), 3);

// Validation should pass
assert!(ccs.assert_m0_is_identity_for_nc().is_ok());
// Legacy validation path requires explicit normalization.
assert!(ccs.assert_m0_is_identity_for_nc().is_err());

// ensure_identity_first should be a no-op
// ensure_identity_first produces identity-first form for square CCS.
let ccs_normalized = ccs.ensure_identity_first().expect("normalize");
assert!(ccs_normalized.assert_m0_is_identity_for_nc().is_ok());
}
Expand Down
38 changes: 38 additions & 0 deletions crates/neo-ccs/tests/r1cs_embedding_shape_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use neo_ccs::{r1cs_to_ccs, Mat};
use neo_math::F;
use p3_field::PrimeCharacteristicRing;

#[test]
fn square_r1cs_uses_three_matrix_embedding() {
let n = 4usize;
let m = 4usize;

let mut a = Mat::zero(n, m, F::ZERO);
let mut b = Mat::zero(n, m, F::ZERO);
let mut c = Mat::zero(n, m, F::ZERO);
a[(0, 0)] = F::ONE;
b[(0, 1)] = F::ONE;
c[(0, 2)] = F::ONE;

let ccs = r1cs_to_ccs(a, b, c);
assert_eq!(ccs.t(), 3, "square R1CS must not auto-insert identity matrix");
assert!(!ccs.matrices[0].is_identity(), "M0 should be A, not identity");
}

#[test]
fn rectangular_r1cs_uses_three_matrix_embedding() {
let n = 2usize;
let m = 5usize;

let mut a = Mat::zero(n, m, F::ZERO);
let mut b = Mat::zero(n, m, F::ZERO);
let mut c = Mat::zero(n, m, F::ZERO);
a[(0, 0)] = F::ONE;
b[(0, 1)] = F::ONE;
c[(0, 2)] = F::ONE;

let ccs = r1cs_to_ccs(a, b, c);
assert_eq!(ccs.t(), 3);
assert_eq!(ccs.n, n);
assert_eq!(ccs.m, m);
}
Loading