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