ff_derive: Generate modulus representation with correct endianness

Now that PrimeField::ReprEndianness exists, users can obtain a
known-endianness representation from the output of PrimeField::char
(which is a PrimeField::Repr, and should return a representation with
the same endianness as PrimeField::into_repr).
This commit is contained in:
Jack Grigg 2020-05-02 18:25:26 +12:00
parent 15e229509a
commit 9114c367f4
3 changed files with 42 additions and 29 deletions

View File

@ -38,6 +38,23 @@ impl ReprEndianness {
} }
} }
fn modulus_repr(&self, modulus: &BigUint, bytes: usize) -> Vec<u8> {
match self {
ReprEndianness::Big => {
let buf = modulus.to_bytes_be();
iter::repeat(0)
.take(bytes - buf.len())
.chain(buf.into_iter())
.collect()
}
ReprEndianness::Little => {
let mut buf = modulus.to_bytes_le();
buf.extend(iter::repeat(0).take(bytes - buf.len()));
buf
}
}
}
fn from_repr(&self, name: &syn::Ident, limbs: usize) -> proc_macro2::TokenStream { fn from_repr(&self, name: &syn::Ident, limbs: usize) -> proc_macro2::TokenStream {
let read_repr = match self { let read_repr = match self {
ReprEndianness::Big => quote! { ReprEndianness::Big => quote! {
@ -159,8 +176,14 @@ pub fn prime_field(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let mut gen = proc_macro2::TokenStream::new(); let mut gen = proc_macro2::TokenStream::new();
let (constants_impl, sqrt_impl) = let (constants_impl, sqrt_impl) = prime_field_constants_and_sqrt(
prime_field_constants_and_sqrt(&ast.ident, &repr_ident, &modulus, limbs, generator); &ast.ident,
&repr_ident,
&modulus,
&endianness,
limbs,
generator,
);
gen.extend(constants_impl); gen.extend(constants_impl);
gen.extend(prime_field_repr_impl(&repr_ident, &endianness, limbs * 8)); gen.extend(prime_field_repr_impl(&repr_ident, &endianness, limbs * 8));
@ -466,6 +489,7 @@ fn prime_field_constants_and_sqrt(
name: &syn::Ident, name: &syn::Ident,
repr: &syn::Ident, repr: &syn::Ident,
modulus: &BigUint, modulus: &BigUint,
endianness: &ReprEndianness,
limbs: usize, limbs: usize,
generator: BigUint, generator: BigUint,
) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) { ) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
@ -576,11 +600,7 @@ fn prime_field_constants_and_sqrt(
let r2 = biguint_to_u64_vec((&r * &r) % modulus, limbs); let r2 = biguint_to_u64_vec((&r * &r) % modulus, limbs);
let r = biguint_to_u64_vec(r, limbs); let r = biguint_to_u64_vec(r, limbs);
let modulus_repr = { let modulus_repr = endianness.modulus_repr(modulus, limbs * 8);
let mut buf = modulus.to_bytes_le();
buf.extend(iter::repeat(0).take((limbs * 8) - buf.len()));
buf
};
let modulus = biguint_to_real_u64_vec(modulus.clone(), limbs); let modulus = biguint_to_real_u64_vec(modulus.clone(), limbs);
// Compute -m^-1 mod 2**64 by exponentiating by totient(2**64) - 1 // Compute -m^-1 mod 2**64 by exponentiating by totient(2**64) - 1

View File

@ -1644,7 +1644,8 @@ fn test_fq_pow() {
use byteorder::ByteOrder; use byteorder::ByteOrder;
let mut char_limbs = [0; 6]; let mut char_limbs = [0; 6];
byteorder::LittleEndian::read_u64_into(Fq::char().as_ref(), &mut char_limbs); byteorder::BigEndian::read_u64_into(Fq::char().as_ref(), &mut char_limbs);
char_limbs.reverse();
for _ in 0..1000 { for _ in 0..1000 {
// Exponentiating by the modulus should have no effect in a prime field. // Exponentiating by the modulus should have no effect in a prime field.

View File

@ -147,13 +147,11 @@ fn test_g1_uncompressed_invalid_vectors() {
} }
} }
// PrimeField::char() returns the modulus in its little-endian byte representation, let m = Fq::char();
// but Fq field elements use big-endian encoding, so flip the endianness.
let m: Vec<_> = Fq::char().as_ref().iter().cloned().rev().collect();
{ {
let mut o = o; let mut o = o;
o.as_mut()[..48].copy_from_slice(&m[..]); o.as_mut()[..48].copy_from_slice(m.as_ref());
if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() {
assert_eq!(coordinate, "x coordinate"); assert_eq!(coordinate, "x coordinate");
@ -164,7 +162,7 @@ fn test_g1_uncompressed_invalid_vectors() {
{ {
let mut o = o; let mut o = o;
o.as_mut()[48..].copy_from_slice(&m[..]); o.as_mut()[48..].copy_from_slice(m.as_ref());
if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() {
assert_eq!(coordinate, "y coordinate"); assert_eq!(coordinate, "y coordinate");
@ -265,13 +263,11 @@ fn test_g2_uncompressed_invalid_vectors() {
} }
} }
// PrimeField::char() returns the modulus in its little-endian byte representation, let m = Fq::char();
// but Fq field elements use big-endian encoding, so flip the endianness.
let m: Vec<_> = Fq::char().as_ref().iter().cloned().rev().collect();
{ {
let mut o = o; let mut o = o;
o.as_mut()[..48].copy_from_slice(&m[..]); o.as_mut()[..48].copy_from_slice(m.as_ref());
if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() {
assert_eq!(coordinate, "x coordinate (c1)"); assert_eq!(coordinate, "x coordinate (c1)");
@ -282,7 +278,7 @@ fn test_g2_uncompressed_invalid_vectors() {
{ {
let mut o = o; let mut o = o;
o.as_mut()[48..96].copy_from_slice(&m[..]); o.as_mut()[48..96].copy_from_slice(m.as_ref());
if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() {
assert_eq!(coordinate, "x coordinate (c0)"); assert_eq!(coordinate, "x coordinate (c0)");
@ -293,7 +289,7 @@ fn test_g2_uncompressed_invalid_vectors() {
{ {
let mut o = o; let mut o = o;
o.as_mut()[96..144].copy_from_slice(&m[..]); o.as_mut()[96..144].copy_from_slice(m.as_ref());
if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() {
assert_eq!(coordinate, "y coordinate (c1)"); assert_eq!(coordinate, "y coordinate (c1)");
@ -304,7 +300,7 @@ fn test_g2_uncompressed_invalid_vectors() {
{ {
let mut o = o; let mut o = o;
o.as_mut()[144..].copy_from_slice(&m[..]); o.as_mut()[144..].copy_from_slice(m.as_ref());
if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() {
assert_eq!(coordinate, "y coordinate (c0)"); assert_eq!(coordinate, "y coordinate (c0)");
@ -411,13 +407,11 @@ fn test_g1_compressed_invalid_vectors() {
} }
} }
// PrimeField::char() returns the modulus in its little-endian byte representation, let m = Fq::char();
// but Fq field elements use big-endian encoding, so flip the endianness.
let m: Vec<_> = Fq::char().as_ref().iter().cloned().rev().collect();
{ {
let mut o = o; let mut o = o;
o.as_mut()[..48].copy_from_slice(&m[..]); o.as_mut()[..48].copy_from_slice(m.as_ref());
o.as_mut()[0] |= 0b1000_0000; o.as_mut()[0] |= 0b1000_0000;
if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() {
@ -527,13 +521,11 @@ fn test_g2_compressed_invalid_vectors() {
} }
} }
// PrimeField::char() returns the modulus in its little-endian byte representation, let m = Fq::char();
// but Fq field elements use big-endian encoding, so flip the endianness.
let m: Vec<_> = Fq::char().as_ref().iter().cloned().rev().collect();
{ {
let mut o = o; let mut o = o;
o.as_mut()[..48].copy_from_slice(&m[..]); o.as_mut()[..48].copy_from_slice(m.as_ref());
o.as_mut()[0] |= 0b1000_0000; o.as_mut()[0] |= 0b1000_0000;
if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() {
@ -545,7 +537,7 @@ fn test_g2_compressed_invalid_vectors() {
{ {
let mut o = o; let mut o = o;
o.as_mut()[48..96].copy_from_slice(&m[..]); o.as_mut()[48..96].copy_from_slice(m.as_ref());
o.as_mut()[0] |= 0b1000_0000; o.as_mut()[0] |= 0b1000_0000;
if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() { if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() {