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

Field generator macros #154

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

kilic
Copy link
Collaborator

@kilic kilic commented Apr 25, 2024

This PR adds field generator macros and as a result removes many duplicates. There is an important breaking change that it now wraps all field representations for example as ReprFq([u8; SIZE]).

Also it will help to add new fields and thus new curves. For example base field for BLS12-381 which has 6 limbs internal representation can be added as:

impl_field!(
    bls12381_scalar,
    Fp,
    modulus = "1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab",
    mul_gen = "2",
    zeta = "1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac",
    from_uniform = [96],
);

@kilic kilic force-pushed the field-gen-macro branch 2 times, most recently from ce1512f to 84edae1 Compare May 13, 2024 22:54
Copy link
Contributor

@davidnevadoc davidnevadoc left a comment

Choose a reason for hiding this comment

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

Finished first pass and left some comments.
Looking amazing so far :)


let impl_arith_always_const = arith::impl_arith_always_const(&field, num_limbs, inv64);

let impl_from_uniform_bytes = from_uniform
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we enforce that the elements of from_uniform are within [size, 2*size]?
I think we would get unexpected/buggy behavior if someone accidentally added values outside that range.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

should be handled now in compile time after 851ed19


impl FromUniformBytes<{ $field::SIZE * 2 }> for $tower {
fn from_uniform_bytes(bytes: &[u8; $field::SIZE * 2]) -> Self {
Self::new($field::from_uniform_bytes(bytes), $field::ZERO)
Copy link
Contributor

Choose a reason for hiding this comment

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

I've seen that we had this implementation where the c1 part of the element is fixed to 0 but I can't remember why we needed it in the first place. The tests don't seem to need it. I'd remove it altogether.

}
}

impl FromUniformBytes<{ $field::SIZE * 2 * 2 }> for $tower {
Copy link
Contributor

Choose a reason for hiding this comment

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

The last *2 is easily understandable since we are dealing with a quadratic extension, and therefore we need 2 base field elements. The first one though... not so much.
I find more logical something along the lines of: ( SIZE + k/8 ) * 2) where k is the target bit security.
For the usual case where we have SIZE = 32 and k=128 the result is the same. But for Bls12-381 and Pluto/Eris we will get 48 * 4 = 192 instead of (48+32)*2= 160 and 56*4 = 224 instead of (56+32)*2 = 176.

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe it's necessary to pass this value explicitly to the macro like you do on the prime fields.

src/bn256/fq2.rs Outdated Show resolved Hide resolved
@kilic kilic mentioned this pull request May 30, 2024
Copy link
Contributor

@davidnevadoc davidnevadoc left a comment

Choose a reason for hiding this comment

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

LGTM! Good job 🎉
Left some minor comments, but I think this can be merged.
Since it is such a big change, I wouldn't mind having an extra review though.

let d_i = fmtid!("d_{}", i);
gen.extend(quote! { let ( #d_i, carry) = adc(self.0[#i], rhs.0[#i], #carry); });
});

Copy link
Contributor

Choose a reason for hiding this comment

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

Can we add the original comment (or something similar):

// Attempt to subtract the modulus, to ensure the value
// is smaller than the modulus.

I think this part is not so obvious so it makes it more understandable.

}
}

fn impl_from_mont(field: &syn::Ident, num_limbs: usize, inv: u64) -> TokenStream {
Copy link
Contributor

Choose a reason for hiding this comment

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

This is new function right?

}
}

impl From<$field> for [u64; 4] {
Copy link
Contributor

Choose a reason for hiding this comment

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

I assume this is now exposed through montgomery_reduce_256 directly, but I think it is good to have the From trait. Is it implemented elsewhere?

@@ -313,16 +187,10 @@ impl Field for Fp12 {
}

fn sqrt(&self) -> CtOption<Self> {
// The square root method is typically only required for finding y-coordinate
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd rather keep the comment, otherwise looks like this is WIP 😅

Copy link
Contributor

@han0110 han0110 left a comment

Choose a reason for hiding this comment

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

LGTM! Nice rework! Just left some small suggestions.

Comment on lines +222 to +224
for &b in tmp.as_ref().iter().rev() {
write!(f, "{:02x}", b)?;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems to assume little endian, should we conditionally call rev here by endian?

let right = other.to_repr();
left.as_ref().iter()
.zip(right.as_ref().iter())
.rev()
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto

impl WithSmallOrderMulGroup<3> for $tower {
// $field::ZETA ^2
const ZETA: Self = $tower {
c0: ZETA,
Copy link
Contributor

Choose a reason for hiding this comment

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

We could remove the ZETA constant in fq2.rs by using the generated one?

Suggested change
c0: ZETA,
c0: $field::ZETA,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants