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