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