mpc_ristretto/
commitment.rs1use curve25519_dalek::{
5 constants::{RISTRETTO_BASEPOINT_COMPRESSED, RISTRETTO_BASEPOINT_POINT},
6 ristretto::RistrettoPoint,
7 scalar::Scalar,
8 traits::MultiscalarMul,
9};
10use rand_core::{OsRng, RngCore};
11use sha3::{Digest, Sha3_512};
12
13#[allow(non_snake_case)]
16#[derive(Copy, Clone)]
17pub(crate) struct PedersenGens {
18 pub B: RistrettoPoint,
20 pub B_blinding: RistrettoPoint,
22}
23
24impl PedersenGens {
25 pub fn commit(&self, value: Scalar, blinding: Scalar) -> RistrettoPoint {
27 RistrettoPoint::multiscalar_mul(&[value, blinding], &[self.B, self.B_blinding])
28 }
29}
30
31impl Default for PedersenGens {
32 fn default() -> Self {
33 PedersenGens {
34 B: RISTRETTO_BASEPOINT_POINT,
35 B_blinding: RistrettoPoint::hash_from_bytes::<Sha3_512>(
36 RISTRETTO_BASEPOINT_COMPRESSED.as_bytes(),
37 ),
38 }
39 }
40}
41
42#[derive(Clone, Debug)]
44pub(crate) struct PedersenCommitment {
45 commitment: RistrettoPoint,
47 blinding_factor: Scalar,
49 value: Scalar,
51}
52
53impl PedersenCommitment {
54 #[inline]
56 pub fn get_commitment(&self) -> RistrettoPoint {
57 self.commitment
58 }
59
60 #[inline]
61 pub fn get_blinding(&self) -> Scalar {
62 self.blinding_factor
63 }
64
65 #[inline]
66 pub fn get_value(&self) -> Scalar {
67 self.value
68 }
69
70 pub fn commit(value: Scalar) -> PedersenCommitment {
72 let mut rng = OsRng {};
74 let blinding_factor = Scalar::random(&mut rng);
75
76 Self {
77 commitment: PedersenGens::default().commit(value, blinding_factor),
78 blinding_factor,
79 value,
80 }
81 }
82
83 #[allow(dead_code)]
85 pub fn verify(&self) -> bool {
86 PedersenCommitment::verify_from_values(self.commitment, self.blinding_factor, self.value)
87 }
88
89 pub fn verify_from_values(
92 commitment: RistrettoPoint,
93 blinding_factor: Scalar,
94 value: Scalar,
95 ) -> bool {
96 PedersenGens::default()
97 .commit(value, blinding_factor)
98 .eq(&commitment)
99 }
100}
101
102#[derive(Clone, Debug)]
104pub struct RistrettoCommitment {
105 commitment: Scalar,
107 blinding_factor: Scalar,
109 value: RistrettoPoint,
111}
112
113impl RistrettoCommitment {
114 #[inline]
115 pub fn get_commitment(&self) -> Scalar {
116 self.commitment
117 }
118
119 #[inline]
120 pub fn get_blinding(&self) -> Scalar {
121 self.blinding_factor
122 }
123
124 #[inline]
125 pub fn get_value(&self) -> RistrettoPoint {
126 self.value
127 }
128
129 pub fn commit(point: RistrettoPoint) -> RistrettoCommitment {
131 let mut rng = OsRng {};
133 let blinding_factor = rng.next_u64();
134
135 let mut hasher = Sha3_512::new();
137 hasher.input(point.compress().as_bytes());
138 hasher.input(blinding_factor.to_le_bytes());
139
140 Self {
141 commitment: Scalar::from_hash(hasher),
142 blinding_factor: Scalar::from(blinding_factor),
143 value: point,
144 }
145 }
146
147 pub fn verify(&self) -> bool {
149 RistrettoCommitment::verify_from_values(self.commitment, self.blinding_factor, self.value)
150 }
151
152 pub fn verify_from_values(
154 commitment: Scalar,
155 blinding_factor: Scalar,
156 value: RistrettoPoint,
157 ) -> bool {
158 let mut hasher = Sha3_512::new();
160 hasher.input(value.compress().as_bytes());
161
162 let blinding_factor_bytes: [u8; 8] = blinding_factor.to_bytes()[..8]
163 .try_into()
164 .expect("Not enough bytes in hash");
165 hasher.input(blinding_factor_bytes);
166
167 Scalar::from_hash(hasher).eq(&commitment)
168 }
169}
170
171#[cfg(test)]
172mod pedersen_tests {
173 use curve25519_dalek::scalar::Scalar;
174 use rand_core::OsRng;
175
176 use super::PedersenCommitment;
177
178 #[test]
179 fn test_commit_and_open() {
180 let mut rng = OsRng {};
182 let value = Scalar::random(&mut rng);
183 let bad_value = Scalar::random(&mut rng);
184
185 let commitment = PedersenCommitment::commit(value);
186 assert!(commitment.verify());
187 assert!(!PedersenCommitment::verify_from_values(
188 commitment.commitment,
189 commitment.blinding_factor,
190 bad_value
191 ))
192 }
193}
194
195#[cfg(test)]
196mod hash_commit_tests {
197 use curve25519_dalek::ristretto::RistrettoPoint;
198 use rand_core::OsRng;
199
200 use super::RistrettoCommitment;
201
202 #[test]
203 fn test_commit_and_open() {
204 let mut rng = OsRng {};
206 let value = RistrettoPoint::random(&mut rng);
207 let bad_value = RistrettoPoint::random(&mut rng);
208
209 let commitment = RistrettoCommitment::commit(value);
210 assert!(commitment.verify());
211 assert!(!RistrettoCommitment::verify_from_values(
212 commitment.get_commitment(),
213 commitment.get_blinding(),
214 bad_value
215 ))
216 }
217}