-
Notifications
You must be signed in to change notification settings - Fork 87
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
no_std fuel-crypto #578
no_std fuel-crypto #578
Conversation
/// | ||
/// The compression scheme is described in | ||
/// <https://github.com/FuelLabs/fuel-specs/blob/master/src/protocol/cryptographic-primitives.md> | ||
pub fn sign<SK: Into<k256::SecretKey>>(secret: SK, message: &Message) -> [u8; 64] { |
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.
maybe we should use an actual trait interface in front of these backends so that it's less likely users of this crate get unexpected errors when switching between std and nostd?
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 considered it, but I really don't see what extra value using a trait here would bring. Any errors would already be caught by the type system, or at least the tests. I wont mind wrapping them in a trait here if you feel like it's better like that.
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.
Also, the types used by public_key
and sign
functions are not the same for both modules, as they use Into<...>
with a type from the corresponding backing crate, although that could be changed as well.
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.
It would probably be better if we had our own types on the public interfaces, and then implemented conversion to various backends as needed based on what's compiled in. Otherwise if one of these crypto libs changes their types or interfaces it could cause a lot of breaking changes in other unrelated places.
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.
Agreed, although I find it unlikely to actually cause breakage, but it's true that upgrading an underlying crypto library is a breaking change in the current implementation. I'll fix that.
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.
Ok, I've fixed this now for secp256k1
. For secp256r1
we currently have only a single implementation, which still exposes some types from the underlying crypto lib under #[cfg(feature = "test-helpers")]
, which I think is fine.
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.
Which commit has this fix? I'm not seeing 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.
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 am not very familiar with the cryptography concepts in this PR, but nothing sticks out as an obvious issue. Overall, it looks good.
Just one small suggestion related to implementing Distribution
for SecretKey
.
@@ -712,9 +712,9 @@ mod tests { | |||
let tx = TransactionBuilder::script(vec![], vec![]) | |||
.gas_price(gas_price) | |||
.gas_limit(gas_limit) | |||
.add_unsigned_message_input(rng.gen(), rng.gen(), rng.gen(), input_amount, vec![0xff; 10]) |
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.
Instead of replacing all the instances of rng.gen()
, is it possible to do something like:
impl Distribution<SecretKey> for Standard { ... }
instead? I believe this should allow you to keep the existing syntax in these places.
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 don't hate this syntax. It's explicit.
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. We had that before, but sadly the elliptic-curve
crate (used by k256
) requires us to accept only rngs with CryptoRngCore
trait. At least I couldn't figure out how to make impl Distribution
work with 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.
LGTM. IDK if I feel comfortable approving because a bit of the crypto stuff is too unfamiliar for me to scrutinize closely.
No additional questions from me. Again, I'm not familiar with all the cryptography concepts, so I will have to go by the tests and your judgement here. |
use rand::{ | ||
rngs::StdRng, | ||
SeedableRng, | ||
}; | ||
|
||
#[cfg(feature = "std")] |
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 get that the secret key generation doesn't work in no_std, but do we have tests in other places to ensure that the no_std backends work the same as std?
Signature verification is probably the most critical thing to support from a no_std perspective, as that is the only logic we'll really be using in a fraud-proof mode. So we should make sure that signature verification tests work in both std and no_std.
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 test for backend equivalency is in fuel-crypto/src/secp256/backend.rs
. Only the secp256k1 has different implementations currently.
I agree that it makes sense to add some tests to the backends themselves.
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 added standalone test cases for k256 module that also run in no_std
mode, in e3943de
@@ -19,7 +19,7 @@ derivative = "2.2" | |||
dyn-clone = { version = "1.0", optional = true } | |||
ethnum = "1.3" | |||
fuel-asm = { workspace = true } | |||
fuel-crypto = { workspace = true } | |||
fuel-crypto = { workspace = true, default-features = false } |
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.
Would this make the VM use the no-std backend by default in all cases? Maybe we should also enable the std feature on fuel-crypto if it's enabled on fuel-vm so we can take advantage of the more optimized implementation in native mode?
ie.
std = ["fuel-crypto/std", "fuel-tx/std"]
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.
Using the no-std version by default could also impact our gas pricing if the performance between the native secp256k1 lib is very different from the pure-rust impl.
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'll check that the features are correct, as that seems like a potential issue. It's somewhat hard to verify that the correct crypto backend is getting used, as they have the same external API.
Using the no-std version by default could also impact our gas pricing if the performance between the native secp256k1 lib is very different from the pure-rust impl.
It certainly does, the no_std
version is about 5x slower. The gas pricing shouldn't care about no_std
performance, as the standard option would be to run the nodes with native secp256k1.
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 feature propagation in dc6962a
Addresses breaking fuel-vm changes from FuelLabs/fuel-vm#582, FuelLabs/fuel-vm#578, FuelLabs/fuel-vm#588 and FuelLabs/fuel-vm#587. Waiting for a new fuel-vm release. --------- Co-authored-by: Green Baneling <XgreenX9999@gmail.com>
Addresses breaking fuel-vm changes from FuelLabs/fuel-vm#582, FuelLabs/fuel-vm#578, FuelLabs/fuel-vm#588 and FuelLabs/fuel-vm#587. Waiting for a new fuel-vm release. --------- Co-authored-by: Green Baneling <XgreenX9999@gmail.com>
Work towards #536.
This PR removes
secp256k1
dependency fromfuel-crypto
when not depending on stdlib, and uses currently un-auditedk256
crate, which is a pure-rust implementation. There's an audit underway for the it, though.The API doesn't change much, but generating new private secp256k1 keys now requires the rng to implement the
rand::CryptoRng
trait, meaning they cannot be generated usingrng.gen()
but requireSecretKey::random(&mut rng)
instead.