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::{
  3  poseidon::PoseidonRO,
  4  traits::{ChallengeTrait, CompressedGroup, Group},
  5};
  6use digest::{ExtendableOutput, Input};
  7use ff::Field;
  8use merlin::Transcript;
  9use num_bigint::BigInt;
 10use num_traits::Num;
 11use pasta_curves::{
 12  self,
 13  arithmetic::{CurveAffine, CurveExt},
 14  group::{Curve, GroupEncoding},
 15  pallas, vesta, Ep, Eq,
 16};
 17use rand::SeedableRng;
 18use rand_chacha::ChaCha20Rng;
 19use sha3::Shake256;
 20use std::io::Read;
 21
 22//////////////////////////////////////Pallas///////////////////////////////////////////////
 23
 24/// A wrapper for compressed group elements that come from the pallas curve
 25#[derive(Clone, Copy, Debug, Eq, PartialEq)]
 26pub struct PallasCompressedElementWrapper {
 27  repr: [u8; 32],
 28}
 29
 30impl PallasCompressedElementWrapper {
 31  /// Wraps repr into the wrapper
 32  pub fn new(repr: [u8; 32]) -> Self {
 33    Self { repr }
 34  }
 35}
 36
 37impl Group for pallas::Point {
 38  type Base = pallas::Base;
 39  type Scalar = pallas::Scalar;
 40  type CompressedGroupElement = PallasCompressedElementWrapper;
 41  type PreprocessedGroupElement = pallas::Affine;
 42  type HashFunc = PoseidonRO<Self::Base, Self::Scalar>;
 43
 44  fn vartime_multiscalar_mul(
 45    scalars: &[Self::Scalar],
 46    bases: &[Self::PreprocessedGroupElement],
 47  ) -> Self {
 48    pasta_msm::pallas(bases, scalars)
 49  }
 50
 51  fn compress(&self) -> Self::CompressedGroupElement {
 52    PallasCompressedElementWrapper::new(self.to_bytes())
 53  }
 54
 55  fn from_label(label: &'static [u8], n: usize) -> Vec<Self::PreprocessedGroupElement> {
 56    let mut shake = Shake256::default();
 57    shake.input(label);
 58    let mut reader = shake.xof_result();
 59    let mut gens: Vec<Self::PreprocessedGroupElement> = Vec::new();
 60    let mut uniform_bytes = [0u8; 32];
 61    for _ in 0..n {
 62      reader.read_exact(&mut uniform_bytes).unwrap();
 63      let hash = Ep::hash_to_curve("from_uniform_bytes");
 64      gens.push(hash(&uniform_bytes).to_affine());
 65    }
 66    gens
 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  fn get_order() -> BigInt {
 79    BigInt::from_str_radix(
 80      "40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001",
 81      16,
 82    )
 83    .unwrap()
 84  }
 85}
 86
 87impl ChallengeTrait for pallas::Scalar {
 88  fn challenge(label: &'static [u8], transcript: &mut Transcript) -> Self {
 89    let mut key: <ChaCha20Rng as SeedableRng>::Seed = Default::default();
 90    transcript.challenge_bytes(label, &mut key);
 91    let mut rng = ChaCha20Rng::from_seed(key);
 92    pallas::Scalar::random(&mut rng)
 93  }
 94}
 95
 96impl CompressedGroup for PallasCompressedElementWrapper {
 97  type GroupElement = pallas::Point;
 98
 99  fn decompress(&self) -> Option<pallas::Point> {
100    Some(Ep::from_bytes(&self.repr).unwrap())
101  }
102  fn as_bytes(&self) -> &[u8] {
103    &self.repr
104  }
105}
106
107//////////////////////////////////////Vesta////////////////////////////////////////////////
108
109/// A wrapper for compressed group elements that come from the vesta curve
110#[derive(Clone, Copy, Debug, Eq, PartialEq)]
111pub struct VestaCompressedElementWrapper {
112  repr: [u8; 32],
113}
114
115impl VestaCompressedElementWrapper {
116  /// Wraps repr into the wrapper
117  pub fn new(repr: [u8; 32]) -> Self {
118    Self { repr }
119  }
120}
121
122impl Group for vesta::Point {
123  type Base = vesta::Base;
124  type Scalar = vesta::Scalar;
125  type CompressedGroupElement = VestaCompressedElementWrapper;
126  type PreprocessedGroupElement = vesta::Affine;
127  type HashFunc = PoseidonRO<Self::Base, Self::Scalar>;
128
129  fn vartime_multiscalar_mul(
130    scalars: &[Self::Scalar],
131    bases: &[Self::PreprocessedGroupElement],
132  ) -> Self {
133    pasta_msm::vesta(bases, scalars)
134  }
135
136  fn compress(&self) -> Self::CompressedGroupElement {
137    VestaCompressedElementWrapper::new(self.to_bytes())
138  }
139
140  fn from_label(label: &'static [u8], n: usize) -> Vec<Self::PreprocessedGroupElement> {
141    let mut shake = Shake256::default();
142    shake.input(label);
143    let mut reader = shake.xof_result();
144    let mut gens: Vec<Self::PreprocessedGroupElement> = Vec::new();
145    let mut uniform_bytes = [0u8; 32];
146    for _ in 0..n {
147      reader.read_exact(&mut uniform_bytes).unwrap();
148      let hash = Eq::hash_to_curve("from_uniform_bytes");
149      gens.push(hash(&uniform_bytes).to_affine());
150    }
151    gens
152  }
153
154  fn to_coordinates(&self) -> (Self::Base, Self::Base, bool) {
155    let coordinates = self.to_affine().coordinates();
156    if coordinates.is_some().unwrap_u8() == 1 {
157      (*coordinates.unwrap().x(), *coordinates.unwrap().y(), false)
158    } else {
159      (Self::Base::zero(), Self::Base::zero(), true)
160    }
161  }
162
163  fn get_order() -> BigInt {
164    BigInt::from_str_radix(
165      "40000000000000000000000000000000224698fc094cf91b992d30ed00000001",
166      16,
167    )
168    .unwrap()
169  }
170}
171
172impl ChallengeTrait for vesta::Scalar {
173  fn challenge(label: &'static [u8], transcript: &mut Transcript) -> Self {
174    let mut key: <ChaCha20Rng as SeedableRng>::Seed = Default::default();
175    transcript.challenge_bytes(label, &mut key);
176    let mut rng = ChaCha20Rng::from_seed(key);
177    vesta::Scalar::random(&mut rng)
178  }
179}
180
181impl CompressedGroup for VestaCompressedElementWrapper {
182  type GroupElement = vesta::Point;
183
184  fn decompress(&self) -> Option<vesta::Point> {
185    Some(Eq::from_bytes(&self.repr).unwrap())
186  }
187  fn as_bytes(&self) -> &[u8] {
188    &self.repr
189  }
190}