Nova/src/provider/pedersen.rs
src/provider/pedersen.rsRaw
1//! This module provides an implementation of a commitment engine
2use crate::{
3 errors::NovaError,
4 traits::{
5 commitment::{CommitmentEngineTrait, CommitmentTrait},
6 AbsorbInROTrait, CompressedGroup, Group, ROTrait, TranscriptReprTrait,
7 },
8};
9use core::{
10 fmt::Debug,
11 marker::PhantomData,
12 ops::{Add, AddAssign, Mul, MulAssign},
13};
14use ff::Field;
15use rayon::prelude::*;
16use serde::{Deserialize, Serialize};
17
18/// A type that holds commitment generators
19#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
20pub struct CommitmentKey<G: Group> {
21 ck: Vec<G::PreprocessedGroupElement>,
22 _p: PhantomData<G>,
23}
24
25/// A type that holds a commitment
26#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
27#[serde(bound = "")]
28pub struct Commitment<G: Group> {
29 pub(crate) comm: G,
30}
31
32/// A type that holds a compressed commitment
33#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
34#[serde(bound = "")]
35pub struct CompressedCommitment<G: Group> {
36 comm: G::CompressedGroupElement,
37}
38
39impl<G: Group> CommitmentTrait<G> for Commitment<G> {
40 type CompressedCommitment = CompressedCommitment<G>;
41
42 fn compress(&self) -> Self::CompressedCommitment {
43 CompressedCommitment {
44 comm: self.comm.compress(),
45 }
46 }
47
48 fn to_coordinates(&self) -> (G::Base, G::Base, bool) {
49 self.comm.to_coordinates()
50 }
51
52 fn decompress(c: &Self::CompressedCommitment) -> Result<Self, NovaError> {
53 let comm = c.comm.decompress();
54 if comm.is_none() {
55 return Err(NovaError::DecompressionError);
56 }
57 Ok(Commitment {
58 comm: comm.unwrap(),
59 })
60 }
61}
62
63impl<G: Group> Default for Commitment<G> {
64 fn default() -> Self {
65 Commitment { comm: G::zero() }
66 }
67}
68
69impl<G: Group> TranscriptReprTrait<G> for Commitment<G> {
70 fn to_transcript_bytes(&self) -> Vec<u8> {
71 let (x, y, is_infinity) = self.comm.to_coordinates();
72 let is_infinity_byte = if is_infinity { 0u8 } else { 1u8 };
73 [
74 x.to_transcript_bytes(),
75 y.to_transcript_bytes(),
76 [is_infinity_byte].to_vec(),
77 ]
78 .concat()
79 }
80}
81
82impl<G: Group> AbsorbInROTrait<G> for Commitment<G> {
83 fn absorb_in_ro(&self, ro: &mut G::RO) {
84 let (x, y, is_infinity) = self.comm.to_coordinates();
85 ro.absorb(x);
86 ro.absorb(y);
87 ro.absorb(if is_infinity {
88 G::Base::ONE
89 } else {
90 G::Base::ZERO
91 });
92 }
93}
94
95impl<G: Group> TranscriptReprTrait<G> for CompressedCommitment<G> {
96 fn to_transcript_bytes(&self) -> Vec<u8> {
97 self.comm.to_transcript_bytes()
98 }
99}
100
101impl<G: Group> MulAssign<G::Scalar> for Commitment<G> {
102 fn mul_assign(&mut self, scalar: G::Scalar) {
103 let result = (self as &Commitment<G>).comm * scalar;
104 *self = Commitment { comm: result };
105 }
106}
107
108impl<'a, 'b, G: Group> Mul<&'b G::Scalar> for &'a Commitment<G> {
109 type Output = Commitment<G>;
110 fn mul(self, scalar: &'b G::Scalar) -> Commitment<G> {
111 Commitment {
112 comm: self.comm * scalar,
113 }
114 }
115}
116
117impl<G: Group> Mul<G::Scalar> for Commitment<G> {
118 type Output = Commitment<G>;
119
120 fn mul(self, scalar: G::Scalar) -> Commitment<G> {
121 Commitment {
122 comm: self.comm * scalar,
123 }
124 }
125}
126
127impl<'b, G: Group> AddAssign<&'b Commitment<G>> for Commitment<G> {
128 fn add_assign(&mut self, other: &'b Commitment<G>) {
129 let result = (self as &Commitment<G>).comm + other.comm;
130 *self = Commitment { comm: result };
131 }
132}
133
134impl<'a, 'b, G: Group> Add<&'b Commitment<G>> for &'a Commitment<G> {
135 type Output = Commitment<G>;
136 fn add(self, other: &'b Commitment<G>) -> Commitment<G> {
137 Commitment {
138 comm: self.comm + other.comm,
139 }
140 }
141}
142
143macro_rules! define_add_variants {
144 (G = $g:path, LHS = $lhs:ty, RHS = $rhs:ty, Output = $out:ty) => {
145 impl<'b, G: $g> Add<&'b $rhs> for $lhs {
146 type Output = $out;
147 fn add(self, rhs: &'b $rhs) -> $out {
148 &self + rhs
149 }
150 }
151
152 impl<'a, G: $g> Add<$rhs> for &'a $lhs {
153 type Output = $out;
154 fn add(self, rhs: $rhs) -> $out {
155 self + &rhs
156 }
157 }
158
159 impl<G: $g> Add<$rhs> for $lhs {
160 type Output = $out;
161 fn add(self, rhs: $rhs) -> $out {
162 &self + &rhs
163 }
164 }
165 };
166}
167
168macro_rules! define_add_assign_variants {
169 (G = $g:path, LHS = $lhs:ty, RHS = $rhs:ty) => {
170 impl<G: $g> AddAssign<$rhs> for $lhs {
171 fn add_assign(&mut self, rhs: $rhs) {
172 *self += &rhs;
173 }
174 }
175 };
176}
177
178define_add_assign_variants!(G = Group, LHS = Commitment<G>, RHS = Commitment<G>);
179define_add_variants!(G = Group, LHS = Commitment<G>, RHS = Commitment<G>, Output = Commitment<G>);
180
181/// Provides a commitment engine
182#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
183pub struct CommitmentEngine<G: Group> {
184 _p: PhantomData<G>,
185}
186
187impl<G: Group> CommitmentEngineTrait<G> for CommitmentEngine<G> {
188 type CommitmentKey = CommitmentKey<G>;
189 type Commitment = Commitment<G>;
190
191 fn setup(label: &'static [u8], n: usize) -> Self::CommitmentKey {
192 Self::CommitmentKey {
193 ck: G::from_label(label, n.next_power_of_two()),
194 _p: Default::default(),
195 }
196 }
197
198 fn commit(ck: &Self::CommitmentKey, v: &[G::Scalar]) -> Self::Commitment {
199 assert!(ck.ck.len() >= v.len());
200 Commitment {
201 comm: G::vartime_multiscalar_mul(v, &ck.ck[..v.len()]),
202 }
203 }
204}
205
206pub(crate) trait CommitmentKeyExtTrait<G: Group> {
207 type CE: CommitmentEngineTrait<G>;
208
209 /// Splits the commitment key into two pieces at a specified point
210 fn split_at(&self, n: usize) -> (Self, Self)
211 where
212 Self: Sized;
213
214 /// Combines two commitment keys into one
215 fn combine(&self, other: &Self) -> Self;
216
217 /// Folds the two commitment keys into one using the provided weights
218 fn fold(&self, w1: &G::Scalar, w2: &G::Scalar) -> Self;
219
220 /// Scales the commitment key using the provided scalar
221 fn scale(&self, r: &G::Scalar) -> Self;
222
223 /// Reinterprets commitments as commitment keys
224 fn reinterpret_commitments_as_ck(
225 c: &[<<<Self as CommitmentKeyExtTrait<G>>::CE as CommitmentEngineTrait<G>>::Commitment as CommitmentTrait<G>>::CompressedCommitment],
226 ) -> Result<Self, NovaError>
227 where
228 Self: Sized;
229}
230
231impl<G: Group> CommitmentKeyExtTrait<G> for CommitmentKey<G> {
232 type CE = CommitmentEngine<G>;
233
234 fn split_at(&self, n: usize) -> (CommitmentKey<G>, CommitmentKey<G>) {
235 (
236 CommitmentKey {
237 ck: self.ck[0..n].to_vec(),
238 _p: Default::default(),
239 },
240 CommitmentKey {
241 ck: self.ck[n..].to_vec(),
242 _p: Default::default(),
243 },
244 )
245 }
246
247 fn combine(&self, other: &CommitmentKey<G>) -> CommitmentKey<G> {
248 let ck = {
249 let mut c = self.ck.clone();
250 c.extend(other.ck.clone());
251 c
252 };
253 CommitmentKey {
254 ck,
255 _p: Default::default(),
256 }
257 }
258
259 // combines the left and right halves of `self` using `w1` and `w2` as the weights
260 fn fold(&self, w1: &G::Scalar, w2: &G::Scalar) -> CommitmentKey<G> {
261 let w = vec![*w1, *w2];
262 let (L, R) = self.split_at(self.ck.len() / 2);
263
264 let ck = (0..self.ck.len() / 2)
265 .into_par_iter()
266 .map(|i| {
267 let bases = [L.ck[i].clone(), R.ck[i].clone()].to_vec();
268 G::vartime_multiscalar_mul(&w, &bases).preprocessed()
269 })
270 .collect();
271
272 CommitmentKey {
273 ck,
274 _p: Default::default(),
275 }
276 }
277
278 /// Scales each element in `self` by `r`
279 fn scale(&self, r: &G::Scalar) -> Self {
280 let ck_scaled = self
281 .ck
282 .clone()
283 .into_par_iter()
284 .map(|g| G::vartime_multiscalar_mul(&[*r], &[g]).preprocessed())
285 .collect();
286
287 CommitmentKey {
288 ck: ck_scaled,
289 _p: Default::default(),
290 }
291 }
292
293 /// reinterprets a vector of commitments as a set of generators
294 fn reinterpret_commitments_as_ck(c: &[CompressedCommitment<G>]) -> Result<Self, NovaError> {
295 let d = (0..c.len())
296 .into_par_iter()
297 .map(|i| Commitment::<G>::decompress(&c[i]))
298 .collect::<Result<Vec<Commitment<G>>, NovaError>>()?;
299 let ck = (0..d.len())
300 .into_par_iter()
301 .map(|i| d[i].comm.preprocessed())
302 .collect();
303 Ok(CommitmentKey {
304 ck,
305 _p: Default::default(),
306 })
307 }
308}