soroban_sdk/crypto/
bls12_381.rs

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; // Size in bytes of a serialized Fp element in BLS12-381. The field modulus is 381 bits, requiring 48 bytes (384 bits) with 3 bits reserved for flags.
16pub const FP2_SERIALIZED_SIZE: usize = FP_SERIALIZED_SIZE * 2;
17pub const G1_SERIALIZED_SIZE: usize = FP_SERIALIZED_SIZE * 2; // Must match soroban_sdk_macro::map_type::G1_SERIALIZED_SIZE.
18pub const G2_SERIALIZED_SIZE: usize = FP2_SERIALIZED_SIZE * 2; // Must match soroban_sdk_macro::map_type::G2_SERIALIZED_SIZE.
19
20/// Bls12_381 provides access to curve and field arithmetics on the BLS12-381
21/// curve.
22pub struct Bls12_381 {
23    env: Env,
24}
25
26// This routine was copied with slight modification from the arkworks library:
27// https://github.com/arkworks-rs/algebra/blob/bf1c9b22b30325ef4df4f701dedcb6dea904c587/ff/src/biginteger/arithmetic.rs#L66-L79
28fn 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    // casting is safe here because `tmp` can only exceed u64 by a single
31    // (borrow) bit, which we capture in the next line.
32    *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/// `G1Affine` is a point in the G1 group (subgroup defined over the base field
86///  `Fq`) of the BLS12-381 elliptic curve
87///
88/// # Serialization:
89/// - The 96 bytes represent the **uncompressed encoding** of a point in G1. The
90///   Bytes consist of `be_byte(X) || be_byte(Y)`  (`||` is concatenation),
91///   where 'X' and 'Y' are the two coordinates, each being a base field element
92///   `Fp`
93/// - The most significant three bits (bits 0-3) of the first byte are reserved
94///   for encoding flags:
95///   - compression_flag (bit 0): Must always be unset (0), as only uncompressed
96///     points are supported.
97///   - infinity_flag (bit 1): Set if the point is the point at infinity (zero
98///     point), in which case all other bits must be zero.
99///   - sort_flag (bit 2): Must always be unset (0).
100///
101/// # Example Usage:
102/// ```rust
103/// use soroban_sdk::{Env, bytesn, crypto::bls12_381::{Bls12_381, G1Affine}};
104/// let env = Env::default();
105/// let bls12_381 = env.crypto().bls12_381();
106/// let zero = G1Affine::from_bytes(bytesn!(&env, 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000));
107/// let one = G1Affine::from_bytes(bytesn!(&env, 0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1));
108/// let res = bls12_381.g1_add(&zero, &one);
109/// assert_eq!(res, one);
110/// ```
111#[derive(Clone)]
112#[repr(transparent)]
113pub struct G1Affine(BytesN<G1_SERIALIZED_SIZE>);
114
115/// `G2Affine` is a point in the G2 group (subgroup defined over the quadratic
116/// extension field `Fq2`) of the BLS12-381 elliptic curve
117///
118/// # Serialization:
119/// - The 192 bytes represent the **uncompressed encoding** of a point in G2.
120///   The bytes consist of `be_bytes(X_c1) || be_bytes(X_c0) || be_bytes(Y_c1)
121///   || be_bytes(Y_c0)` (`||` is concatenation), where 'X' and 'Y' are the two
122///   coordinates, each being an extension field element `Fp2` and `c0`, `c1`
123///   are components of `Fp2` (each being `Fp`).
124/// - The most significant three bits (bits 0-3) of the first byte are reserved
125///   for encoding flags:
126///   - compression_flag (bit 0): Must always be unset (0), as only uncompressed
127///     points are supported.
128///   - infinity_flag (bit 1): Set if the point is the point at infinity (zero
129///     point), in which case all other bits must be zero.
130///   - sort_flag (bit 2): Must always be unset (0).
131#[derive(Clone)]
132#[repr(transparent)]
133pub struct G2Affine(BytesN<G2_SERIALIZED_SIZE>);
134
135/// `Fp` represents an element of the base field `Fq` of the BLS12-381 elliptic
136/// curve
137///
138/// # Serialization:
139/// - The 48 bytes represent the **big-endian encoding** of an element in the
140///   field `Fp`. The value is serialized as a big-endian integer.
141#[derive(Clone)]
142#[repr(transparent)]
143pub struct Fp(BytesN<FP_SERIALIZED_SIZE>);
144
145/// `Fp2` represents an element of the quadratic extension field `Fq2` of the
146/// BLS12-381 elliptic curve
147///
148/// # Serialization:
149/// - The 96 bytes represent the **big-endian encoding** of an element in the
150///   field `Fp2`. The bytes consist of `be_bytes(c1) || be_bytes(c0)` (`||` is
151///   concatenation), where `c0` and `c1` are the two `Fp` elements (the real
152///   and imaginary components).
153#[derive(Clone)]
154#[repr(transparent)]
155pub struct Fp2(BytesN<FP2_SERIALIZED_SIZE>);
156
157/// `Fr` represents an element in the BLS12-381 scalar field, which is a prime
158/// field of order `r` (the order of the G1 and G2 groups). The struct is
159/// internally represented with an `U256`, all arithmetic operations follow
160/// modulo `r`.
161#[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    // `Fp` represents an element in the base field of the BLS12-381 elliptic curve.
176    // For an element a ∈ Fp, its negation `-a` is defined as:
177    //   a + (-a) = 0 (mod p)
178    // where `p` is the field modulus, and to make a valid point coordinate on the
179    // curve, `a` also must be within the field range (i.e., 0 ≤ a < p).
180    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        // BLS12-381 base field modulus
187        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        // Compute modulus - value
198        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    /// Maps this `Fp` element to a `G1Affine` point using the [simplified SWU
209    /// mapping](https://www.rfc-editor.org/rfc/rfc9380.html#name-simplified-swu-for-ab-0).
210    ///
211    /// <div class="warning">
212    /// <h6>Warning</h6>
213    /// The resulting point is on the curve but may not be in the prime-order subgroup (operations
214    /// like pairing may fail). To ensure the point is in the prime-order subgroup, cofactor
215    /// clearing must be performed on the output.
216    ///
217    /// For applications requiring a point directly in the prime-order subgroup, consider using
218    /// `hash_to_g1`, which handles subgroup checks and cofactor clearing internally.
219    /// </div>
220    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
288// G1Affine represents a point (X, Y) on the BLS12-381 curve where X, Y ∈ Fp
289// Negation of (X, Y) is defined as (X, -Y)
290impl 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    // An Fp2 element is represented as c0 + c1 * X, where:
320    // - c0, c1 are base field elements (Fp)
321    // - X is the quadratic non-residue used to construct the field extension
322    // The negation of c0 + c1 * X is (-c0) + (-c1) * X.
323    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        // Convert both components to Fp and negate them
331        let c0 = Fp::from_array(self.env(), &slice0);
332        let c1 = Fp::from_array(self.env(), &slice1);
333
334        // If either component's negation fails, the whole operation fails
335        let neg_c0 = c0.checked_neg()?;
336        let neg_c1 = c1.checked_neg()?;
337
338        // Reconstruct the Fp2 element from negated components
339        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    /// Maps this `Fp2` element to a `G2Affine` point using the [simplified SWU
346    /// mapping](https://www.rfc-editor.org/rfc/rfc9380.html#name-simplified-swu-for-ab-0).
347    ///
348    /// <div class="warning">
349    /// <h6>Warning</h6>
350    /// The resulting point is on the curve but may not be in the prime-order subgroup (operations
351    /// like pairing may fail). To ensure the point is in the prime-order subgroup, cofactor
352    /// clearing must be performed on the output.
353    ///
354    /// For applications requiring a point directly in the prime-order subgroup, consider using
355    /// `hash_to_g2`, which handles subgroup checks and cofactor clearing internally.
356    /// </div>
357    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
411// G2Affine represents a point (X, Y) on the BLS12-381 quadratic extension curve where X, Y ∈ Fp2
412// Negation of (X, Y) is defined as (X, -Y)
413impl 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    // g1
570
571    /// Checks if a point `p` in G1 is in the correct subgroup.
572    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    /// Adds two points `p0` and `p1` in G1.
580    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    /// Adds two points `p0` and `p1` in G1, ensuring that the result is in the
588    /// correct subgroup. Note the subgroup check is computationally expensive,
589    /// so if want to perform a series of additions i.e. `agg = p0 + p1 + .. + pn`,
590    /// it may make sense to only call g1_checked_add on the final addition,
591    /// while using `g1_add` (non-checked version) on the intermediate ones.
592    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    /// Multiplies a point `p0` in G1 by a scalar.
608    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    /// Performs a multi-scalar multiplication (MSM) operation in G1.
616    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    /// Maps an element in the base field `Fp` to a point in G1.
623    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    /// Hashes a message `msg` to a point in G1, using a domain separation tag `dst`.
630    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    // g2
638
639    /// Checks if a point `p` in G2 is in the correct subgroup.
640    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    /// Adds two points `p0` and `p1` in G2.
648    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    /// Adds two points `p0` and `p1` in G2, ensuring that the result is in the
656    /// correct subgroup. Note the subgroup check is computationally expensive,
657    /// so if want to perform a series of additions i.e. `agg = p0 + p1 + .. +pn`,     
658    /// it may make sense to only call g2_checked_add on the final addition,
659    /// while using `g2_add` (non-checked version) on the intermediate ones.
660    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    /// Multiplies a point `p0` in G2 by a scalar.
676    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    /// Performs a multi-scalar multiplication (MSM) operation in G2.
684    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    /// Maps an element in the base field `Fp2` to a point in G2.
691    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    /// Hashes a message `msg` to a point in G2, using a domain separation tag `dst`.
698    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    // pairing
706
707    /// Performs a pairing check between vectors of points in G1 and G2.
708    ///
709    /// This function computes the pairing for each pair of points in the
710    /// provided vectors `vp1` (G1 points) and `vp2` (G2 points) and verifies if
711    /// the overall pairing result is equal to the identity in the target group.
712    ///
713    /// # Returns:
714    /// - `true` if the pairing check holds (i.e., the pairing result is valid
715    ///   and equal to the identity element), otherwise `false`.
716    ///
717    /// # Panics:
718    /// - If the lengths of `vp1` and `vp2` are not equal or if they are empty.
719    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    // scalar arithmetic
727
728    /// Adds two scalars in the BLS12-381 scalar field `Fr`.
729    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    /// Subtracts one scalar from another in the BLS12-381 scalar field `Fr`.
736    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    /// Multiplies two scalars in the BLS12-381 scalar field `Fr`.
743    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    /// Raises a scalar to the power of a given exponent in the BLS12-381 scalar field `Fr`.
750    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    /// Computes the multiplicative inverse of a scalar in the BLS12-381 scalar field `Fr`.
758    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}