ff: Add PrimeField::ReprEndianness associated type

This enables generic code to reliably operate on the bits of an encoded
field element, by converting them to and from a known (little)
endianness.

The BitAnd and Shr bounds on PrimeField are now removed, as users can
perform these operations themselves as needed.
This commit is contained in:
Jack Grigg
2020-05-01 14:20:35 +12:00
parent 55568b4d6e
commit 38f87c2e73
12 changed files with 101 additions and 323 deletions

View File

@@ -11,7 +11,7 @@ repository = "https://github.com/ebfull/ff"
edition = "2018"
[dependencies]
byteorder = { version = "1", optional = true }
byteorder = { version = "1", default-features = false }
ff_derive = { version = "0.6", path = "ff_derive", optional = true }
rand_core = { version = "0.5", default-features = false }
subtle = { version = "2.2.1", default-features = false, features = ["i128"] }
@@ -19,7 +19,7 @@ subtle = { version = "2.2.1", default-features = false, features = ["i128"] }
[features]
default = ["std"]
derive = ["ff_derive"]
std = ["byteorder"]
std = []
[badges]
maintenance = { status = "actively-developed" }

View File

@@ -31,6 +31,13 @@ impl FromStr for ReprEndianness {
}
impl ReprEndianness {
fn repr_endianness(&self) -> proc_macro2::TokenStream {
match self {
ReprEndianness::Big => quote! {::byteorder::BigEndian},
ReprEndianness::Little => quote! {::byteorder::LittleEndian},
}
}
fn from_repr(&self, name: &syn::Ident, limbs: usize) -> proc_macro2::TokenStream {
let read_repr = match self {
ReprEndianness::Big => quote! {
@@ -885,6 +892,7 @@ fn prime_field_impl(
let mont_reduce_self_params = mont_reduce_params(quote! {self}, limbs);
let mont_reduce_other_params = mont_reduce_params(quote! {other}, limbs);
let repr_endianness = endianness.repr_endianness();
let from_repr_impl = endianness.from_repr(name, limbs);
let into_repr_impl = endianness.into_repr(repr, &mont_reduce_self_params, limbs);
@@ -1117,58 +1125,9 @@ fn prime_field_impl(
}
}
impl ::core::ops::BitAnd<u64> for #name {
type Output = u64;
#[inline(always)]
fn bitand(mut self, rhs: u64) -> u64 {
self.mont_reduce(
#mont_reduce_self_params
);
self.0[0] & rhs
}
}
impl ::core::ops::Shr<u32> for #name {
type Output = #name;
#[inline(always)]
fn shr(mut self, mut n: u32) -> #name {
if n as usize >= 64 * #limbs {
return Self::from(0);
}
// Convert from Montgomery to native representation.
self.mont_reduce(
#mont_reduce_self_params
);
while n >= 64 {
let mut t = 0;
for i in self.0.iter_mut().rev() {
::core::mem::swap(&mut t, i);
}
n -= 64;
}
if n > 0 {
let mut t = 0;
for i in self.0.iter_mut().rev() {
let t2 = *i << (64 - n);
*i >>= n;
*i |= t;
t = t2;
}
}
// Convert back to Montgomery representation
self * R2
}
}
impl ::ff::PrimeField for #name {
type Repr = #repr;
type ReprEndianness = #repr_endianness;
fn from_repr(r: #repr) -> Option<#name> {
#from_repr_impl

View File

@@ -12,6 +12,7 @@ extern crate std;
#[cfg(feature = "derive")]
pub use ff_derive::*;
use byteorder::ByteOrder;
use core::convert::TryFrom;
use core::fmt;
use core::marker::PhantomData;
@@ -124,14 +125,36 @@ impl<T: Field> PowVartime<u64> for T {
const LIMB_SIZE: u64 = 64;
}
/// Helper trait for converting the binary representation of a prime field element into a
/// specific endianness. This is useful when you need to act on the bit representation
/// of an element generically, as the native binary representation of a prime field is
/// field-dependent.
pub trait Endianness: ByteOrder {
/// Converts the provided representation between native and little-endian.
fn toggle_little_endian<T: AsMut<[u8]>>(t: &mut T);
}
impl Endianness for byteorder::BigEndian {
fn toggle_little_endian<T: AsMut<[u8]>>(t: &mut T) {
t.as_mut().reverse();
}
}
impl Endianness for byteorder::LittleEndian {
fn toggle_little_endian<T: AsMut<[u8]>>(_: &mut T) {
// No-op
}
}
/// This represents an element of a prime field.
pub trait PrimeField:
Field + Ord + From<u64> + BitAnd<u64, Output = u64> + Shr<u32, Output = Self>
{
pub trait PrimeField: Field + Ord + From<u64> {
/// The prime field can be converted back and forth into this binary
/// representation.
type Repr: Default + AsRef<[u8]> + AsMut<[u8]> + From<Self> + for<'r> From<&'r Self>;
/// This indicates the endianness of [`PrimeField::Repr`].
type ReprEndianness: Endianness;
/// Interpret a string of numbers as a (congruent) prime field element.
/// Does not accept unnecessary leading zeroes or a blank string.
fn from_str(s: &str) -> Option<Self> {
@@ -176,16 +199,15 @@ pub trait PrimeField:
/// this prime field, failing if the input is not canonical (is not smaller than the
/// field's modulus).
///
/// The byte representation is interpreted with the same endianness as is returned
/// by [`PrimeField::into_repr`].
/// The byte representation is interpreted with the endianness defined by
/// [`PrimeField::ReprEndianness`].
fn from_repr(_: Self::Repr) -> Option<Self>;
/// Converts an element of the prime field into the standard byte representation for
/// this field.
///
/// Endianness of the byte representation is defined by the field implementation.
/// Callers should assume that it is the standard endianness used to represent encoded
/// elements of this particular field.
/// The endianness of the byte representation is defined by
/// [`PrimeField::ReprEndianness`].
fn into_repr(&self) -> Self::Repr;
/// Returns true iff this element is odd.