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}