Skip to content

Add the basefold recursive verifier. #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 69 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
fcb8ed5
Dense Matrix
Apr 22, 2025
66c7734
Added hints
Apr 22, 2025
6f8fe11
Finished get_base_codeword_dimensions
Apr 23, 2025
3813078
WIP mmcs
Apr 23, 2025
b10539b
WIP mmcs
Apr 24, 2025
8c35009
Update mmcs
Apr 25, 2025
3afc01b
WIP mmcs
Apr 26, 2025
1156331
Finished MMCS
Apr 28, 2025
18aef52
Added dot_product
Apr 29, 2025
31cd29c
query_phase input
Apr 29, 2025
85f00f2
WIP query_phase
Apr 29, 2025
ef34a42
Fix bug in sorting
Apr 30, 2025
b63abd8
WIP query phase
May 1, 2025
2a5f3da
WIP query phase
May 1, 2025
f4c21af
WIP query phase
May 1, 2025
746f04f
WIP query phase
May 2, 2025
6f98a17
New Sorting Impl
May 4, 2025
8e3312b
WIP query phase
May 5, 2025
dda2fff
WIP query phase
May 6, 2025
39443ef
WIP query phase
May 6, 2025
520da7e
Finished query_phase encoding
May 6, 2025
282892f
Support serialized input
May 10, 2025
0dc7b56
Implement the naive encode small method
yczhangsjtu May 15, 2025
c06f3c9
Bug workaround
May 16, 2025
7da7077
Merge branch 'kunming/basefold-verifier' into cyte/remove-early-stopping
yczhangsjtu May 16, 2025
4553fc3
Temp store: starting to use openvm mmcs instruction
yczhangsjtu May 30, 2025
39fa15c
Temp store: index to bits
yczhangsjtu May 30, 2025
2acf9eb
Temp store: clean up mmcs
yczhangsjtu May 30, 2025
4ffe361
Temp store: clear compilation errors
yczhangsjtu May 30, 2025
fbeda8b
Merge e2e modification
yczhangsjtu Jun 3, 2025
629bb23
Fix compilation error
yczhangsjtu Jun 3, 2025
8044af5
Merge remote-tracking branch 'origin/main' into cyte/switch-mmcs
yczhangsjtu Jun 3, 2025
2516cf5
Fix hash variable reading bug
yczhangsjtu Jun 3, 2025
ba93b0b
Use dyn array for dimensions
yczhangsjtu Jun 3, 2025
ec5e218
Fix multiplication between var and ext
yczhangsjtu Jun 3, 2025
586bc0d
Fix mmcs reading
yczhangsjtu Jun 6, 2025
b35aa5d
Remove unnecessary witness stream
yczhangsjtu Jun 10, 2025
0b8d751
Add doc for generating mmcs test data
yczhangsjtu Jun 10, 2025
ac1cbfd
Try fixing mmcs
yczhangsjtu Jun 11, 2025
4f22895
Try fixing mmcs
yczhangsjtu Jun 11, 2025
0b66801
Try fixing mmcs
yczhangsjtu Jun 11, 2025
25c21c0
Add comment
yczhangsjtu Jun 11, 2025
edc4848
Use the same poseidon2 constants as the test data
yczhangsjtu Jun 11, 2025
c04e4b7
Specify branch for test data gen
yczhangsjtu Jun 11, 2025
d5c8baa
MMCS test passes
yczhangsjtu Jun 11, 2025
8029daa
Rewrite fold coeff according to current basefold code
yczhangsjtu Jun 13, 2025
c1e92b0
Fix
yczhangsjtu Jun 19, 2025
188eb85
Merge branch 'main' of https://github.com/scroll-tech/ceno-recursion-…
yczhangsjtu Jun 19, 2025
fa3210c
Merge branches 'cyte/fix-query-phase' and 'main' of https://github.co…
yczhangsjtu Jun 23, 2025
e28b481
Merge e2e modification
yczhangsjtu Jun 23, 2025
dd6d6bd
Fix compilation errors from merge
yczhangsjtu Jun 23, 2025
6ba1fea
Fix compilation errors from merge
yczhangsjtu Jun 23, 2025
5c2b6b5
Fix compilation errors from merge
yczhangsjtu Jun 23, 2025
8cb2ad7
(WIP) Connecting e2e with query phase
yczhangsjtu Jun 23, 2025
cde8886
Merge remote-tracking branch 'origin/main' into cyte/fix-query-phase
kunxian-xia Jun 23, 2025
5361f3f
WIP
yczhangsjtu Jun 23, 2025
5f60470
Merge branch 'cyte/fix-query-phase' of https://github.com/scroll-tech…
yczhangsjtu Jun 23, 2025
37fb5f8
(WIP) transform ceno query phase verifier input to current
yczhangsjtu Jun 24, 2025
1feb92c
(WIP) Fix query phase transform
yczhangsjtu Jun 24, 2025
410e996
(WIP) Fix query phase transform
yczhangsjtu Jun 24, 2025
fbd5f1f
(WIP) Fix query phase transform
yczhangsjtu Jun 24, 2025
dd7951d
(WIP) Fix query phase transform
yczhangsjtu Jun 24, 2025
6f35d7b
Fix query phase transform
yczhangsjtu Jun 24, 2025
478ef69
Comment out connecting code temporarily
yczhangsjtu Jun 25, 2025
9689d1d
Query phase compile successful
yczhangsjtu Jun 25, 2025
94d4c13
(WIP) Debugging query phase
yczhangsjtu Jun 25, 2025
d0a45ca
Fix a bug in verifier query phase
yczhangsjtu Jun 26, 2025
8a61142
Read additional hints from binary file
yczhangsjtu Jun 26, 2025
f01ae48
Fix: batch opening (#28)
kunxian-xia Jul 8, 2025
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
340 changes: 207 additions & 133 deletions Cargo.lock

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ p3-util = { git = "https://github.com/Plonky3/Plonky3.git", rev = "1ba4e5c" }
p3-challenger = { git = "https://github.com/Plonky3/Plonky3.git", rev = "1ba4e5c" }
p3-monty-31 = { git = "https://github.com/Plonky3/Plonky3.git", rev = "1ba4e5c" }
p3-symmetric = { git = "https://github.com/Plonky3/Plonky3.git", rev = "1ba4e5c" }
p3-fri = { git = "https://github.com/Plonky3/Plonky3.git", rev = "1ba4e5c" }
p3-goldilocks = { git = "https://github.com/Plonky3/plonky3", rev = "1ba4e5c" }

# WHIR
Expand All @@ -41,6 +42,7 @@ ark-serialize = "0.5"
ceno_mle = { git = "https://github.com/scroll-tech/ceno.git", branch = "feat/export_ff_ext", package = "multilinear_extensions" }
ceno_sumcheck = { git = "https://github.com/scroll-tech/ceno.git", branch = "feat/export_ff_ext", package = "sumcheck" }
ceno_transcript = { git = "https://github.com/scroll-tech/ceno.git", branch = "feat/export_ff_ext", package = "transcript" }
ceno_witness = { git = "https://github.com/scroll-tech/ceno.git", branch = "feat/export_ff_ext", package = "witness" }
ceno_zkvm = { git = "https://github.com/scroll-tech/ceno.git", branch = "feat/export_ff_ext" }
ceno_emul = { git = "https://github.com/scroll-tech/ceno.git", branch = "feat/export_ff_ext" }
mpcs = { git = "https://github.com/scroll-tech/ceno.git", branch = "feat/export_ff_ext" }
Expand All @@ -50,3 +52,13 @@ serde_json = "1.0"

[features]
bench-metrics = ["openvm-circuit/bench-metrics"]

# [patch."https://github.com/scroll-tech/ceno.git"]
# ceno_mle = { path = "../ceno/multilinear_extensions", package = "multilinear_extensions" }
# ceno_sumcheck = { path = "../ceno/sumcheck", package = "sumcheck" }
# ceno_transcript = { path = "../ceno/transcript", package = "transcript" }
# ceno_witness = { path = "../ceno/witness", package = "witness" }
# ceno_zkvm = { path = "../ceno/ceno_zkvm" }
# ceno_emul = { path = "../ceno/ceno_emul" }
# mpcs = { path = "../ceno/mpcs" }
# ff_ext = { path = "../ceno/ff_ext" }
173 changes: 134 additions & 39 deletions src/arithmetics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,6 @@ pub unsafe fn exts_to_felts<C: Config>(
builder: &mut Builder<C>,
exts: &Array<C, Ext<C::F, C::EF>>,
) -> Array<C, Felt<C::F>> {
assert!(
matches!(exts, Array::Dyn(_, _)),
"Expected dynamic array of Exts"
);
let f_len: Usize<C::N> = builder.eval(exts.len() * Usize::from(C::EF::D));
let f_arr: Array<C, Felt<C::F>> = Array::Dyn(exts.ptr(), f_len);
f_arr
Expand Down Expand Up @@ -101,6 +97,23 @@ pub fn evaluate_at_point<C: Config>(
builder.eval(r * (right - left) + left)
}

pub fn fixed_dot_product<C: Config>(
builder: &mut Builder<C>,
a: &[Ext<C::F, C::EF>],
b: &Array<C, Ext<C::F, C::EF>>,
zero: Ext<C::F, C::EF>,
) -> Ext<<C as Config>::F, <C as Config>::EF> {
// simple trick to prefer AddE(1 cycle) than AddEI(4 cycles)
let acc: Ext<C::F, C::EF> = builder.eval(zero + zero);

for (i, va) in a.iter().enumerate() {
let vb = builder.get(b, i);
builder.assign(&acc, acc + *va * vb);
}

acc
}

pub fn dot_product<C: Config>(
builder: &mut Builder<C>,
a: &Array<C, Ext<C::F, C::EF>>,
Expand All @@ -117,19 +130,20 @@ pub fn dot_product<C: Config>(
acc
}

pub fn fixed_dot_product<C: Config>(
pub fn dot_product_pt_n_eval<C: Config>(
builder: &mut Builder<C>,
a: &[Ext<C::F, C::EF>],
pt_and_eval: &Array<C, PointAndEvalVariable<C>>,
b: &Array<C, Ext<C::F, C::EF>>,
zero: Ext<C::F, C::EF>,
) -> Ext<<C as Config>::F, <C as Config>::EF> {
// simple trick to prefer AddE(1 cycle) than AddEI(4 cycles)
let acc: Ext<C::F, C::EF> = builder.eval(zero + zero);

for (i, va) in a.iter().enumerate() {
let vb = builder.get(b, i);
builder.assign(&acc, acc + *va * vb);
}
let acc: Ext<C::F, C::EF> = builder.eval(C::F::ZERO);

iter_zip!(builder, pt_and_eval, b).for_each(|idx_vec, builder| {
let ptr_a = idx_vec[0];
let ptr_b = idx_vec[1];
let v_a = builder.iter_ptr_get(&pt_and_eval, ptr_a);
let v_b = builder.iter_ptr_get(&b, ptr_b);
builder.assign(&acc, acc + v_a.eval * v_b);
});

acc
}
Expand Down Expand Up @@ -207,6 +221,32 @@ pub fn eq_eval<C: Config>(
acc
}

// Evaluate eq polynomial.
pub fn eq_eval_with_index<C: Config>(
builder: &mut Builder<C>,
x: &Array<C, Ext<C::F, C::EF>>,
y: &Array<C, Ext<C::F, C::EF>>,
xlo: Usize<C::N>,
ylo: Usize<C::N>,
len: Usize<C::N>,
) -> Ext<C::F, C::EF> {
let acc: Ext<C::F, C::EF> = builder.constant(C::EF::ONE);

builder.range(0, len).for_each(|i_vec, builder| {
let i = i_vec[0];
let ptr_x: Var<C::N> = builder.eval(xlo.clone() + i);
let ptr_y: Var<C::N> = builder.eval(ylo.clone() + i);
let v_x = builder.get(&x, ptr_x);
let v_y = builder.get(&y, ptr_y);
let xi_yi: Ext<C::F, C::EF> = builder.eval(v_x * v_y);
let one: Ext<C::F, C::EF> = builder.constant(C::EF::ONE);
let new_acc: Ext<C::F, C::EF> = builder.eval(acc * (xi_yi + xi_yi - v_x - v_y + one));
builder.assign(&acc, new_acc);
});

acc
}

// Multiply all elements in the Array
pub fn product<C: Config>(
builder: &mut Builder<C>,
Expand Down Expand Up @@ -235,21 +275,29 @@ pub fn sum<C: Config>(
acc
}

// Extend an array by one element
pub fn extend<C: Config>(
// Join two arrays
pub fn join<C: Config>(
builder: &mut Builder<C>,
arr: &Array<C, Ext<C::F, C::EF>>,
elem: &Ext<C::F, C::EF>,
a: &Array<C, Ext<C::F, C::EF>>,
b: &Array<C, Ext<C::F, C::EF>>,
) -> Array<C, Ext<C::F, C::EF>> {
let new_len: Var<C::N> = builder.eval(arr.len() + C::N::ONE);
let out = builder.dyn_array(new_len);
let a_len = a.len();
let b_len = b.len();
let out_len = builder.eval_expr(a_len.clone() + b_len.clone());
let out = builder.dyn_array(out_len);

builder.range(0, arr.len()).for_each(|i_vec, builder| {
builder.range(0, a_len.clone()).for_each(|i_vec, builder| {
let i = i_vec[0];
let val = builder.get(arr, i);
builder.set_value(&out, i, val);
let a_val = builder.get(a, i);
builder.set(&out, i, a_val);
});

builder.range(0, b_len).for_each(|i_vec, builder| {
let b_i = i_vec[0];
let i = builder.eval_expr(b_i + a_len.clone());
let b_val = builder.get(b, b_i);
builder.set(&out, i, b_val);
});
builder.set_value(&out, arr.len(), elem.clone());

out
}
Expand Down Expand Up @@ -392,6 +440,35 @@ pub fn build_eq_x_r_vec_sequential<C: Config>(
evals
}

pub fn build_eq_x_r_vec_sequential_with_offset<C: Config>(
builder: &mut Builder<C>,
r: &Array<C, Ext<C::F, C::EF>>,
offset: Usize<C::N>,
) -> Array<C, Ext<C::F, C::EF>> {
// we build eq(x,r) from its evaluations
// we want to evaluate eq(x,r) over x \in {0, 1}^num_vars
// for example, with num_vars = 4, x is a binary vector of 4, then
// 0 0 0 0 -> (1-r0) * (1-r1) * (1-r2) * (1-r3)
// 1 0 0 0 -> r0 * (1-r1) * (1-r2) * (1-r3)
// 0 1 0 0 -> (1-r0) * r1 * (1-r2) * (1-r3)
// 1 1 0 0 -> r0 * r1 * (1-r2) * (1-r3)
// ....
// 1 1 1 1 -> r0 * r1 * r2 * r3
// we will need 2^num_var evaluations

let r_len: Var<C::N> = builder.eval(r.len() - offset);
let evals_len: Felt<C::F> = builder.constant(C::F::ONE);
let evals_len = builder.exp_power_of_2_v::<Felt<C::F>>(evals_len, r_len);
let evals_len = builder.cast_felt_to_var(evals_len);

let evals: Array<C, Ext<C::F, C::EF>> = builder.dyn_array(evals_len);
// _debug
// build_eq_x_r_helper_sequential_offset(r, &mut evals, E::ONE);
// unsafe { std::mem::transmute(evals) }
// FIXME: this function is not implemented yet
evals
}

pub fn ceil_log2(x: usize) -> usize {
assert!(x > 0, "ceil_log2: x must be positive");
// Calculate the number of bits in usize
Expand Down Expand Up @@ -742,7 +819,7 @@ impl<C: Config> UniPolyExtrapolator<C> {
p_i: &Array<C, Ext<C::F, C::EF>>,
eval_at: Ext<C::F, C::EF>,
) -> Ext<C::F, C::EF> {
let res: Ext<C::F, C::EF> = builder.eval(self.constants[0] + self.constants[0]);
let res: Ext<C::F, C::EF> = builder.constant(C::EF::ZERO);

builder.if_eq(p_i.len(), Usize::from(4)).then_or_else(
|builder| {
Expand Down Expand Up @@ -797,8 +874,8 @@ impl<C: Config> UniPolyExtrapolator<C> {
let p_i_0 = builder.get(p_i, 0);
let p_i_1 = builder.get(p_i, 1);

let t0: Ext<C::F, C::EF> = builder.eval(self.constants[5] * p_i_0 / d0);
let t1: Ext<C::F, C::EF> = builder.eval(self.constants[1] * p_i_1 / d1);
let t0: Ext<C::F, C::EF> = builder.eval(self.constants[5] * p_i_0 * d0.inverse());
let t1: Ext<C::F, C::EF> = builder.eval(self.constants[1] * p_i_1 * d1.inverse());

builder.eval(l * (t0 + t1))
}
Expand All @@ -822,9 +899,9 @@ impl<C: Config> UniPolyExtrapolator<C> {
let p_i_1: Ext<C::F, C::EF> = builder.get(p_i, 1);
let p_i_2: Ext<C::F, C::EF> = builder.get(p_i, 2);

let t0: Ext<C::F, C::EF> = builder.eval(self.constants[6] * p_i_0 / d0);
let t1: Ext<C::F, C::EF> = builder.eval(self.constants[5] * p_i_1 / d1);
let t2: Ext<C::F, C::EF> = builder.eval(self.constants[6] * p_i_2 / d2);
let t0: Ext<C::F, C::EF> = builder.eval(self.constants[6] * p_i_0 * d0.inverse());
let t1: Ext<C::F, C::EF> = builder.eval(self.constants[5] * p_i_1 * d1.inverse());
let t2: Ext<C::F, C::EF> = builder.eval(self.constants[6] * p_i_2 * d2.inverse());

builder.eval(l * (t0 + t1 + t2))
}
Expand All @@ -851,10 +928,10 @@ impl<C: Config> UniPolyExtrapolator<C> {
let p_i_2: Ext<C::F, C::EF> = builder.get(p_i, 2);
let p_i_3: Ext<C::F, C::EF> = builder.get(p_i, 3);

let t0: Ext<C::F, C::EF> = builder.eval(self.constants[9] * p_i_0 / d0);
let t1: Ext<C::F, C::EF> = builder.eval(self.constants[6] * p_i_1 / d1);
let t2: Ext<C::F, C::EF> = builder.eval(self.constants[7] * p_i_2 / d2);
let t3: Ext<C::F, C::EF> = builder.eval(self.constants[8] * p_i_3 / d3);
let t0: Ext<C::F, C::EF> = builder.eval(self.constants[9] * p_i_0 * d0.inverse());
let t1: Ext<C::F, C::EF> = builder.eval(self.constants[6] * p_i_1 * d1.inverse());
let t2: Ext<C::F, C::EF> = builder.eval(self.constants[7] * p_i_2 * d2.inverse());
let t3: Ext<C::F, C::EF> = builder.eval(self.constants[8] * p_i_3 * d3.inverse());

builder.eval(l * (t0 + t1 + t2 + t3))
}
Expand Down Expand Up @@ -884,12 +961,30 @@ impl<C: Config> UniPolyExtrapolator<C> {
let p_i_3: Ext<C::F, C::EF> = builder.get(p_i, 3);
let p_i_4: Ext<C::F, C::EF> = builder.get(p_i, 4);

let t0: Ext<C::F, C::EF> = builder.eval(self.constants[11] * p_i_0 / d0);
let t1: Ext<C::F, C::EF> = builder.eval(self.constants[9] * p_i_1 / d1);
let t2: Ext<C::F, C::EF> = builder.eval(self.constants[10] * p_i_2 / d2);
let t3: Ext<C::F, C::EF> = builder.eval(self.constants[9] * p_i_3 / d3);
let t4: Ext<C::F, C::EF> = builder.eval(self.constants[11] * p_i_4 / d4);
let t0: Ext<C::F, C::EF> = builder.eval(self.constants[11] * p_i_0 * d0.inverse());
let t1: Ext<C::F, C::EF> = builder.eval(self.constants[9] * p_i_1 * d1.inverse());
let t2: Ext<C::F, C::EF> = builder.eval(self.constants[10] * p_i_2 * d2.inverse());
let t3: Ext<C::F, C::EF> = builder.eval(self.constants[9] * p_i_3 * d3.inverse());
let t4: Ext<C::F, C::EF> = builder.eval(self.constants[11] * p_i_4 * d4.inverse());

builder.eval(l * (t0 + t1 + t2 + t3 + t4))
}
}

pub fn extend<C: Config>(
builder: &mut Builder<C>,
arr: &Array<C, Ext<C::F, C::EF>>,
elem: &Ext<C::F, C::EF>,
) -> Array<C, Ext<C::F, C::EF>> {
let new_len: Var<C::N> = builder.eval(arr.len() + C::N::ONE);
let out = builder.dyn_array(new_len);

builder.range(0, arr.len()).for_each(|i_vec, builder| {
let i = i_vec[0];
let val = builder.get(arr, i);
builder.set_value(&out, i, val);
});
builder.set_value(&out, arr.len(), elem.clone());

out
}
73 changes: 73 additions & 0 deletions src/basefold_verifier/basefold.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use openvm_native_compiler::{asm::AsmConfig, prelude::*};
use openvm_native_recursion::hints::Hintable;
use openvm_stark_sdk::p3_baby_bear::BabyBear;
use p3_field::extension::BinomialExtensionField;
use serde::Deserialize;

use crate::basefold_verifier::hash::Hash;

use super::{mmcs::*, structs::DIMENSIONS};

pub type F = BabyBear;
pub type E = BinomialExtensionField<F, DIMENSIONS>;
pub type InnerConfig = AsmConfig<F, E>;

pub type HashDigest = MmcsCommitment;
#[derive(Deserialize)]
pub struct BasefoldCommitment {
pub commit: HashDigest,
pub log2_max_codeword_size: usize,
pub trivial_commits: Vec<HashDigest>,
}

use mpcs::BasefoldCommitment as InnerBasefoldCommitment;

impl From<InnerBasefoldCommitment<E>> for BasefoldCommitment {
fn from(value: InnerBasefoldCommitment<E>) -> Self {
Self {
commit: Hash {
value: value.commit().into(),
},
log2_max_codeword_size: value.log2_max_codeword_size,
trivial_commits: value
.trivial_commits
.into_iter()
.map(|c| c.into())
.collect(),
}
}
}

impl Hintable<InnerConfig> for BasefoldCommitment {
type HintVariable = BasefoldCommitmentVariable<InnerConfig>;

fn read(builder: &mut Builder<InnerConfig>) -> Self::HintVariable {
let commit = HashDigest::read(builder);
let log2_max_codeword_size = Usize::Var(usize::read(builder));
// let trivial_commits = Vec::<HashDigest>::read(builder);

BasefoldCommitmentVariable {
commit,
log2_max_codeword_size,
// trivial_commits,
}
}

fn write(&self) -> Vec<Vec<<InnerConfig as Config>::N>> {
let mut stream = Vec::new();
stream.extend(self.commit.write());
stream.extend(<usize as Hintable<InnerConfig>>::write(
&self.log2_max_codeword_size,
));
// stream.extend(self.trivial_commits.write());
stream
}
}

pub type HashDigestVariable<C> = MmcsCommitmentVariable<C>;
#[derive(DslVariable, Clone)]
pub struct BasefoldCommitmentVariable<C: Config> {
pub commit: HashDigestVariable<C>,
pub log2_max_codeword_size: Usize<C::N>,
// pub trivial_commits: Array<C, HashDigestVariable<C>>,
}
Loading