Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
3714bb6
reduce degree AIR poseidon
TomWambsgans Apr 15, 2026
68e4e4c
wip
TomWambsgans Apr 15, 2026
b9f7c21
wip
TomWambsgans Apr 16, 2026
bb7be6f
test_plonky3_compatibility
TomWambsgans Apr 16, 2026
82c624e
wip
TomWambsgans Apr 16, 2026
d1c525f
wip
TomWambsgans Apr 16, 2026
beaf0d6
degree 7 air (instead of 3) for poseidon
TomWambsgans Apr 16, 2026
c7448bc
w
TomWambsgans Apr 16, 2026
4b78c6e
wip
TomWambsgans Apr 16, 2026
ae2401d
wip
TomWambsgans Apr 16, 2026
7771454
w
TomWambsgans Apr 16, 2026
ff61a47
w
TomWambsgans Apr 16, 2026
ec26c52
wip
TomWambsgans Apr 16, 2026
4d91224
w
TomWambsgans Apr 16, 2026
1daffe2
w
TomWambsgans Apr 17, 2026
abc56ce
Merge branch 'main' into goldilocks
TomWambsgans Apr 25, 2026
a635928
w
TomWambsgans Apr 25, 2026
ec4acbd
fix
TomWambsgans Apr 25, 2026
26e06b9
Merge remote-tracking branch 'origin/goldilocks' into goldilocks
TomWambsgans Apr 25, 2026
1663a9e
low level optis
TomWambsgans Apr 26, 2026
84f208b
w
TomWambsgans Apr 26, 2026
80b3a98
w
TomWambsgans Apr 26, 2026
89a2dc5
2x faster poseidon
TomWambsgans Apr 26, 2026
6efc061
much faster poseidn on avx512
TomWambsgans Apr 26, 2026
7baaf62
Merge commit 'a6f398eb3841acc74e424b788c0c50fd64df26f5' into goldilocks
TomWambsgans May 3, 2026
87ef493
Merge main into goldilocks: MTU-XMSS with halved sizes
TomWambsgans May 3, 2026
c308fb6
w
TomWambsgans May 4, 2026
0470d7a
better encoding
TomWambsgans May 4, 2026
4c1209a
clippy
TomWambsgans May 4, 2026
086ab06
f
TomWambsgans May 4, 2026
37f052f
whir: remove folding pow grinding (not needed when field is big enoug…
TomWambsgans May 4, 2026
ddfd849
chunks of 2w in xmss
TomWambsgans May 4, 2026
e5617e0
128 bit security
TomWambsgans May 4, 2026
c0befb9
EFFECTIVE_TWO_ADICITY = 24
TomWambsgans May 4, 2026
d2027e6
Merge branch 'main' into goldilocks
TomWambsgans May 4, 2026
41a1529
change whir params
TomWambsgans May 4, 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
25 changes: 20 additions & 5 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ members = [
"crates/*",
"crates/backend/utils",
"crates/backend/field",
"crates/backend/koala-bear",
"crates/backend/goldilocks",
"crates/backend/poly",
"crates/backend/symetric",
"crates/backend/air",
Expand Down
10 changes: 4 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Machine: M4 Max 48GB (CPU only)
### XMSS aggregation

```bash
cargo run --release -- xmss --n-signatures 1500 --log-inv-rate 1
cargo run --release -- xmss --n-signatures 1550 --log-inv-rate 1
```

| WHIR rate | Proven Regime | Proximity Gaps Conjecture |
Expand All @@ -40,7 +40,7 @@ cargo run --release -- xmss --n-signatures 1500 --log-inv-rate 1

### Recursion

Aggregating together n previously aggregated signatures, each containing 700 XMSS.
Aggregating together n previously aggregated signatures, each containing 775 XMSS.


```bash
Expand Down Expand Up @@ -77,13 +77,11 @@ cargo run --release -- fancy-aggregation

### snark

124 bits of provable security, given by Johnson bound + degree 5 extension of koala-bear. (128 bits requires bigger hash digests (8 koalabears ≈ 248 bits) -> TODO). In the benchmarks, we also display performance with conjectured security, even though leanVM targets the proven regime by default.
128 bits of provable security, given by Johnson bound + degree 5 extension of koala-bear. (128 bits requires bigger hash digests (8 koalabears ≈ 248 bits) -> TODO). In the benchmarks, we also display performance with conjectured security, even though leanVM targets the proven regime by default.

### XMSS

Currently, we use an [XMSS](crates/xmss/xmss.md) with hash digests of 4 field elements ≈ 124 bits. Tweaks and public parameters ensure domain separation. An analysis in the ROM (resp. QROM), inspired by the section 3.1 of [Tight adaptive reprogramming in the QROM](https://arxiv.org/pdf/2010.15103) would lead to ≈ 124 (resp. 62) bits of classical (resp. quantum) security. Going to 128 / 64 bits of classical / quantum security, i.e. NIST level 1 (in the ROM/QROM), is an ongoing effort. It requires either:
- hash digests of 5 field elements (drawback: we need to double the hash chain length from 8 to 16 if we want to stay below one IPv6 MTU = 1280 bytes)
- a new prime, close to 32 bits (typically p = 125.2^25 + 1) or 64 bits ([goldilocks](https://2π.com/22/goldilocks/))
Currently, we use an [XMSS](crates/xmss/xmss.md) with hash digests of 2 goldilocks ≈ 128 bits. Tweaks and public parameters ensure domain separation. An analysis in the ROM (resp. QROM), inspired by the section 3.1 of [Tight adaptive reprogramming in the QROM](https://arxiv.org/pdf/2010.15103) would lead to ≈ 128 (resp. 64) bits of classical (resp. quantum) security, i.e. NIST level 1.

It's important to mention that a security analysis in the ROM / QROM is not the most conservative. In particular, [eprint 2025/055](https://eprint.iacr.org/2025/055.pdf)'s security proof holds in the standard model (at the cost of bigger hash digests): the implementation is available in the [leanSig](https://github.com/leanEthereum/leanSig) repository. A compatible version of leanMultisig can be found in the [devnet4](https://github.com/leanEthereum/leanMultisig/tree/devnet4) branch.

Expand Down
1 change: 0 additions & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

## Security:

- 128 bits security? (currently 124)
- Fiat Shamir: add a claim tracing feature, to ensure all the claims are indeed checked (Lev)
- Double Check AIR constraints, logup overflows etc
- Do we need to enforce some values at the first row of the dot-product table?
Expand Down
2 changes: 1 addition & 1 deletion crates/backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ rayon.workspace = true
whir = { path = "../whir", package = "mt-whir" }
tracing.workspace = true
fiat-shamir = { path = "fiat-shamir", package = "mt-fiat-shamir" }
koala-bear = { path = "koala-bear", package = "mt-koala-bear" }
goldilocks = { path = "goldilocks", package = "mt-goldilocks" }
utils = { path = "utils", package = "mt-utils" }
26 changes: 0 additions & 26 deletions crates/backend/air/src/constraint_folder/packed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,32 +71,6 @@ where
self.constraint_index += 1;
}

#[inline]
fn assert_eq_low(&mut self, x: IF, y: IF) {
let alpha_power = self.extra_data.alpha_powers()[self.constraint_index];
let contrib = EFPacking::<EF>::from(alpha_power) * (x - y);
self.accumulator += contrib;
self.accumulator_low += contrib;
self.constraint_index += 1;
}

#[inline]
fn low_degree_block<F>(&mut self, state: &mut [IF], block: F)
where
F: FnOnce(&mut Self, &mut [IF]),
{
if self.skip_low {
state.copy_from_slice(self.cached_state.as_ref().unwrap());
self.constraint_index += self.low_ci_count;
} else {
block(self, state);
if let Some(cache) = &mut self.cached_state {
cache.clear();
cache.extend_from_slice(state);
}
}
}

#[inline]
fn eval_virtual_column(&mut self, x: Self::EF) {
self.assert_zero_ef(x);
Expand Down
18 changes: 0 additions & 18 deletions crates/backend/air/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,6 @@ pub trait Air: Send + Sync + 'static {

fn eval<AB: AirBuilder>(&self, builder: &mut AB, extra_data: &Self::ExtraData);

/// If the AIR contains a `low_degree_block` sub-region, returns `(degree, n_constraints)`
fn low_degree_air(&self) -> Option<(usize, usize)> {
None
}

fn n_down_columns(&self) -> usize {
self.down_column_indexes().len()
}
Expand Down Expand Up @@ -64,19 +59,6 @@ pub trait AirBuilder: Sized {
self.assert_zero(x.bool_check());
}

fn assert_eq_low(&mut self, x: Self::IF, y: Self::IF) {
self.assert_eq(x, y);
}

/// Execute `block` as a low-degree sub-region whose post-state is "cacheable"
/// = linear in z without the low-degree constraints
fn low_degree_block<F>(&mut self, state: &mut [Self::IF], block: F)
where
F: FnOnce(&mut Self, &mut [Self::IF]),
{
block(self, state);
}

/// useful to build the recursion program
#[inline(always)]
fn declare_values(&mut self, values: &[Self::IF]) {
Expand Down
2 changes: 1 addition & 1 deletion crates/backend/fiat-shamir/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ edition.workspace = true

[dependencies]
field = { path = "../field", package = "mt-field" }
koala-bear = { path = "../koala-bear", package = "mt-koala-bear" }
goldilocks = { path = "../goldilocks", package = "mt-goldilocks" }
symetric = { path = "../symetric", package = "mt-symetric" }
utils = { path = "../utils", package = "mt-utils" }
tracing.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion crates/backend/fiat-shamir/src/challenger.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use field::PrimeField64;
use symetric::Compression;

pub(crate) const RATE: usize = 8;
pub(crate) const RATE: usize = 4;
pub(crate) const WIDTH: usize = RATE * 2;

#[derive(Clone, Debug)]
Expand Down
2 changes: 1 addition & 1 deletion crates/backend/fiat-shamir/src/transcript.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};

use crate::PrunedMerklePaths;

pub const DIGEST_LEN_FE: usize = 8;
pub const DIGEST_LEN_FE: usize = 4;

#[derive(Debug, Clone)]
pub struct MerkleOpening<F> {
Expand Down
20 changes: 10 additions & 10 deletions crates/backend/fiat-shamir/src/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{
};
use field::PrimeCharacteristicRing;
use field::{ExtensionField, PrimeField64};
use koala_bear::{KoalaBear, default_koalabear_poseidon1_16};
use goldilocks::{Goldilocks, default_goldilocks_poseidon1_8};
use symetric::Compression;

pub struct VerifierState<EF: ExtensionField<PF<EF>>, P> {
Expand Down Expand Up @@ -68,24 +68,24 @@ where

#[allow(clippy::missing_transmute_annotations)]
fn restore_merkle_paths(paths: PrunedMerklePaths<PF<EF>, PF<EF>>) -> Option<Vec<MerkleOpening<PF<EF>>>> {
assert_eq!(TypeId::of::<PF<EF>>(), TypeId::of::<KoalaBear>());
// SAFETY: We've confirmed PF<EF> == KoalaBear
let paths: PrunedMerklePaths<KoalaBear, KoalaBear> = unsafe { std::mem::transmute(paths) };
let perm = default_koalabear_poseidon1_16();
let hash_fn = |data: &[KoalaBear]| symetric::hash_slice::<_, _, 16, 8, DIGEST_LEN_FE>(&perm, data);
let combine_fn = |left: &[KoalaBear; DIGEST_LEN_FE], right: &[KoalaBear; DIGEST_LEN_FE]| {
assert_eq!(TypeId::of::<PF<EF>>(), TypeId::of::<Goldilocks>());
// SAFETY: We've confirmed PF<EF> == Goldilocks
let paths: PrunedMerklePaths<Goldilocks, Goldilocks> = unsafe { std::mem::transmute(paths) };
let perm = default_goldilocks_poseidon1_8();
let hash_fn = |data: &[Goldilocks]| symetric::hash_slice::<_, _, 8, 4, DIGEST_LEN_FE>(&perm, data);
let combine_fn = |left: &[Goldilocks; DIGEST_LEN_FE], right: &[Goldilocks; DIGEST_LEN_FE]| {
symetric::compress(&perm, [*left, *right])
};
let restored: MerklePaths<KoalaBear, KoalaBear> = paths.restore(&hash_fn, &combine_fn)?;
let openings: Vec<MerkleOpening<KoalaBear>> = restored
let restored: MerklePaths<Goldilocks, Goldilocks> = paths.restore(&hash_fn, &combine_fn)?;
let openings: Vec<MerkleOpening<Goldilocks>> = restored
.0
.into_iter()
.map(|path| MerkleOpening {
leaf_data: path.leaf_data,
path: path.sibling_hashes,
})
.collect();
// SAFETY: PF<EF> == KoalaBear
// SAFETY: PF<EF> == Goldilocks
Some(unsafe { std::mem::transmute(openings) })
}
}
Expand Down
8 changes: 4 additions & 4 deletions crates/backend/fiat-shamir/tests/grinding.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
use koala_bear::{QuinticExtensionFieldKB, default_koalabear_poseidon1_16};
use goldilocks::{CubicExtensionFieldGL, default_goldilocks_poseidon1_8};
use mt_fiat_shamir::{FSProver, FSVerifier, ProverState, VerifierState};
use std::time::Instant;

type EF = QuinticExtensionFieldKB;
type EF = CubicExtensionFieldGL;

#[test]
#[ignore]
fn bench_grinding() {
let n_reps = 100;
for grinding_bits in 20..=20 {
let mut prover_state = ProverState::<EF, _>::new(default_koalabear_poseidon1_16());
let mut prover_state = ProverState::<EF, _>::new(default_goldilocks_poseidon1_8());
let time = Instant::now();
for _ in 0..n_reps {
prover_state.pow_grinding(grinding_bits);
}
let elapsed = time.elapsed();
let mut verifier_state =
VerifierState::<EF, _>::new(prover_state.into_proof(), default_koalabear_poseidon1_16()).unwrap();
VerifierState::<EF, _>::new(prover_state.into_proof(), default_goldilocks_poseidon1_8()).unwrap();
for _ in 0..n_reps {
verifier_state.check_pow_grinding(grinding_bits).unwrap()
}
Expand Down
2 changes: 1 addition & 1 deletion crates/backend/field/src/exponentiation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub(crate) const fn bits_u64(n: u64) -> usize {

/// Compute the exponential `x -> x^1420470955` using a custom addition chain.
///
/// This map computes the third root of `x` if `x` is a member of the field `KoalaBear`.
/// This map computes the third root of `x` if `x` is a member of the field `Goldilocks`.
/// This follows from the computation: `3 * 1420470955 = 2*(2^31 - 2^24) + 1 = 1 mod (p - 1)`.
#[must_use]
pub fn exp_1420470955<R: PrimeCharacteristicRing>(val: R) -> R {
Expand Down
2 changes: 1 addition & 1 deletion crates/backend/field/src/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ pub trait PrimeCharacteristicRing:
+ PartialEq
{
/// The field `ℤ/p` where the characteristic of this ring is p.
type PrimeSubfield: PrimeField32;
type PrimeSubfield: PrimeField64;

/// The additive identity of the ring.
///
Expand Down
16 changes: 16 additions & 0 deletions crates/backend/goldilocks/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "mt-goldilocks"
version.workspace = true
edition.workspace = true

[dependencies]
field = { path = "../field", package = "mt-field" }
utils = { path = "../utils", package = "mt-utils" }

rand.workspace = true
rayon.workspace = true
serde.workspace = true
itertools.workspace = true
tracing.workspace = true
num-bigint = "*"
paste = "1"
5 changes: 5 additions & 0 deletions crates/backend/goldilocks/src/aarch64_neon/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Credits: Plonky3 (https://github.com/Plonky3/Plonky3) (MIT and Apache-2.0 licenses).

mod packing;

pub use packing::*;
Loading
Loading