aurora_engine_precompiles/
alt_bn256.rs1use crate::prelude::types::{make_address, Address, EthGas};
2use crate::prelude::{PhantomData, Vec};
3use crate::utils;
4use crate::{Byzantium, EvmPrecompileResult, HardFork, Istanbul, Precompile, PrecompileOutput};
5use aurora_engine_sdk::bn128::PAIR_ELEMENT_LEN;
6use aurora_evm::{Context, ExitError};
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
38#[derive(Default)]
39pub struct Bn256Add<HF: HardFork>(PhantomData<HF>);
40
41impl<HF: HardFork> Bn256Add<HF> {
42 pub const ADDRESS: Address = make_address(0, 6);
43
44 #[must_use]
45 pub const fn new() -> Self {
46 Self(PhantomData)
47 }
48}
49
50impl<HF: HardFork> Bn256Add<HF> {
51 fn run_inner(input: &[u8], _context: &Context) -> Result<Vec<u8>, ExitError> {
52 let output = aurora_engine_sdk::bn128::alt_bn128_g1_sum(input)
53 .map_err(|err| ExitError::Other(err.into()))?;
54
55 Ok(output.to_vec())
56 }
57}
58
59impl Precompile for Bn256Add<Byzantium> {
60 fn required_gas(_input: &[u8]) -> Result<EthGas, ExitError> {
61 Ok(costs::BYZANTIUM_ADD)
62 }
63
64 fn run(
70 &self,
71 input: &[u8],
72 target_gas: Option<EthGas>,
73 context: &Context,
74 _is_static: bool,
75 ) -> EvmPrecompileResult {
76 let cost = Self::required_gas(input)?;
77 if let Some(target_gas) = target_gas {
78 if cost > target_gas {
79 return Err(ExitError::OutOfGas);
80 }
81 }
82
83 let output = Self::run_inner(input, context)?;
84 Ok(PrecompileOutput::without_logs(cost, output))
85 }
86}
87
88impl Precompile for Bn256Add<Istanbul> {
89 fn required_gas(_input: &[u8]) -> Result<EthGas, ExitError> {
90 Ok(costs::ISTANBUL_ADD)
91 }
92
93 fn run(
99 &self,
100 input: &[u8],
101 target_gas: Option<EthGas>,
102 context: &Context,
103 _is_static: bool,
104 ) -> EvmPrecompileResult {
105 let cost = Self::required_gas(input)?;
106 if let Some(target_gas) = target_gas {
107 if cost > target_gas {
108 return Err(ExitError::OutOfGas);
109 }
110 }
111 let output = Self::run_inner(input, context)?;
112 Ok(PrecompileOutput::without_logs(cost, output))
113 }
114}
115
116#[derive(Default)]
117pub struct Bn256Mul<HF: HardFork>(PhantomData<HF>);
118
119impl<HF: HardFork> Bn256Mul<HF> {
120 pub const ADDRESS: Address = make_address(0, 7);
121
122 #[must_use]
123 pub const fn new() -> Self {
124 Self(PhantomData)
125 }
126}
127
128impl<HF: HardFork> Bn256Mul<HF> {
129 fn run_inner(input: &[u8], _context: &Context) -> Result<Vec<u8>, ExitError> {
130 let output = aurora_engine_sdk::bn128::alt_bn128_g1_scalar_multiple(input)
131 .map_err(|err| ExitError::Other(err.into()))?;
132
133 Ok(output.to_vec())
134 }
135}
136
137impl Precompile for Bn256Mul<Byzantium> {
138 fn required_gas(_input: &[u8]) -> Result<EthGas, ExitError> {
139 Ok(costs::BYZANTIUM_MUL)
140 }
141
142 fn run(
147 &self,
148 input: &[u8],
149 target_gas: Option<EthGas>,
150 context: &Context,
151 _is_static: bool,
152 ) -> EvmPrecompileResult {
153 let cost = Self::required_gas(input)?;
154 if let Some(target_gas) = target_gas {
155 if cost > target_gas {
156 return Err(ExitError::OutOfGas);
157 }
158 }
159
160 let output = Self::run_inner(input, context)?;
161 Ok(PrecompileOutput::without_logs(cost, output))
162 }
163}
164
165impl Precompile for Bn256Mul<Istanbul> {
166 fn required_gas(_input: &[u8]) -> Result<EthGas, ExitError> {
167 Ok(costs::ISTANBUL_MUL)
168 }
169
170 fn run(
175 &self,
176 input: &[u8],
177 target_gas: Option<EthGas>,
178 context: &Context,
179 _is_static: bool,
180 ) -> EvmPrecompileResult {
181 let cost = Self::required_gas(input)?;
182 if let Some(target_gas) = target_gas {
183 if cost > target_gas {
184 return Err(ExitError::OutOfGas);
185 }
186 }
187
188 let output = Self::run_inner(input, context)?;
189 Ok(PrecompileOutput::without_logs(cost, output))
190 }
191}
192
193#[derive(Default)]
194pub struct Bn256Pair<HF: HardFork>(PhantomData<HF>);
195
196impl<HF: HardFork> Bn256Pair<HF> {
197 pub const ADDRESS: Address = make_address(0, 8);
198
199 #[must_use]
200 pub const fn new() -> Self {
201 Self(PhantomData)
202 }
203}
204
205impl<HF: HardFork> Bn256Pair<HF> {
206 fn run_inner(input: &[u8], _context: &Context) -> Result<Vec<u8>, ExitError> {
207 let mut pairing_result = crate::vec![0u8; 32];
209 if aurora_engine_sdk::bn128::alt_bn128_pairing(input)
210 .map_err(|err| ExitError::Other(err.into()))?
211 {
212 pairing_result[31] = 1;
214 }
215
216 Ok(pairing_result)
217 }
218}
219
220impl Precompile for Bn256Pair<Byzantium> {
221 fn required_gas(input: &[u8]) -> Result<EthGas, ExitError> {
222 let input_len = u64::try_from(input.len()).map_err(utils::err_usize_conv)?;
223 let pair_element_len = NonZeroUsize::try_from(PAIR_ELEMENT_LEN)
224 .and_then(NonZeroU64::try_from)
225 .map_err(utils::err_usize_conv)?;
226 Ok(
227 costs::BYZANTIUM_PAIR_PER_POINT * input_len / pair_element_len
228 + costs::BYZANTIUM_PAIR_BASE,
229 )
230 }
231
232 fn run(
237 &self,
238 input: &[u8],
239 target_gas: Option<EthGas>,
240 context: &Context,
241 _is_static: bool,
242 ) -> EvmPrecompileResult {
243 let cost = Self::required_gas(input)?;
244 if let Some(target_gas) = target_gas {
245 if cost > target_gas {
246 return Err(ExitError::OutOfGas);
247 }
248 }
249
250 let output = Self::run_inner(input, context)?;
251 Ok(PrecompileOutput::without_logs(cost, output))
252 }
253}
254
255impl Precompile for Bn256Pair<Istanbul> {
256 fn required_gas(input: &[u8]) -> Result<EthGas, ExitError> {
257 let input_len = u64::try_from(input.len()).map_err(utils::err_usize_conv)?;
258 let pair_element_len = NonZeroUsize::try_from(PAIR_ELEMENT_LEN)
259 .and_then(NonZeroU64::try_from)
260 .map_err(utils::err_usize_conv)?;
261 Ok(
262 costs::ISTANBUL_PAIR_PER_POINT * input_len / pair_element_len
263 + costs::ISTANBUL_PAIR_BASE,
264 )
265 }
266
267 fn run(
272 &self,
273 input: &[u8],
274 target_gas: Option<EthGas>,
275 context: &Context,
276 _is_static: bool,
277 ) -> EvmPrecompileResult {
278 let cost = Self::required_gas(input)?;
279 if let Some(target_gas) = target_gas {
280 if cost > target_gas {
281 return Err(ExitError::OutOfGas);
282 }
283 }
284
285 let output = Self::run_inner(input, context)?;
286 Ok(PrecompileOutput::without_logs(cost, output))
287 }
288}
289
290#[cfg(test)]
291mod tests {
292 use crate::utils::new_context;
293 use std::borrow::Cow::Borrowed;
294
295 use super::*;
296
297 #[test]
298 fn test_alt_bn128_add() {
299 let input = hex::decode(
300 "\
301 18b18acfb4c2c30276db5411368e7185b311dd124691610c5d3b74034e093dc9\
302 063c909c4720840cb5134cb9f59fa749755796819658d32efc0d288198f37266\
303 07c2b7f58a84bd6145f00c9c2bc0bb1a187f20ff2c92963a88019e7c6a014eed\
304 06614e20c147e940f2d70da3f74c9a17df361706a4485c742bd6788478fa17d7",
305 )
306 .unwrap();
307 let expected = hex::decode(
308 "\
309 2243525c5efd4b9c3d3c45ac0ca3fe4dd85e830a4ce6b65fa1eeaee202839703\
310 301d1d33be6da8e509df21cc35964723180eed7532537db9ae5e7d48f195c915",
311 )
312 .unwrap();
313
314 let res = Bn256Add::<Byzantium>::new()
315 .run(&input, Some(EthGas::new(500)), &new_context(), false)
316 .unwrap()
317 .output;
318 assert_eq!(res, expected);
319
320 let input = hex::decode(
322 "\
323 0000000000000000000000000000000000000000000000000000000000000000\
324 0000000000000000000000000000000000000000000000000000000000000000\
325 0000000000000000000000000000000000000000000000000000000000000000\
326 0000000000000000000000000000000000000000000000000000000000000000",
327 )
328 .unwrap();
329 let expected = hex::decode(
330 "\
331 0000000000000000000000000000000000000000000000000000000000000000\
332 0000000000000000000000000000000000000000000000000000000000000000",
333 )
334 .unwrap();
335
336 let res = Bn256Add::<Byzantium>::new()
337 .run(&input, Some(EthGas::new(500)), &new_context(), false)
338 .unwrap()
339 .output;
340 assert_eq!(res, expected);
341
342 let input = hex::decode(
344 "\
345 0000000000000000000000000000000000000000000000000000000000000000\
346 0000000000000000000000000000000000000000000000000000000000000000\
347 0000000000000000000000000000000000000000000000000000000000000000\
348 0000000000000000000000000000000000000000000000000000000000000000",
349 )
350 .unwrap();
351 let res =
352 Bn256Add::<Byzantium>::new().run(&input, Some(EthGas::new(499)), &new_context(), false);
353 assert!(matches!(res, Err(ExitError::OutOfGas)));
354
355 let input = [0u8; 0];
357 let expected = hex::decode(
358 "\
359 0000000000000000000000000000000000000000000000000000000000000000\
360 0000000000000000000000000000000000000000000000000000000000000000",
361 )
362 .unwrap();
363
364 let res = Bn256Add::<Byzantium>::new()
365 .run(&input, Some(EthGas::new(500)), &new_context(), false)
366 .unwrap()
367 .output;
368 assert_eq!(res, expected);
369
370 let input = hex::decode(
372 "\
373 1111111111111111111111111111111111111111111111111111111111111111\
374 1111111111111111111111111111111111111111111111111111111111111111\
375 1111111111111111111111111111111111111111111111111111111111111111\
376 1111111111111111111111111111111111111111111111111111111111111111",
377 )
378 .unwrap();
379
380 let res =
381 Bn256Add::<Byzantium>::new().run(&input, Some(EthGas::new(500)), &new_context(), false);
382
383 assert!(matches!(
384 res,
385 Err(ExitError::Other(Borrowed(
386 "ERR_BN_AFFINE_G_FAILED_TO_CREATE"
387 )))
388 ));
389 }
390
391 #[test]
392 fn test_alt_bn128_mul() {
393 let input = hex::decode(
394 "\
395 2bd3e6d0f3b142924f5ca7b49ce5b9d54c4703d7ae5648e61d02268b1a0a9fb7\
396 21611ce0a6af85915e2f1d70300909ce2e49dfad4a4619c8390cae66cefdb204\
397 00000000000000000000000000000000000000000000000011138ce750fa15c2",
398 )
399 .unwrap();
400 let expected = hex::decode(
401 "\
402 070a8d6a982153cae4be29d434e8faef8a47b274a053f5a4ee2a6c9c13c31e5c\
403 031b8ce914eba3a9ffb989f9cdd5b0f01943074bf4f0f315690ec3cec6981afc",
404 )
405 .unwrap();
406
407 let res = Bn256Mul::<Byzantium>::new()
408 .run(&input, Some(EthGas::new(40_000)), &new_context(), false)
409 .unwrap()
410 .output;
411 assert_eq!(res, expected);
412
413 let input = hex::decode(
415 "\
416 0000000000000000000000000000000000000000000000000000000000000000\
417 0000000000000000000000000000000000000000000000000000000000000000\
418 0200000000000000000000000000000000000000000000000000000000000000",
419 )
420 .unwrap();
421 let res = Bn256Mul::<Byzantium>::new().run(
422 &input,
423 Some(EthGas::new(39_999)),
424 &new_context(),
425 false,
426 );
427 assert!(matches!(res, Err(ExitError::OutOfGas)));
428
429 let input = hex::decode(
431 "\
432 0000000000000000000000000000000000000000000000000000000000000000\
433 0000000000000000000000000000000000000000000000000000000000000000\
434 0200000000000000000000000000000000000000000000000000000000000000",
435 )
436 .unwrap();
437 let expected = hex::decode(
438 "\
439 0000000000000000000000000000000000000000000000000000000000000000\
440 0000000000000000000000000000000000000000000000000000000000000000",
441 )
442 .unwrap();
443
444 let res = Bn256Mul::<Byzantium>::new()
445 .run(&input, Some(EthGas::new(40_000)), &new_context(), false)
446 .unwrap()
447 .output;
448 assert_eq!(res, expected);
449
450 let input = [0u8; 0];
452 let expected = hex::decode(
453 "\
454 0000000000000000000000000000000000000000000000000000000000000000\
455 0000000000000000000000000000000000000000000000000000000000000000",
456 )
457 .unwrap();
458
459 let res = Bn256Mul::<Byzantium>::new()
460 .run(&input, Some(EthGas::new(40_000)), &new_context(), false)
461 .unwrap()
462 .output;
463 assert_eq!(res, expected);
464
465 let input = hex::decode(
467 "\
468 1111111111111111111111111111111111111111111111111111111111111111\
469 1111111111111111111111111111111111111111111111111111111111111111\
470 0f00000000000000000000000000000000000000000000000000000000000000",
471 )
472 .unwrap();
473
474 let res = Bn256Mul::<Byzantium>::new().run(
475 &input,
476 Some(EthGas::new(40_000)),
477 &new_context(),
478 false,
479 );
480 assert!(matches!(
481 res,
482 Err(ExitError::Other(Borrowed(
483 "ERR_BN_AFFINE_G_FAILED_TO_CREATE"
484 )))
485 ));
486 }
487
488 #[test]
489 #[allow(clippy::too_many_lines)]
490 fn test_alt_bn128_pair() {
491 let input = hex::decode(
492 "\
493 1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f59\
494 3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41\
495 209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf7\
496 04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a41678\
497 2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d\
498 120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550\
499 111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c\
500 2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411\
501 198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2\
502 1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed\
503 090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b\
504 12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa",
505 )
506 .unwrap();
507 let expected =
508 hex::decode("0000000000000000000000000000000000000000000000000000000000000001")
509 .unwrap();
510
511 let res = Bn256Pair::<Byzantium>::new()
512 .run(&input, Some(EthGas::new(260_000)), &new_context(), false)
513 .unwrap()
514 .output;
515 assert_eq!(res, expected);
516
517 let input = hex::decode(
519 "\
520 1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f59\
521 3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41\
522 209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf7\
523 04bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a41678\
524 2bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d\
525 120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550\
526 111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c\
527 2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411\
528 198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2\
529 1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed\
530 090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b\
531 12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa",
532 )
533 .unwrap();
534 let res = Bn256Pair::<Byzantium>::new().run(
535 &input,
536 Some(EthGas::new(259_999)),
537 &new_context(),
538 false,
539 );
540 assert!(matches!(res, Err(ExitError::OutOfGas)));
541
542 let input = [0u8; 0];
544 let expected =
545 hex::decode("0000000000000000000000000000000000000000000000000000000000000001")
546 .unwrap();
547
548 let res = Bn256Pair::<Byzantium>::new()
549 .run(&input, Some(EthGas::new(260_000)), &new_context(), false)
550 .unwrap()
551 .output;
552 assert_eq!(res, expected);
553
554 let input = hex::decode(
556 "\
557 1111111111111111111111111111111111111111111111111111111111111111\
558 1111111111111111111111111111111111111111111111111111111111111111\
559 1111111111111111111111111111111111111111111111111111111111111111\
560 1111111111111111111111111111111111111111111111111111111111111111\
561 1111111111111111111111111111111111111111111111111111111111111111\
562 1111111111111111111111111111111111111111111111111111111111111111",
563 )
564 .unwrap();
565
566 let res = Bn256Pair::<Byzantium>::new().run(
567 &input,
568 Some(EthGas::new(260_000)),
569 &new_context(),
570 false,
571 );
572 assert!(matches!(
573 res,
574 Err(ExitError::Other(Borrowed(
575 "ERR_BN_AFFINE_G_FAILED_TO_CREATE"
576 )))
577 ));
578
579 let input = hex::decode(
581 "\
582 1111111111111111111111111111111111111111111111111111111111111111\
583 1111111111111111111111111111111111111111111111111111111111111111\
584 111111111111111111111111111111\
585 ",
586 )
587 .unwrap();
588
589 let res = Bn256Pair::<Byzantium>::new().run(
590 &input,
591 Some(EthGas::new(260_000)),
592 &new_context(),
593 false,
594 );
595 assert!(matches!(
596 res,
597 Err(ExitError::Other(Borrowed("ERR_BN_INVALID_PAIR_LEN",)))
598 ));
599
600 let input = hex::decode(
602 "\
603 0000000000000000000000000000000000000000000000000000000000000000\
604 0000000000000000000000000000000000000000000000000000000000000000\
605 0000000000000000000000000000000000000000000000000000000000000000\
606 0000000000000000000000000000000000000000000000000000000000000000\
607 0000000000000000000000000000000000000000000000000000000000000000\
608 0000000000000000000000000000000000000000000000000000000000000000",
609 )
610 .unwrap();
611 let expected =
612 hex::decode("0000000000000000000000000000000000000000000000000000000000000001")
613 .unwrap();
614
615 let res = Bn256Pair::<Byzantium>::new()
616 .run(&input, Some(EthGas::new(260_000)), &new_context(), false)
617 .unwrap()
618 .output;
619 assert_eq!(res, expected);
620 }
621}