soroban_sdk/crypto/
bn254.rs1#[cfg(not(target_family = "wasm"))]
2use crate::xdr::ScVal;
3use crate::{
4 crypto::utils::BigInt,
5 env::internal::{self, BytesObject, U256Val},
6 impl_bytesn_repr,
7 unwrap::{UnwrapInfallible, UnwrapOptimized},
8 Bytes, BytesN, ConversionError, Env, IntoVal, TryFromVal, Val, Vec, U256,
9};
10use core::{
11 cmp::Ordering,
12 fmt::Debug,
13 ops::{Add, Mul, Neg},
14};
15
16pub const BN254_FP_SERIALIZED_SIZE: usize = 32; pub const BN254_G1_SERIALIZED_SIZE: usize = BN254_FP_SERIALIZED_SIZE * 2; pub const BN254_G2_SERIALIZED_SIZE: usize = BN254_G1_SERIALIZED_SIZE * 2; pub struct Bn254 {
23 env: Env,
24}
25
26#[derive(Clone)]
39#[repr(transparent)]
40pub struct Bn254G1Affine(BytesN<BN254_G1_SERIALIZED_SIZE>);
41
42#[derive(Clone)]
56#[repr(transparent)]
57pub struct Bn254G2Affine(BytesN<BN254_G2_SERIALIZED_SIZE>);
58
59#[derive(Clone)]
65#[repr(transparent)]
66pub struct Fr(U256);
67
68#[derive(Clone)]
74#[repr(transparent)]
75pub struct Bn254Fp(BytesN<BN254_FP_SERIALIZED_SIZE>);
76
77impl_bytesn_repr!(Bn254G1Affine, BN254_G1_SERIALIZED_SIZE);
78impl_bytesn_repr!(Bn254G2Affine, BN254_G2_SERIALIZED_SIZE);
79impl_bytesn_repr!(Bn254Fp, BN254_FP_SERIALIZED_SIZE);
80
81impl Bn254G1Affine {
82 pub fn env(&self) -> &Env {
83 self.0.env()
84 }
85}
86
87impl Bn254Fp {
88 pub fn env(&self) -> &Env {
89 self.0.env()
90 }
91
92 fn checked_neg(&self) -> Option<Bn254Fp> {
98 let fq_bigint: BigInt<4> = (&self.0).into();
99 if fq_bigint.is_zero() {
100 return Some(self.clone());
101 }
102
103 const BN254_MODULUS: [u64; 4] = [
105 4332616871279656263,
106 10917124144477883021,
107 13281191951274694749,
108 3486998266802970665,
109 ];
110 let mut res = BigInt(BN254_MODULUS);
111
112 let borrow = res.sub_with_borrow(&fq_bigint);
114 if borrow {
115 return None;
116 }
117
118 let mut bytes = [0u8; BN254_FP_SERIALIZED_SIZE];
119 res.copy_into_array(&mut bytes);
120 Some(Bn254Fp::from_array(self.env(), &bytes))
121 }
122}
123
124impl Neg for &Bn254Fp {
125 type Output = Bn254Fp;
126
127 fn neg(self) -> Self::Output {
128 match self.checked_neg() {
129 Some(v) => v,
130 None => sdk_panic!("invalid input - Bn254Fp is larger than the field modulus"),
131 }
132 }
133}
134
135impl Neg for Bn254Fp {
136 type Output = Bn254Fp;
137
138 fn neg(self) -> Self::Output {
139 (&self).neg()
140 }
141}
142
143impl Add for Bn254G1Affine {
144 type Output = Bn254G1Affine;
145
146 fn add(self, rhs: Self) -> Self::Output {
147 self.env().crypto().bn254().g1_add(&self, &rhs)
148 }
149}
150
151impl Mul<Fr> for Bn254G1Affine {
152 type Output = Bn254G1Affine;
153
154 fn mul(self, rhs: Fr) -> Self::Output {
155 self.env().crypto().bn254().g1_mul(&self, &rhs)
156 }
157}
158
159impl Neg for &Bn254G1Affine {
162 type Output = Bn254G1Affine;
163
164 fn neg(self) -> Self::Output {
165 let mut inner: Bytes = (&self.0).into();
166 let y = Bn254Fp::try_from_val(
167 inner.env(),
168 inner.slice(BN254_FP_SERIALIZED_SIZE as u32..).as_val(),
169 )
170 .unwrap_optimized();
171 let neg_y = -y;
172 inner.copy_from_slice(BN254_FP_SERIALIZED_SIZE as u32, &neg_y.to_array());
173 Bn254G1Affine::from_bytes(
174 BytesN::try_from_val(inner.env(), inner.as_val()).unwrap_optimized(),
175 )
176 }
177}
178
179impl Neg for Bn254G1Affine {
180 type Output = Bn254G1Affine;
181
182 fn neg(self) -> Self::Output {
183 (&self).neg()
184 }
185}
186
187impl Bn254G2Affine {
188 pub fn env(&self) -> &Env {
189 self.0.env()
190 }
191}
192
193impl Fr {
194 pub fn env(&self) -> &Env {
195 self.0.env()
196 }
197
198 pub fn from_u256(value: U256) -> Self {
199 value.into()
200 }
201
202 pub fn to_u256(&self) -> U256 {
203 self.0.clone()
204 }
205
206 pub fn as_u256(&self) -> &U256 {
207 &self.0
208 }
209
210 pub fn from_bytes(bytes: BytesN<32>) -> Self {
211 U256::from_be_bytes(bytes.env(), bytes.as_ref()).into()
212 }
213
214 pub fn to_bytes(&self) -> BytesN<32> {
215 self.as_u256().to_be_bytes().try_into().unwrap_optimized()
216 }
217
218 pub fn as_val(&self) -> &Val {
219 self.0.as_val()
220 }
221
222 pub fn to_val(&self) -> Val {
223 self.0.to_val()
224 }
225}
226
227impl From<U256> for Fr {
228 fn from(value: U256) -> Self {
229 Self(value)
230 }
231}
232
233impl From<&Fr> for U256Val {
234 fn from(value: &Fr) -> Self {
235 value.as_u256().into()
236 }
237}
238
239impl TryFromVal<Env, Val> for Fr {
240 type Error = ConversionError;
241
242 fn try_from_val(env: &Env, val: &Val) -> Result<Self, Self::Error> {
243 let u = U256::try_from_val(env, val)?;
244 Ok(Fr(u))
245 }
246}
247
248impl TryFromVal<Env, Fr> for Val {
249 type Error = ConversionError;
250
251 fn try_from_val(_env: &Env, fr: &Fr) -> Result<Self, Self::Error> {
252 Ok(fr.to_val())
253 }
254}
255
256impl TryFromVal<Env, &Fr> for Val {
257 type Error = ConversionError;
258
259 fn try_from_val(_env: &Env, fr: &&Fr) -> Result<Self, Self::Error> {
260 Ok(fr.to_val())
261 }
262}
263
264#[cfg(not(target_family = "wasm"))]
265impl From<&Fr> for ScVal {
266 fn from(v: &Fr) -> Self {
267 Self::from(&v.0)
268 }
269}
270
271#[cfg(not(target_family = "wasm"))]
272impl From<Fr> for ScVal {
273 fn from(v: Fr) -> Self {
274 (&v).into()
275 }
276}
277
278impl Eq for Fr {}
279
280impl PartialEq for Fr {
281 fn eq(&self, other: &Self) -> bool {
282 self.as_u256().partial_cmp(other.as_u256()) == Some(core::cmp::Ordering::Equal)
283 }
284}
285
286impl Debug for Fr {
287 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
288 write!(f, "Fr({:?})", self.as_u256())
289 }
290}
291
292impl Bn254 {
293 pub(crate) fn new(env: &Env) -> Bn254 {
294 Bn254 { env: env.clone() }
295 }
296
297 pub fn env(&self) -> &Env {
298 &self.env
299 }
300
301 pub fn g1_add(&self, p0: &Bn254G1Affine, p1: &Bn254G1Affine) -> Bn254G1Affine {
303 let env = self.env();
304 let bin =
305 internal::Env::bn254_g1_add(env, p0.to_object(), p1.to_object()).unwrap_infallible();
306 unsafe { Bn254G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) }
307 }
308
309 pub fn g1_mul(&self, p0: &Bn254G1Affine, scalar: &Fr) -> Bn254G1Affine {
311 let env = self.env();
312 let bin =
313 internal::Env::bn254_g1_mul(env, p0.to_object(), scalar.into()).unwrap_infallible();
314 unsafe { Bn254G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) }
315 }
316
317 pub fn pairing_check(&self, vp1: Vec<Bn254G1Affine>, vp2: Vec<Bn254G2Affine>) -> bool {
332 let env = self.env();
333 internal::Env::bn254_multi_pairing_check(env, vp1.into(), vp2.into())
334 .unwrap_infallible()
335 .into()
336 }
337}
338
339#[cfg(test)]
340mod test {
341 use super::*;
342
343 #[test]
344 fn test_g1affine_to_val() {
345 let env = Env::default();
346
347 let g1 = Bn254G1Affine::from_bytes(BytesN::from_array(&env, &[1; 64]));
348 let val: Val = g1.clone().into_val(&env);
349 let rt: Bn254G1Affine = val.into_val(&env);
350
351 assert_eq!(g1, rt);
352 }
353
354 #[test]
355 fn test_ref_g1affine_to_val() {
356 let env = Env::default();
357
358 let g1 = Bn254G1Affine::from_bytes(BytesN::from_array(&env, &[1; 64]));
359 let val: Val = (&g1).into_val(&env);
360 let rt: Bn254G1Affine = val.into_val(&env);
361
362 assert_eq!(g1, rt);
363 }
364
365 #[test]
366 fn test_double_ref_g1affine_to_val() {
367 let env = Env::default();
368
369 let g1 = Bn254G1Affine::from_bytes(BytesN::from_array(&env, &[1; 64]));
370 let val: Val = (&&g1).into_val(&env);
371 let rt: Bn254G1Affine = val.into_val(&env);
372
373 assert_eq!(g1, rt);
374 }
375
376 #[test]
377 fn test_fr_to_val() {
378 let env = Env::default();
379
380 let fr = Fr::from_bytes(BytesN::from_array(&env, &[1; 32]));
381 let val: Val = fr.clone().into_val(&env);
382 let rt: Fr = val.into_val(&env);
383
384 assert_eq!(fr, rt);
385 }
386
387 #[test]
388 fn test_ref_fr_to_val() {
389 let env = Env::default();
390
391 let fr = Fr::from_bytes(BytesN::from_array(&env, &[1; 32]));
392 let val: Val = (&fr).into_val(&env);
393 let rt: Fr = val.into_val(&env);
394
395 assert_eq!(fr, rt);
396 }
397
398 #[test]
399 fn test_double_ref_fr_to_val() {
400 let env = Env::default();
401
402 let fr = Fr::from_bytes(BytesN::from_array(&env, &[1; 32]));
403 let val: Val = (&&fr).into_val(&env);
404 let rt: Fr = val.into_val(&env);
405
406 assert_eq!(fr, rt);
407 }
408}