noah_algebra/ristretto/
mod.rs

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
16/// The number of bytes for a scalar value over BLS12-381
17pub const RISTRETTO_SCALAR_LEN: usize = 32;
18
19/// The wrapped struct for `curve25519_dalek::scalar::Scalar`
20#[derive(Copy, Clone, Default, PartialEq, Eq)]
21pub struct RistrettoScalar(pub curve25519_dalek::scalar::Scalar);
22
23/// The wrapped struct for `curve25519_dalek::ristretto::CompressedRistretto`
24#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
25pub struct CompressedRistretto(pub CR);
26
27/// The wrapped struct for `curve25519_dalek::edwards::CompressedEdwardsY`
28#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
29pub struct CompressedEdwardsY(pub curve25519_dalek::edwards::CompressedEdwardsY);
30
31/// The wrapped struct for `curve25519_dalek::ristretto::RistrettoPoint`
32#[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        // Ristretto scalar field size: 2**252 + 27742317777372353535851937790883648493
227        [
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    /// Return a tuple of (r, g^r)
275    /// where r is a random `RistrettoScalar`, and g is the `ED25519_BASEPOINT_POINT`
276    #[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    /// Compress the point and output `CompressedRistretto`
288    #[inline]
289    pub fn compress(&self) -> CompressedRistretto {
290        CompressedRistretto(self.0.compress())
291    }
292}
293
294impl CompressedRistretto {
295    /// Recover the point from the `CompressedRistretto`
296    #[inline]
297    pub fn decompress(&self) -> Option<RistrettoPoint> {
298        self.0.decompress().map(RistrettoPoint)
299    }
300
301    /// Return the `CompressedRistretto` for the identity point
302    #[inline]
303    pub fn identity() -> Self {
304        Self(CR::identity())
305    }
306}
307
308impl CompressedEdwardsY {
309    /// Build a `CompressedEdwardsY` from slice of bytes
310    #[inline]
311    pub fn from_slice(bytes: &[u8]) -> Self {
312        Self(CEY::from_slice(bytes))
313    }
314
315    /// Convert into bytes.
316    #[inline]
317    pub fn to_bytes(&self) -> [u8; 32] {
318        self.0.to_bytes()
319    }
320
321    /// Recover the point from the `CompressedEdwardsY`
322    #[inline]
323    pub fn decompress(&self) -> Option<EdwardsPoint> {
324        self.0.decompress()
325    }
326
327    /// Return compressed edwards point of (`ED25519_BASEPOINT_POINT` ^ s)
328    #[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)]
465/// The Pedersen commitment implementation for the Ristretto group.
466pub struct PedersenCommitmentRistretto {
467    /// The generator for the value part.
468    pub B: RistrettoPoint,
469    /// The generator for the blinding part.
470    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}