Skip to content

Commit

Permalink
ff: Add PrimeField::ReprEndianness associated type
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
str4d committed May 2, 2020
1 parent a8be9d5 commit e6030c4
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 60 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ 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"] }

[features]
default = ["std"]
derive = ["ff_derive"]
std = ["byteorder"]
std = []

[badges]
maintenance = { status = "actively-developed" }
59 changes: 9 additions & 50 deletions ff_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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! {
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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
Expand Down
38 changes: 30 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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> {
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit e6030c4

Please sign in to comment.