aurora_engine_modexp/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2// All `as` conversions in this code base have been carefully reviewed
3// and are safe.
4#![allow(
5    clippy::as_conversions,
6    clippy::cast_possible_wrap,
7    clippy::cast_possible_truncation,
8    clippy::cast_lossless,
9    clippy::many_single_char_names
10)]
11
12mod arith;
13mod maybe_std;
14mod mpnat;
15
16use maybe_std::Vec;
17
18/// Trait providing the interface for the modexp function.
19/// The implementation provided by this crate is `AuroraModExp` below,
20/// but other users of Aurora Engine may wish to select a different implementation.
21pub trait ModExpAlgorithm: 'static {
22    /// Computes `(base ^ exp) % modulus`, where all values are given as big-endian encoded bytes.
23    fn modexp(base: &[u8], exp: &[u8], modulus: &[u8]) -> Vec<u8>;
24}
25
26pub struct AuroraModExp;
27
28impl ModExpAlgorithm for AuroraModExp {
29    fn modexp(base: &[u8], exp: &[u8], modulus: &[u8]) -> Vec<u8> {
30        modexp(base, exp, modulus)
31    }
32}
33
34/// Computes `(base ^ exp) % modulus`, where all values are given as big-endian
35/// encoded bytes.
36#[must_use]
37pub fn modexp(base: &[u8], exp: &[u8], modulus: &[u8]) -> Vec<u8> {
38    let mut x = mpnat::MPNat::from_big_endian(base);
39    let m = mpnat::MPNat::from_big_endian(modulus);
40    if m.digits.len() == 1 && m.digits[0] == 0 {
41        return Vec::new();
42    }
43    let result = x.modpow(exp, &m);
44    result.to_big_endian()
45}
46
47#[cfg(feature = "bench")]
48pub fn modexp_ibig(base: &[u8], exp: &[u8], modulus: &[u8]) -> Vec<u8> {
49    use num::Zero;
50
51    let base = ibig::UBig::from_be_bytes(base);
52    let modulus = ibig::UBig::from_be_bytes(modulus);
53    if modulus.is_zero() {
54        return Vec::new();
55    }
56    let exponent = ibig::UBig::from_be_bytes(exp);
57    let ring = ibig::modular::ModuloRing::new(&modulus);
58    let result = ring.from(base).pow(&exponent);
59    result.residue().to_be_bytes()
60}
61
62#[cfg(feature = "bench")]
63pub fn modexp_num(base: &[u8], exp: &[u8], modulus: &[u8]) -> Vec<u8> {
64    use num::Zero;
65
66    let base = num::BigUint::from_bytes_be(base);
67    let modulus = num::BigUint::from_bytes_be(modulus);
68    if modulus.is_zero() {
69        return Vec::new();
70    }
71    let exponent = num::BigUint::from_bytes_be(exp);
72    base.modpow(&exponent, &modulus).to_bytes_be()
73}