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