Skip to content

Commit 24eb8a4

Browse files
committed
whirlaway: cp pcs crate
1 parent 8440073 commit 24eb8a4

File tree

8 files changed

+1142
-0
lines changed

8 files changed

+1142
-0
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ members = [
1414
"crates/utils",
1515
"crates/air",
1616
"crates/sumcheck",
17+
"crates/pcs",
1718
]
1819
resolver = "3"
1920

@@ -48,6 +49,7 @@ lean-lookup = { path = "crates/leanLookup" }
4849
utils = { path = "crates/utils" }
4950
air = { path = "crates/air" }
5051
sumcheck = { path = "crates/sumcheck" }
52+
pcs = { path = "crates/pcs" }
5153

5254
rand = "0.9.2"
5355
sha3 = "0.10.8"

crates/pcs/Cargo.toml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[package]
2+
name = "pcs"
3+
version.workspace = true
4+
edition.workspace = true
5+
rust-version.workspace = true
6+
license.workspace = true
7+
8+
[lints]
9+
workspace = true
10+
11+
[dependencies]
12+
p3-field.workspace = true
13+
tracing.workspace = true
14+
sumcheck.workspace = true
15+
utils.workspace = true
16+
whir-p3.workspace = true
17+
rayon.workspace = true
18+
p3-symmetric.workspace = true
19+
serde.workspace = true
20+
p3-util.workspace = true
21+
22+
[dev-dependencies]
23+
p3-koala-bear.workspace = true
24+
rand.workspace = true

crates/pcs/src/batch_pcs.rs

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
use p3_field::{ExtensionField, Field, TwoAdicField};
2+
use p3_symmetric::{CryptographicHasher, PseudoCompressionFunction};
3+
use serde::{Deserialize, Serialize};
4+
use utils::{Evaluation, FSProver, FSVerifier, PF, PFPacking};
5+
use whir_p3::{
6+
dft::EvalsDft,
7+
fiat_shamir::{FSChallenger, errors::ProofError},
8+
poly::evals::EvaluationsList,
9+
whir::{
10+
config::{FoldingFactor, WhirConfig, WhirConfigBuilder},
11+
prover::Prover,
12+
statement::Statement,
13+
verifier::Verifier,
14+
},
15+
};
16+
17+
use crate::pcs::PCS;
18+
19+
pub trait BatchPCS<FA: Field, FB: Field, EF: ExtensionField<FA> + ExtensionField<FB>> {
20+
type PcsA: PCS<FA, EF>;
21+
type PcsB: PCS<FB, EF>;
22+
23+
fn pcs_a(&self) -> &Self::PcsA;
24+
25+
fn pcs_b(&self, num_variables_a: usize, num_variables_b: usize) -> Self::PcsB;
26+
27+
fn batch_open(
28+
&self,
29+
dft: &EvalsDft<PF<EF>>,
30+
prover_state: &mut FSProver<EF, impl FSChallenger<EF>>,
31+
statements_a: &[Evaluation<EF>],
32+
witness_a: <Self::PcsA as PCS<FA, EF>>::Witness,
33+
polynomial_a: &[FA],
34+
statements_b: &[Evaluation<EF>],
35+
witness_b: <Self::PcsB as PCS<FB, EF>>::Witness,
36+
polynomial_b: &[FB],
37+
);
38+
39+
fn batch_verify(
40+
&self,
41+
verifier_state: &mut FSVerifier<EF, impl FSChallenger<EF>>,
42+
parsed_commitment_a: &<Self::PcsA as PCS<FA, EF>>::ParsedCommitment,
43+
statements_a: &[Evaluation<EF>],
44+
parsed_commitment_b: &<Self::PcsB as PCS<FB, EF>>::ParsedCommitment,
45+
statements_b: &[Evaluation<EF>],
46+
) -> Result<(), ProofError>;
47+
}
48+
49+
#[derive(Debug)]
50+
pub struct WhirBatchPcs<FA, FB, EF, H, C, const DIGEST_ELEMS: usize>(
51+
pub WhirConfigBuilder<FA, EF, H, C, DIGEST_ELEMS>,
52+
pub WhirConfigBuilder<FB, EF, H, C, DIGEST_ELEMS>,
53+
);
54+
55+
impl<F, EF, H, C, const DIGEST_ELEMS: usize> BatchPCS<F, EF, EF>
56+
for WhirBatchPcs<F, EF, EF, H, C, DIGEST_ELEMS>
57+
where
58+
F: TwoAdicField,
59+
PF<EF>: TwoAdicField,
60+
EF: ExtensionField<F> + TwoAdicField + ExtensionField<PF<EF>>,
61+
F: ExtensionField<PF<EF>>,
62+
H: CryptographicHasher<PF<EF>, [PF<EF>; DIGEST_ELEMS]>
63+
+ CryptographicHasher<PFPacking<EF>, [PFPacking<EF>; DIGEST_ELEMS]>
64+
+ Sync,
65+
C: PseudoCompressionFunction<[PF<EF>; DIGEST_ELEMS], 2>
66+
+ PseudoCompressionFunction<[PFPacking<EF>; DIGEST_ELEMS], 2>
67+
+ Sync,
68+
[PF<EF>; DIGEST_ELEMS]: Serialize + for<'de> Deserialize<'de>,
69+
{
70+
type PcsA = WhirConfigBuilder<F, EF, H, C, DIGEST_ELEMS>;
71+
type PcsB = WhirConfigBuilder<EF, EF, H, C, DIGEST_ELEMS>;
72+
73+
fn pcs_a(&self) -> &Self::PcsA {
74+
&self.0
75+
}
76+
77+
fn pcs_b(&self, num_variables_a: usize, num_variables_b: usize) -> Self::PcsB {
78+
let mut pcs_b = self.1.clone();
79+
let var_diff = num_variables_a.checked_sub(num_variables_b).unwrap();
80+
let initial_folding_factor_b = self
81+
.0
82+
.folding_factor
83+
.at_round(0)
84+
.checked_sub(var_diff)
85+
.unwrap();
86+
let new_folding_factor_b = FoldingFactor::ConstantFromSecondRound(
87+
initial_folding_factor_b,
88+
pcs_b.folding_factor.at_round(1),
89+
);
90+
pcs_b.folding_factor = new_folding_factor_b;
91+
pcs_b
92+
}
93+
94+
fn batch_open(
95+
&self,
96+
dft: &EvalsDft<PF<EF>>,
97+
prover_state: &mut FSProver<EF, impl FSChallenger<EF>>,
98+
statements_a: &[Evaluation<EF>],
99+
witness_a: <Self::PcsA as PCS<F, EF>>::Witness,
100+
polynomial_a: &[F],
101+
statements_b: &[Evaluation<EF>],
102+
witness_b: <Self::PcsB as PCS<EF, EF>>::Witness,
103+
polynomial_b: &[EF],
104+
) {
105+
// TODO need to improve inside WHIR repo
106+
107+
let config_a = WhirConfig::new(self.0.clone(), polynomial_a.num_variables());
108+
let mut whir_statements_a = Statement::new(polynomial_a.num_variables());
109+
for statement in statements_a {
110+
whir_statements_a.add_constraint(statement.point.clone(), statement.value);
111+
}
112+
let mut whir_statements_b = Statement::new(polynomial_b.num_variables());
113+
for statement in statements_b {
114+
whir_statements_b.add_constraint(statement.point.clone(), statement.value);
115+
}
116+
Prover(&config_a)
117+
.batch_prove(
118+
dft,
119+
prover_state,
120+
whir_statements_a,
121+
witness_a,
122+
polynomial_a,
123+
whir_statements_b,
124+
witness_b,
125+
polynomial_b,
126+
)
127+
.unwrap();
128+
}
129+
130+
fn batch_verify(
131+
&self,
132+
verifier_state: &mut FSVerifier<EF, impl FSChallenger<EF>>,
133+
parsed_commitment_a: &<Self::PcsA as PCS<F, EF>>::ParsedCommitment,
134+
statements_a: &[Evaluation<EF>],
135+
parsed_commitment_b: &<Self::PcsB as PCS<EF, EF>>::ParsedCommitment,
136+
statements_b: &[Evaluation<EF>],
137+
) -> Result<(), ProofError> {
138+
let config = WhirConfig::new(self.0.clone(), parsed_commitment_a.num_variables);
139+
let mut whir_statements_a = Statement::new(parsed_commitment_a.num_variables);
140+
for statement in statements_a {
141+
whir_statements_a.add_constraint(statement.point.clone(), statement.value);
142+
}
143+
let mut whir_statements_b = Statement::new(parsed_commitment_b.num_variables);
144+
for statement in statements_b {
145+
whir_statements_b.add_constraint(statement.point.clone(), statement.value);
146+
}
147+
Verifier(&config).batch_verify(
148+
verifier_state,
149+
parsed_commitment_a,
150+
&whir_statements_a,
151+
parsed_commitment_b,
152+
&whir_statements_b,
153+
)?;
154+
Ok(())
155+
}
156+
}

crates/pcs/src/combinatorics.rs

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
use std::cmp::Reverse;
2+
use std::collections::BinaryHeap;
3+
4+
#[derive(Debug, Clone)]
5+
pub struct TreeOfVariables {
6+
pub vars_per_polynomial: Vec<usize>,
7+
pub root: TreeOfVariablesInner,
8+
}
9+
10+
#[derive(Debug, Clone, PartialEq, Eq)]
11+
pub enum TreeOfVariablesInner {
12+
Polynomial(usize),
13+
Composed {
14+
left: Box<TreeOfVariablesInner>,
15+
right: Box<TreeOfVariablesInner>,
16+
},
17+
}
18+
19+
#[derive(Debug, Clone, PartialEq, Eq)]
20+
struct TreeNode {
21+
tree: TreeOfVariablesInner,
22+
var_count: usize,
23+
}
24+
25+
impl PartialOrd for TreeNode {
26+
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
27+
Some(self.cmp(other))
28+
}
29+
}
30+
31+
impl Ord for TreeNode {
32+
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
33+
self.var_count.cmp(&other.var_count)
34+
}
35+
}
36+
37+
impl TreeOfVariables {
38+
pub fn total_vars(&self) -> usize {
39+
self.root.total_vars(&self.vars_per_polynomial)
40+
}
41+
}
42+
43+
impl TreeOfVariablesInner {
44+
pub fn total_vars(&self, vars_per_polynomial: &[usize]) -> usize {
45+
match self {
46+
TreeOfVariablesInner::Polynomial(i) => vars_per_polynomial[*i],
47+
TreeOfVariablesInner::Composed { left, right } => {
48+
1 + left
49+
.total_vars(vars_per_polynomial)
50+
.max(right.total_vars(vars_per_polynomial))
51+
}
52+
}
53+
}
54+
}
55+
56+
impl TreeOfVariables {
57+
pub fn compute_optimal(vars_per_polynomial: Vec<usize>) -> Self {
58+
let n = vars_per_polynomial.len();
59+
assert!(n > 0);
60+
61+
let root = Self::compute_greedy(&vars_per_polynomial);
62+
63+
Self {
64+
root,
65+
vars_per_polynomial,
66+
}
67+
}
68+
69+
fn compute_greedy(vars_per_polynomial: &[usize]) -> TreeOfVariablesInner {
70+
let mut heap: BinaryHeap<Reverse<TreeNode>> = vars_per_polynomial
71+
.iter()
72+
.enumerate()
73+
.map(|(i, &var_count)| {
74+
Reverse(TreeNode {
75+
tree: TreeOfVariablesInner::Polynomial(i),
76+
var_count,
77+
})
78+
})
79+
.collect();
80+
81+
while heap.len() > 1 {
82+
let Reverse(left_node) = heap.pop().unwrap();
83+
let Reverse(right_node) = heap.pop().unwrap();
84+
85+
let combined_var_count = 1 + left_node.var_count.max(right_node.var_count);
86+
87+
let combined_tree = TreeOfVariablesInner::Composed {
88+
left: Box::new(left_node.tree),
89+
right: Box::new(right_node.tree),
90+
};
91+
92+
heap.push(Reverse(TreeNode {
93+
tree: combined_tree,
94+
var_count: combined_var_count,
95+
}));
96+
}
97+
98+
heap.pop().unwrap().0.tree
99+
}
100+
}
101+
102+
#[cfg(test)]
103+
mod tests {
104+
use super::*;
105+
106+
#[cfg(test)]
107+
#[test]
108+
fn test_tree_of_variables() {
109+
let vars_per_polynomial = vec![2];
110+
let tree = TreeOfVariables::compute_optimal(vars_per_polynomial.clone());
111+
dbg!(&tree, tree.total_vars());
112+
}
113+
}

crates/pcs/src/lib.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
2+
3+
mod pcs;
4+
pub use pcs::*;
5+
6+
mod ring_switch;
7+
pub use ring_switch::*;
8+
9+
mod combinatorics;
10+
11+
mod packed_pcs;
12+
pub use packed_pcs::*;
13+
14+
mod batch_pcs;
15+
pub use batch_pcs::*;

0 commit comments

Comments
 (0)