Nova/src/commitments.rs
src/commitments.rsRaw
1use super::{
2 errors::NovaError,
3 traits::{AbsorbInROTrait, AppendToTranscriptTrait, CompressedGroup, Group, HashFuncTrait},
4};
5use core::{
6 fmt::Debug,
7 marker::PhantomData,
8 ops::{Add, AddAssign, Mul, MulAssign},
9};
10use digest::{ExtendableOutput, Input};
11use ff::Field;
12use merlin::Transcript;
13use sha3::Shake256;
14use std::io::Read;
15
16#[derive(Debug)]
17pub struct CommitGens<G: Group> {
18 gens: Vec<G::PreprocessedGroupElement>,
19 _p: PhantomData<G>,
20}
21
22#[derive(Clone, Copy, Debug, PartialEq, Eq)]
23pub struct Commitment<G: Group> {
24 pub(crate) comm: G,
25}
26
27#[derive(Clone, Debug, PartialEq, Eq)]
28pub struct CompressedCommitment<C: CompressedGroup> {
29 comm: C,
30}
31
32impl<G: Group> CommitGens<G> {
33 pub fn new(label: &[u8], n: usize) -> Self {
34 let mut shake = Shake256::default();
35 shake.input(label);
36 let mut reader = shake.xof_result();
37 let mut gens: Vec<G::PreprocessedGroupElement> = Vec::new();
38 let mut uniform_bytes = [0u8; 64];
39 for _ in 0..n {
40 reader.read_exact(&mut uniform_bytes).unwrap();
41 gens.push(G::from_uniform_bytes(&uniform_bytes).unwrap());
42 }
43
44 CommitGens {
45 gens,
46 _p: PhantomData::default(),
47 }
48 }
49}
50
51impl<G: Group> Commitment<G> {
52 pub fn compress(&self) -> CompressedCommitment<G::CompressedGroupElement> {
53 CompressedCommitment {
54 comm: self.comm.compress(),
55 }
56 }
57}
58
59impl<C: CompressedGroup> CompressedCommitment<C> {
60 pub fn decompress(&self) -> Result<Commitment<C::GroupElement>, NovaError> {
61 let comm = self.comm.decompress();
62 if comm.is_none() {
63 return Err(NovaError::DecompressionError);
64 }
65 Ok(Commitment {
66 comm: comm.unwrap(),
67 })
68 }
69}
70
71pub trait CommitTrait<G: Group> {
72 fn commit(&self, gens: &CommitGens<G>) -> Commitment<G>;
73}
74
75impl<G: Group> CommitTrait<G> for [G::Scalar] {
76 fn commit(&self, gens: &CommitGens<G>) -> Commitment<G> {
77 assert!(gens.gens.len() >= self.len());
78 Commitment {
79 comm: G::vartime_multiscalar_mul(self, &gens.gens[..self.len()]),
80 }
81 }
82}
83
84impl<G: Group> AppendToTranscriptTrait for Commitment<G> {
85 fn append_to_transcript(&self, label: &'static [u8], transcript: &mut Transcript) {
86 transcript.append_message(label, self.comm.compress().as_bytes());
87 }
88}
89
90impl<G: Group> AbsorbInROTrait<G> for Commitment<G> {
91 fn absorb_in_ro(&self, ro: &mut G::HashFunc) {
92 let (x, y, is_infinity) = self.comm.to_coordinates();
93 ro.absorb(x);
94 ro.absorb(y);
95 ro.absorb(if is_infinity {
96 G::Base::one()
97 } else {
98 G::Base::zero()
99 });
100 }
101}
102
103impl<C: CompressedGroup> AppendToTranscriptTrait for CompressedCommitment<C> {
104 fn append_to_transcript(&self, label: &'static [u8], transcript: &mut Transcript) {
105 transcript.append_message(label, self.comm.as_bytes());
106 }
107}
108
109impl<'b, G: Group> MulAssign<&'b G::Scalar> for Commitment<G> {
110 fn mul_assign(&mut self, scalar: &'b G::Scalar) {
111 let result = (self as &Commitment<G>).comm * scalar;
112 *self = Commitment { comm: result };
113 }
114}
115
116impl<'a, 'b, G: Group> Mul<&'b G::Scalar> for &'a Commitment<G> {
117 type Output = Commitment<G>;
118 fn mul(self, scalar: &'b G::Scalar) -> Commitment<G> {
119 Commitment {
120 comm: self.comm * scalar,
121 }
122 }
123}
124
125impl<G: Group> Mul<G::Scalar> for Commitment<G> {
126 type Output = Commitment<G>;
127
128 fn mul(self, scalar: G::Scalar) -> Commitment<G> {
129 Commitment {
130 comm: self.comm * scalar,
131 }
132 }
133}
134
135impl<'b, G: Group> AddAssign<&'b Commitment<G>> for Commitment<G> {
136 fn add_assign(&mut self, other: &'b Commitment<G>) {
137 let result = (self as &Commitment<G>).comm + other.comm;
138 *self = Commitment { comm: result };
139 }
140}
141
142impl<'a, 'b, G: Group> Add<&'b Commitment<G>> for &'a Commitment<G> {
143 type Output = Commitment<G>;
144 fn add(self, other: &'b Commitment<G>) -> Commitment<G> {
145 Commitment {
146 comm: self.comm + other.comm,
147 }
148 }
149}
150
151macro_rules! define_add_variants {
152 (G = $g:path, LHS = $lhs:ty, RHS = $rhs:ty, Output = $out:ty) => {
153 impl<'b, G: $g> Add<&'b $rhs> for $lhs {
154 type Output = $out;
155 fn add(self, rhs: &'b $rhs) -> $out {
156 &self + rhs
157 }
158 }
159
160 impl<'a, G: $g> Add<$rhs> for &'a $lhs {
161 type Output = $out;
162 fn add(self, rhs: $rhs) -> $out {
163 self + &rhs
164 }
165 }
166
167 impl<G: $g> Add<$rhs> for $lhs {
168 type Output = $out;
169 fn add(self, rhs: $rhs) -> $out {
170 &self + &rhs
171 }
172 }
173 };
174}
175
176macro_rules! define_add_assign_variants {
177 (G = $g:path, LHS = $lhs:ty, RHS = $rhs:ty) => {
178 impl<G: $g> AddAssign<$rhs> for $lhs {
179 fn add_assign(&mut self, rhs: $rhs) {
180 *self += &rhs;
181 }
182 }
183 };
184}
185
186define_add_assign_variants!(G = Group, LHS = Commitment<G>, RHS = Commitment<G>);
187define_add_variants!(G = Group, LHS = Commitment<G>, RHS = Commitment<G>, Output = Commitment<G>);