sonobe_fs/nova/algorithms/
prover.rs1use ark_ff::{Field, One};
4use ark_std::{borrow::Borrow, cfg_into_iter, cfg_iter, ops::Mul, rand::RngCore};
5#[cfg(not(feature = "parallel"))]
6use itertools::Itertools;
7#[cfg(feature = "parallel")]
8use rayon::prelude::*;
9use sonobe_primitives::{
10 algebra::ops::bits::FromBits,
11 arithmetizations::r1cs::R1CS,
12 circuits::{Assignments, AssignmentsOwned},
13 commitments::GroupBasedCommitment,
14 traits::SonobeField,
15 transcripts::Transcript,
16};
17
18use crate::{
19 Error, FoldingSchemeProver,
20 nova::{AbstractNova, NovaKey},
21};
22
23fn cross_term<'a, F: Field>(
24 arith: &R1CS<F>,
25 z1: impl Into<Assignments<F, &'a [F]>>,
26 z2: impl Into<Assignments<F, &'a [F]>>,
27 #[cfg(feature = "parallel")] e: impl IndexedParallelIterator<Item: Borrow<F>>,
28 #[cfg(not(feature = "parallel"))] e: impl Iterator<Item: Borrow<F>>,
29) -> Result<Vec<F>, Error> {
30 let z1 = z1.into();
31 let z2 = z2.into();
32
33 let v = arith.evaluate_r1cs(AssignmentsOwned::from((
36 z1.constant + z2.constant,
37 cfg_iter!(z1.public)
38 .zip_eq(z2.public)
39 .map(|(a, b)| *a + b)
40 .collect(),
41 cfg_iter!(z1.private)
42 .zip_eq(z2.private)
43 .map(|(a, b)| *a + b)
44 .collect(),
45 )))?;
46 Ok(cfg_into_iter!(v)
47 .zip_eq(e)
48 .map(|(a, b)| a - b.borrow())
49 .collect())
50}
51
52impl<CM: GroupBasedCommitment, TF: SonobeField, const B: usize> FoldingSchemeProver<1, 1>
53 for AbstractNova<CM, TF, B>
54{
55 #[allow(non_snake_case)]
56 fn prove(
57 pk: &NovaKey<Self::Arith, CM>,
58 transcript: &mut impl Transcript<TF>,
59 Ws: &[impl Borrow<Self::RW>; 1],
60 Us: &[impl Borrow<Self::RU>; 1],
61 ws: &[impl Borrow<Self::IW>; 1],
62 us: &[impl Borrow<Self::IU>; 1],
63 rng: impl RngCore,
64 ) -> Result<(Self::RW, Self::RU, Self::Proof<1, 1>), Error> {
65 let (W, U) = (Ws[0].borrow(), Us[0].borrow());
66 let (w, u) = (ws[0].borrow(), us[0].borrow());
67
68 let (z1, z2) = ((U.u, &U.x[..], &W.w[..]), (One::one(), &u.x[..], &w.w[..]));
69 let t = cross_term(&pk.arith, z1, z2, cfg_iter!(W.e))?;
70
71 let (cm_t, r_t) = CM::commit(&pk.ck, &t, rng)?;
72
73 let rho_bits = transcript.add(&U).add(&u).add(&cm_t).challenge_bits(B);
74 let rho = CM::Scalar::from_bits_le(&rho_bits);
75
76 let WW = Self::RW {
77 e: cfg_iter!(W.e)
78 .zip_eq(&t)
79 .map(|(a, b)| rho * b + a)
80 .collect(),
81 r_e: W.r_e + r_t * rho,
82 w: cfg_iter!(W.w)
83 .zip_eq(&w.w)
84 .map(|(a, b)| rho * b + a)
85 .collect(),
86 r_w: W.r_w + w.r_w * rho,
87 };
88 let UU = Self::RU {
89 cm_e: U.cm_e + cm_t.mul(rho),
90 u: U.u + rho,
91 cm_w: U.cm_w + u.cm_w.mul(rho),
92 x: cfg_iter!(U.x)
93 .zip_eq(&u.x)
94 .map(|(a, b)| rho * b + a)
95 .collect(),
96 };
97 Ok((WW, UU, cm_t))
98 }
99}
100
101impl<CM: GroupBasedCommitment, TF: SonobeField, const B: usize> FoldingSchemeProver<2, 0>
102 for AbstractNova<CM, TF, B>
103{
104 #[allow(non_snake_case)]
105 fn prove(
106 pk: &NovaKey<Self::Arith, CM>,
107 transcript: &mut impl Transcript<TF>,
108 [W1, W2]: &[impl Borrow<Self::RW>; 2],
109 [U1, U2]: &[impl Borrow<Self::RU>; 2],
110 _: &[impl Borrow<Self::IW>; 0],
111 _: &[impl Borrow<Self::IU>; 0],
112 rng: impl RngCore,
113 ) -> Result<(Self::RW, Self::RU, Self::Proof<2, 0>), Error> {
114 let (W1, U1) = (W1.borrow(), U1.borrow());
115 let (W2, U2) = (W2.borrow(), U2.borrow());
116
117 let (z1, z2) = ((U1.u, &U1.x[..], &W1.w[..]), (U2.u, &U2.x[..], &W2.w[..]));
118 let e = cfg_iter!(W1.e).zip_eq(&W2.e).map(|(a, b)| *a + b);
119 let t = cross_term(&pk.arith, z1, z2, e)?;
120
121 let (cm_t, r_t) = CM::commit(&pk.ck, &t, rng)?;
122
123 let rho_bits = transcript.add(&(U1, U2)).add(&cm_t).challenge_bits(B);
124 let rho = CM::Scalar::from_bits_le(&rho_bits);
125 let rho_squared = rho * rho;
126
127 let WW = Self::RW {
128 e: cfg_iter!(W1.e)
129 .zip_eq(&t)
130 .zip_eq(&W2.e)
131 .map(|((a, b), c)| rho_squared * c + rho * b + a)
132 .collect(),
133 r_e: W1.r_e + r_t * rho + W2.r_e * rho_squared,
134 w: cfg_iter!(W1.w)
135 .zip_eq(&W2.w)
136 .map(|(a, b)| rho * b + a)
137 .collect(),
138 r_w: W1.r_w + W2.r_w * rho,
139 };
140 let UU = Self::RU {
141 cm_e: U1.cm_e + cm_t.mul(rho) + U2.cm_e.mul(rho_squared),
142 u: U1.u + rho * U2.u,
143 cm_w: U1.cm_w + U2.cm_w.mul(rho),
144 x: cfg_iter!(U1.x)
145 .zip_eq(&U2.x)
146 .map(|(a, b)| rho * b + a)
147 .collect(),
148 };
149 Ok((WW, UU, cm_t))
150 }
151}