cairo-native 0.8.0

A compiler to convert Cairo's IR Sierra code to MLIR and execute it.
// Copied from: https://github.com/keep-starknet-strange/alexandria
// License: MIT

//! # Fast power algorithm
use core::ops::DivAssign;

/// Calculate the base ^ power
/// using the fast powering algorithm
/// # Arguments
/// * ` base ` - The base of the exponentiation
/// * ` power ` - The power of the exponentiation
/// # Returns
/// * ` T ` - The result of base ^ power
/// # Panics
/// * ` base ` is 0
pub fn fast_power<
    T,
    +Div<T>,
    +DivAssign<T, T>,
    +Rem<T>,
    +Into<u8, T>,
    +Into<T, u256>,
    +TryInto<u256, T>,
    +PartialEq<T>,
    +Copy<T>,
    +Drop<T>
>(
    base: T, mut power: T
) -> T {
    assert!(base != 0_u8.into(), "fast_power: invalid input");

    let mut base: u256 = base.into();
    let mut result: u256 = 1;

    loop {
        if power % 2_u8.into() != 0_u8.into() {
            result *= base;
        }
        power /= 2_u8.into();
        if (power == 0_u8.into()) {
            break;
        }
        base *= base;
    };

    result.try_into().expect('too large to fit output type')
}

/// Calculate the ( base ^ power ) mod modulus
/// using the fast powering algorithm
/// # Arguments
/// * ` base ` - The base of the exponentiation
/// * ` power ` - The power of the exponentiation
/// * ` modulus ` - The modulus used in the calculation
/// # Returns
/// * ` T ` - The result of ( base ^ power ) mod modulus
/// # Panics
/// * ` base ` is 0
pub fn fast_power_mod<
    T,
    +Div<T>,
    +DivAssign<T, T>,
    +Rem<T>,
    +Into<u8, T>,
    +Into<T, u256>,
    +TryInto<u256, T>,
    +PartialEq<T>,
    +Copy<T>,
    +Drop<T>
>(
    base: T, mut power: T, modulus: T
) -> T {
    assert!(base != 0_u8.into(), "fast_power: invalid input");

    if modulus == 1_u8.into() {
        return 0_u8.into();
    }

    let mut base: u256 = base.into();
    let modulus: u256 = modulus.into();
    let mut result: u256 = 1;

    loop {
        if power % 2_u8.into() != 0_u8.into() {
            result = (result * base) % modulus;
        }
        power /= 2_u8.into();
        if (power == 0_u8.into()) {
            break;
        }
        base = (base * base) % modulus;
    };

    result.try_into().expect('too large to fit output type')
}