arnaucube
arnaucube/NovaPublic Self-hosted repository
Nova/src/pasta.rs
src/pasta.rsRaw
  1//! This module implements the Nova traits for pallas::Point, pallas::Scalar, vesta::Point, vesta::Scalar.
  2use crate::traits::{ChallengeTrait, CompressedGroup, Group};
  3use ff::Field;
  4use merlin::Transcript;
  5use pasta_curves::{
  6  self,
  7  arithmetic::{CurveAffine, CurveExt, Group as Grp},
  8  group::{Curve, GroupEncoding},
  9  pallas, vesta, Ep, Eq,
 10};
 11use rand::SeedableRng;
 12use rand_chacha::ChaCha20Rng;
 13use rug::Integer;
 14use std::{borrow::Borrow, ops::Mul};
 15
 16//////////////////////////////////////Pallas///////////////////////////////////////////////
 17
 18/// A wrapper for compressed group elements that come from the pallas curve
 19#[derive(Clone, Copy, Debug, Eq, PartialEq)]
 20pub struct PallasCompressedElementWrapper {
 21  repr: [u8; 32],
 22}
 23
 24impl PallasCompressedElementWrapper {
 25  /// Wraps repr into the wrapper
 26  pub fn new(repr: [u8; 32]) -> Self {
 27    Self { repr }
 28  }
 29}
 30
 31unsafe impl Send for PallasCompressedElementWrapper {}
 32unsafe impl Sync for PallasCompressedElementWrapper {}
 33
 34impl Group for pallas::Point {
 35  type Base = pallas::Base;
 36  type Scalar = pallas::Scalar;
 37  type CompressedGroupElement = PallasCompressedElementWrapper;
 38
 39  fn vartime_multiscalar_mul<I, J>(scalars: I, points: J) -> Self
 40  where
 41    I: IntoIterator,
 42    I::Item: Borrow<Self::Scalar>,
 43    J: IntoIterator,
 44    J::Item: Borrow<Self>,
 45    Self: Clone,
 46  {
 47    // Unoptimized.
 48    scalars
 49      .into_iter()
 50      .zip(points)
 51      .map(|(scalar, point)| (*point.borrow()).mul(*scalar.borrow()))
 52      .fold(Ep::group_zero(), |acc, x| acc + x)
 53  }
 54
 55  fn compress(&self) -> Self::CompressedGroupElement {
 56    PallasCompressedElementWrapper::new(self.to_bytes())
 57  }
 58
 59  fn from_uniform_bytes(bytes: &[u8]) -> Option<Self> {
 60    if bytes.len() != 64 {
 61      None
 62    } else {
 63      let mut arr = [0; 32];
 64      arr.copy_from_slice(&bytes[0..32]);
 65
 66      let hash = Ep::hash_to_curve("from_uniform_bytes");
 67      Some(hash(&arr))
 68    }
 69  }
 70
 71  fn to_coordinates(&self) -> (Self::Base, Self::Base, bool) {
 72    let coordinates = self.to_affine().coordinates();
 73    if coordinates.is_some().unwrap_u8() == 1 {
 74      (*coordinates.unwrap().x(), *coordinates.unwrap().y(), false)
 75    } else {
 76      (Self::Base::zero(), Self::Base::zero(), true)
 77    }
 78  }
 79
 80  fn get_order() -> Integer {
 81    Integer::from_str_radix(
 82      "40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001",
 83      16,
 84    )
 85    .unwrap()
 86  }
 87}
 88
 89impl ChallengeTrait for pallas::Scalar {
 90  fn challenge(label: &'static [u8], transcript: &mut Transcript) -> Self {
 91    let mut key: <ChaCha20Rng as SeedableRng>::Seed = Default::default();
 92    transcript.challenge_bytes(label, &mut key);
 93    let mut rng = ChaCha20Rng::from_seed(key);
 94    pallas::Scalar::random(&mut rng)
 95  }
 96}
 97
 98impl CompressedGroup for PallasCompressedElementWrapper {
 99  type GroupElement = pallas::Point;
100
101  fn decompress(&self) -> Option<pallas::Point> {
102    Some(Ep::from_bytes(&self.repr).unwrap())
103  }
104  fn as_bytes(&self) -> &[u8] {
105    &self.repr
106  }
107}
108
109//////////////////////////////////////Vesta////////////////////////////////////////////////
110
111/// A wrapper for compressed group elements that come from the vesta curve
112#[derive(Clone, Copy, Debug, Eq, PartialEq)]
113pub struct VestaCompressedElementWrapper {
114  repr: [u8; 32],
115}
116
117impl VestaCompressedElementWrapper {
118  /// Wraps repr into the wrapper
119  pub fn new(repr: [u8; 32]) -> Self {
120    Self { repr }
121  }
122}
123
124unsafe impl Send for VestaCompressedElementWrapper {}
125unsafe impl Sync for VestaCompressedElementWrapper {}
126
127impl Group for vesta::Point {
128  type Base = vesta::Base;
129  type Scalar = vesta::Scalar;
130  type CompressedGroupElement = VestaCompressedElementWrapper;
131
132  fn vartime_multiscalar_mul<I, J>(scalars: I, points: J) -> Self
133  where
134    I: IntoIterator,
135    I::Item: Borrow<Self::Scalar>,
136    J: IntoIterator,
137    J::Item: Borrow<Self>,
138    Self: Clone,
139  {
140    // Unoptimized.
141    scalars
142      .into_iter()
143      .zip(points)
144      .map(|(scalar, point)| (*point.borrow()).mul(*scalar.borrow()))
145      .fold(Eq::group_zero(), |acc, x| acc + x)
146  }
147
148  fn compress(&self) -> Self::CompressedGroupElement {
149    VestaCompressedElementWrapper::new(self.to_bytes())
150  }
151
152  fn from_uniform_bytes(bytes: &[u8]) -> Option<Self> {
153    if bytes.len() != 64 {
154      None
155    } else {
156      let mut arr = [0; 32];
157      arr.copy_from_slice(&bytes[0..32]);
158
159      let hash = Eq::hash_to_curve("from_uniform_bytes");
160      Some(hash(&arr))
161    }
162  }
163
164  fn to_coordinates(&self) -> (Self::Base, Self::Base, bool) {
165    let coordinates = self.to_affine().coordinates();
166    if coordinates.is_some().unwrap_u8() == 1 {
167      (*coordinates.unwrap().x(), *coordinates.unwrap().y(), false)
168    } else {
169      (Self::Base::zero(), Self::Base::zero(), true)
170    }
171  }
172
173  fn get_order() -> Integer {
174    Integer::from_str_radix(
175      "40000000000000000000000000000000224698fc094cf91b992d30ed00000001",
176      16,
177    )
178    .unwrap()
179  }
180}
181
182impl ChallengeTrait for vesta::Scalar {
183  fn challenge(label: &'static [u8], transcript: &mut Transcript) -> Self {
184    let mut key: <ChaCha20Rng as SeedableRng>::Seed = Default::default();
185    transcript.challenge_bytes(label, &mut key);
186    let mut rng = ChaCha20Rng::from_seed(key);
187    vesta::Scalar::random(&mut rng)
188  }
189}
190
191impl CompressedGroup for VestaCompressedElementWrapper {
192  type GroupElement = vesta::Point;
193
194  fn decompress(&self) -> Option<vesta::Point> {
195    Some(Eq::from_bytes(&self.repr).unwrap())
196  }
197  fn as_bytes(&self) -> &[u8] {
198    &self.repr
199  }
200}