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