1use crate::core::{
2 aggregate,
3 challenge_set::ChallengeSet,
4 crs::PublicPrams,
5 env_params::EnvironmentParameters,
6 jl::{ProjectionMatrix, Projections},
7 statement::Statement,
8};
9use crate::ring::poly::{PolyVector, ZqVector};
10use crate::ring::zq::Zq;
11use rand::rng;
12
13const D: usize = 64;
15
16#[derive(Debug)]
17pub enum ProverError {
18 WitnessL2NormViolated { norm_squared: Zq, allowed: Zq },
20 ProjectionError {
21 index: usize,
22 expected: Zq,
23 computed: Zq,
24 },
25}
26
27pub struct Proof {
30 pub u_1: PolyVector,
31 pub p: Projections,
32 pub b_ct_aggr: PolyVector,
33 pub u_2: PolyVector,
34 pub z: PolyVector,
35 pub t_i: Vec<PolyVector>,
36 pub g_ij: Vec<PolyVector>,
37 pub h_ij: Vec<PolyVector>,
38}
39
40pub struct Challenges {
42 pub pi: Vec<Vec<ZqVector>>,
43 pub psi: Vec<ZqVector>,
44 pub omega: Vec<ZqVector>,
45 pub random_alpha: PolyVector,
46 pub random_beta: PolyVector,
47 pub random_c: PolyVector,
48}
49
50impl Challenges {
51 pub fn new(ep: &EnvironmentParameters) -> Self {
52 let psi: Vec<ZqVector> = (0..ep.k)
54 .map(|_| ZqVector::random(&mut rng(), ep.constraint_l))
55 .collect();
56
57 let omega: Vec<ZqVector> = (0..ep.k)
59 .map(|_| ZqVector::random(&mut rng(), ep.lambda2))
60 .collect();
61
62 let pi: Vec<Vec<ZqVector>> = Self::get_pi(ep.r, ep.n);
64
65 let cs_alpha: ChallengeSet = ChallengeSet::new(ep.deg_bound_d);
67 let random_alpha: PolyVector = (0..ep.constraint_k)
68 .map(|_| cs_alpha.get_challenges().clone())
69 .collect();
70
71 let cs_beta: ChallengeSet = ChallengeSet::new(ep.deg_bound_d);
72 let random_beta: PolyVector = (0..ep.constraint_k)
73 .map(|_| cs_beta.get_challenges().clone())
74 .collect();
75
76 let cs_c: ChallengeSet = ChallengeSet::new(ep.deg_bound_d);
77 let random_c: PolyVector = (0..ep.r).map(|_| cs_c.get_challenges().clone()).collect();
78
79 Self {
80 pi,
81 psi,
82 omega,
83 random_alpha,
84 random_beta,
85 random_c,
86 }
87 }
88
89 pub fn get_pi(r: usize, n: usize) -> Vec<Vec<ZqVector>> {
90 (0..r)
91 .map(|_| ProjectionMatrix::<D>::new(n).get_matrix().clone())
92 .collect()
93 }
94}
95pub struct Witness {
96 pub s: Vec<PolyVector>,
97}
98
99impl Witness {
100 pub fn new(ep: &EnvironmentParameters) -> Self {
101 let s = (0..ep.r)
102 .map(|_| PolyVector::random_ternary(ep.n, ep.deg_bound_d))
103 .collect();
104 Self { s }
105 }
106}
107
108pub struct LabradorProver<'a> {
109 pub pp: &'a PublicPrams,
110 pub witness: &'a Witness,
111 pub st: &'a Statement,
112 pub tr: &'a Challenges,
113}
114
115impl<'a> LabradorProver<'a> {
116 pub fn new(
117 pp: &'a PublicPrams,
118 witness: &'a Witness,
119 st: &'a Statement,
120 tr: &'a Challenges,
121 ) -> Self {
122 Self {
123 pp,
124 witness,
125 st,
126 tr,
127 }
128 }
129
130 pub fn prove(&self, ep: &EnvironmentParameters) -> Result<Proof, ProverError> {
132 Self::check_witness_l2norm(self, ep).unwrap();
135 let matrix_a = &self.pp.matrix_a;
139 let t_i: Vec<PolyVector> = self.witness.s.iter().map(|s_i| s_i * matrix_a).collect();
140
141 let t_ij: Vec<Vec<PolyVector>> = t_i
143 .iter()
144 .map(|i| PolyVector::decompose(i, ep.b, ep.t_1))
145 .collect();
146 let g_gp: Vec<PolyVector> = aggregate::calculate_gij(&self.witness.s, ep.r);
148 let g_ij: Vec<Vec<PolyVector>> = g_gp
150 .iter()
151 .map(|i| PolyVector::decompose(i, ep.b, ep.t_2))
152 .collect();
153 let matrix_b = &self.pp.matrix_b;
154 let matrix_c = &self.pp.matrix_c;
155 let u_1 = aggregate::calculate_u_1(matrix_b, matrix_c, &t_ij, &g_ij, ep);
157
158 let matrices = &self.tr.pi;
164 let p = Projections::new(matrices, &self.witness.s);
165
166 Self::check_projection(self, p.get_projection()).unwrap();
169
170 let aggr_1 = aggregate::AggregationOne::new(self.witness, self.st, ep, self.tr);
176 let aggr_2 = aggregate::AggregationTwo::new(&aggr_1, self.st, ep, self.tr);
178
179 let phi_i = aggr_2.phi_i;
184 let h_gp = aggregate::calculate_hij(&phi_i, &self.witness.s, ep);
185 let h_ij: Vec<Vec<PolyVector>> = h_gp
187 .iter()
188 .map(|i| PolyVector::decompose(i, ep.b, ep.t_1))
189 .collect();
190 let matrix_d = &self.pp.matrix_d;
192 let u_2 = aggregate::calculate_u_2(matrix_d, &h_ij, ep);
194 let z = aggregate::calculate_z(&self.witness.s, &self.tr.random_c);
196
197 Ok(Proof {
200 u_1,
201 p,
202 b_ct_aggr: aggr_1.b_ct_aggr,
203 u_2,
204 z,
205 t_i,
206 g_ij: g_gp,
207 h_ij: h_gp,
208 })
209 }
210
211 fn check_projection(&self, p: &ZqVector) -> Result<bool, ProverError> {
213 let s_coeffs: Vec<ZqVector> = self
214 .witness
215 .s
216 .iter()
217 .map(|s_i| {
218 s_i.iter()
219 .flat_map(|s_i_p| s_i_p.get_coeffs().clone())
220 .collect()
221 })
222 .collect();
223
224 for (j, &p_j) in p.iter().enumerate() {
225 let mut poly = ZqVector::zero(p.len());
226 for (i, s_i) in s_coeffs.iter().enumerate() {
227 let pi_ele = &self.tr.pi[i][j];
228 let pi_ele_ca = &pi_ele.conjugate_automorphism();
229 poly = &poly + &(pi_ele_ca * s_i);
230 }
231
232 if poly.get_coeffs()[0] != p_j {
233 return Err(ProverError::ProjectionError {
234 index: j,
235 expected: p_j,
236 computed: poly.get_coeffs()[0],
237 });
238 }
239 }
240
241 Ok(true)
242 }
243
244 fn check_witness_l2norm(&self, ep: &EnvironmentParameters) -> Result<bool, ProverError> {
246 let beta2 = ep.beta * ep.beta;
247 for polys in &self.witness.s {
248 let witness_l2norm_squared = PolyVector::compute_norm_squared(polys);
249 if witness_l2norm_squared > beta2 {
250 return Err(ProverError::WitnessL2NormViolated {
251 norm_squared: witness_l2norm_squared,
252 allowed: beta2,
253 });
254 }
255 }
256 Ok(true)
257 }
258}
259
260#[cfg(test)]
261mod tests {
262 use super::*;
263
264 #[test]
265 fn test_prove() {
266 let ep_1 = EnvironmentParameters::default();
268 let witness_1 = Witness::new(&ep_1);
270 let st: Statement = Statement::new(&witness_1, &ep_1);
272 let pp = PublicPrams::new(&ep_1);
274 let tr = Challenges::new(&ep_1);
276
277 let prover = LabradorProver::new(&pp, &witness_1, &st, &tr);
279 let _proof = prover.prove(&ep_1).unwrap();
280 }
281}