Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
63b67b8
fix: exercise production event-store replay in regressions
hmzakhalid Sep 11, 2026
48aeda5
fix: require complete tally results and proof counts
hmzakhalid Sep 11, 2026
6eaaceb
fix: require every test runner to report its scenario results
hmzakhalid Sep 11, 2026
dffaaad
fix: require all crate-level threshold tallies
hmzakhalid Sep 11, 2026
b21400a
fix: require complete circuit test and verifier selections
hmzakhalid Sep 11, 2026
20dd966
fix: preserve the CI integration prebuild entry point
hmzakhalid Sep 11, 2026
9473430
chore: keep audit runner script changes merge-independent
hmzakhalid Sep 11, 2026
01fa581
chore: keep circuit runner checks independent of proof lanes
hmzakhalid Sep 11, 2026
bc37099
fix: include production replay regressions in test audit
hmzakhalid Sep 11, 2026
ff206a2
fix: include runner result checks in test audit
hmzakhalid Sep 11, 2026
52d5b9d
fix: include circuit selection checks in test audit
hmzakhalid Sep 11, 2026
dcd6d51
fix: align integration input windows with DKG readiness
hmzakhalid Sep 11, 2026
e78f522
chore: simplify integration timing regression checks
hmzakhalid Sep 11, 2026
d2be0a1
fix: isolate audit harnesses and require DAppNode regressions
hmzakhalid Sep 11, 2026
1a381be
fix: validate circuit tooling after dependency changes
hmzakhalid Sep 11, 2026
b9da01b
chore: merge main into test audit fixes
hmzakhalid Sep 18, 2026
982b8b1
Merge branch 'main' into fix/test-audit-tally-results
hmzakhalid Sep 18, 2026
898f084
Merge branch 'main' into fix/test-audit-tally-results
hmzakhalid Sep 18, 2026
bbce639
test: remediate audit findings across suites
hmzakhalid Sep 18, 2026
be8491f
Merge remote-tracking branch 'origin/fix/test-audit-tally-results' in…
hmzakhalid Sep 18, 2026
3a18cd9
fix(crisp): retry failed holder discovery live
hmzakhalid Sep 18, 2026
92833ec
test: remove stale registry fixture bindings
hmzakhalid Sep 18, 2026
293685d
test(net): await inflight document request
hmzakhalid Sep 18, 2026
3d0e3f5
test: remove wall-clock wait from gossip retry
hmzakhalid Sep 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
28 changes: 28 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,13 @@ jobs:
- '!**/*.md'
- '!**/*.mdx'
circuits:
- 'package.json'
- 'pnpm-lock.yaml'
- 'circuits/**'
- 'scripts/*-circuits.sh'
- 'scripts/generate-verifiers*.ts'
- 'scripts/test-circuits.test.ts'
- 'scripts/circuit-constants.ts'
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- '!**/*.md'
- '!**/*.mdx'
crisp:
Expand Down Expand Up @@ -174,6 +179,23 @@ jobs:
- name: Check release promotion safeguards
run: node --test scripts/release.test.mjs

- name: Check test runner dispatch and results
run: node --test scripts/test-harnesses.test.mjs

test_dappnode:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa # v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Install shell test prerequisites
run: sudo apt-get update && sudo apt-get install -y jq gettext-base
- name: Test DAppNode credentials and health checks
run: pnpm test:dappnode

rust_unit_tests:
needs: [detect_changes]
if: needs.detect_changes.outputs.rust_unit_tests == 'true'
Expand Down Expand Up @@ -1101,6 +1123,12 @@ jobs:
- name: Test circuit artifact validation
run: pnpm test:circuit-tooling

- name: Test verifier circuit selection
run: pnpm test:verifier-tooling

- name: Test Noir runner selection and failure propagation
run: pnpm test:noir-runner

# The generated verifier contracts must match the freshly built verification keys. A drift
# means the deployed verifier accepts a different circuit from the one in this tree.
#
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.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ alloy-primitives = { version = "=1.4.1", default-features = false, features = [
"serde",
"std",
] }
alloy-json-rpc = "=1.0.41"
alloy-sol-types = "=1.4.1"
alloy-dyn-abi = "=1.4.1"
avail-rust-client = "=0.5.1"
Expand Down Expand Up @@ -206,6 +207,7 @@ tracing = "=0.1.41"
tracing-opentelemetry = "=0.30.0"
tracing-subscriber = { version = "=0.3.20", features = ["env-filter", "time"] }
tracing-test = { version = "=0.2.5", features = ["no-env-filter"] }
tower = "=0.5.3"
url = "=2.5.4"
vfs = { git = "https://github.com/ryardley/rust-vfs.git", features = ["async-vfs"] }
libc = "=0.2.180"
Expand Down
9 changes: 9 additions & 0 deletions agent/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -444,9 +444,18 @@ Recovery tests use a crash matrix around each effect:
Each case must converge to the same state and external outcome as uninterrupted execution. Snapshot
hydration and full replay must produce equivalent state plus pending intents.

EventStore replay regressions load fixtures through `ReplaySpool::load` and deliver them through
`ReplaySpool::replay`. Use a separate source bus so fixture setup cannot seed the destination clock
or its deduplication state. Do not replace production replay with a test-only sorting or delivery
loop.

Integration tests assert end-to-end protocol behavior. Long cryptographic tests run after fast
domain, workflow, crate, and workspace checks have passed.

The `test_trbfv_actor` and `test_trbfv_isolation` tally checks compare the complete result vector.
The actor test also requires one decryption proof per tally. Empty, missing, and surplus tallies
must fail even when the event sequence succeeds.

The recursive `node_fold_correlated_sparse_self_slot_proves_and_verifies` test and the full
`test_trbfv_actor` flow belong to the slow lane. Debug builds may spend minutes in real proof/FHE
work and may emit a "running for over 60 seconds" progress warning. That warning is not a failure;
Expand Down
8 changes: 8 additions & 0 deletions agent/CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,13 @@ Run from repo root via pnpm scripts — not raw cargo/nargo/hardhat.
| Test everything | `pnpm test` (evm → rust → sdk → noir) |
| Test one layer | `pnpm evm:test` · `pnpm rust:test` · `pnpm sdk:test` · `pnpm noir:test` |
| Integration tests | `pnpm test:integration [name]` (`--no-prebuild` to skip binary build) |
| Test runner regressions | `pnpm test:harnesses` (local stand-ins; no Docker services or browser stack) |
| DAppNode hardening tests | `pnpm test:dappnode` (requires Node.js, `jq`, and `envsubst`; runs in CI) |
| Lint / format | `pnpm lint` · `pnpm format` / `pnpm format:check` |
| Build circuits | `pnpm build:circuits [--preset …] [--committee …]` (needs `nargo` + `bb`; `interfold noir setup` installs them) |
| Generate Solidity verifiers | `pnpm generate:verifiers [--check\|--write]` |
| Verifier selection tests | `pnpm test:verifier-tooling` (isolated CLI fixtures; no proof generation) |
| Noir runner tests | `pnpm test:noir-runner` (package selection and failure propagation; command stand-ins) |
| Circuit artifact cache | `pnpm store:circuits push\|pull` (orphan branch `circuit-artifacts`) |
| Consistency checks | `pnpm check:committee` · `check:docs` · `check:addresses` · `check:invariants` · `check:license` · `check:verifiers` · `check:pnpm` · `check:size` |
| Prepare release branch | `pnpm bump:versions X.Y.Z` |
Expand Down Expand Up @@ -122,6 +126,10 @@ opentelemetry/tracing.

## Circuit map (IDs ↔ `CircuitName` in `crates/events`)

`pnpm noir:test` runs the Noir library tests and the standalone recursive-decryption party-ID guard
tests. Verifier generation and consistency checks fail if the selected circuit set is empty or any
requested circuit is missing after group filtering.

- **DKG** (`circuits/bin/dkg/`): C0 `pk` (PkBfv) · C2a `sk_share_computation` · C2b
`e_sm_share_computation` · C3 `share_encryption` · C4 `share_decryption`
- **Threshold** (`circuits/bin/threshold/`): C1 `pk_generation` · C5 `pk_aggregation` · P3
Expand Down
8 changes: 0 additions & 8 deletions circuits/lib/src/math/modulo/U128.nr
Original file line number Diff line number Diff line change
Expand Up @@ -472,14 +472,6 @@ fn test_reduce_mod_function() {
assert(m.reduce_mod(14) == 0);
}

#[test]
fn test_field_properties_additive_identity() {
let a = 42;
let m = ModU128::new(100);
// a + 0 = a
assert(m.add(a, 0) == a);
}

#[test]
fn test_field_properties_multiplicative_identity() {
let a = 42;
Expand Down
21 changes: 0 additions & 21 deletions circuits/lib/src/math/modulo/U64.nr
Original file line number Diff line number Diff line change
Expand Up @@ -224,12 +224,6 @@ fn test_u64_mul_mod_with_zero() {
assert(m.mul_mod(42, 0) == 0);
}

#[test]
fn test_u64_mul_mod_prime_modulus() {
let m = ModU64::new(97);
assert(m.mul_mod(42, 13) == 61); // 546 mod 97
}

#[test]
fn test_u64_neg_nonzero() {
let m = ModU64::new(100);
Expand Down Expand Up @@ -317,12 +311,6 @@ fn test_u64_additive_inverse() {
assert(m.add(a, neg_a) == 0);
}

#[test]
fn test_u64_additive_identity() {
let m = ModU64::new(100);
assert(m.add(42, 0) == 42);
}

#[test]
fn test_u64_multiplicative_identity() {
let m = ModU64::new(100);
Expand All @@ -348,15 +336,6 @@ fn test_u64_inverse_of_inverse() {
assert(m.inv_mod(m.inv_mod(a)) == a);
}

#[test]
fn test_u64_division_multiplication_inverse() {
let m = ModU64::new(97);
let a = 35;
let b = 7;
let quotient = m.div_mod(a, b);
assert(m.mul_mod(quotient, b) == m.reduce_mod(a));
}

#[test(should_fail_with = "Division verification failed: result * b != a (mod m)")]
fn test_u64_div_mod_rejects_non_invertible_divisor() {
// m = 100 is composite and b = 10 shares a factor with it, so b has no true
Expand Down
17 changes: 0 additions & 17 deletions circuits/lib/src/math/modulo/unconstrained_U128.nr
Original file line number Diff line number Diff line change
Expand Up @@ -339,23 +339,6 @@ fn test_sub_with_underflow_equal_values() {
assert(result == 0);
}

#[test]
fn test_sub_with_underflow_verification() {
let lhs: Field = 30;
let rhs: Field = 50;
let m: Field = 100;
// Safety: Test function calling unconstrained helper
let (result, underflow) = unsafe { __sub_with_underflow(lhs, rhs, m) };

if underflow {
// Verify: lhs + m = rhs + result
assert(lhs + m == rhs + result);
} else {
// Verify: lhs = rhs + result
assert(lhs == rhs + result);
}
}

#[test]
fn test_mul_with_quotient_simple() {
// Safety: Test function calling unconstrained helper
Expand Down
45 changes: 0 additions & 45 deletions circuits/lib/src/math/polynomial.nr
Original file line number Diff line number Diff line change
Expand Up @@ -224,18 +224,6 @@ impl<let N: u32> Polynomial<N> {
}
}

#[test]
fn test_polynomial_eval() {
let coeffs = [1, 2, 3]; // represents 1x^2 + 2x + 3
let poly = Polynomial::new(coeffs);

let x = 2; // evaluate at x = 2
let result = poly.eval(x);

// (1 * 2^2) + (2 * 2) + 3 = 4 + 4 + 3 = 11
assert(result == 11);
}

#[test]
fn test_polynomial_eval_zero() {
let coeffs = [1, -2, 1]; // x^2 - 2x + 1 = (x-1)^2
Expand Down Expand Up @@ -342,18 +330,6 @@ fn test_eval_mod_simple() {
assert(result2 == 6);
}

#[test]
fn test_eval_mod_degree_2() {
// p(x) = x^2 + 2x + 3 at x=5od 7
// Using Horner's method: ((1)*5 + 2)*5 + 3 = (5+2)*5 + 3 = 7*5 + 3 = 35 + 3 = 38
// 38 mod 7 = 3 (since 38 = 5*7 + 3)
let q = ModU128::new(7);

let poly = Polynomial::new([1, 2, 3]);
let result = poly.eval_mod(5, q);
assert(result == 3);
}

#[test]
fn test_eval_mod() {
// Test 1: Simple polynomial x^2 + 2x + 3 at x=5od 7
Expand Down Expand Up @@ -432,24 +408,3 @@ fn test_eval_vs_eval_mod() {
assert(result_normal == 11);
assert(result_mod == 11);
}

#[test]
fn test_eval_mod_step_by_step() {
// p(x) = x + 1 at x=5od 7
// Step by step: acc = 1, then acc = 1*5 + 1 = 6
let poly = Polynomial::new([1, 1]);

// Manually compute
let mut acc = 1; // coefficients[0]
acc = acc * 5 + 1; // = 6
assert(acc == 6);

// Now with reduce_mod
let m = ModU128::new(7);
let reduced = m.reduce_mod(acc);
assert(reduced == 6);

// Now test the actual function
let result = poly.eval_mod(5, m);
assert(result == 6);
}
4 changes: 3 additions & 1 deletion crates/aggregator/src/plaintext_aggregation/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ async fn standby_persists_and_resumes_plaintext_work() -> Result<()> {

#[actix::test]
async fn decryption_share_after_collection_closed_is_ignored() -> Result<()> {
let (mut aggregator, _history, e3_id) =
let (mut aggregator, history, e3_id) =
build_plaintext_aggregator(verifying_c6_state(), false).await?;

aggregator.add_share(
Expand All @@ -285,6 +285,8 @@ async fn decryption_share_after_collection_closed_is_ignored() -> Result<()> {
aggregator.state.get(),
Some(ThresholdPlaintextAggregatorState::VerifyingC6(_))
));
let events = history.send(GetEvents::<InterfoldEvent>::new()).await?;
assert!(events.is_empty(), "late share must not emit side effects");
Ok(())
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,6 @@ fn handle_member_expelled_does_not_start_c1_without_a_roster() {
assert_eq!(submission_order.len(), 1);
assert_eq!(canonical_party_nodes.len(), 3);
}
_ => panic!("expected VerifyingC1"),
_ => panic!("expected Collecting"),
}
}
15 changes: 11 additions & 4 deletions crates/cli/src/start.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,11 +205,18 @@ mod tests {
#[tokio::test]
async fn persistence_failure_is_reported_after_publish() -> Result<()> {
let (signal, mut health) = tokio::sync::watch::channel(None);
let failure = wait_for_persistence_failure(&mut health);
tokio::pin!(failure);
std::future::poll_fn(|context| {
use std::future::Future;

assert!(failure.as_mut().poll(context).is_pending());
std::task::Poll::Ready(())
})
.await;

signal.send_replace(Some("append failed".to_string()));
assert_eq!(
wait_for_persistence_failure(&mut health).await?,
"append failed"
);
assert_eq!(failure.await?, "append failed");
Ok(())
}
}
12 changes: 0 additions & 12 deletions crates/committee-hash/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,18 +130,6 @@ mod tests {
use super::*;
use alloy::primitives::address;

#[test]
fn encode_packed_matches_solidity_layout() {
let nodes = vec![
address!("0x0000000000000000000000000000000000000001"),
address!("0x0000000000000000000000000000000000000002"),
];
let hash = hash_committee_addresses(&nodes);
let limbs = split_committee_hash(hash);
assert_ne!(limbs.hi, B256::ZERO);
assert_ne!(limbs.lo, B256::ZERO);
}

#[test]
fn committee_hash_matches_cross_language_vector() {
let nodes = vec![
Expand Down
28 changes: 9 additions & 19 deletions crates/crypto/src/cipher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,27 +226,17 @@ mod tests {
}

#[tokio::test]
async fn test_binary_data() -> Result<()> {
async fn test_binary_and_unicode_data() -> Result<()> {
let cipher = Cipher::from_password("test_password").await?;

let data = vec![0xFF, 0x00, 0xAA, 0x55, 0x12, 0xED];

let encrypted = cipher.encrypt_data(&mut data.clone()).unwrap();
let decrypted = cipher.decrypt_data(&encrypted).unwrap();

assert_eq!(data, decrypted);
Ok(())
}

#[tokio::test]
async fn test_unicode_data() -> Result<()> {
let cipher = Cipher::from_password("test_password").await?;
let data = "Hello 🌍 привет 世界".as_bytes().to_vec();

let encrypted = cipher.encrypt_data(&mut data.clone()).unwrap();
let decrypted = cipher.decrypt_data(&encrypted).unwrap();

assert_eq!(data, decrypted);
for data in [
vec![0xFF, 0x00, 0xAA, 0x55, 0x12, 0xED],
"Hello 🌍 привет 世界".as_bytes().to_vec(),
] {
let encrypted = cipher.encrypt_data(&mut data.clone()).unwrap();
let decrypted = cipher.decrypt_data(&encrypted).unwrap();
assert_eq!(data, decrypted);
}
Ok(())
}

Expand Down
Loading
Loading