-
Notifications
You must be signed in to change notification settings - Fork 157
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
feat: switch from num-bigint-dig to crypto-bigint #394
base: master
Are you sure you want to change the base?
Conversation
CI is finally green again, time for lots of review and cleanup |
@zeerooth |
src/algorithms/generate.rs
Outdated
let mut pi = prime_limit / (prime_limit.ln() - 1f64); | ||
#[cfg(not(feature = "std"))] | ||
let mut pi = prime_limit / (libm::logf(prime_limit as f32) as f64 - 1f64); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is not entirely correct or optimal, but I am not sure what other way there is
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fjarri is there anything in crypto-primes
for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, nothing like that currently
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dignifiedquire so if I understand correctly, the purpose of this calculation is ultimately for a check that keygen terminates in a reasonable amount of time?
@dignifiedquire seems like you can remove "Very, very WIP" now |
🤣 yeah, finally |
@dignifiedquire how it's going ? |
He's waiting on review, which I'll try to do soon |
digest = { version = "=0.11.0-pre.9", default-features = false, features = ["alloc", "oid"] } | ||
pkcs1 = { version = "0.8.0-rc.0", default-features = false, features = ["alloc", "pkcs8"] } | ||
pkcs8 = { version = "0.11.0-rc.0", default-features = false, features = ["alloc"] } | ||
signature = { version = "=2.3.0-pre.4", default-features = false, features = ["alloc", "digest", "rand_core"] } | ||
spki = { version = "0.8.0-rc.1", default-features = false, features = ["alloc"] } | ||
zeroize = { version = "1.5", features = ["alloc"] } | ||
crypto-bigint = { version = "0.6.0-rc.6", default-features = false, features = ["zeroize", "alloc"] } | ||
crypto-primes = { version = "0.6.0-pre.2", default-features = false } | ||
libm = "0.2" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO it would be nice to avoid this, especially if its only used for no_std
prime counting
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If all you need from there is logf(x)
, you can probably just approximate it with x.bits() / log2(e)
, pre-calculating log2(e)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or even take log2(e) == 1
if the approximation allows it :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bits()
seems to not be around either..
README.md
Outdated
@@ -81,7 +81,7 @@ You can follow our work on mitigating this issue in [#390]. | |||
|
|||
## Minimum Supported Rust Version (MSRV) | |||
|
|||
This crate supports Rust 1.72 or higher. | |||
This crate supports Rust 1.73 or higher. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is crypto-bigint
's latest MSRV:
This crate supports Rust 1.73 or higher. | |
This crate supports Rust 1.83 or higher. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed all around
@@ -222,7 +223,6 @@ extern crate alloc; | |||
#[cfg(feature = "std")] | |||
extern crate std; | |||
|
|||
pub use num_bigint::BigUint; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps consider a BoxedUint
re-export here, possibly using a shorter name:
pub use crypto_bigint::BoxedUint as Uint;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added
// TODO: reenable, currently slow | ||
// key_generation!(key_generation_multi_16_1024, 16, 1024); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😢
let two = NonZero::new(BoxedUint::from(2u64)) | ||
.expect("2 is non zero") | ||
.widen(bits); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something which makes this pattern better would be nice. We have various NonZero::new_unwrap
constructors which allow you to infallibly construct a NonZero
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
278 | let two = NonZero::new_unwrap(2).widen(bits);
| ^^^^^^^^^^ multiple `new_unwrap` found
|
= note: candidate #1 is defined in an impl for the type `crypto_bigint::NonZero<Limb>`
= note: candidate #2 is defined in an impl for the type `crypto_bigint::NonZero<crypto_bigint::Uint<LIMBS>>`
seems to not exist for theBoxedUint
version
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dignifiedquire aah, yeah the idea would be to const construct a NonZero<Uint>
first and either convert it to a NonZero<BoxedUint>
first or make it possible to use NonZero<Uint>
as an operand.
src/algorithms/generate.rs
Outdated
@@ -93,14 +95,14 @@ pub(crate) fn generate_multi_prime_key_with_exp<R: CryptoRngCore + ?Sized>( | |||
|
|||
let n = compute_modulus(&primes); | |||
|
|||
if n.bits() != bit_size { | |||
if n.bits() as usize != bit_size { | |||
// This should never happen for nprimes == 2 because | |||
// gen_prime should set the top two bits in each prime. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment should be updated for the new name of the function.
Also I don't quite understand "gen_prime should set the top two bits in each prime" - what was that behavior for? generate_prime_with_rng()
only sets one top bit, to ensure that the returned primes are of the requested bit size.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was a bit curious about that myself. I saw @FiloSottile mention the same thing in this post:
https://words.filippo.io/dispatches/rsa-keygen-bench/
There is almost nothing special to selecting prime candidates. You draw an appropriately sized random number from a CSPRNG, and to avoid wasting time, you set the least significant bit and the two most significant bits: large even numbers are not prime, and setting the top two guarantees N won’t come out too small.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you set only the top bit of a n/2 bits number, you get a value >= 2^(n/2-1). If you multiply two of them, you get a value >= 2^(n-2), which is at a minimum n-1 bits long, one too short for a n-bit modulus.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I see, that makes sense. Do you think it should be the default behavior in crypto-primes
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you mainly need the primes for RSA, yes, you are only wasting CPU rejecting small moduli after you found the primes. If you're using the primes for something else, it might depend on what they are for.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fjarri are you planning on changing the behaviour?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about it, and I don't think it should be the default - too specialized. It can be achieved with custom sieves, but I need to make a release first
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's fair, please do let me know if you have a release/how to make replicate the desired behavior with custom sieves
FYI: release PR for |
d: d_final, | ||
primes, | ||
}) | ||
} | ||
|
||
/// Natural logrithm for `f64`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo here: logrithm -> logarithm
(and the same on line 123). Could add the typos GitHub action to the repo to avoid that.
Very, very WIPNot anymore, this is ready for review.
Replaces all usage of
num-bigint-dig
basedBigInt
usage with the newcrypto-bigint
crate, usingBoxedUint
Current known issue is that we do have a performance regression, which will be able to get rid of over time:
TODOs
RsaPrivateKey
RsaPublicKey
decrypt
implementationBigUint
to return owned versions