-
Notifications
You must be signed in to change notification settings - Fork 57
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MulMod not implemented and not properly documented #70
Comments
We attempted to, and the trait still being around is a vestige of that. See:
The attempted implementation was incorrect, so it did not land with the rest of the modular arithmetic. It would be beneficial for quite a few projects if we could get it working, though.
The trait in its current form is specialized to a Montgomery reduction, where typically the modulus is odd. I'm not terribly familiar with how to do a Montgomery reduction with an even modulus (in all of the @RustCrypto project's applications which could benefit from a generic Here's a paper I found on Montgomery reductions with an even modulus: http://www.people.vcu.edu/~jwang3/CMSC691/j34monex.pdf |
For an even modulus |
Did you take this into account when chosing Montgomery multiplication? |
Looking at the old implementation, it looks like it doesn't bring the number into Montgomery form before calling |
Yes, that is definitely why it didn't work. We use both Montgomery and Barrett reductions in the https://github.com/rustcrypto/elliptic-curves crates (for base and scalar field elements respectively, although the latter only for For the elliptic curve crates specifically we generally perform a sequence of operations on field elements in Montgomery form, and thus the overhead of converting to/from Montgomery form is ammortized. There's a question of how to expose values in Montgomery form. There have been various problems with using the same type for both, namely confusing which form a particular value/field element is in. As such I've largely moved the crates to where the I'd love to add a generic We've considered porting over @cronokirby's implementation of modexp using Montgomery multiplication here: https://github.com/cronokirby/saferith/blob/08ff755fd8f7e060d9756857368435c53540d83b/num.go#L1361 ...but I'd agree there's a case to be made for using a Barrett reduction instead in the event the inputs and outputs are all in canonical form. |
That's also what I'm doing in my project.
For what exactly do you need them? I'm on stable rustc 1.60.0 and do it like this: pub trait ResidueParameters<const L: usize>: PartialEq + Debug {
const MODULUS: Option<UInt<L>>;
}
#[derive(PartialEq)]
pub struct Residue<P, const L: usize>
where
P: ResidueParameters<L>,
{
repr: UInt<L>,
phantom: PhantomData<P>,
} I call it |
There's various ways to work within the limits of what's available on stable now.
That works but is a bit clunky as you have to crate a ZST and impl pub struct Residue<const LIMBS: usize, const MODULUS: UInt<LIMBS>> { ... } This will be possible after valtrees are implemented. |
I think for starters we can implement |
Now that it seems that valtrees have been implemented, where is this standing? |
Also, can't the And why isn't there a |
As that issue notes, implementing valtrees is step 1 of 5. We target stable Rust, so we need all of those steps complete to make use of the feature.
All
That is a notable API gap in the traits. |
It seems that they also closed the issue after this step, and from my understanding that's because what has been implemented should suffice at least partially?
I'm not sure I understand what "rhs is stored in self" means. The signature is that a Uint gets an rhs of the same type, and a modulo of the same type and returns the same type right? So if I:
Can't such an API be easily added? |
Huh? rust-lang/rust#95174 is still open and only the first checkbox of 5 is checked. Though the feature exists on
Because the modulus is stored in Unless you're proposing there's a second modulus, which doesn't make sense to me?
Yes |
It is locked for discussion, which made me assume it is closed, sorry.
I'm not sure I get it. E.g. for AddMod there's three prams there, one of them is the Modulus:
Will do. Should this also address traits for AddMod, MulMod etc that we could implement using DynResidue ? |
So it doesn't need
Again, I don't think it makes sense to implement those traits for |
Yeah I know how DynResidue works, but I need a type that has both normal "over the intigers" bigint operations and modular operations. This is why I think it does make sense to implement these traits. Because now we have either-or. Either you're using an e.g. U2048 with over the integers operations, or you're using a DynResidue that allows you finite field operations. But e.g. for Paillier I need both. |
But what would you be passing as the modulus? Also why are you doing modular arithmetic with both |
Why do you need the exact same set of traits on both, especially when those traits don't make sense to implement? |
Let me rephrase. I'd like to write a Paillier decryption first raises the ciphertext Next, we switch to work over the integers to perform Now, we need to think of that result again as in a finite field but this time I can and have written such code using crypto-bigint directly, but want to decouple myself and work over traits instead, and have crypto-bigint implement these traits e.g. for U4096. I think that's possible, maybe the current traits aren't the ones to satisfy it tho. let me know if this makes sense now, and I'll open an issue for this. |
I actually have written Paillier encryption working via traits for a library at work. It is possible, but it is not pleasant (in part because Rust can be quite daft about trait bounds sometimes). I have two traits, |
@fjarri what's does We could potentially add an |
Currently it's pub trait UintLike:
Integer
+ JacobiSymbolTrait
+ Hashable
+ RandomPrimeWithRng
+ RandomMod
{
// TODO: do we really need this? Or can we just use a simple RNG and `random_mod()`?
fn hash_into_mod(reader: &mut impl XofReader, modulus: &NonZero<Self>) -> Self;
fn add_mod(&self, rhs: &Self, modulus: &NonZero<Self>) -> Self;
fn trailing_zeros(&self) -> usize;
fn inv_odd_mod(&self, modulus: &Self) -> CtOption<Self>;
fn inv_mod2k(&self, k: usize) -> Self;
fn wrapping_sub(&self, other: &Self) -> Self;
fn wrapping_mul(&self, other: &Self) -> Self;
fn wrapping_add(&self, other: &Self) -> Self;
fn bits(&self) -> usize;
fn bit(&self, index: usize) -> Choice;
fn neg(&self) -> Self;
fn neg_mod(&self, modulus: &Self) -> Self;
} ( Edit: now that I look at |
These are the other two traits I mentioned: pub trait UintModLike:
Pow<Self::RawUint>
+ core::fmt::Debug
+ Add<Output = Self>
+ Neg<Output = Self>
+ Copy
+ Clone
+ PartialEq
+ Eq
+ Retrieve<Output = Self::RawUint>
+ Invert<Output = CtOption<Self>>
+ Mul<Output = Self>
+ Sub<Output = Self>
+ for<'a> Mul<&'a Self, Output = Self>
{
type RawUint: UintLike;
fn new(value: &Self::RawUint, modulus: &NonZero<Self::RawUint>) -> Self;
}
pub trait HasWide: Sized + Zero {
type Wide: UintLike;
fn mul_wide(&self, other: &Self) -> Self::Wide;
fn square_wide(&self) -> Self::Wide;
fn into_wide(self) -> Self::Wide;
fn from_wide(value: Self::Wide) -> (Self, Self);
fn try_from_wide(value: Self::Wide) -> Option<Self> {
let (hi, lo) = Self::from_wide(value);
if hi.is_zero().into() {
return Some(lo);
}
None
}
} Edit: I am planning to add a generic method to create Montgomery params separately instead of doing it internally; this is just scaffolding for now. |
Yeah, definitely some gaps in what is possible via traits right now. Perhaps we should look into what is available in |
Uses Montgomery multiplication although it may not be the most efficient approach (e.g. a Barrett reduction might be faster). This also changes the `MulMod` trait to remove the Montgomery-specific implementation details, allowing a simple `mul_mod(self, rhs, p)`. Optimized Montgomery multiplication is still available via `DynResidue`. Closes #70
Uses Montgomery multiplication although it may not be the most efficient approach (e.g. a Barrett reduction might be faster). This also changes the `MulMod` trait to remove the Montgomery-specific implementation details, allowing a simple `mul_mod(self, rhs, p)`. Optimized Montgomery multiplication is still available via `DynResidue`. Closes #70
Uses Montgomery multiplication although it may not be the most efficient approach (e.g. a Barrett reduction might be faster). This also changes the `MulMod` trait to remove the Montgomery-specific implementation details, allowing a simple `mul_mod(self, rhs, p)`. Optimized Montgomery multiplication is still available via `DynResidue`. Closes #70
It would be nice if the trait
MulMod
could be implemented.Furthermore, the current documentation (v0.3.2) states that
mul_mod
However, any even
p
is not invertible. An evenp
might be used e.g. when computing over a ring rather than a prime field. So, how shouldp_inv
be set ifp
is even?The text was updated successfully, but these errors were encountered: