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