Search code examples
rustbigint

simple operations like remainder for Wrapping(Uint) in rust


I am using the crate crypto_bigint to manipulate big numbers, but the documentation really confuses me. So apparently you need to decide whether you want your operations checked or wrapped, I need to do bit_and operations, and for some reason it's not possible for checked Uint, so I chose wrapping.

I am barely able to perform an addition a and and a right shift.

I want to get some remainder. So I tried to simply do %, then the compiler tells me that the rem method has no implementation for the type crypto-bigint::Wrapping but I can see it does exist in the doc and the corresponding type implements the Traits Rem.

Here is an example that creates plenty of errors

use crypto_bigint::{Wrapping, U2048}; //apparently not the correct imports

pub fn mod_exp(
    base: Wrapping<U2048>,
    exp: Wrapping<U2048>,
    modulus: Wrapping<U2048>,
) -> Wrapping<U2048> {
    let one = Wrapping(U2048::ONE);
    let mut result = Wrapping(U2048::ONE);
    let mut base = base % modulus; // Ensure base is reduced modulo
    let mut exp = exp;

    while exp > Wrapping(U2048::ZERO) {
        if exp & one == one {
            result = (result * base).rem(modulus);
        }
        exp = Wrapping(exp.0.shr(1_usize));
        base = (base * base).rem(modulus); // Modular square
    }
    result
}
error[E0277]: cannot calculate the remainder of `crypto_bigint::Wrapping<Uint<32>>` divided by `crypto_bigint::Wrapping<Uint<32>>`
  --> src\lib.rs:10:25
   |
10 |     let mut base = base % modulus; // Ensure base is reduced modulo
   |                         ^ no implementation for `crypto_bigint::Wrapping<Uint<32>> % crypto_bigint::Wrapping<Uint<32>>`
   |
   = help: the trait `Rem` is not implemented for `crypto_bigint::Wrapping<Uint<32>>`
   = help: the following other types implement trait `Rem<Rhs>`:
             `&crypto_bigint::Wrapping<Uint<LIMBS>>` implements `Rem<&crypto_bigint::NonZero<Limb>>`
             `&crypto_bigint::Wrapping<Uint<LIMBS>>` implements `Rem<&crypto_bigint::NonZero<Uint<LIMBS>>>`
             `&crypto_bigint::Wrapping<Uint<LIMBS>>` implements `Rem<crypto_bigint::NonZero<Limb>>`
             `&crypto_bigint::Wrapping<Uint<LIMBS>>` implements `Rem<crypto_bigint::NonZero<Uint<LIMBS>>>`
             `crypto_bigint::Wrapping<Uint<LIMBS>>` implements `Rem<&crypto_bigint::NonZero<Limb>>`
             `crypto_bigint::Wrapping<Uint<LIMBS>>` implements `Rem<&crypto_bigint::NonZero<Uint<LIMBS>>>`
             `crypto_bigint::Wrapping<Uint<LIMBS>>` implements `Rem<crypto_bigint::NonZero<Limb>>`
             `crypto_bigint::Wrapping<Uint<LIMBS>>` implements `Rem<crypto_bigint::NonZero<Uint<LIMBS>>>`

It may be just a bad import, but I do not know how to do it. I tried the "solutions" suggested by the compiler, but it created more problems than it solved. For example, I tried to cast Wrapping(U2048) into Rem<NonZero<Uint<32>>> using 'as Rem<NonZero<Uint<32>>>', but then I need to define the Output type, and the syntax I used didn't work.


Solution

  • Look like you need to use NonZero:

    use crypto_bigint::{NonZero, Wrapping, U2048};
    
    pub fn mod_exp<const LIMBS: usize>(
        base: Wrapping<U2048>,
        exp: Wrapping<U2048>,
        modulus: NonZero<U2048>,
    ) -> Wrapping<U2048> {
        let one = Wrapping(U2048::ONE);
        let mut result = Wrapping(U2048::ONE);
        let mut base = Wrapping(base.0.rem(&modulus)); // Ensure base is reduced modulo
        let mut exp = exp;
    
        while exp > Wrapping(U2048::ZERO) {
            if exp & one == one {
                result = Wrapping((result * base).0.rem(&modulus));
            }
            exp = Wrapping(exp.0.shr(1_usize));
            base = Wrapping((base * base).0.rem(&modulus)); // Modular square
        }
        result
    }