1use crate::prelude::types::{make_address, Address, EthGas};
2use crate::prelude::{Borrowed, PhantomData, Vec};
3use crate::utils;
4use crate::{Byzantium, EvmPrecompileResult, HardFork, Istanbul, Precompile, PrecompileOutput};
5use aurora_evm::{Context, ExitError};
6use bn::Group;
7use core::num::{NonZeroU64, NonZeroUsize};
8
9mod costs {
11 use crate::prelude::types::EthGas;
12
13 pub(super) const BYZANTIUM_ADD: EthGas = EthGas::new(500);
15
16 pub(super) const BYZANTIUM_MUL: EthGas = EthGas::new(40_000);
18
19 pub(super) const BYZANTIUM_PAIR_PER_POINT: EthGas = EthGas::new(80_000);
21
22 pub(super) const BYZANTIUM_PAIR_BASE: EthGas = EthGas::new(100_000);
24
25 pub(super) const ISTANBUL_ADD: EthGas = EthGas::new(150);
27
28 pub(super) const ISTANBUL_MUL: EthGas = EthGas::new(6_000);
30
31 pub(super) const ISTANBUL_PAIR_PER_POINT: EthGas = EthGas::new(34_000);
33
34 pub(super) const ISTANBUL_PAIR_BASE: EthGas = EthGas::new(45_000);
36}
37
38mod consts {
40 use crate::prelude::Borrowed;
41 use aurora_evm::ExitError;
42
43 pub(super) const ADD_INPUT_LEN: usize = 128;
45
46 pub(super) const MUL_INPUT_LEN: usize = 128;
48
49 pub(super) const PAIR_ELEMENT_LEN: usize = 192;
51
52 pub(super) const SCALAR_LEN: usize = 32;
54
55 pub(super) const POINT_LEN: usize = 64;
57
58 #[cfg(feature = "contract")]
60 pub(super) const POINT_PAIR_LEN: usize = 128;
61
62 pub(super) const OUTPUT_LEN: usize = 64;
64
65 pub(super) const ERR_BIG_ENDIAN: ExitError = ExitError::Other(Borrowed("ERR_BIG_ENDIAN"));
68}
69
70#[cfg(feature = "contract")]
71mod type_arith {
72 pub struct Double<const P: usize>;
73 pub trait Is<const S: usize> {}
74 impl Is<128> for Double<64> {}
75 impl Is<64> for Double<32> {}
76 impl Is<32> for Double<16> {}
77}
78
79#[cfg(feature = "contract")]
80trait HostFnEncode {
81 type Encoded;
82
83 fn host_fn_encode(self) -> Self::Encoded;
84}
85
86#[cfg(feature = "contract")]
87fn concat_low_high<const P: usize, const S: usize>(low: [u8; P], high: [u8; P]) -> [u8; S]
88where
89 type_arith::Double<P>: type_arith::Is<S>,
90{
91 let mut bytes = [0u8; S];
92 bytes[0..P].copy_from_slice(&low);
93 bytes[P..S].copy_from_slice(&high);
94 bytes
95}
96
97#[cfg(feature = "contract")]
98impl HostFnEncode for bn::Fr {
99 type Encoded = [u8; consts::SCALAR_LEN];
100
101 fn host_fn_encode(self) -> Self::Encoded {
102 let [low, high] = self.into_u256().0;
103 concat_low_high(low.to_le_bytes(), high.to_le_bytes())
104 }
105}
106
107#[cfg(feature = "contract")]
108impl HostFnEncode for bn::Fq {
109 type Encoded = [u8; consts::SCALAR_LEN];
110
111 fn host_fn_encode(self) -> Self::Encoded {
112 let [low, high] = self.into_u256().0;
113 concat_low_high(low.to_le_bytes(), high.to_le_bytes())
114 }
115}
116
117#[cfg(feature = "contract")]
118impl HostFnEncode for bn::Fq2 {
119 type Encoded = [u8; consts::SCALAR_LEN * 2];
120
121 fn host_fn_encode(self) -> Self::Encoded {
122 let [real_low, real_high] = self.real().into_u256().0;
123 let real: [u8; consts::SCALAR_LEN] =
124 concat_low_high(real_low.to_le_bytes(), real_high.to_le_bytes());
125
126 let [imaginary_low, imaginary_high] = self.imaginary().into_u256().0;
127 let imaginary: [u8; consts::SCALAR_LEN] =
128 concat_low_high(imaginary_low.to_le_bytes(), imaginary_high.to_le_bytes());
129 concat_low_high(real, imaginary)
130 }
131}
132
133#[cfg(feature = "contract")]
134impl HostFnEncode for bn::G1 {
135 type Encoded = [u8; consts::POINT_LEN];
136
137 fn host_fn_encode(self) -> Self::Encoded {
138 bn::AffineG1::from_jacobian(self).map_or_else(
139 || [0u8; consts::POINT_LEN],
140 |p| {
141 let (px, py) = (p.x().host_fn_encode(), p.y().host_fn_encode());
142 concat_low_high(px, py)
143 },
144 )
145 }
146}
147
148#[cfg(feature = "contract")]
149impl HostFnEncode for bn::G2 {
150 type Encoded = [u8; consts::POINT_PAIR_LEN];
151
152 fn host_fn_encode(self) -> Self::Encoded {
153 bn::AffineG2::from_jacobian(self).map_or_else(
154 || [0u8; consts::POINT_PAIR_LEN],
155 |g2| {
156 let x = g2.x().host_fn_encode();
157 let y = g2.y().host_fn_encode();
158 concat_low_high(x, y)
159 },
160 )
161 }
162}
163
164fn read_point(input: &[u8], pos: usize) -> Result<bn::G1, ExitError> {
166 use bn::{AffineG1, Fq, G1};
167 if input.len() < (pos + consts::SCALAR_LEN * 2) {
168 return Err(ExitError::Other(Borrowed("INVALID_INPUT_LENGTH")));
169 }
170
171 let px = Fq::from_slice(&input[pos..(pos + consts::SCALAR_LEN)])
172 .map_err(|_e| ExitError::Other(Borrowed("ERR_FQ_INCORRECT")))?;
173 let py = Fq::from_slice(&input[(pos + consts::SCALAR_LEN)..(pos + consts::SCALAR_LEN * 2)])
174 .map_err(|_e| ExitError::Other(Borrowed("ERR_FQ_INCORRECT")))?;
175
176 Ok(if px == Fq::zero() && py == Fq::zero() {
177 G1::zero()
178 } else {
179 AffineG1::new(px, py)
180 .map_err(|_| ExitError::Other(Borrowed("ERR_BN128_INVALID_POINT")))?
181 .into()
182 })
183}
184
185#[derive(Default)]
186pub struct Bn256Add<HF: HardFork>(PhantomData<HF>);
187
188impl<HF: HardFork> Bn256Add<HF> {
189 pub const ADDRESS: Address = make_address(0, 6);
190
191 #[must_use]
192 pub const fn new() -> Self {
193 Self(PhantomData)
194 }
195}
196
197impl<HF: HardFork> Bn256Add<HF> {
198 fn run_inner(input: &[u8], _context: &Context) -> Result<Vec<u8>, ExitError> {
199 let mut input = input.to_vec();
200 input.resize(consts::ADD_INPUT_LEN, 0);
201
202 let p1 = read_point(&input, 0)?;
203 let p2 = read_point(&input, consts::POINT_LEN)?;
204
205 let output = Self::execute(p1, p2)?;
206 Ok(output.to_vec())
207 }
208
209 #[cfg(not(feature = "contract"))]
210 fn execute(p1: bn::G1, p2: bn::G1) -> Result<[u8; consts::OUTPUT_LEN], ExitError> {
211 let mut output = [0u8; consts::POINT_LEN];
212 if let Some(sum) = bn::AffineG1::from_jacobian(p1 + p2) {
213 sum.x()
214 .to_big_endian(&mut output[0..consts::SCALAR_LEN])
215 .map_err(|_| consts::ERR_BIG_ENDIAN)?;
216 sum.y()
217 .to_big_endian(&mut output[consts::SCALAR_LEN..consts::SCALAR_LEN * 2])
218 .map_err(|_| consts::ERR_BIG_ENDIAN)?;
219 }
220 Ok(output)
221 }
222
223 #[cfg(feature = "contract")]
224 #[allow(clippy::unnecessary_wraps)]
225 fn execute(p1: bn::G1, p2: bn::G1) -> Result<[u8; consts::OUTPUT_LEN], ExitError> {
226 Ok(aurora_engine_sdk::alt_bn128_g1_sum(
227 p1.host_fn_encode(),
228 p2.host_fn_encode(),
229 ))
230 }
231}
232
233impl Precompile for Bn256Add<Byzantium> {
234 fn required_gas(_input: &[u8]) -> Result<EthGas, ExitError> {
235 Ok(costs::BYZANTIUM_ADD)
236 }
237
238 fn run(
244 &self,
245 input: &[u8],
246 target_gas: Option<EthGas>,
247 context: &Context,
248 _is_static: bool,
249 ) -> EvmPrecompileResult {
250 let cost = Self::required_gas(input)?;
251 if let Some(target_gas) = target_gas {
252 if cost > target_gas {
253 return Err(ExitError::OutOfGas);
254 }
255 }
256
257 let output = Self::run_inner(input, context)?;
258 Ok(PrecompileOutput::without_logs(cost, output))
259 }
260}
261
262impl Precompile for Bn256Add<Istanbul> {
263 fn required_gas(_input: &[u8]) -> Result<EthGas, ExitError> {
264 Ok(costs::ISTANBUL_ADD)
265 }
266
267 fn run(
273 &self,
274 input: &[u8],
275 target_gas: Option<EthGas>,
276 context: &Context,
277 _is_static: bool,
278 ) -> EvmPrecompileResult {
279 let cost = Self::required_gas(input)?;
280 if let Some(target_gas) = target_gas {
281 if cost > target_gas {
282 return Err(ExitError::OutOfGas);
283 }
284 }
285 let output = Self::run_inner(input, context)?;
286 Ok(PrecompileOutput::without_logs(cost, output))
287 }
288}
289
290#[derive(Default)]
291pub struct Bn256Mul<HF: HardFork>(PhantomData<HF>);
292
293impl<HF: HardFork> Bn256Mul<HF> {
294 pub const ADDRESS: Address = make_address(0, 7);
295
296 #[must_use]
297 pub const fn new() -> Self {
298 Self(PhantomData)
299 }
300}
301
302impl<HF: HardFork> Bn256Mul<HF> {
303 fn run_inner(input: &[u8], _context: &Context) -> Result<Vec<u8>, ExitError> {
304 let mut input = input.to_vec();
305 input.resize(consts::MUL_INPUT_LEN, 0);
306
307 let p = read_point(&input, 0)?;
308 let fr =
309 bn::Fr::from_slice(&input[consts::POINT_LEN..consts::POINT_LEN + consts::SCALAR_LEN])
310 .map_err(|_e| ExitError::Other(Borrowed("ERR_BN128_INVALID_FR")))?;
311
312 let output = Self::execute(p, fr)?;
313 Ok(output.to_vec())
314 }
315
316 #[cfg(not(feature = "contract"))]
317 fn execute(p: bn::G1, fr: bn::Fr) -> Result<[u8; consts::OUTPUT_LEN], ExitError> {
318 let mut output = [0u8; consts::OUTPUT_LEN];
319 if let Some(mul) = bn::AffineG1::from_jacobian(p * fr) {
320 mul.x()
321 .into_u256()
322 .to_big_endian(&mut output[0..consts::SCALAR_LEN])
323 .map_err(|_e| consts::ERR_BIG_ENDIAN)?;
324 mul.y()
325 .into_u256()
326 .to_big_endian(&mut output[consts::SCALAR_LEN..consts::SCALAR_LEN * 2])
327 .map_err(|_e| consts::ERR_BIG_ENDIAN)?;
328 }
329 Ok(output)
330 }
331
332 #[cfg(feature = "contract")]
333 #[allow(clippy::unnecessary_wraps)]
334 fn execute(g1: bn::G1, fr: bn::Fr) -> Result<[u8; consts::OUTPUT_LEN], ExitError> {
335 Ok(aurora_engine_sdk::alt_bn128_g1_scalar_multiple(
336 g1.host_fn_encode(),
337 fr.host_fn_encode(),
338 ))
339 }
340}
341
342impl Precompile for Bn256Mul<Byzantium> {
343 fn required_gas(_input: &[u8]) -> Result<EthGas, ExitError> {
344 Ok(costs::BYZANTIUM_MUL)
345 }
346
347 fn run(
352 &self,
353 input: &[u8],
354 target_gas: Option<EthGas>,
355 context: &Context,
356 _is_static: bool,
357 ) -> EvmPrecompileResult {
358 let cost = Self::required_gas(input)?;
359 if let Some(target_gas) = target_gas {
360 if cost > target_gas {
361 return Err(ExitError::OutOfGas);
362 }
363 }
364
365 let output = Self::run_inner(input, context)?;
366 Ok(PrecompileOutput::without_logs(cost, output))
367 }
368}
369
370impl Precompile for Bn256Mul<Istanbul> {
371 fn required_gas(_input: &[u8]) -> Result<EthGas, ExitError> {
372 Ok(costs::ISTANBUL_MUL)
373 }
374
375 fn run(
380 &self,
381 input: &[u8],
382 target_gas: Option<EthGas>,
383 context: &Context,
384 _is_static: bool,
385 ) -> EvmPrecompileResult {
386 let cost = Self::required_gas(input)?;
387 if let Some(target_gas) = target_gas {
388 if cost > target_gas {
389 return Err(ExitError::OutOfGas);
390 }
391 }
392
393 let output = Self::run_inner(input, context)?;
394 Ok(PrecompileOutput::without_logs(cost, output))
395 }
396}
397
398#[derive(Default)]
399pub struct Bn256Pair<HF: HardFork>(PhantomData<HF>);
400
401impl<HF: HardFork> Bn256Pair<HF> {
402 pub const ADDRESS: Address = make_address(0, 8);
403
404 #[must_use]
405 pub const fn new() -> Self {
406 Self(PhantomData)
407 }
408}
409
410impl<HF: HardFork> Bn256Pair<HF> {
411 fn run_inner(input: &[u8], _context: &Context) -> Result<Vec<u8>, ExitError> {
412 if input.len() % consts::PAIR_ELEMENT_LEN != 0 {
413 return Err(ExitError::Other(Borrowed("ERR_BN128_INVALID_LEN")));
414 }
415
416 let output = if input.is_empty() {
417 bn::arith::U256::one()
418 } else {
419 let elements = input.len() / consts::PAIR_ELEMENT_LEN;
420 let mut vals = Vec::with_capacity(elements);
421 for idx in 0..elements {
422 let ax = bn::Fq::from_slice(
423 &input[(idx * consts::PAIR_ELEMENT_LEN)
424 ..(idx * consts::PAIR_ELEMENT_LEN + consts::SCALAR_LEN)],
425 )
426 .map_err(|_e| ExitError::Other(Borrowed("ERR_BN128_INVALID_AX")))?;
427 let ay = bn::Fq::from_slice(
428 &input[(idx * consts::PAIR_ELEMENT_LEN + consts::SCALAR_LEN)
429 ..(idx * consts::PAIR_ELEMENT_LEN + consts::SCALAR_LEN * 2)],
430 )
431 .map_err(|_e| ExitError::Other(Borrowed("ERR_BN128_INVALID_AY")))?;
432 let bay = bn::Fq::from_slice(
433 &input[(idx * consts::PAIR_ELEMENT_LEN + consts::SCALAR_LEN * 2)
434 ..(idx * consts::PAIR_ELEMENT_LEN + consts::SCALAR_LEN * 3)],
435 )
436 .map_err(|_e| ExitError::Other(Borrowed("ERR_BN128_INVALID_BAY")))?;
437 let bax = bn::Fq::from_slice(
438 &input[(idx * consts::PAIR_ELEMENT_LEN + consts::SCALAR_LEN * 3)
439 ..(idx * consts::PAIR_ELEMENT_LEN + consts::SCALAR_LEN * 4)],
440 )
441 .map_err(|_e| ExitError::Other(Borrowed("ERR_BN128_INVALID_BAX")))?;
442 let bby = bn::Fq::from_slice(
443 &input[(idx * consts::PAIR_ELEMENT_LEN + consts::SCALAR_LEN * 4)
444 ..(idx * consts::PAIR_ELEMENT_LEN + consts::SCALAR_LEN * 5)],
445 )
446 .map_err(|_e| ExitError::Other(Borrowed("ERR_BN128_INVALID_BBY")))?;
447 let bbx = bn::Fq::from_slice(
448 &input[(idx * consts::PAIR_ELEMENT_LEN + consts::SCALAR_LEN * 5)
449 ..(idx * consts::PAIR_ELEMENT_LEN + consts::SCALAR_LEN * 6)],
450 )
451 .map_err(|_e| ExitError::Other(Borrowed("ERR_BN128_INVALID_BBX")))?;
452
453 let g1_a = {
454 if ax.is_zero() && ay.is_zero() {
455 bn::G1::zero()
456 } else {
457 bn::AffineG1::new(ax, ay)
458 .map_err(|_e| ExitError::Other(Borrowed("ERR_BN128_INVALID_A")))?
459 .into()
460 }
461 };
462 let g1_b = {
463 let ba = bn::Fq2::new(bax, bay);
464 let bb = bn::Fq2::new(bbx, bby);
465
466 if ba.is_zero() && bb.is_zero() {
467 bn::G2::zero()
468 } else {
469 bn::AffineG2::new(ba, bb)
470 .map_err(|_e| ExitError::Other(Borrowed("ERR_BN128_INVALID_B")))?
471 .into()
472 }
473 };
474 vals.push((g1_a, g1_b));
475 }
476
477 let result = Self::execute(vals);
478 if result {
479 bn::arith::U256::one()
480 } else {
481 bn::arith::U256::zero()
482 }
483 };
484
485 let mut res = crate::vec![0u8; 32];
486 output
487 .to_big_endian(&mut res[0..32])
488 .map_err(|_e| consts::ERR_BIG_ENDIAN)?;
489 Ok(res)
490 }
491
492 #[cfg(not(feature = "contract"))]
493 #[allow(clippy::needless_pass_by_value)]
494 fn execute(vals: Vec<(bn::G1, bn::G2)>) -> bool {
495 bn::pairing_batch(&vals) == bn::Gt::one()
496 }
497
498 #[cfg(feature = "contract")]
499 fn execute(vals: Vec<(bn::G1, bn::G2)>) -> bool {
500 let points = vals
501 .into_iter()
502 .map(|(g1, g2)| (g1.host_fn_encode(), g2.host_fn_encode()));
503 aurora_engine_sdk::alt_bn128_pairing(points)
504 }
505}
506
507impl Precompile for Bn256Pair<Byzantium> {
508 fn required_gas(input: &[u8]) -> Result<EthGas, ExitError> {
509 let input_len = u64::try_from(input.len()).map_err(utils::err_usize_conv)?;
510 let pair_element_len = NonZeroUsize::try_from(consts::PAIR_ELEMENT_LEN)
511 .and_then(NonZeroU64::try_from)
512 .map_err(utils::err_usize_conv)?;
513 Ok(
514 costs::BYZANTIUM_PAIR_PER_POINT * input_len / pair_element_len
515 + costs::BYZANTIUM_PAIR_BASE,
516 )
517 }
518
519 fn run(
524 &self,
525 input: &[u8],
526 target_gas: Option<EthGas>,
527 context: &Context,
528 _is_static: bool,
529 ) -> EvmPrecompileResult {
530 let cost = Self::required_gas(input)?;
531 if let Some(target_gas) = target_gas {
532 if cost > target_gas {
533 return Err(ExitError::OutOfGas);
534 }
535 }
536
537 let output = Self::run_inner(input, context)?;
538 Ok(PrecompileOutput::without_logs(cost, output))
539 }
540}
541
542impl Precompile for Bn256Pair<Istanbul> {
543 fn required_gas(input: &[u8]) -> Result<EthGas, ExitError> {
544 let input_len = u64::try_from(input.len()).map_err(utils::err_usize_conv)?;
545 let pair_element_len = NonZeroUsize::try_from(consts::PAIR_ELEMENT_LEN)
546 .and_then(NonZeroU64::try_from)
547 .map_err(utils::err_usize_conv)?;
548 Ok(
549 costs::ISTANBUL_PAIR_PER_POINT * input_len / pair_element_len
550 + costs::ISTANBUL_PAIR_BASE,
551 )
552 }
553
554 fn run(
559 &self,
560 input: &[u8],
561 target_gas: Option<EthGas>,
562 context: &Context,
563 _is_static: bool,
564 ) -> EvmPrecompileResult {
565 let cost = Self::required_gas(input)?;
566 if let Some(target_gas) = target_gas {
567 if cost > target_gas {
568 return Err(ExitError::OutOfGas);
569 }
570 }
571
572 let output = Self::run_inner(input, context)?;
573 Ok(PrecompileOutput::without_logs(cost, output))
574 }
575}
576
577#[cfg(test)]
578mod tests {
579 use crate::utils::new_context;
580
581 use super::*;
582
583 #[test]
584 fn test_alt_bn128_add() {
585 let input = hex::decode(
586 "\
587 18b18acfb4c2c30276db5411368e7185b311dd124691610c5d3b74034e093dc9\
588 063c909c4720840cb5134cb9f59fa749755796819658d32efc0d288198f37266\
589 07c2b7f58a84bd6145f00c9c2bc0bb1a187f20ff2c92963a88019e7c6a014eed\
590 06614e20c147e940f2d70da3f74c9a17df361706a4485c742bd6788478fa17d7",
591 )
592 .unwrap();
593 let expected = hex::decode(
594 "\
595 2243525c5efd4b9c3d3c45ac0ca3fe4dd85e830a4ce6b65fa1eeaee202839703\
596 301d1d33be6da8e509df21cc35964723180eed7532537db9ae5e7d48f195c915",
597 )
598 .unwrap();
599
600 let res = Bn256Add::<Byzantium>::new()
601 .run(&input, Some(EthGas::new(500)), &new_context(), false)
602 .unwrap()
603 .output;
604 assert_eq!(res, expected);
605
606 let input = hex::decode(
608 "\
609 0000000000000000000000000000000000000000000000000000000000000000\
610 0000000000000000000000000000000000000000000000000000000000000000\
611 0000000000000000000000000000000000000000000000000000000000000000\
612 0000000000000000000000000000000000000000000000000000000000000000",
613 )
614 .unwrap();
615 let expected = hex::decode(
616 "\
617 0000000000000000000000000000000000000000000000000000000000000000\
618 0000000000000000000000000000000000000000000000000000000000000000",
619 )
620 .unwrap();
621
622 let res = Bn256Add::<Byzantium>::new()
623 .run(&input, Some(EthGas::new(500)), &new_context(), false)
624 .unwrap()
625 .output;
626 assert_eq!(res, expected);
627
628 let input = hex::decode(
630 "\
631 0000000000000000000000000000000000000000000000000000000000000000\
632 0000000000000000000000000000000000000000000000000000000000000000\
633 0000000000000000000000000000000000000000000000000000000000000000\
634 0000000000000000000000000000000000000000000000000000000000000000",
635 )
636 .unwrap();
637 let res =
638 Bn256Add::<Byzantium>::new().run(&input, Some(EthGas::new(499)), &new_context(), false);
639 assert!(matches!(res, Err(ExitError::OutOfGas)));
640
641 let input = [0u8; 0];
643 let expected = hex::decode(
644 "\
645 0000000000000000000000000000000000000000000000000000000000000000\
646 0000000000000000000000000000000000000000000000000000000000000000",
647 )
648 .unwrap();
649
650 let res = Bn256Add::<Byzantium>::new()
651 .run(&input, Some(EthGas::new(500)), &new_context(), false)
652 .unwrap()
653 .output;
654 assert_eq!(res, expected);
655
656 let input = hex::decode(
658 "\
659 1111111111111111111111111111111111111111111111111111111111111111\
660 1111111111111111111111111111111111111111111111111111111111111111\
661 1111111111111111111111111111111111111111111111111111111111111111\
662 1111111111111111111111111111111111111111111111111111111111111111",
663 )
664 .unwrap();
665
666 let res =
667 Bn256Add::<Byzantium>::new().run(&input, Some(EthGas::new(500)), &new_context(), false);
668 assert!(matches!(
669 res,
670 Err(ExitError::Other(Borrowed("ERR_BN128_INVALID_POINT")))
671 ));
672 }
673
674 #[test]
675 fn test_alt_bn128_mul() {
676 let input = hex::decode(
677 "\
678 2bd3e6d0f3b142924f5ca7b49ce5b9d54c4703d7ae5648e61d02268b1a0a9fb7\
679 21611ce0a6af85915e2f1d70300909ce2e49dfad4a4619c8390cae66cefdb204\
680 00000000000000000000000000000000000000000000000011138ce750fa15c2",
681 )
682 .unwrap();
683 let expected = hex::decode(
684 "\
685 070a8d6a982153cae4be29d434e8faef8a47b274a053f5a4ee2a6c9c13c31e5c\
686 031b8ce914eba3a9ffb989f9cdd5b0f01943074bf4f0f315690ec3cec6981afc",
687 )
688 .unwrap();
689
690 let res = Bn256Mul::<Byzantium>::new()
691 .run(&input, Some(EthGas::new(40_000)), &new_context(), false)
692 .unwrap()
693 .output;
694 assert_eq!(res, expected);
695
696 let input = hex::decode(
698 "\
699 0000000000000000000000000000000000000000000000000000000000000000\
700 0000000000000000000000000000000000000000000000000000000000000000\
701 0200000000000000000000000000000000000000000000000000000000000000",
702 )
703 .unwrap();
704 let res = Bn256Mul::<Byzantium>::new().run(
705 &input,
706 Some(EthGas::new(39_999)),
707 &new_context(),
708 false,
709 );
710 assert!(matches!(res, Err(ExitError::OutOfGas)));
711
712 let input = hex::decode(
714 "\
715 0000000000000000000000000000000000000000000000000000000000000000\
716 0000000000000000000000000000000000000000000000000000000000000000\
717 0200000000000000000000000000000000000000000000000000000000000000",
718 )
719 .unwrap();
720 let expected = hex::decode(
721 "\
722 0000000000000000000000000000000000000000000000000000000000000000\
723 0000000000000000000000000000000000000000000000000000000000000000",
724 )
725 .unwrap();
726
727 let res = Bn256Mul::<Byzantium>::new()
728 .run(&input, Some(EthGas::new(40_000)), &new_context(), false)
729 .unwrap()
730 .output;
731 assert_eq!(res, expected);
732
733 let input = [0u8; 0];
735 let expected = hex::decode(
736 "\
737 0000000000000000000000000000000000000000000000000000000000000000\
738 0000000000000000000000000000000000000000000000000000000000000000",
739 )
740 .unwrap();
741
742 let res = Bn256Mul::<Byzantium>::new()
743 .run(&input, Some(EthGas::new(40_000)), &new_context(), false)
744 .unwrap()
745 .output;
746 assert_eq!(res, expected);
747
748 let input = hex::decode(
750 "\
751 1111111111111111111111111111111111111111111111111111111111111111\
752 1111111111111111111111111111111111111111111111111111111111111111\
753 0f00000000000000000000000000000000000000000000000000000000000000",
754 )
755 .unwrap();
756
757 let res = Bn256Mul::<Byzantium>::new().run(
758 &input,
759 Some(EthGas::new(40_000)),
760 &new_context(),
761 false,
762 );
763 assert!(matches!(
764 res,
765 Err(ExitError::Other(Borrowed("ERR_BN128_INVALID_POINT")))
766 ));
767 }
768
769 #[test]
770 #[allow(clippy::too_many_lines)]
771 fn test_alt_bn128_pair() {
772 let input = hex::decode(
773 "\
774 1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f59\
775 3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41\
776 209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf7\
777 04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a41678\
778 2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d\
779 120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550\
780 111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c\
781 2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411\
782 198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2\
783 1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed\
784 090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b\
785 12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa",
786 )
787 .unwrap();
788 let expected =
789 hex::decode("0000000000000000000000000000000000000000000000000000000000000001")
790 .unwrap();
791
792 let res = Bn256Pair::<Byzantium>::new()
793 .run(&input, Some(EthGas::new(260_000)), &new_context(), false)
794 .unwrap()
795 .output;
796 assert_eq!(res, expected);
797
798 let input = hex::decode(
800 "\
801 1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f59\
802 3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41\
803 209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf7\
804 04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a41678\
805 2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d\
806 120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550\
807 111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c\
808 2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411\
809 198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2\
810 1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed\
811 090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b\
812 12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa",
813 )
814 .unwrap();
815 let res = Bn256Pair::<Byzantium>::new().run(
816 &input,
817 Some(EthGas::new(259_999)),
818 &new_context(),
819 false,
820 );
821 assert!(matches!(res, Err(ExitError::OutOfGas)));
822
823 let input = [0u8; 0];
825 let expected =
826 hex::decode("0000000000000000000000000000000000000000000000000000000000000001")
827 .unwrap();
828
829 let res = Bn256Pair::<Byzantium>::new()
830 .run(&input, Some(EthGas::new(260_000)), &new_context(), false)
831 .unwrap()
832 .output;
833 assert_eq!(res, expected);
834
835 let input = hex::decode(
837 "\
838 1111111111111111111111111111111111111111111111111111111111111111\
839 1111111111111111111111111111111111111111111111111111111111111111\
840 1111111111111111111111111111111111111111111111111111111111111111\
841 1111111111111111111111111111111111111111111111111111111111111111\
842 1111111111111111111111111111111111111111111111111111111111111111\
843 1111111111111111111111111111111111111111111111111111111111111111",
844 )
845 .unwrap();
846
847 let res = Bn256Pair::<Byzantium>::new().run(
848 &input,
849 Some(EthGas::new(260_000)),
850 &new_context(),
851 false,
852 );
853 assert!(matches!(
854 res,
855 Err(ExitError::Other(Borrowed("ERR_BN128_INVALID_A")))
856 ));
857
858 let input = hex::decode(
860 "\
861 1111111111111111111111111111111111111111111111111111111111111111\
862 1111111111111111111111111111111111111111111111111111111111111111\
863 111111111111111111111111111111\
864 ",
865 )
866 .unwrap();
867
868 let res = Bn256Pair::<Byzantium>::new().run(
869 &input,
870 Some(EthGas::new(260_000)),
871 &new_context(),
872 false,
873 );
874 assert!(matches!(
875 res,
876 Err(ExitError::Other(Borrowed("ERR_BN128_INVALID_LEN",)))
877 ));
878
879 let input = hex::decode(
881 "\
882 0000000000000000000000000000000000000000000000000000000000000000\
883 0000000000000000000000000000000000000000000000000000000000000000\
884 0000000000000000000000000000000000000000000000000000000000000000\
885 0000000000000000000000000000000000000000000000000000000000000000\
886 0000000000000000000000000000000000000000000000000000000000000000\
887 0000000000000000000000000000000000000000000000000000000000000000",
888 )
889 .unwrap();
890 let expected =
891 hex::decode("0000000000000000000000000000000000000000000000000000000000000001")
892 .unwrap();
893
894 let res = Bn256Pair::<Byzantium>::new()
895 .run(&input, Some(EthGas::new(260_000)), &new_context(), false)
896 .unwrap()
897 .output;
898 assert_eq!(res, expected);
899 }
900}