1#[cfg(not(target_family = "wasm"))]
2use crate::xdr::ScVal;
3use crate::{
4 env::internal::{self, BytesObject, U256Val, U64Val},
5 impl_bytesn_repr,
6 unwrap::{UnwrapInfallible, UnwrapOptimized},
7 Bytes, BytesN, ConversionError, Env, IntoVal, TryFromVal, Val, Vec, U256,
8};
9use core::{
10 cmp::Ordering,
11 fmt::Debug,
12 ops::{Add, Mul, Neg, Sub},
13};
14
15pub const FP_SERIALIZED_SIZE: usize = 48; pub const FP2_SERIALIZED_SIZE: usize = FP_SERIALIZED_SIZE * 2;
17pub const G1_SERIALIZED_SIZE: usize = FP_SERIALIZED_SIZE * 2; pub const G2_SERIALIZED_SIZE: usize = FP2_SERIALIZED_SIZE * 2; pub struct Bls12_381 {
23 env: Env,
24}
25
26fn sbb_for_sub_with_borrow(a: &mut u64, b: u64, borrow: u8) -> u8 {
29 let tmp = (1u128 << 64) + u128::from(*a) - u128::from(b) - u128::from(borrow);
30 *a = tmp as u64;
33 u8::from(tmp >> 64 == 0)
34}
35
36#[derive(Debug)]
37pub(crate) struct BigInt<const N: usize>(pub [u64; N]);
38
39impl<const N: usize> BigInt<N> {
40 pub fn sub_with_borrow(&mut self, other: &Self) -> bool {
41 let mut borrow = 0;
42 for i in 0..N {
43 borrow = sbb_for_sub_with_borrow(&mut self.0[i], other.0[i], borrow);
44 }
45 borrow != 0
46 }
47
48 pub fn copy_into_array<const M: usize>(&self, slice: &mut [u8; M]) {
49 const {
50 if M != N * 8 {
51 panic!("BigInt::copy_into_array with mismatched array length")
52 }
53 }
54
55 for i in 0..N {
56 let limb_bytes = self.0[N - 1 - i].to_be_bytes();
57 slice[i * 8..(i + 1) * 8].copy_from_slice(&limb_bytes);
58 }
59 }
60
61 pub fn is_zero(&self) -> bool {
62 self.0 == [0; N]
63 }
64}
65
66impl<const N: usize, const M: usize> From<&BytesN<M>> for BigInt<N> {
67 fn from(bytes: &BytesN<M>) -> Self {
68 if M != N * 8 {
69 panic!("BytesN::Into<BigInt> - length mismatch")
70 }
71
72 let array = bytes.to_array();
73 let mut limbs = [0u64; N];
74 for i in 0..N {
75 let start = i * 8;
76 let end = start + 8;
77 let mut chunk = [0u8; 8];
78 chunk.copy_from_slice(&array[start..end]);
79 limbs[N - 1 - i] = u64::from_be_bytes(chunk);
80 }
81 BigInt(limbs)
82 }
83}
84
85#[derive(Clone)]
112#[repr(transparent)]
113pub struct G1Affine(BytesN<G1_SERIALIZED_SIZE>);
114
115#[derive(Clone)]
132#[repr(transparent)]
133pub struct G2Affine(BytesN<G2_SERIALIZED_SIZE>);
134
135#[derive(Clone)]
142#[repr(transparent)]
143pub struct Fp(BytesN<FP_SERIALIZED_SIZE>);
144
145#[derive(Clone)]
154#[repr(transparent)]
155pub struct Fp2(BytesN<FP2_SERIALIZED_SIZE>);
156
157#[derive(Clone)]
162#[repr(transparent)]
163pub struct Fr(U256);
164
165impl_bytesn_repr!(G1Affine, G1_SERIALIZED_SIZE);
166impl_bytesn_repr!(G2Affine, G2_SERIALIZED_SIZE);
167impl_bytesn_repr!(Fp, FP_SERIALIZED_SIZE);
168impl_bytesn_repr!(Fp2, FP2_SERIALIZED_SIZE);
169
170impl Fp {
171 pub fn env(&self) -> &Env {
172 self.0.env()
173 }
174
175 fn checked_neg(&self) -> Option<Fp> {
181 let fp_bigint: BigInt<6> = (&self.0).into();
182 if fp_bigint.is_zero() {
183 return Some(self.clone());
184 }
185
186 const BLS12_381_MODULUS: [u64; 6] = [
188 13402431016077863595,
189 2210141511517208575,
190 7435674573564081700,
191 7239337960414712511,
192 5412103778470702295,
193 1873798617647539866,
194 ];
195 let mut res = BigInt(BLS12_381_MODULUS);
196
197 let borrow = res.sub_with_borrow(&fp_bigint);
199 if borrow {
200 return None;
201 }
202
203 let mut bytes = [0u8; FP_SERIALIZED_SIZE];
204 res.copy_into_array(&mut bytes);
205 Some(Fp::from_array(self.env(), &bytes))
206 }
207
208 pub fn map_to_g1(&self) -> G1Affine {
221 self.env().crypto().bls12_381().map_fp_to_g1(self)
222 }
223}
224
225impl From<Fp> for BigInt<6> {
226 fn from(fp: Fp) -> Self {
227 let inner: Bytes = fp.0.into();
228 let mut limbs = [0u64; 6];
229 for i in 0..6u32 {
230 let start = i * 8;
231 let mut slice = [0u8; 8];
232 inner.slice(start..start + 8).copy_into_slice(&mut slice);
233 limbs[5 - i as usize] = u64::from_be_bytes(slice);
234 }
235 BigInt(limbs)
236 }
237}
238
239impl Neg for &Fp {
240 type Output = Fp;
241
242 fn neg(self) -> Self::Output {
243 match self.checked_neg() {
244 Some(v) => v,
245 None => sdk_panic!("invalid input - Fp is larger than the field modulus"),
246 }
247 }
248}
249
250impl Neg for Fp {
251 type Output = Fp;
252
253 fn neg(self) -> Self::Output {
254 (&self).neg()
255 }
256}
257
258impl G1Affine {
259 pub fn env(&self) -> &Env {
260 self.0.env()
261 }
262
263 pub fn is_in_subgroup(&self) -> bool {
264 self.env().crypto().bls12_381().g1_is_in_subgroup(self)
265 }
266
267 pub fn checked_add(&self, rhs: &Self) -> Option<Self> {
268 self.env().crypto().bls12_381().g1_checked_add(self, rhs)
269 }
270}
271
272impl Add for G1Affine {
273 type Output = G1Affine;
274
275 fn add(self, rhs: Self) -> Self::Output {
276 self.env().crypto().bls12_381().g1_add(&self, &rhs)
277 }
278}
279
280impl Mul<Fr> for G1Affine {
281 type Output = G1Affine;
282
283 fn mul(self, rhs: Fr) -> Self::Output {
284 self.env().crypto().bls12_381().g1_mul(&self, &rhs)
285 }
286}
287
288impl Neg for &G1Affine {
291 type Output = G1Affine;
292
293 fn neg(self) -> Self::Output {
294 let mut inner: Bytes = (&self.0).into();
295 let y = Fp::try_from_val(
296 inner.env(),
297 inner.slice(FP_SERIALIZED_SIZE as u32..).as_val(),
298 )
299 .unwrap_optimized();
300 let neg_y = -y;
301 inner.copy_from_slice(FP_SERIALIZED_SIZE as u32, &neg_y.to_array());
302 G1Affine::from_bytes(BytesN::try_from_val(inner.env(), inner.as_val()).unwrap_optimized())
303 }
304}
305
306impl Neg for G1Affine {
307 type Output = G1Affine;
308
309 fn neg(self) -> Self::Output {
310 (&self).neg()
311 }
312}
313
314impl Fp2 {
315 pub fn env(&self) -> &Env {
316 self.0.env()
317 }
318
319 fn checked_neg(&self) -> Option<Fp2> {
324 let mut inner = self.to_array();
325 let mut slice0 = [0; FP_SERIALIZED_SIZE];
326 let mut slice1 = [0; FP_SERIALIZED_SIZE];
327 slice0.copy_from_slice(&inner[0..FP_SERIALIZED_SIZE]);
328 slice1.copy_from_slice(&inner[FP_SERIALIZED_SIZE..FP2_SERIALIZED_SIZE]);
329
330 let c0 = Fp::from_array(self.env(), &slice0);
332 let c1 = Fp::from_array(self.env(), &slice1);
333
334 let neg_c0 = c0.checked_neg()?;
336 let neg_c1 = c1.checked_neg()?;
337
338 inner[0..FP_SERIALIZED_SIZE].copy_from_slice(&neg_c0.to_array());
340 inner[FP_SERIALIZED_SIZE..FP2_SERIALIZED_SIZE].copy_from_slice(&neg_c1.to_array());
341
342 Some(Fp2::from_array(self.env(), &inner))
343 }
344
345 pub fn map_to_g2(&self) -> G2Affine {
358 self.env().crypto().bls12_381().map_fp2_to_g2(self)
359 }
360}
361
362impl Neg for &Fp2 {
363 type Output = Fp2;
364
365 fn neg(self) -> Self::Output {
366 match self.checked_neg() {
367 Some(v) => v,
368 None => sdk_panic!("invalid input - Fp2 component is larger than the field modulus"),
369 }
370 }
371}
372
373impl Neg for Fp2 {
374 type Output = Fp2;
375
376 fn neg(self) -> Self::Output {
377 (&self).neg()
378 }
379}
380
381impl G2Affine {
382 pub fn env(&self) -> &Env {
383 self.0.env()
384 }
385
386 pub fn is_in_subgroup(&self) -> bool {
387 self.env().crypto().bls12_381().g2_is_in_subgroup(self)
388 }
389
390 pub fn checked_add(&self, rhs: &Self) -> Option<Self> {
391 self.env().crypto().bls12_381().g2_checked_add(self, rhs)
392 }
393}
394
395impl Add for G2Affine {
396 type Output = G2Affine;
397
398 fn add(self, rhs: Self) -> Self::Output {
399 self.env().crypto().bls12_381().g2_add(&self, &rhs)
400 }
401}
402
403impl Mul<Fr> for G2Affine {
404 type Output = G2Affine;
405
406 fn mul(self, rhs: Fr) -> Self::Output {
407 self.env().crypto().bls12_381().g2_mul(&self, &rhs)
408 }
409}
410
411impl Neg for &G2Affine {
414 type Output = G2Affine;
415
416 fn neg(self) -> Self::Output {
417 let mut inner: Bytes = (&self.0).into();
418 let y = Fp2::try_from_val(
419 inner.env(),
420 inner.slice(FP2_SERIALIZED_SIZE as u32..).as_val(),
421 )
422 .unwrap_optimized();
423 let neg_y = -y;
424 inner.copy_from_slice(FP2_SERIALIZED_SIZE as u32, &neg_y.to_array());
425 G2Affine::from_bytes(BytesN::try_from_val(inner.env(), inner.as_val()).unwrap_optimized())
426 }
427}
428
429impl Neg for G2Affine {
430 type Output = G2Affine;
431
432 fn neg(self) -> Self::Output {
433 (&self).neg()
434 }
435}
436
437impl Fr {
438 pub fn env(&self) -> &Env {
439 self.0.env()
440 }
441
442 pub fn from_u256(value: U256) -> Self {
443 value.into()
444 }
445
446 pub fn to_u256(&self) -> U256 {
447 self.0.clone()
448 }
449
450 pub fn as_u256(&self) -> &U256 {
451 &self.0
452 }
453
454 pub fn from_bytes(bytes: BytesN<32>) -> Self {
455 U256::from_be_bytes(bytes.env(), bytes.as_ref()).into()
456 }
457
458 pub fn to_bytes(&self) -> BytesN<32> {
459 self.as_u256().to_be_bytes().try_into().unwrap_optimized()
460 }
461
462 pub fn as_val(&self) -> &Val {
463 self.0.as_val()
464 }
465
466 pub fn to_val(&self) -> Val {
467 self.0.to_val()
468 }
469
470 pub fn pow(&self, rhs: u64) -> Self {
471 self.env().crypto().bls12_381().fr_pow(self, rhs)
472 }
473
474 pub fn inv(&self) -> Self {
475 self.env().crypto().bls12_381().fr_inv(self)
476 }
477}
478
479impl From<U256> for Fr {
480 fn from(value: U256) -> Self {
481 Self(value)
482 }
483}
484
485impl From<&Fr> for U256Val {
486 fn from(value: &Fr) -> Self {
487 value.as_u256().into()
488 }
489}
490
491impl TryFromVal<Env, Val> for Fr {
492 type Error = ConversionError;
493
494 fn try_from_val(env: &Env, val: &Val) -> Result<Self, Self::Error> {
495 let u = U256::try_from_val(env, val)?;
496 Ok(Fr(u))
497 }
498}
499
500impl TryFromVal<Env, Fr> for Val {
501 type Error = ConversionError;
502
503 fn try_from_val(_env: &Env, fr: &Fr) -> Result<Self, Self::Error> {
504 Ok(fr.to_val())
505 }
506}
507
508#[cfg(not(target_family = "wasm"))]
509impl From<&Fr> for ScVal {
510 fn from(v: &Fr) -> Self {
511 Self::from(&v.0)
512 }
513}
514
515#[cfg(not(target_family = "wasm"))]
516impl From<Fr> for ScVal {
517 fn from(v: Fr) -> Self {
518 (&v).into()
519 }
520}
521
522impl Eq for Fr {}
523
524impl PartialEq for Fr {
525 fn eq(&self, other: &Self) -> bool {
526 self.as_u256().partial_cmp(other.as_u256()) == Some(Ordering::Equal)
527 }
528}
529
530impl Debug for Fr {
531 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
532 write!(f, "Fr({:?})", self.as_u256())
533 }
534}
535
536impl Add for Fr {
537 type Output = Fr;
538
539 fn add(self, rhs: Self) -> Self::Output {
540 self.env().crypto().bls12_381().fr_add(&self, &rhs)
541 }
542}
543
544impl Sub for Fr {
545 type Output = Fr;
546
547 fn sub(self, rhs: Self) -> Self::Output {
548 self.env().crypto().bls12_381().fr_sub(&self, &rhs)
549 }
550}
551
552impl Mul for Fr {
553 type Output = Fr;
554
555 fn mul(self, rhs: Self) -> Self::Output {
556 self.env().crypto().bls12_381().fr_mul(&self, &rhs)
557 }
558}
559
560impl Bls12_381 {
561 pub(crate) fn new(env: &Env) -> Bls12_381 {
562 Bls12_381 { env: env.clone() }
563 }
564
565 pub fn env(&self) -> &Env {
566 &self.env
567 }
568
569 pub fn g1_is_in_subgroup(&self, p: &G1Affine) -> bool {
573 let env = self.env();
574 let res = internal::Env::bls12_381_check_g1_is_in_subgroup(env, p.to_object())
575 .unwrap_infallible();
576 res.into()
577 }
578
579 pub fn g1_add(&self, p0: &G1Affine, p1: &G1Affine) -> G1Affine {
581 let env = self.env();
582 let bin = internal::Env::bls12_381_g1_add(env, p0.to_object(), p1.to_object())
583 .unwrap_infallible();
584 unsafe { G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) }
585 }
586
587 pub fn g1_checked_add(&self, p0: &G1Affine, p1: &G1Affine) -> Option<G1Affine> {
593 let env = self.env();
594 let bin = internal::Env::bls12_381_g1_add(env, p0.to_object(), p1.to_object())
595 .unwrap_infallible();
596 let res = unsafe { G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) };
597 let is_in_correct_subgroup: bool =
598 internal::Env::bls12_381_check_g1_is_in_subgroup(env, res.to_object())
599 .unwrap_optimized()
600 .into();
601 match is_in_correct_subgroup {
602 true => Some(res),
603 false => None,
604 }
605 }
606
607 pub fn g1_mul(&self, p0: &G1Affine, scalar: &Fr) -> G1Affine {
609 let env = self.env();
610 let bin =
611 internal::Env::bls12_381_g1_mul(env, p0.to_object(), scalar.into()).unwrap_infallible();
612 unsafe { G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) }
613 }
614
615 pub fn g1_msm(&self, vp: Vec<G1Affine>, vs: Vec<Fr>) -> G1Affine {
617 let env = self.env();
618 let bin = internal::Env::bls12_381_g1_msm(env, vp.into(), vs.into()).unwrap_infallible();
619 unsafe { G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) }
620 }
621
622 pub fn map_fp_to_g1(&self, fp: &Fp) -> G1Affine {
624 let env = self.env();
625 let bin = internal::Env::bls12_381_map_fp_to_g1(env, fp.to_object()).unwrap_infallible();
626 unsafe { G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) }
627 }
628
629 pub fn hash_to_g1(&self, msg: &Bytes, dst: &Bytes) -> G1Affine {
631 let env = self.env();
632 let bin = internal::Env::bls12_381_hash_to_g1(env, msg.into(), dst.to_object())
633 .unwrap_infallible();
634 unsafe { G1Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) }
635 }
636
637 pub fn g2_is_in_subgroup(&self, p: &G2Affine) -> bool {
641 let env = self.env();
642 let res = internal::Env::bls12_381_check_g2_is_in_subgroup(env, p.to_object())
643 .unwrap_infallible();
644 res.into()
645 }
646
647 pub fn g2_add(&self, p0: &G2Affine, p1: &G2Affine) -> G2Affine {
649 let env = self.env();
650 let bin = internal::Env::bls12_381_g2_add(env, p0.to_object(), p1.to_object())
651 .unwrap_infallible();
652 unsafe { G2Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) }
653 }
654
655 pub fn g2_checked_add(&self, p0: &G2Affine, p1: &G2Affine) -> Option<G2Affine> {
661 let env = self.env();
662 let bin = internal::Env::bls12_381_g2_add(env, p0.to_object(), p1.to_object())
663 .unwrap_infallible();
664 let res = unsafe { G2Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) };
665 let is_in_correct_subgroup: bool =
666 internal::Env::bls12_381_check_g2_is_in_subgroup(env, res.to_object())
667 .unwrap_optimized()
668 .into();
669 match is_in_correct_subgroup {
670 true => Some(res),
671 false => None,
672 }
673 }
674
675 pub fn g2_mul(&self, p0: &G2Affine, scalar: &Fr) -> G2Affine {
677 let env = self.env();
678 let bin =
679 internal::Env::bls12_381_g2_mul(env, p0.to_object(), scalar.into()).unwrap_infallible();
680 unsafe { G2Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) }
681 }
682
683 pub fn g2_msm(&self, vp: Vec<G2Affine>, vs: Vec<Fr>) -> G2Affine {
685 let env = self.env();
686 let bin = internal::Env::bls12_381_g2_msm(env, vp.into(), vs.into()).unwrap_infallible();
687 unsafe { G2Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) }
688 }
689
690 pub fn map_fp2_to_g2(&self, fp2: &Fp2) -> G2Affine {
692 let env = self.env();
693 let bin = internal::Env::bls12_381_map_fp2_to_g2(env, fp2.to_object()).unwrap_infallible();
694 unsafe { G2Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) }
695 }
696
697 pub fn hash_to_g2(&self, msg: &Bytes, dst: &Bytes) -> G2Affine {
699 let env = self.env();
700 let bin = internal::Env::bls12_381_hash_to_g2(env, msg.into(), dst.to_object())
701 .unwrap_infallible();
702 unsafe { G2Affine::from_bytes(BytesN::unchecked_new(env.clone(), bin)) }
703 }
704
705 pub fn pairing_check(&self, vp1: Vec<G1Affine>, vp2: Vec<G2Affine>) -> bool {
720 let env = self.env();
721 internal::Env::bls12_381_multi_pairing_check(env, vp1.into(), vp2.into())
722 .unwrap_infallible()
723 .into()
724 }
725
726 pub fn fr_add(&self, lhs: &Fr, rhs: &Fr) -> Fr {
730 let env = self.env();
731 let v = internal::Env::bls12_381_fr_add(env, lhs.into(), rhs.into()).unwrap_infallible();
732 U256::try_from_val(env, &v).unwrap_infallible().into()
733 }
734
735 pub fn fr_sub(&self, lhs: &Fr, rhs: &Fr) -> Fr {
737 let env = self.env();
738 let v = internal::Env::bls12_381_fr_sub(env, lhs.into(), rhs.into()).unwrap_infallible();
739 U256::try_from_val(env, &v).unwrap_infallible().into()
740 }
741
742 pub fn fr_mul(&self, lhs: &Fr, rhs: &Fr) -> Fr {
744 let env = self.env();
745 let v = internal::Env::bls12_381_fr_mul(env, lhs.into(), rhs.into()).unwrap_infallible();
746 U256::try_from_val(env, &v).unwrap_infallible().into()
747 }
748
749 pub fn fr_pow(&self, lhs: &Fr, rhs: u64) -> Fr {
751 let env = self.env();
752 let rhs = U64Val::try_from_val(env, &rhs).unwrap_optimized();
753 let v = internal::Env::bls12_381_fr_pow(env, lhs.into(), rhs).unwrap_infallible();
754 U256::try_from_val(env, &v).unwrap_infallible().into()
755 }
756
757 pub fn fr_inv(&self, lhs: &Fr) -> Fr {
759 let env = self.env();
760 let v = internal::Env::bls12_381_fr_inv(env, lhs.into()).unwrap_infallible();
761 U256::try_from_val(env, &v).unwrap_infallible().into()
762 }
763}