Skip to content
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

Merged
merged 22 commits into from
Sep 15, 2023
Merged

no_std fuel-crypto #578

merged 22 commits into from
Sep 15, 2023

Conversation

Dentosal
Copy link
Member

@Dentosal Dentosal commented Sep 1, 2023

Work towards #536.

This PR removes secp256k1 dependency from fuel-crypto when not depending on stdlib, and uses currently un-audited k256 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 using rng.gen() but require SecretKey::random(&mut rng) instead.

@Dentosal Dentosal added fuel-crypto Related to the `fuel-crypto` crate. needs-investigation no changelog Skips the CI changelog check labels Sep 1, 2023
@Dentosal Dentosal self-assigned this Sep 1, 2023
@Dentosal Dentosal added breaking A breaking api change and removed needs-investigation no changelog Skips the CI changelog check labels Sep 7, 2023
@Dentosal Dentosal marked this pull request as ready for review September 7, 2023 04:25
@Dentosal Dentosal requested a review from a team September 7, 2023 04:25
.github/workflows/ci.yml Outdated Show resolved Hide resolved
///
/// 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] {
Copy link
Member

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?

Copy link
Member Author

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.

Copy link
Member Author

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.

Copy link
Member

@Voxelot Voxelot Sep 11, 2023

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.

Copy link
Member Author

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.

Copy link
Member Author

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.

Copy link
Member

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

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

f52fe82 and 053fa23. Forgot to push those, sorry.

Copy link
Contributor

@bvrooman bvrooman left a 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])
Copy link
Contributor

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.

Copy link
Member

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.

Copy link
Member Author

@Dentosal Dentosal Sep 11, 2023

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.

Copy link
Member

@MitchTurner MitchTurner left a 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.

bvrooman
bvrooman previously approved these changes Sep 12, 2023
bvrooman
bvrooman previously approved these changes Sep 14, 2023
@bvrooman
Copy link
Contributor

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")]
Copy link
Member

@Voxelot Voxelot Sep 14, 2023

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.

Copy link
Member Author

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.

Copy link
Member Author

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 }
Copy link
Member

@Voxelot Voxelot Sep 14, 2023

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"]

Copy link
Member

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.

Copy link
Member Author

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.

Copy link
Member Author

@Dentosal Dentosal Sep 14, 2023

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

@Dentosal Dentosal added this pull request to the merge queue Sep 15, 2023
Merged via the queue into master with commit e18be55 Sep 15, 2023
35 checks passed
@Dentosal Dentosal deleted the dento/nostd_crypto branch September 15, 2023 05:59
@xgreenx xgreenx mentioned this pull request Sep 27, 2023
Dentosal added a commit to FuelLabs/fuel-core that referenced this pull request Sep 27, 2023
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>
crypto523 added a commit to crypto523/fuel-core that referenced this pull request Oct 7, 2024
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking A breaking api change fuel-crypto Related to the `fuel-crypto` crate.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants