solana_bn254/
lib.rs

1pub mod compression;
2pub mod prelude {
3    pub use crate::{consts::*, target_arch::*, AltBn128Error};
4}
5
6use {
7    bytemuck::{Pod, Zeroable},
8    consts::*,
9    thiserror::Error,
10};
11
12mod consts {
13    /// Input length for the add operation.
14    pub const ALT_BN128_ADDITION_INPUT_LEN: usize = 128;
15
16    /// Input length for the multiplication operation.
17    pub const ALT_BN128_MULTIPLICATION_INPUT_LEN: usize = 96;
18
19    /// Pair element length.
20    pub const ALT_BN128_PAIRING_ELEMENT_LEN: usize = 192;
21
22    /// Output length for the add operation.
23    pub const ALT_BN128_ADDITION_OUTPUT_LEN: usize = 64;
24
25    /// Output length for the multiplication operation.
26    pub const ALT_BN128_MULTIPLICATION_OUTPUT_LEN: usize = 64;
27
28    /// Output length for pairing operation.
29    pub const ALT_BN128_PAIRING_OUTPUT_LEN: usize = 32;
30
31    /// Size of the EC point field, in bytes.
32    pub const ALT_BN128_FIELD_SIZE: usize = 32;
33
34    /// Size of the EC point. `alt_bn128` point contains
35    /// the consistently united x and y fields as 64 bytes.
36    pub const ALT_BN128_POINT_SIZE: usize = 64;
37
38    pub const ALT_BN128_ADD: u64 = 0;
39    pub const ALT_BN128_SUB: u64 = 1;
40    pub const ALT_BN128_MUL: u64 = 2;
41    pub const ALT_BN128_PAIRING: u64 = 3;
42}
43
44// AltBn128Error must be removed once the
45// simplify_alt_bn128_syscall_error_codes feature gets activated
46#[derive(Debug, Error, Clone, PartialEq, Eq)]
47pub enum AltBn128Error {
48    #[error("The input data is invalid")]
49    InvalidInputData,
50    #[error("Invalid group data")]
51    GroupError,
52    #[error("Slice data is going out of input data bounds")]
53    SliceOutOfBounds,
54    #[error("Unexpected error")]
55    UnexpectedError,
56    #[error("Failed to convert a byte slice into a vector {0:?}")]
57    TryIntoVecError(Vec<u8>),
58    #[error("Failed to convert projective to affine g1")]
59    ProjectiveToG1Failed,
60}
61
62impl From<u64> for AltBn128Error {
63    fn from(v: u64) -> AltBn128Error {
64        match v {
65            1 => AltBn128Error::InvalidInputData,
66            2 => AltBn128Error::GroupError,
67            3 => AltBn128Error::SliceOutOfBounds,
68            4 => AltBn128Error::TryIntoVecError(Vec::new()),
69            5 => AltBn128Error::ProjectiveToG1Failed,
70            _ => AltBn128Error::UnexpectedError,
71        }
72    }
73}
74
75impl From<AltBn128Error> for u64 {
76    fn from(v: AltBn128Error) -> u64 {
77        // note: should never return 0, as it risks to be confused with syscall success
78        match v {
79            AltBn128Error::InvalidInputData => 1,
80            AltBn128Error::GroupError => 2,
81            AltBn128Error::SliceOutOfBounds => 3,
82            AltBn128Error::TryIntoVecError(_) => 4,
83            AltBn128Error::ProjectiveToG1Failed => 5,
84            AltBn128Error::UnexpectedError => 6,
85        }
86    }
87}
88
89use consts::{ALT_BN128_FIELD_SIZE as FIELD_SIZE, ALT_BN128_POINT_SIZE as G1_POINT_SIZE};
90
91/// The BN254 (BN128) group element in G1 as a POD type.
92///
93/// A group element in G1 consists of two field elements `(x, y)`. A `PodG1`
94/// type expects a group element to be encoded as `[le(x), le(y)]` where
95/// `le(..)` is the little-endian encoding of the input field element as used
96/// in the `ark-bn254` crate. Note that this differs from the EIP-197 standard,
97/// which specifies that the field elements are encoded as big-endian.
98///
99/// The Solana syscalls still expect the inputs to be encoded in big-endian as
100/// specified in EIP-197. The type `PodG1` is an intermediate type that
101/// facilitates the translation between the EIP-197 encoding and the arkworks
102/// implementation encoding.
103#[derive(Clone, Copy, Debug, PartialEq, Eq, Pod, Zeroable)]
104#[repr(transparent)]
105pub struct PodG1(pub [u8; G1_POINT_SIZE]);
106
107const G2_POINT_SIZE: usize = FIELD_SIZE * 4;
108
109/// The BN254 (BN128) group element in G2 as a POD type.
110///
111/// Elements in G2 is represented by 2 field-extension elements `(x, y)`. Each
112/// field-extension element itself is a degree 1 polynomial `x = x0 + x1*X`,
113/// `y = y0 + y1*X`. The EIP-197 standard encodes a G2 element as
114/// `[be(x1), be(x0), be(y1), be(y0)]` where `be(..)` is the big-endian
115/// encoding of the input field element. The `ark-bn254` crate encodes a G2
116/// element as `[le(x0), le(x1), le(y0), le(y1)]` where `le(..)` is the
117/// little-endian encoding of the input field element. Notably, in addition to
118/// the differences in the big-endian vs. little-endian encodings of field
119/// elements, the order of the polynomial field coefficients `x0`, `x1`, `y0`,
120/// and `y1` are different.
121///
122/// THe Solana syscalls still expect the inputs to be encoded as specified in
123/// EIP-197. The type `PodG2` is an intermediate type that facilitates the
124/// translation between the `EIP-197 encoding and the encoding used in the
125/// arkworks implementation.
126#[derive(Clone, Copy, Debug, PartialEq, Eq, Pod, Zeroable)]
127#[repr(transparent)]
128pub struct PodG2(pub [u8; G2_POINT_SIZE]);
129
130#[cfg(not(target_os = "solana"))]
131mod target_arch {
132    use {
133        super::*,
134        ark_bn254::{self, Config},
135        ark_ec::{self, models::bn::Bn, pairing::Pairing, AffineRepr},
136        ark_ff::{BigInteger, BigInteger256, One},
137        ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, Validate},
138    };
139
140    type G1 = ark_bn254::g1::G1Affine;
141    type G2 = ark_bn254::g2::G2Affine;
142
143    impl PodG1 {
144        /// Takes in an EIP-197 (big-endian) byte encoding of a group element in G1 and constructs a
145        /// `PodG1` struct that encodes the same bytes in little-endian.
146        fn from_be_bytes(be_bytes: &[u8]) -> Result<Self, AltBn128Error> {
147            if be_bytes.len() != G1_POINT_SIZE {
148                return Err(AltBn128Error::SliceOutOfBounds);
149            }
150            let mut pod_bytes = [0u8; G1_POINT_SIZE];
151            reverse_copy(&be_bytes[..FIELD_SIZE], &mut pod_bytes[..FIELD_SIZE])?;
152            reverse_copy(&be_bytes[FIELD_SIZE..], &mut pod_bytes[FIELD_SIZE..])?;
153            Ok(Self(pod_bytes))
154        }
155    }
156
157    impl PodG2 {
158        /// Takes in an EIP-197 (big-endian) byte encoding of a group element in G2
159        /// and constructs a `PodG2` struct that encodes the same bytes in
160        /// little-endian.
161        fn from_be_bytes(be_bytes: &[u8]) -> Result<Self, AltBn128Error> {
162            if be_bytes.len() != G2_POINT_SIZE {
163                return Err(AltBn128Error::SliceOutOfBounds);
164            }
165            // note the cross order
166            const SOURCE_X1_INDEX: usize = 0;
167            const SOURCE_X0_INDEX: usize = SOURCE_X1_INDEX.saturating_add(FIELD_SIZE);
168            const SOURCE_Y1_INDEX: usize = SOURCE_X0_INDEX.saturating_add(FIELD_SIZE);
169            const SOURCE_Y0_INDEX: usize = SOURCE_Y1_INDEX.saturating_add(FIELD_SIZE);
170
171            const TARGET_X0_INDEX: usize = 0;
172            const TARGET_X1_INDEX: usize = TARGET_X0_INDEX.saturating_add(FIELD_SIZE);
173            const TARGET_Y0_INDEX: usize = TARGET_X1_INDEX.saturating_add(FIELD_SIZE);
174            const TARGET_Y1_INDEX: usize = TARGET_Y0_INDEX.saturating_add(FIELD_SIZE);
175
176            let mut pod_bytes = [0u8; G2_POINT_SIZE];
177            reverse_copy(
178                &be_bytes[SOURCE_X1_INDEX..SOURCE_X1_INDEX.saturating_add(FIELD_SIZE)],
179                &mut pod_bytes[TARGET_X1_INDEX..TARGET_X1_INDEX.saturating_add(FIELD_SIZE)],
180            )?;
181            reverse_copy(
182                &be_bytes[SOURCE_X0_INDEX..SOURCE_X0_INDEX.saturating_add(FIELD_SIZE)],
183                &mut pod_bytes[TARGET_X0_INDEX..TARGET_X0_INDEX.saturating_add(FIELD_SIZE)],
184            )?;
185            reverse_copy(
186                &be_bytes[SOURCE_Y1_INDEX..SOURCE_Y1_INDEX.saturating_add(FIELD_SIZE)],
187                &mut pod_bytes[TARGET_Y1_INDEX..TARGET_Y1_INDEX.saturating_add(FIELD_SIZE)],
188            )?;
189            reverse_copy(
190                &be_bytes[SOURCE_Y0_INDEX..SOURCE_Y0_INDEX.saturating_add(FIELD_SIZE)],
191                &mut pod_bytes[TARGET_Y0_INDEX..TARGET_Y0_INDEX.saturating_add(FIELD_SIZE)],
192            )?;
193            Ok(Self(pod_bytes))
194        }
195    }
196
197    impl TryFrom<PodG1> for G1 {
198        type Error = AltBn128Error;
199
200        fn try_from(bytes: PodG1) -> Result<Self, Self::Error> {
201            if bytes.0 == [0u8; 64] {
202                return Ok(G1::zero());
203            }
204            let g1 = Self::deserialize_with_mode(
205                &*[&bytes.0[..], &[0u8][..]].concat(),
206                Compress::No,
207                Validate::Yes,
208            );
209
210            match g1 {
211                Ok(g1) => {
212                    if !g1.is_on_curve() {
213                        Err(AltBn128Error::GroupError)
214                    } else {
215                        Ok(g1)
216                    }
217                }
218                Err(_) => Err(AltBn128Error::InvalidInputData),
219            }
220        }
221    }
222
223    impl TryFrom<PodG2> for G2 {
224        type Error = AltBn128Error;
225
226        fn try_from(bytes: PodG2) -> Result<Self, Self::Error> {
227            if bytes.0 == [0u8; 128] {
228                return Ok(G2::zero());
229            }
230            let g2 = Self::deserialize_with_mode(
231                &*[&bytes.0[..], &[0u8][..]].concat(),
232                Compress::No,
233                Validate::Yes,
234            );
235
236            match g2 {
237                Ok(g2) => {
238                    if !g2.is_on_curve() {
239                        Err(AltBn128Error::GroupError)
240                    } else {
241                        Ok(g2)
242                    }
243                }
244                Err(_) => Err(AltBn128Error::InvalidInputData),
245            }
246        }
247    }
248
249    pub fn alt_bn128_addition(input: &[u8]) -> Result<Vec<u8>, AltBn128Error> {
250        if input.len() > ALT_BN128_ADDITION_INPUT_LEN {
251            return Err(AltBn128Error::InvalidInputData);
252        }
253
254        let mut input = input.to_vec();
255        input.resize(ALT_BN128_ADDITION_INPUT_LEN, 0);
256
257        let p: G1 = PodG1::from_be_bytes(&input[..64])?.try_into()?;
258        let q: G1 = PodG1::from_be_bytes(&input[64..ALT_BN128_ADDITION_INPUT_LEN])?.try_into()?;
259
260        #[allow(clippy::arithmetic_side_effects)]
261        let result_point = p + q;
262
263        let mut result_point_data = [0u8; ALT_BN128_ADDITION_OUTPUT_LEN];
264        let result_point_affine: G1 = result_point.into();
265        result_point_affine
266            .x
267            .serialize_with_mode(&mut result_point_data[..32], Compress::No)
268            .map_err(|_| AltBn128Error::InvalidInputData)?;
269        result_point_affine
270            .y
271            .serialize_with_mode(&mut result_point_data[32..], Compress::No)
272            .map_err(|_| AltBn128Error::InvalidInputData)?;
273
274        Ok(convert_endianness_64(&result_point_data[..]))
275    }
276
277    pub fn alt_bn128_multiplication(input: &[u8]) -> Result<Vec<u8>, AltBn128Error> {
278        alt_bn128_apply_multiplication(input, ALT_BN128_MULTIPLICATION_INPUT_LEN)
279    }
280
281    pub fn alt_bn128_multiplication_128(input: &[u8]) -> Result<Vec<u8>, AltBn128Error> {
282        alt_bn128_apply_multiplication(input, 128) // hard-code length; we will remove this function in the future
283    }
284
285    fn alt_bn128_apply_multiplication(
286        input: &[u8],
287        expected_length: usize,
288    ) -> Result<Vec<u8>, AltBn128Error> {
289        if input.len() > expected_length {
290            return Err(AltBn128Error::InvalidInputData);
291        }
292
293        let mut input = input.to_vec();
294        input.resize(expected_length, 0);
295
296        let p: G1 = PodG1::from_be_bytes(&input[..64])?.try_into()?;
297        let mut fr_bytes = [0u8; 32];
298        reverse_copy(&input[64..96], &mut fr_bytes)?;
299        let fr = BigInteger256::deserialize_uncompressed_unchecked(fr_bytes.as_slice())
300            .map_err(|_| AltBn128Error::InvalidInputData)?;
301
302        let result_point: G1 = p.mul_bigint(fr).into();
303
304        let mut result_point_data = [0u8; ALT_BN128_MULTIPLICATION_OUTPUT_LEN];
305
306        result_point
307            .x
308            .serialize_with_mode(&mut result_point_data[..32], Compress::No)
309            .map_err(|_| AltBn128Error::InvalidInputData)?;
310        result_point
311            .y
312            .serialize_with_mode(&mut result_point_data[32..], Compress::No)
313            .map_err(|_| AltBn128Error::InvalidInputData)?;
314
315        Ok(convert_endianness_64(
316            &result_point_data[..ALT_BN128_MULTIPLICATION_OUTPUT_LEN],
317        ))
318    }
319
320    pub fn alt_bn128_pairing(input: &[u8]) -> Result<Vec<u8>, AltBn128Error> {
321        if input
322            .len()
323            .checked_rem(consts::ALT_BN128_PAIRING_ELEMENT_LEN)
324            .is_none()
325        {
326            return Err(AltBn128Error::InvalidInputData);
327        }
328
329        let ele_len = input.len().saturating_div(ALT_BN128_PAIRING_ELEMENT_LEN);
330
331        let mut vec_pairs: Vec<(G1, G2)> = Vec::with_capacity(ele_len);
332        for chunk in input.chunks(ALT_BN128_PAIRING_ELEMENT_LEN).take(ele_len) {
333            let (p_bytes, q_bytes) = chunk.split_at(G1_POINT_SIZE);
334
335            let g1 = PodG1::from_be_bytes(p_bytes)?.try_into()?;
336            let g2 = PodG2::from_be_bytes(q_bytes)?.try_into()?;
337
338            vec_pairs.push((g1, g2));
339        }
340
341        let mut result = BigInteger256::from(0u64);
342        let res = <Bn<Config> as Pairing>::multi_pairing(
343            vec_pairs.iter().map(|pair| pair.0),
344            vec_pairs.iter().map(|pair| pair.1),
345        );
346
347        if res.0 == ark_bn254::Fq12::one() {
348            result = BigInteger256::from(1u64);
349        }
350
351        let output = result.to_bytes_be();
352        Ok(output)
353    }
354
355    fn convert_endianness_64(bytes: &[u8]) -> Vec<u8> {
356        bytes
357            .chunks(32)
358            .flat_map(|b| b.iter().copied().rev().collect::<Vec<u8>>())
359            .collect::<Vec<u8>>()
360    }
361
362    /// Copies a `source` byte slice into a `destination` byte slice in reverse order.
363    fn reverse_copy(source: &[u8], destination: &mut [u8]) -> Result<(), AltBn128Error> {
364        if source.len() != destination.len() {
365            return Err(AltBn128Error::SliceOutOfBounds);
366        }
367        for (source_index, destination_index) in source.iter().rev().zip(destination.iter_mut()) {
368            *destination_index = *source_index;
369        }
370        Ok(())
371    }
372}
373
374#[cfg(target_os = "solana")]
375mod target_arch {
376    use {super::*, solana_define_syscall::definitions as syscalls};
377
378    pub fn alt_bn128_addition(input: &[u8]) -> Result<Vec<u8>, AltBn128Error> {
379        if input.len() > ALT_BN128_ADDITION_INPUT_LEN {
380            return Err(AltBn128Error::InvalidInputData);
381        }
382        let mut result_buffer = [0; ALT_BN128_ADDITION_OUTPUT_LEN];
383        let result = unsafe {
384            syscalls::sol_alt_bn128_group_op(
385                ALT_BN128_ADD,
386                input as *const _ as *const u8,
387                input.len() as u64,
388                &mut result_buffer as *mut _ as *mut u8,
389            )
390        };
391
392        match result {
393            0 => Ok(result_buffer.to_vec()),
394            _ => Err(AltBn128Error::UnexpectedError),
395        }
396    }
397
398    pub fn alt_bn128_multiplication(input: &[u8]) -> Result<Vec<u8>, AltBn128Error> {
399        if input.len() > ALT_BN128_MULTIPLICATION_INPUT_LEN {
400            return Err(AltBn128Error::InvalidInputData);
401        }
402        let mut result_buffer = [0u8; ALT_BN128_POINT_SIZE];
403        let result = unsafe {
404            syscalls::sol_alt_bn128_group_op(
405                ALT_BN128_MUL,
406                input as *const _ as *const u8,
407                input.len() as u64,
408                &mut result_buffer as *mut _ as *mut u8,
409            )
410        };
411
412        match result {
413            0 => Ok(result_buffer.to_vec()),
414            _ => Err(AltBn128Error::UnexpectedError),
415        }
416    }
417
418    pub fn alt_bn128_pairing(input: &[u8]) -> Result<Vec<u8>, AltBn128Error> {
419        if input
420            .len()
421            .checked_rem(consts::ALT_BN128_PAIRING_ELEMENT_LEN)
422            .is_none()
423        {
424            return Err(AltBn128Error::InvalidInputData);
425        }
426        let mut result_buffer = [0u8; 32];
427        let result = unsafe {
428            syscalls::sol_alt_bn128_group_op(
429                ALT_BN128_PAIRING,
430                input as *const _ as *const u8,
431                input.len() as u64,
432                &mut result_buffer as *mut _ as *mut u8,
433            )
434        };
435
436        match result {
437            0 => Ok(result_buffer.to_vec()),
438            _ => Err(AltBn128Error::UnexpectedError),
439        }
440    }
441}
442
443#[cfg(test)]
444mod tests {
445    use {
446        crate::{prelude::*, PodG1},
447        ark_bn254::g1::G1Affine,
448        ark_ec::AffineRepr,
449        ark_serialize::{CanonicalSerialize, Compress},
450    };
451
452    #[test]
453    fn zero_serialization_test() {
454        let zero = G1Affine::zero();
455        let mut result_point_data = [0u8; 64];
456        zero.x
457            .serialize_with_mode(&mut result_point_data[..32], Compress::No)
458            .map_err(|_| AltBn128Error::InvalidInputData)
459            .unwrap();
460        zero.y
461            .serialize_with_mode(&mut result_point_data[32..], Compress::No)
462            .map_err(|_| AltBn128Error::InvalidInputData)
463            .unwrap();
464        assert_eq!(result_point_data, [0u8; 64]);
465
466        let p: G1Affine = PodG1(result_point_data[..64].try_into().unwrap())
467            .try_into()
468            .unwrap();
469        assert_eq!(p, zero);
470    }
471
472    #[test]
473    fn alt_bn128_addition_test() {
474        use serde_derive::Deserialize;
475
476        let test_data = r#"[
477        {
478            "Input": "18b18acfb4c2c30276db5411368e7185b311dd124691610c5d3b74034e093dc9063c909c4720840cb5134cb9f59fa749755796819658d32efc0d288198f3726607c2b7f58a84bd6145f00c9c2bc0bb1a187f20ff2c92963a88019e7c6a014eed06614e20c147e940f2d70da3f74c9a17df361706a4485c742bd6788478fa17d7",
479            "Expected": "2243525c5efd4b9c3d3c45ac0ca3fe4dd85e830a4ce6b65fa1eeaee202839703301d1d33be6da8e509df21cc35964723180eed7532537db9ae5e7d48f195c915",
480            "Name": "chfast1",
481            "Gas": 150,
482            "NoBenchmark": false
483        },{
484            "Input": "2243525c5efd4b9c3d3c45ac0ca3fe4dd85e830a4ce6b65fa1eeaee202839703301d1d33be6da8e509df21cc35964723180eed7532537db9ae5e7d48f195c91518b18acfb4c2c30276db5411368e7185b311dd124691610c5d3b74034e093dc9063c909c4720840cb5134cb9f59fa749755796819658d32efc0d288198f37266",
485            "Expected": "2bd3e6d0f3b142924f5ca7b49ce5b9d54c4703d7ae5648e61d02268b1a0a9fb721611ce0a6af85915e2f1d70300909ce2e49dfad4a4619c8390cae66cefdb204",
486            "Name": "chfast2",
487            "Gas": 150,
488            "NoBenchmark": false
489        },{
490            "Input": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
491            "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
492            "Name": "cdetrio1",
493            "Gas": 150,
494            "NoBenchmark": false
495        },{
496            "Input": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
497            "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
498            "Name": "cdetrio2",
499            "Gas": 150,
500            "NoBenchmark": false
501        },{
502            "Input": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
503            "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
504            "Name": "cdetrio3",
505            "Gas": 150,
506            "NoBenchmark": false
507        },{
508            "Input": "",
509            "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
510            "Name": "cdetrio4",
511            "Gas": 150,
512            "NoBenchmark": false
513        },{
514            "Input": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
515            "Expected": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
516            "Name": "cdetrio5",
517            "Gas": 150,
518            "NoBenchmark": false
519        },{
520            "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
521            "Expected": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
522            "Name": "cdetrio6",
523            "Gas": 150,
524            "NoBenchmark": false
525        },{
526            "Input": "0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
527            "Expected": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
528            "Gas": 150,
529            "Name": "cdetrio7",
530            "NoBenchmark": false
531        },{
532            "Input": "0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
533            "Expected": "030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4",
534            "Name": "cdetrio8",
535            "Gas": 150,
536            "NoBenchmark": false
537        },{
538            "Input": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98",
539            "Expected": "15bf2bb17880144b5d1cd2b1f46eff9d617bffd1ca57c37fb5a49bd84e53cf66049c797f9ce0d17083deb32b5e36f2ea2a212ee036598dd7624c168993d1355f",
540            "Name": "cdetrio9",
541            "Gas": 150,
542            "NoBenchmark": false
543        }
544        ]"#;
545
546        #[derive(Deserialize)]
547        #[serde(rename_all = "PascalCase")]
548        struct TestCase {
549            input: String,
550            expected: String,
551        }
552
553        let test_cases: Vec<TestCase> = serde_json::from_str(test_data).unwrap();
554
555        test_cases.iter().for_each(|test| {
556            let input = array_bytes::hex2bytes_unchecked(&test.input);
557            let result = alt_bn128_addition(&input);
558            assert!(result.is_ok());
559
560            let expected = array_bytes::hex2bytes_unchecked(&test.expected);
561
562            assert_eq!(result.unwrap(), expected);
563        });
564    }
565
566    #[test]
567    fn alt_bn128_multiplication_test() {
568        use serde_derive::Deserialize;
569
570        let test_data = r#"[
571        {
572            "Input": "2bd3e6d0f3b142924f5ca7b49ce5b9d54c4703d7ae5648e61d02268b1a0a9fb721611ce0a6af85915e2f1d70300909ce2e49dfad4a4619c8390cae66cefdb20400000000000000000000000000000000000000000000000011138ce750fa15c2",
573            "Expected": "070a8d6a982153cae4be29d434e8faef8a47b274a053f5a4ee2a6c9c13c31e5c031b8ce914eba3a9ffb989f9cdd5b0f01943074bf4f0f315690ec3cec6981afc",
574            "Name": "chfast1",
575            "Gas": 6000,
576            "NoBenchmark": false
577        },{
578            "Input": "070a8d6a982153cae4be29d434e8faef8a47b274a053f5a4ee2a6c9c13c31e5c031b8ce914eba3a9ffb989f9cdd5b0f01943074bf4f0f315690ec3cec6981afc30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46",
579            "Expected": "025a6f4181d2b4ea8b724290ffb40156eb0adb514c688556eb79cdea0752c2bb2eff3f31dea215f1eb86023a133a996eb6300b44da664d64251d05381bb8a02e",
580            "Name": "chfast2",
581            "Gas": 6000,
582            "NoBenchmark": false
583        },{
584            "Input": "025a6f4181d2b4ea8b724290ffb40156eb0adb514c688556eb79cdea0752c2bb2eff3f31dea215f1eb86023a133a996eb6300b44da664d64251d05381bb8a02e183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea3",
585            "Expected": "14789d0d4a730b354403b5fac948113739e276c23e0258d8596ee72f9cd9d3230af18a63153e0ec25ff9f2951dd3fa90ed0197bfef6e2a1a62b5095b9d2b4a27",
586            "Name": "chfast3",
587            "Gas": 6000,
588            "NoBenchmark": false
589        },{
590            "Input": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
591            "Expected": "2cde5879ba6f13c0b5aa4ef627f159a3347df9722efce88a9afbb20b763b4c411aa7e43076f6aee272755a7f9b84832e71559ba0d2e0b17d5f9f01755e5b0d11",
592            "Name": "cdetrio1",
593            "Gas": 6000,
594            "NoBenchmark": false
595        },{
596            "Input": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f630644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000",
597            "Expected": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe3163511ddc1c3f25d396745388200081287b3fd1472d8339d5fecb2eae0830451",
598            "Name": "cdetrio2",
599            "Gas": 6000,
600            "NoBenchmark": true
601        },{
602            "Input": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f60000000000000000000000000000000100000000000000000000000000000000",
603            "Expected": "1051acb0700ec6d42a88215852d582efbaef31529b6fcbc3277b5c1b300f5cf0135b2394bb45ab04b8bd7611bd2dfe1de6a4e6e2ccea1ea1955f577cd66af85b",
604            "Name": "cdetrio3",
605            "Gas": 6000,
606            "NoBenchmark": true
607        },{
608            "Input": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f60000000000000000000000000000000000000000000000000000000000000009",
609            "Expected": "1dbad7d39dbc56379f78fac1bca147dc8e66de1b9d183c7b167351bfe0aeab742cd757d51289cd8dbd0acf9e673ad67d0f0a89f912af47ed1be53664f5692575",
610            "Name": "cdetrio4",
611            "Gas": 6000,
612            "NoBenchmark": true
613        },{
614            "Input": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f60000000000000000000000000000000000000000000000000000000000000001",
615            "Expected": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f6",
616            "Name": "cdetrio5",
617            "Gas": 6000,
618            "NoBenchmark": true
619        },{
620            "Input": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
621            "Expected": "29e587aadd7c06722aabba753017c093f70ba7eb1f1c0104ec0564e7e3e21f6022b1143f6a41008e7755c71c3d00b6b915d386de21783ef590486d8afa8453b1",
622            "Name": "cdetrio6",
623            "Gas": 6000,
624            "NoBenchmark": false
625        },{
626            "Input": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000",
627            "Expected": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa92e83f8d734803fc370eba25ed1f6b8768bd6d83887b87165fc2434fe11a830cb",
628            "Name": "cdetrio7",
629            "Gas": 6000,
630            "NoBenchmark": true
631        },{
632            "Input": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c0000000000000000000000000000000100000000000000000000000000000000",
633            "Expected": "221a3577763877920d0d14a91cd59b9479f83b87a653bb41f82a3f6f120cea7c2752c7f64cdd7f0e494bff7b60419f242210f2026ed2ec70f89f78a4c56a1f15",
634            "Name": "cdetrio8",
635            "Gas": 6000,
636            "NoBenchmark": true
637        },{
638            "Input": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c0000000000000000000000000000000000000000000000000000000000000009",
639            "Expected": "228e687a379ba154554040f8821f4e41ee2be287c201aa9c3bc02c9dd12f1e691e0fd6ee672d04cfd924ed8fdc7ba5f2d06c53c1edc30f65f2af5a5b97f0a76a",
640            "Name": "cdetrio9",
641            "Gas": 6000,
642            "NoBenchmark": true
643        },{
644            "Input": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c0000000000000000000000000000000000000000000000000000000000000001",
645            "Expected": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c",
646            "Name": "cdetrio10",
647            "Gas": 6000,
648            "NoBenchmark": true
649        },{
650            "Input": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
651            "Expected": "00a1a234d08efaa2616607e31eca1980128b00b415c845ff25bba3afcb81dc00242077290ed33906aeb8e42fd98c41bcb9057ba03421af3f2d08cfc441186024",
652            "Name": "cdetrio11",
653            "Gas": 6000,
654            "NoBenchmark": false
655        },{
656            "Input": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d9830644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000",
657            "Expected": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b8692929ee761a352600f54921df9bf472e66217e7bb0cee9032e00acc86b3c8bfaf",
658            "Name": "cdetrio12",
659            "Gas": 6000,
660            "NoBenchmark": true
661        },{
662            "Input": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d980000000000000000000000000000000100000000000000000000000000000000",
663            "Expected": "1071b63011e8c222c5a771dfa03c2e11aac9666dd097f2c620852c3951a4376a2f46fe2f73e1cf310a168d56baa5575a8319389d7bfa6b29ee2d908305791434",
664            "Name": "cdetrio13",
665            "Gas": 6000,
666            "NoBenchmark": true
667        },{
668            "Input": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d980000000000000000000000000000000000000000000000000000000000000009",
669            "Expected": "19f75b9dd68c080a688774a6213f131e3052bd353a304a189d7a2ee367e3c2582612f545fb9fc89fde80fd81c68fc7dcb27fea5fc124eeda69433cf5c46d2d7f",
670            "Name": "cdetrio14",
671            "Gas": 6000,
672            "NoBenchmark": true
673        },{
674            "Input": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d980000000000000000000000000000000000000000000000000000000000000001",
675            "Expected": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98",
676            "Name": "cdetrio15",
677            "Gas": 6000,
678            "NoBenchmark": true
679        }
680        ]"#;
681
682        #[derive(Deserialize)]
683        #[serde(rename_all = "PascalCase")]
684        struct TestCase {
685            input: String,
686            expected: String,
687        }
688
689        let test_cases: Vec<TestCase> = serde_json::from_str(test_data).unwrap();
690
691        test_cases.iter().for_each(|test| {
692            let input = array_bytes::hex2bytes_unchecked(&test.input);
693            let result = alt_bn128_multiplication(&input);
694            assert!(result.is_ok());
695            let expected = array_bytes::hex2bytes_unchecked(&test.expected);
696            assert_eq!(result.unwrap(), expected);
697        });
698    }
699
700    #[test]
701    fn alt_bn128_pairing_test() {
702        use serde_derive::Deserialize;
703
704        let test_data = r#"[
705        {
706            "Input": "1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa",
707            "Expected": "0000000000000000000000000000000000000000000000000000000000000001",
708            "Name": "jeff1",
709            "Gas": 113000,
710            "NoBenchmark": false
711        },{
712            "Input": "2eca0c7238bf16e83e7a1e6c5d49540685ff51380f309842a98561558019fc0203d3260361bb8451de5ff5ecd17f010ff22f5c31cdf184e9020b06fa5997db841213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f06967a1237ebfeca9aaae0d6d0bab8e28c198c5a339ef8a2407e31cdac516db922160fa257a5fd5b280642ff47b65eca77e626cb685c84fa6d3b6882a283ddd1198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa",
713            "Expected": "0000000000000000000000000000000000000000000000000000000000000001",
714            "Name": "jeff2",
715            "Gas": 113000,
716            "NoBenchmark": false
717        },{
718            "Input": "0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd216da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba2e89718ad33c8bed92e210e81d1853435399a271913a6520736a4729cf0d51eb01a9e2ffa2e92599b68e44de5bcf354fa2642bd4f26b259daa6f7ce3ed57aeb314a9a87b789a58af499b314e13c3d65bede56c07ea2d418d6874857b70763713178fb49a2d6cd347dc58973ff49613a20757d0fcc22079f9abd10c3baee245901b9e027bd5cfc2cb5db82d4dc9677ac795ec500ecd47deee3b5da006d6d049b811d7511c78158de484232fc68daf8a45cf217d1c2fae693ff5871e8752d73b21198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa",
719            "Expected": "0000000000000000000000000000000000000000000000000000000000000001",
720            "Name": "jeff3",
721            "Gas": 113000,
722            "NoBenchmark": false
723        },{
724            "Input": "2f2ea0b3da1e8ef11914acf8b2e1b32d99df51f5f4f206fc6b947eae860eddb6068134ddb33dc888ef446b648d72338684d678d2eb2371c61a50734d78da4b7225f83c8b6ab9de74e7da488ef02645c5a16a6652c3c71a15dc37fe3a5dcb7cb122acdedd6308e3bb230d226d16a105295f523a8a02bfc5e8bd2da135ac4c245d065bbad92e7c4e31bf3757f1fe7362a63fbfee50e7dc68da116e67d600d9bf6806d302580dc0661002994e7cd3a7f224e7ddc27802777486bf80f40e4ca3cfdb186bac5188a98c45e6016873d107f5cd131f3a3e339d0375e58bd6219347b008122ae2b09e539e152ec5364e7e2204b03d11d3caa038bfc7cd499f8176aacbee1f39e4e4afc4bc74790a4a028aff2c3d2538731fb755edefd8cb48d6ea589b5e283f150794b6736f670d6a1033f9b46c6f5204f50813eb85c8dc4b59db1c5d39140d97ee4d2b36d99bc49974d18ecca3e7ad51011956051b464d9e27d46cc25e0764bb98575bd466d32db7b15f582b2d5c452b36aa394b789366e5e3ca5aabd415794ab061441e51d01e94640b7e3084a07e02c78cf3103c542bc5b298669f211b88da1679b0b64a63b7e0e7bfe52aae524f73a55be7fe70c7e9bfc94b4cf0da1213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f",
725            "Expected": "0000000000000000000000000000000000000000000000000000000000000001",
726            "Name": "jeff4",
727            "Gas": 147000,
728            "NoBenchmark": false
729        },{
730            "Input": "20a754d2071d4d53903e3b31a7e98ad6882d58aec240ef981fdf0a9d22c5926a29c853fcea789887315916bbeb89ca37edb355b4f980c9a12a94f30deeed30211213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f1abb4a25eb9379ae96c84fff9f0540abcfc0a0d11aeda02d4f37e4baf74cb0c11073b3ff2cdbb38755f8691ea59e9606696b3ff278acfc098fa8226470d03869217cee0a9ad79a4493b5253e2e4e3a39fc2df38419f230d341f60cb064a0ac290a3d76f140db8418ba512272381446eb73958670f00cf46f1d9e64cba057b53c26f64a8ec70387a13e41430ed3ee4a7db2059cc5fc13c067194bcc0cb49a98552fd72bd9edb657346127da132e5b82ab908f5816c826acb499e22f2412d1a2d70f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd2198a1f162a73261f112401aa2db79c7dab1533c9935c77290a6ce3b191f2318d198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa",
731            "Expected": "0000000000000000000000000000000000000000000000000000000000000001",
732            "Name": "jeff5",
733            "Gas": 147000,
734            "NoBenchmark": false
735        },{
736            "Input": "1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c103188585e2364128fe25c70558f1560f4f9350baf3959e603cc91486e110936198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa",
737            "Expected": "0000000000000000000000000000000000000000000000000000000000000000",
738            "Name": "jeff6",
739            "Gas": 113000,
740            "NoBenchmark": false
741        },{
742            "Input": "",
743            "Expected": "0000000000000000000000000000000000000000000000000000000000000001",
744            "Name": "empty_data",
745            "Gas": 45000,
746            "NoBenchmark": false
747        },{
748            "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa",
749            "Expected": "0000000000000000000000000000000000000000000000000000000000000000",
750            "Name": "one_point",
751            "Gas": 79000,
752            "NoBenchmark": false
753        },{
754            "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d",
755            "Expected": "0000000000000000000000000000000000000000000000000000000000000001",
756            "Name": "two_point_match_2",
757            "Gas": 113000,
758            "NoBenchmark": false
759        },{
760            "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa",
761            "Expected": "0000000000000000000000000000000000000000000000000000000000000001",
762            "Name": "two_point_match_3",
763            "Gas": 113000,
764            "NoBenchmark": false
765        },{
766            "Input": "105456a333e6d636854f987ea7bb713dfd0ae8371a72aea313ae0c32c0bf10160cf031d41b41557f3e7e3ba0c51bebe5da8e6ecd855ec50fc87efcdeac168bcc0476be093a6d2b4bbf907172049874af11e1b6267606e00804d3ff0037ec57fd3010c68cb50161b7d1d96bb71edfec9880171954e56871abf3d93cc94d745fa114c059d74e5b6c4ec14ae5864ebe23a71781d86c29fb8fb6cce94f70d3de7a2101b33461f39d9e887dbb100f170a2345dde3c07e256d1dfa2b657ba5cd030427000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021a2c3013d2ea92e13c800cde68ef56a294b883f6ac35d25f587c09b1b3c635f7290158a80cd3d66530f74dc94c94adb88f5cdb481acca997b6e60071f08a115f2f997f3dbd66a7afe07fe7862ce239edba9e05c5afff7f8a1259c9733b2dfbb929d1691530ca701b4a106054688728c9972c8512e9789e9567aae23e302ccd75",
767            "Expected": "0000000000000000000000000000000000000000000000000000000000000001",
768            "Name": "two_point_match_4",
769            "Gas": 113000,
770            "NoBenchmark": false
771        },{
772            "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d",
773            "Expected": "0000000000000000000000000000000000000000000000000000000000000001",
774            "Name": "ten_point_match_1",
775            "Gas": 385000,
776            "NoBenchmark": false
777        },{
778            "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa",
779            "Expected": "0000000000000000000000000000000000000000000000000000000000000001",
780            "Name": "ten_point_match_2",
781            "Gas": 385000,
782            "NoBenchmark": false
783        },{
784            "Input": "105456a333e6d636854f987ea7bb713dfd0ae8371a72aea313ae0c32c0bf10160cf031d41b41557f3e7e3ba0c51bebe5da8e6ecd855ec50fc87efcdeac168bcc0476be093a6d2b4bbf907172049874af11e1b6267606e00804d3ff0037ec57fd3010c68cb50161b7d1d96bb71edfec9880171954e56871abf3d93cc94d745fa114c059d74e5b6c4ec14ae5864ebe23a71781d86c29fb8fb6cce94f70d3de7a2101b33461f39d9e887dbb100f170a2345dde3c07e256d1dfa2b657ba5cd030427000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021a2c3013d2ea92e13c800cde68ef56a294b883f6ac35d25f587c09b1b3c635f7290158a80cd3d66530f74dc94c94adb88f5cdb481acca997b6e60071f08a115f2f997f3dbd66a7afe07fe7862ce239edba9e05c5afff7f8a1259c9733b2dfbb929d1691530ca701b4a106054688728c9972c8512e9789e9567aae23e302ccd75",
785            "Expected": "0000000000000000000000000000000000000000000000000000000000000001",
786            "Name": "ten_point_match_3",
787            "Gas": 113000,
788            "NoBenchmark": false
789        }
790        ]"#;
791
792        #[derive(Deserialize)]
793        #[serde(rename_all = "PascalCase")]
794        struct TestCase {
795            input: String,
796            expected: String,
797        }
798
799        let test_cases: Vec<TestCase> = serde_json::from_str(test_data).unwrap();
800
801        test_cases.iter().for_each(|test| {
802            let input = array_bytes::hex2bytes_unchecked(&test.input);
803            let result = alt_bn128_pairing(&input);
804            assert!(result.is_ok());
805            let expected = array_bytes::hex2bytes_unchecked(&test.expected);
806            assert_eq!(result.unwrap(), expected);
807        });
808    }
809
810    #[test]
811    fn alt_bn128_pairing_invalid_length() {
812        use ark_ff::{BigInteger, BigInteger256};
813
814        let input = [0; 193];
815        let result = alt_bn128_pairing(&input);
816        assert!(result.is_ok());
817        let expected = BigInteger256::from(1u64).to_bytes_be();
818        assert_eq!(result.unwrap(), expected);
819    }
820}