Skip to content
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

Add support for constant column in STWO backend #2112

Merged
merged 51 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
4a7f349
add support for constant column
ShuangWu121 Nov 19, 2024
d1becd0
building constant columns
ShuangWu121 Nov 21, 2024
53183d4
test pil
ShuangWu121 Nov 21, 2024
a3f6d0f
cleaner
ShuangWu121 Nov 21, 2024
eb6f2ec
constant support
ShuangWu121 Nov 21, 2024
7169334
Merge branch 'main' into stwo-constant-support
ShuangWu121 Nov 21, 2024
cd67a59
clean up
ShuangWu121 Nov 22, 2024
12146be
add setup
ShuangWu121 Nov 24, 2024
2c100ba
put setup into new function
ShuangWu121 Nov 24, 2024
c9606b5
clean up
ShuangWu121 Nov 24, 2024
9756ef4
clean up
ShuangWu121 Nov 25, 2024
9f9c20d
clean up
ShuangWu121 Nov 25, 2024
b99c1a9
add challenge channel to tableProvingkey
ShuangWu121 Nov 25, 2024
e688e3e
handle empty constant case
ShuangWu121 Nov 25, 2024
d9db236
add more test, and comments
ShuangWu121 Nov 25, 2024
3ea95b5
add test in pil
ShuangWu121 Nov 25, 2024
6fa35a7
remove prover channel from table key
ShuangWu121 Nov 27, 2024
648435d
avoid clone witness, using better API to do bit reverse order of the …
ShuangWu121 Nov 27, 2024
b4a2411
Update backend/src/stwo/circuit_builder.rs
ShuangWu121 Nov 28, 2024
fe6f220
cannot make setup work because of 'a
ShuangWu121 Nov 28, 2024
94c1ac2
avoid using refcell, and std::mem::take
ShuangWu121 Nov 28, 2024
f19f557
fix error with empty constant, simplified code
ShuangWu121 Nov 29, 2024
14f76ba
add enumerate to plonk(i)
ShuangWu121 Nov 29, 2024
07ceb5d
clean up
ShuangWu121 Nov 29, 2024
c422ffd
add more comment
ShuangWu121 Nov 29, 2024
d3f7782
add fail test
ShuangWu121 Nov 29, 2024
61a989e
merge main
ShuangWu121 Nov 29, 2024
d4e0bb1
fix test case
ShuangWu121 Nov 30, 2024
998a240
Update backend/src/stwo/prover.rs
ShuangWu121 Dec 3, 2024
26c8ce9
make gen_stwo_circle_column work on slice
ShuangWu121 Dec 4, 2024
567b0f8
support constant column with next reference
ShuangWu121 Dec 5, 2024
2e627dd
use a wrong clippy command, now fixed it
ShuangWu121 Dec 5, 2024
0f05f72
use identities, so no panic for lookups
ShuangWu121 Dec 5, 2024
bc4bf30
add test for fixed col with next reference, remove mc generic in prov…
ShuangWu121 Dec 6, 2024
50521e9
fix fmt
ShuangWu121 Dec 6, 2024
34e8963
merge to main Merge remote-tracking branch 'origin/main' into stwo-co…
ShuangWu121 Dec 6, 2024
410c68a
no intermidate panic
ShuangWu121 Dec 6, 2024
a1a663c
serialize and deserialize proving keys
ShuangWu121 Dec 9, 2024
9503341
add test file
ShuangWu121 Dec 9, 2024
66b1c1b
simplify serilization
ShuangWu121 Dec 9, 2024
b18e937
simplify serilization
ShuangWu121 Dec 9, 2024
524d9ff
clean up
ShuangWu121 Dec 9, 2024
5e592f7
refactor proof serilization and next reference on constant
ShuangWu121 Dec 10, 2024
30bd4ae
Update backend/src/stwo/prover.rs
ShuangWu121 Dec 10, 2024
9ab7a3b
clean up
ShuangWu121 Dec 10, 2024
3e2a078
clean up
ShuangWu121 Dec 10, 2024
2b56587
log size correction
ShuangWu121 Dec 10, 2024
8f6eb44
Update backend/src/stwo/circuit_builder.rs
ShuangWu121 Dec 10, 2024
af61413
simplify the function to create list of constant with next reference
ShuangWu121 Dec 11, 2024
f446e46
use all_children to create list
ShuangWu121 Dec 11, 2024
0557c60
create name list for constant with next
ShuangWu121 Dec 11, 2024
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
3 changes: 2 additions & 1 deletion backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ p3-commit = { git = "https://github.com/plonky3/Plonky3.git", rev = "2192432ddf2
p3-matrix = { git = "https://github.com/plonky3/Plonky3.git", rev = "2192432ddf28e7359dd2c577447886463e6124f0", optional = true }
p3-uni-stark = { git = "https://github.com/plonky3/Plonky3.git", rev = "2192432ddf28e7359dd2c577447886463e6124f0", optional = true }
# TODO: Change this to main branch when the `andrew/dev/update-toolchain` branch is merged,the main branch is using "nightly-2024-01-04", not compatiable with plonky3
stwo-prover = { git = "https://github.com/starkware-libs/stwo.git", optional = true, rev = "e6d10bc107c11cce54bb4aa152c3afa2e15e92c1" }
# stwo-prover = { git = "https://github.com/starkware-libs/stwo.git", optional = true, rev = "e6d10bc107c11cce54bb4aa152c3afa2e15e92c1" }
Schaeff marked this conversation as resolved.
Show resolved Hide resolved
stwo-prover = { git = "https://github.com/ShuangWu121/stwo.git", optional = true, rev = "564a4ddcde376ba0ae78da4d86ea5ad7338ef6fe" }

strum = { version = "0.24.1", features = ["derive"] }
log = "0.4.17"
Expand Down
49 changes: 39 additions & 10 deletions backend/src/stwo/circuit_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ use std::sync::Arc;
use powdr_ast::analyzed::{
AlgebraicUnaryOperation, AlgebraicUnaryOperator, PolyID, PolynomialType,
};
use stwo_prover::constraint_framework::{EvalAtRow, FrameworkComponent, FrameworkEval};
use stwo_prover::constraint_framework::preprocessed_columns::{gen_is_first, PreprocessedColumn};
use stwo_prover::constraint_framework::{
EvalAtRow, FrameworkComponent, FrameworkEval, ORIGINAL_TRACE_IDX, PREPROCESSED_TRACE_IDX,
};
use stwo_prover::core::backend::ColumnOps;
use stwo_prover::core::fields::m31::{BaseField, M31};
use stwo_prover::core::fields::{ExtensionOf, FieldExpOps, FieldOps};
Expand Down Expand Up @@ -53,6 +56,7 @@ where
pub struct PowdrEval<T> {
analyzed: Arc<Analyzed<T>>,
witness_columns: BTreeMap<PolyID, usize>,
constant_columns: BTreeMap<PolyID, usize>,
}

impl<T: FieldElement> PowdrEval<T> {
Expand All @@ -63,10 +67,18 @@ impl<T: FieldElement> PowdrEval<T> {
.enumerate()
.map(|(index, (_, id))| (id, index))
.collect();

let constant_columns: BTreeMap<PolyID, usize> = analyzed
.definitions_in_source_order(PolynomialType::Constant)
.flat_map(|(symbol, _)| symbol.array_elements())
.enumerate()
.map(|(index, (_, id))| (id, index))
.collect();

Self {
analyzed,
witness_columns,
constant_columns,
}
}
}
Expand All @@ -80,14 +92,29 @@ impl<T: FieldElement> FrameworkEval for PowdrEval<T> {
}
fn evaluate<E: EvalAtRow>(&self, mut eval: E) -> E {
assert!(
self.analyzed.constant_count() == 0 && self.analyzed.publics_count() == 0,
"Error: Expected no fixed columns nor public inputs, as they are not supported yet.",
self.analyzed.publics_count() == 0,
"Error: Expected no public inputs, as they are not supported yet.",
);

let witness_eval: BTreeMap<PolyID, [<E as EvalAtRow>::F; 2]> = self
.witness_columns
.keys()
.map(|poly_id| (*poly_id, eval.next_interaction_mask(0, [0, 1])))
.map(|poly_id| {
(
*poly_id,
eval.next_interaction_mask(ORIGINAL_TRACE_IDX, [0, 1]),
Schaeff marked this conversation as resolved.
Show resolved Hide resolved
Schaeff marked this conversation as resolved.
Show resolved Hide resolved
)
})
.collect();
let constant_eval: BTreeMap<PolyID, <E as EvalAtRow>::F> = self
ShuangWu121 marked this conversation as resolved.
Show resolved Hide resolved
.constant_columns
.keys()
.map(|poly_id| {
(
*poly_id,
eval.get_preprocessed_column(PreprocessedColumn::Plonk(3)),
Schaeff marked this conversation as resolved.
Show resolved Hide resolved
)
})
.collect();

for id in self
Expand All @@ -96,7 +123,8 @@ impl<T: FieldElement> FrameworkEval for PowdrEval<T> {
{
match id {
Identity::Polynomial(identity) => {
let expr = to_stwo_expression(&identity.expression, &witness_eval);
let expr =
to_stwo_expression(&identity.expression, &witness_eval, &constant_eval);
eval.add_constraint(expr);
}
Identity::Connect(..) => {
Expand All @@ -119,6 +147,7 @@ impl<T: FieldElement> FrameworkEval for PowdrEval<T> {
fn to_stwo_expression<T: FieldElement, F>(
expr: &AlgebraicExpression<T>,
witness_eval: &BTreeMap<PolyID, [F; 2]>,
constant_eval: &BTreeMap<PolyID, F>,
) -> F
where
F: FieldExpOps
Expand All @@ -145,7 +174,7 @@ where
true => witness_eval[&poly_id][1].clone(),
},
PolynomialType::Constant => {
unimplemented!("Constant polynomials are not supported in stwo yet")
constant_eval[&poly_id].clone()
Schaeff marked this conversation as resolved.
Show resolved Hide resolved
}
PolynomialType::Intermediate => {
unimplemented!("Intermediate polynomials are not supported in stwo yet")
Expand All @@ -162,15 +191,15 @@ where
right,
}) => match **right {
AlgebraicExpression::Number(n) => {
let left = to_stwo_expression(left, witness_eval);
let left = to_stwo_expression(left, witness_eval, constant_eval);
(0u32..n.to_integer().try_into_u32().unwrap())
.fold(F::one(), |acc, _| acc * left.clone())
}
_ => unimplemented!("pow with non-constant exponent"),
},
AlgebraicExpression::BinaryOperation(AlgebraicBinaryOperation { left, op, right }) => {
let left = to_stwo_expression(left, witness_eval);
let right = to_stwo_expression(right, witness_eval);
let left = to_stwo_expression(left, witness_eval, constant_eval);
let right = to_stwo_expression(right, witness_eval, constant_eval);

match op {
Add => left + right,
Expand All @@ -180,7 +209,7 @@ where
}
}
AlgebraicExpression::UnaryOperation(AlgebraicUnaryOperation { op, expr }) => {
let expr = to_stwo_expression(expr, witness_eval);
let expr = to_stwo_expression(expr, witness_eval, constant_eval);

match op {
AlgebraicUnaryOperator::Minus => -expr,
Expand Down
4 changes: 1 addition & 3 deletions backend/src/stwo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use stwo_prover::core::vcs::blake2_merkle::Blake2sMerkleChannel;

mod circuit_builder;
mod prover;
//mod proof;
#[allow(dead_code)]

struct RestrictedFactory;
Expand All @@ -42,9 +43,6 @@ impl<F: FieldElement> BackendFactory<F> for RestrictedFactory {
if pil.degrees().len() > 1 {
return Err(Error::NoVariableDegreeAvailable);
}
let fixed = Arc::new(
get_uniquely_sized_cloned(&fixed).map_err(|_| Error::NoVariableDegreeAvailable)?,
);
let stwo: Box<StwoProver<F, SimdBackend, Blake2sMerkleChannel, Blake2sChannel>> =
Box::new(StwoProver::new(pil, fixed)?);
Ok(stwo)
Expand Down
85 changes: 62 additions & 23 deletions backend/src/stwo/prover.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use powdr_ast::analyzed::Analyzed;
use powdr_backend_utils::machine_fixed_columns;
use powdr_executor::constant_evaluator::VariablySizedColumn;
use serde::de::DeserializeOwned;
use serde::ser::Serialize;
use std::io;
Expand All @@ -14,10 +16,12 @@ use powdr_number::FieldElement;
use stwo_prover::core::air::{Component, ComponentProver};
use stwo_prover::core::backend::{Backend, BackendForChannel};
use stwo_prover::core::channel::{Channel, MerkleChannel};
use stwo_prover::core::fields::m31::M31;
use stwo_prover::core::fields::m31::{BaseField, M31};
use stwo_prover::core::fri::FriConfig;
use stwo_prover::core::pcs::{CommitmentSchemeProver, CommitmentSchemeVerifier, PcsConfig};
use stwo_prover::core::poly::circle::CanonicCoset;
use stwo_prover::core::poly::circle::{CanonicCoset, CircleEvaluation};
use stwo_prover::core::poly::BitReversedOrder;
use stwo_prover::core::ColumnVec;

const FRI_LOG_BLOWUP: usize = 1;
const FRI_NUM_QUERIES: usize = 100;
Expand All @@ -26,7 +30,7 @@ const LOG_LAST_LAYER_DEGREE_BOUND: usize = 0;

pub struct StwoProver<T, B: Backend + Send, MC: MerkleChannel, C: Channel> {
pub analyzed: Arc<Analyzed<T>>,
_fixed: Arc<Vec<(String, Vec<T>)>>,
fixed: Arc<Vec<(String, VariablySizedColumn<T>)>>,
/// Proving key placeholder
_proving_key: Option<()>,
/// Verifying key placeholder
Expand All @@ -46,11 +50,11 @@ where
{
pub fn new(
analyzed: Arc<Analyzed<F>>,
_fixed: Arc<Vec<(String, Vec<F>)>>,
fixed: Arc<Vec<(String, VariablySizedColumn<F>)>>,
) -> Result<Self, io::Error> {
Ok(Self {
analyzed,
_fixed,
fixed,
_proving_key: None,
_verifying_key: None,
_channel_marker: PhantomData,
Expand All @@ -70,26 +74,69 @@ where
);

// Setup protocol.
let mut prover_channel = <MC as MerkleChannel>::C::default();
let prover_channel = &mut <MC as MerkleChannel>::C::default();
let commitment_scheme = &mut CommitmentSchemeProver::<B, MC>::new(config, &twiddles);

// get fix_columns evaluations
let fixed_columns = machine_fixed_columns(&self.fixed, &self.analyzed);

let domain = CanonicCoset::new(
fixed_columns
.keys()
.next()
.map(|&first_key| first_key.ilog2())
.unwrap_or(0),
)
.circle_domain();

let constant_trace: ColumnVec<CircleEvaluation<B, BaseField, BitReversedOrder>> =
fixed_columns
.values()
.flat_map(|vec| {
println!("vec is {:?}", vec);
vec.iter().map(|(_name, values)| {
let values = values
.iter()
.map(|v| v.try_into_i32().unwrap().into())
.collect();
CircleEvaluation::new(domain, values)
})
})
.collect();

// Preprocessed trace
let mut tree_builder = commitment_scheme.tree_builder();
tree_builder.extend_evals(constant_trace);
tree_builder.commit(prover_channel);

// committed/witness trace
let trace = gen_stwo_circuit_trace::<F, B, M31>(witness);
Schaeff marked this conversation as resolved.
Show resolved Hide resolved

let mut tree_builder = commitment_scheme.tree_builder();
tree_builder.extend_evals(trace);
tree_builder.commit(&mut prover_channel);
tree_builder.commit(prover_channel);

let component = PowdrComponent::new(
&mut TraceLocationAllocator::default(),
PowdrEval::new(self.analyzed.clone()),
);

let n_preprocessed_columns = commitment_scheme.trees[0]
.polynomials
.len();
println!("n_preprocessed_columns is {}", n_preprocessed_columns);

let trace = commitment_scheme.trace();
println!("trace is {:?}", trace.evals);

let proof = stwo_prover::core::prover::prove::<B, MC>(
&[&component],
&mut prover_channel,
prover_channel,
commitment_scheme,
)
.unwrap();



Ok(bincode::serialize(&proof).unwrap())
}
Expand All @@ -105,8 +152,8 @@ where
let proof: StarkProof<MC::H> =
bincode::deserialize(proof).map_err(|e| format!("Failed to deserialize proof: {e}"))?;

let mut verifier_channel = <MC as MerkleChannel>::C::default();
let mut commitment_scheme = CommitmentSchemeVerifier::<MC>::new(config);
let verifier_channel = &mut <MC as MerkleChannel>::C::default();
let commitment_scheme = &mut CommitmentSchemeVerifier::<MC>::new(config);

//Constraints that are to be proved
let component = PowdrComponent::new(
Expand All @@ -115,21 +162,13 @@ where
);

// Retrieve the expected column sizes in each commitment interaction, from the AIR.
// TODO: When constant columns are supported, there will be more than one sizes and proof.commitments
// size[0] is for constant columns, size[1] is for witness columns, size[2] is for lookup columns
// pass size[1] for witness columns now is not doable due to this branch is outdated for the new feature of constant columns
// it will throw errors.
Schaeff marked this conversation as resolved.
Show resolved Hide resolved
let sizes = component.trace_log_degree_bounds();
assert_eq!(sizes.len(), 1);
commitment_scheme.commit(proof.commitments[0], &sizes[0], &mut verifier_channel);

stwo_prover::core::prover::verify(
&[&component],
&mut verifier_channel,
&mut commitment_scheme,
proof,
)
.map_err(|e| e.to_string())
commitment_scheme.commit(proof.commitments[0], &sizes[0], verifier_channel);
commitment_scheme.commit(proof.commitments[1], &sizes[1], verifier_channel);

stwo_prover::core::prover::verify(&[&component], verifier_channel, commitment_scheme, proof)
.map_err(|e| e.to_string())
}
}

Expand Down
13 changes: 13 additions & 0 deletions test_data/pil/fibo_no_public.pil
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
let N = 4;

// This uses the alternative nomenclature as well.

namespace Fibonacci(N);
col fixed ISLAST(i) { if i == N - 1 { 1 } else { 0 } };
col witness x, y;

ISLAST * (y' - 1) = 0;
ISLAST * (x' - 1) = 0;

(1-ISLAST) * (x' - y) = 0;
(1-ISLAST) * (y' - (x + y)) = 0;
Loading