Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

chore: Switch to ruint, cleanup conversion functions and add tests #33

Merged
merged 3 commits into from
Mar 6, 2024

Conversation

winston-h-zhang
Copy link
Contributor

This PR swtiches the bignum crate from crypto-bigint to ruint. The motivation for this particular switch is because https://github.com/philsippl/circom-witness-rs/tree/master uses ruint. After considering whether to switch to ruint or stay with crypto-bigint and port the code from circom-witness-rs, I decided ruint is a bit easier to work with.

After making the switch, I cleaned up the from_vec_u32, etc, conversion functions into a utils module with tests for safety.

huitseeker
huitseeker previously approved these changes Mar 2, 2024
Copy link
Contributor

@huitseeker huitseeker left a comment

Choose a reason for hiding this comment

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

This LGTM, just left a question

@@ -186,7 +186,7 @@ impl SafeMemory {
/// * `ptr` - The memory address where the field element will be written.
/// * `fr` - The [`U256`] field element to write.
fn write_short(&mut self, store: &impl AsStoreRef, ptr: usize, fr: U256) -> Result<()> {
let num = fr.to_words()[0] as u32;
let num = fr.as_limbs()[0] as u32; // wtf is happening
Copy link
Contributor

Choose a reason for hiding this comment

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

what's the issue here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought there might be a bug here, but after the tests passed and the constraints were satisfied, the behavior is correct

src/util.rs Outdated
pub fn ff_as_limbs<F: PrimeField>(f: &F) -> &[u32; 8] {
let binding = f.to_repr();
let repr: &[u8; 32] = binding.as_ref().try_into().unwrap();
// this doesn't work if the platform we're on is not little endian :scream:
Copy link
Contributor

Choose a reason for hiding this comment

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

It's even a bit worse than that: it assumes that the field implementation is using LE for to_repr(), see the tests introduced in lurk-lang/arecibo@fd3ae7a

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, should I be more explicit in mentioning this issue? There's also no way to directly test within circom-scotia, since we can't guarantee downstream will use any particular field impl... soooo

Copy link
Contributor

@tchataigner tchataigner Mar 5, 2024

Choose a reason for hiding this comment

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

I guess we have two ways of addressing this:

  1. Keep this as a limitation for now, document it more clearly and open an issue
  2. Change the trait we deal with to PrimeFieldBits instead of PrimeField to allow for to_le_bits method call, ensuring correctness.

@winston-h-zhang, feel free to chose any.

Copy link
Contributor

@tchataigner tchataigner left a comment

Choose a reason for hiding this comment

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

Thanks! That looks awesome, I have few nitpicks to look at but I think we should take one of the two ways I suggested for the endianness problem.

src/util.rs Outdated
/// Assumes little endian
pub fn ff_as_limbs<F: PrimeField>(f: F) -> [u32; 8] {
let binding = f.to_repr();
let repr: [u8; 32] = binding.as_ref().try_into().unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

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

Better error definition and propagation could be defined here. Or at least an expect giving us some context :)

src/util.rs Outdated
*digit = limbs[i];
}

F::from_repr(repr).unwrap()
Copy link
Contributor

Choose a reason for hiding this comment

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

As above, would be great to have Rust error handling or at least an expect

@winston-h-zhang
Copy link
Contributor Author

@tchataigner Thanks for the review! I rewrote the functions to use PrimeFieldBits so that we no longer rely on any implementation details. This also removed the calls to .unwrap(), so everything worked out nicely

Copy link
Contributor

@tchataigner tchataigner left a comment

Choose a reason for hiding this comment

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

LGTM!

@winston-h-zhang winston-h-zhang merged commit 9756f51 into main Mar 6, 2024
4 checks passed
@winston-h-zhang winston-h-zhang deleted the use-ruint branch March 6, 2024 17:53
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants