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}