1use crate::fmt::{Debug, Formatter};
2use crate::traits::PedersenCommitment;
3use crate::{errors::AlgebraError, prelude::*};
4use byteorder::ByteOrder;
5use curve25519_dalek::traits::MultiscalarMul;
6use curve25519_dalek::{
7 constants::{ED25519_BASEPOINT_POINT, RISTRETTO_BASEPOINT_POINT},
8 edwards::{CompressedEdwardsY as CEY, EdwardsPoint},
9 ristretto::{CompressedRistretto as CR, RistrettoPoint as RPoint},
10 traits::Identity,
11};
12use digest::{generic_array::typenum::U64, Digest};
13use num_bigint::BigUint;
14use num_traits::Num;
15
16pub const RISTRETTO_SCALAR_LEN: usize = 32;
18
19#[derive(Copy, Clone, Default, PartialEq, Eq)]
21pub struct RistrettoScalar(pub curve25519_dalek::scalar::Scalar);
22
23#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
25pub struct CompressedRistretto(pub CR);
26
27#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
29pub struct CompressedEdwardsY(pub curve25519_dalek::edwards::CompressedEdwardsY);
30
31#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
33pub struct RistrettoPoint(pub RPoint);
34
35impl Debug for RistrettoScalar {
36 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
37 <curve25519_dalek::scalar::Scalar as Debug>::fmt(&self.0, f)
38 }
39}
40
41impl From<u128> for RistrettoScalar {
42 #[inline]
43 fn from(x: u128) -> Self {
44 Self(curve25519_dalek::scalar::Scalar::from(x))
45 }
46}
47
48impl One for RistrettoScalar {
49 #[inline]
50 fn one() -> Self {
51 Self(curve25519_dalek::scalar::Scalar::one())
52 }
53}
54
55impl Zero for RistrettoScalar {
56 #[inline]
57 fn zero() -> Self {
58 Self(curve25519_dalek::scalar::Scalar::zero())
59 }
60
61 #[inline]
62 fn is_zero(&self) -> bool {
63 self.0.eq(&curve25519_dalek::scalar::Scalar::zero())
64 }
65}
66
67impl Add for RistrettoScalar {
68 type Output = RistrettoScalar;
69
70 #[inline]
71 fn add(self, rhs: Self) -> Self::Output {
72 Self(self.0 + rhs.0)
73 }
74}
75
76impl Mul for RistrettoScalar {
77 type Output = RistrettoScalar;
78
79 #[inline]
80 fn mul(self, rhs: Self) -> Self::Output {
81 Self(self.0 * rhs.0)
82 }
83}
84
85impl Sum<RistrettoScalar> for RistrettoScalar {
86 #[inline]
87 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
88 iter.fold(Self::zero(), Add::add)
89 }
90}
91
92impl<'a> Add<&'a RistrettoScalar> for RistrettoScalar {
93 type Output = RistrettoScalar;
94
95 #[inline]
96 fn add(self, rhs: &Self) -> Self::Output {
97 Self(self.0 + rhs.0)
98 }
99}
100
101impl<'a> AddAssign<&'a RistrettoScalar> for RistrettoScalar {
102 #[inline]
103 fn add_assign(&mut self, rhs: &Self) {
104 (self.0).add_assign(&rhs.0);
105 }
106}
107
108impl<'a> Sub<&'a RistrettoScalar> for RistrettoScalar {
109 type Output = RistrettoScalar;
110
111 #[inline]
112 fn sub(self, rhs: &Self) -> Self::Output {
113 Self(self.0 - rhs.0)
114 }
115}
116
117impl<'a> SubAssign<&'a RistrettoScalar> for RistrettoScalar {
118 #[inline]
119 fn sub_assign(&mut self, rhs: &Self) {
120 (self.0).sub_assign(&rhs.0);
121 }
122}
123
124impl<'a> Mul<&'a RistrettoScalar> for RistrettoScalar {
125 type Output = RistrettoScalar;
126
127 #[inline]
128 fn mul(self, rhs: &Self) -> Self::Output {
129 Self(self.0 * rhs.0)
130 }
131}
132
133impl<'a> MulAssign<&'a RistrettoScalar> for RistrettoScalar {
134 #[inline]
135 fn mul_assign(&mut self, rhs: &Self) {
136 (self.0).mul_assign(&rhs.0);
137 }
138}
139
140impl<'a> Sum<&'a RistrettoScalar> for RistrettoScalar {
141 #[inline]
142 fn sum<I: Iterator<Item = &'a RistrettoScalar>>(iter: I) -> Self {
143 iter.fold(Self::zero(), Add::add)
144 }
145}
146
147impl Neg for RistrettoScalar {
148 type Output = RistrettoScalar;
149
150 #[inline]
151 fn neg(self) -> Self::Output {
152 Self(self.0.neg())
153 }
154}
155
156impl From<u32> for RistrettoScalar {
157 #[inline]
158 fn from(value: u32) -> Self {
159 Self(curve25519_dalek::scalar::Scalar::from(value))
160 }
161}
162
163impl From<u64> for RistrettoScalar {
164 #[inline]
165 fn from(value: u64) -> Self {
166 Self(curve25519_dalek::scalar::Scalar::from(value))
167 }
168}
169
170impl Into<BigUint> for RistrettoScalar {
171 #[inline]
172 fn into(self) -> BigUint {
173 BigUint::from_bytes_le(self.0.as_bytes())
174 }
175}
176
177impl<'a> From<&'a BigUint> for RistrettoScalar {
178 #[inline]
179 fn from(x: &BigUint) -> Self {
180 let biguint = x % RistrettoScalar::get_field_size_biguint();
181
182 let mut bytes = [0u8; 32];
183 bytes.copy_from_slice(&biguint.to_bytes_le()[0..32]);
184
185 Self(curve25519_dalek::scalar::Scalar::from_bytes_mod_order(
186 bytes,
187 ))
188 }
189}
190
191impl Scalar for RistrettoScalar {
192 #[inline]
193 fn random<R: CryptoRng + RngCore>(rng: &mut R) -> Self {
194 Self(curve25519_dalek::scalar::Scalar::random(rng))
195 }
196
197 #[inline]
198 fn from_hash<D>(hash: D) -> Self
199 where
200 D: Digest<OutputSize = U64> + Default,
201 {
202 Self(curve25519_dalek::scalar::Scalar::from_hash(hash))
203 }
204
205 #[inline]
206 fn capacity() -> usize {
207 252
208 }
209
210 #[inline]
211 fn multiplicative_generator() -> Self {
212 Self(curve25519_dalek::scalar::Scalar::from(2u8))
213 }
214
215 #[inline]
216 fn get_field_size_biguint() -> BigUint {
217 BigUint::from_str_radix(
218 "7237005577332262213973186563042994240857116359379907606001950938285454250989",
219 10,
220 )
221 .unwrap()
222 }
223
224 #[inline]
225 fn get_field_size_le_bytes() -> Vec<u8> {
226 [
228 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9,
229 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
230 0x00, 0x00, 0x00, 0x10,
231 ]
232 .to_vec()
233 }
234
235 #[inline]
236 fn get_little_endian_u64(&self) -> Vec<u64> {
237 let mut r = vec![0u64; 4];
238 byteorder::LittleEndian::read_u64_into(self.0.as_bytes(), &mut r[0..4]);
239 r
240 }
241
242 #[inline]
243 fn bytes_len() -> usize {
244 RISTRETTO_SCALAR_LEN
245 }
246
247 #[inline]
248 fn to_bytes(&self) -> Vec<u8> {
249 self.0.as_bytes().to_vec()
250 }
251
252 #[inline]
253 fn from_bytes(bytes: &[u8]) -> Result<Self> {
254 if bytes.len() > Self::bytes_len() {
255 return Err(eg!(AlgebraError::DeserializationError));
256 }
257 let mut array = [0u8; RISTRETTO_SCALAR_LEN];
258 array[0..bytes.len()].copy_from_slice(bytes);
259 Ok(Self(curve25519_dalek::scalar::Scalar::from_bits(array)))
260 }
261
262 #[inline]
263 fn inv(&self) -> Result<Self> {
264 Ok(Self(self.0.invert()))
265 }
266
267 #[inline]
268 fn square(&self) -> Self {
269 *self * self
270 }
271}
272
273impl RistrettoScalar {
274 #[inline]
277 pub fn random_scalar_with_compressed_point<R: CryptoRng + RngCore>(
278 prng: &mut R,
279 ) -> (Self, CompressedEdwardsY) {
280 let r = Self::random(prng);
281 let r_mul_edwards_base = CompressedEdwardsY::scalar_mul_basepoint(&r);
282 (r, r_mul_edwards_base)
283 }
284}
285
286impl RistrettoPoint {
287 #[inline]
289 pub fn compress(&self) -> CompressedRistretto {
290 CompressedRistretto(self.0.compress())
291 }
292}
293
294impl CompressedRistretto {
295 #[inline]
297 pub fn decompress(&self) -> Option<RistrettoPoint> {
298 self.0.decompress().map(RistrettoPoint)
299 }
300
301 #[inline]
303 pub fn identity() -> Self {
304 Self(CR::identity())
305 }
306}
307
308impl CompressedEdwardsY {
309 #[inline]
311 pub fn from_slice(bytes: &[u8]) -> Self {
312 Self(CEY::from_slice(bytes))
313 }
314
315 #[inline]
317 pub fn to_bytes(&self) -> [u8; 32] {
318 self.0.to_bytes()
319 }
320
321 #[inline]
323 pub fn decompress(&self) -> Option<EdwardsPoint> {
324 self.0.decompress()
325 }
326
327 #[inline]
329 pub fn scalar_mul_basepoint(s: &RistrettoScalar) -> Self {
330 Self((s.0 * ED25519_BASEPOINT_POINT).compress())
331 }
332}
333
334impl Neg for RistrettoPoint {
335 type Output = Self;
336
337 fn neg(self) -> Self::Output {
338 Self(self.0.neg())
339 }
340}
341
342impl Group for RistrettoPoint {
343 type ScalarType = RistrettoScalar;
344 const COMPRESSED_LEN: usize = 32;
345
346 #[inline]
347 fn double(&self) -> Self {
348 Self(self.0 + self.0)
349 }
350
351 #[inline]
352 fn get_identity() -> Self {
353 Self(RPoint::identity())
354 }
355
356 #[inline]
357 fn get_base() -> Self {
358 Self(RISTRETTO_BASEPOINT_POINT)
359 }
360
361 #[inline]
362 fn random<R: CryptoRng + RngCore>(rng: &mut R) -> Self {
363 Self(RPoint::random(rng))
364 }
365
366 #[inline]
367 fn to_compressed_bytes(&self) -> Vec<u8> {
368 let mut v = vec![];
369 v.extend_from_slice(self.0.compress().as_bytes());
370 v
371 }
372
373 #[inline]
374 fn to_unchecked_bytes(&self) -> Vec<u8> {
375 let mut v = vec![];
376 v.extend_from_slice(self.0.compress().as_bytes());
377 v
378 }
379
380 #[inline]
381 fn from_compressed_bytes(bytes: &[u8]) -> Result<Self> {
382 Ok(Self(
383 CR::from_slice(bytes)
384 .decompress()
385 .ok_or(eg!(AlgebraError::DecompressElementError))?,
386 ))
387 }
388
389 #[inline]
390 fn from_unchecked_bytes(bytes: &[u8]) -> Result<Self> {
391 Ok(Self(
392 CR::from_slice(bytes)
393 .decompress()
394 .ok_or(eg!(AlgebraError::DecompressElementError))?,
395 ))
396 }
397
398 #[inline]
399 fn unchecked_size() -> usize {
400 RISTRETTO_SCALAR_LEN
401 }
402
403 #[inline]
404 fn from_hash<D>(hash: D) -> Self
405 where
406 D: Digest<OutputSize = U64> + Default,
407 {
408 Self(RPoint::from_hash(hash))
409 }
410}
411
412impl<'a> Add<&'a RistrettoPoint> for RistrettoPoint {
413 type Output = RistrettoPoint;
414
415 #[inline]
416 fn add(self, rhs: &Self) -> Self::Output {
417 Self(self.0 + rhs.0)
418 }
419}
420
421impl<'a> Sub<&'a RistrettoPoint> for RistrettoPoint {
422 type Output = RistrettoPoint;
423
424 #[inline]
425 fn sub(self, rhs: &Self) -> Self::Output {
426 Self(self.0 - rhs.0)
427 }
428}
429
430impl<'a> Mul<&'a RistrettoScalar> for RistrettoPoint {
431 type Output = RistrettoPoint;
432
433 #[inline]
434 fn mul(self, rhs: &RistrettoScalar) -> Self::Output {
435 Self(self.0 * rhs.0)
436 }
437}
438
439impl<'a> Mul<&'a RistrettoScalar> for CompressedEdwardsY {
440 type Output = CompressedEdwardsY;
441
442 #[inline]
443 fn mul(self, rhs: &RistrettoScalar) -> Self::Output {
444 let p = self.decompress().unwrap().mul(rhs.0);
445 CompressedEdwardsY(p.compress())
446 }
447}
448
449impl<'a> AddAssign<&'a RistrettoPoint> for RistrettoPoint {
450 #[inline]
451 fn add_assign(&mut self, rhs: &RistrettoPoint) {
452 self.0.add_assign(&rhs.0)
453 }
454}
455
456impl<'a> SubAssign<&'a RistrettoPoint> for RistrettoPoint {
457 #[inline]
458 fn sub_assign(&mut self, rhs: &'a RistrettoPoint) {
459 self.0.sub_assign(&rhs.0)
460 }
461}
462
463#[allow(non_snake_case)]
464#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
465pub struct PedersenCommitmentRistretto {
467 pub B: RistrettoPoint,
469 pub B_blinding: RistrettoPoint,
471}
472
473impl Default for PedersenCommitmentRistretto {
474 fn default() -> Self {
475 let pc_gens = bulletproofs::PedersenGens::default();
476 Self {
477 B: RistrettoPoint(pc_gens.B),
478 B_blinding: RistrettoPoint(pc_gens.B_blinding),
479 }
480 }
481}
482impl PedersenCommitment<RistrettoPoint> for PedersenCommitmentRistretto {
483 fn generator(&self) -> RistrettoPoint {
484 self.B
485 }
486
487 fn blinding_generator(&self) -> RistrettoPoint {
488 self.B_blinding
489 }
490
491 fn commit(&self, value: RistrettoScalar, blinding: RistrettoScalar) -> RistrettoPoint {
492 RistrettoPoint(
493 curve25519_dalek::ristretto::RistrettoPoint::multiscalar_mul(
494 &[value.0, blinding.0],
495 &[self.B.0, self.B_blinding.0],
496 ),
497 )
498 }
499}
500
501impl From<&PedersenCommitmentRistretto> for bulletproofs::PedersenGens {
502 fn from(rp: &PedersenCommitmentRistretto) -> Self {
503 bulletproofs::PedersenGens {
504 B: rp.B.0,
505 B_blinding: rp.B_blinding.0,
506 }
507 }
508}
509
510#[cfg(test)]
511mod ristretto_group_test {
512 use crate::traits::group_tests::{test_scalar_operations, test_scalar_serialization};
513
514 #[test]
515 fn scalar_ops() {
516 test_scalar_operations::<super::RistrettoScalar>();
517 }
518 #[test]
519 fn scalar_serialization() {
520 test_scalar_serialization::<super::RistrettoScalar>();
521 }
522 #[test]
523 fn scalar_to_radix() {
524 crate::traits::group_tests::test_to_radix::<super::RistrettoScalar>();
525 }
526}