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.
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
}