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

@@ -1,6 +1,6 @@
//! Helpers for testing circuit implementations.
use ff::{Field, PowVartime, PrimeField, ScalarEngine};
use ff::{Endianness, Field, PowVartime, PrimeField, ScalarEngine};
use crate::{ConstraintSystem, Index, LinearCombination, SynthesisError, Variable};
@@ -106,11 +106,9 @@ fn hash_lc<E: ScalarEngine>(terms: &[(Variable, E::Fr)], h: &mut Blake2sState) {
}
}
// BLS12-381's Fr is canonically serialized in little-endian, but the hasher
// writes its coefficients in big endian. For now, we flip the endianness
// manually, which is not necessarily correct for circuits using other curves.
// TODO: Fix this in a standalone commit, and document the no-op change.
let coeff_be: Vec<_> = coeff.into_repr().as_ref().iter().cloned().rev().collect();
let mut coeff_repr = coeff.into_repr();
<E::Fr as PrimeField>::ReprEndianness::toggle_little_endian(&mut coeff_repr);
let coeff_be: Vec<_> = coeff_repr.as_ref().iter().cloned().rev().collect();
buf[9..].copy_from_slice(&coeff_be[..]);
h.update(&buf);

View File

@@ -285,6 +285,7 @@ impl Default for FrRepr {
impl PrimeField for Fr {
type Repr = FrRepr;
type ReprEndianness = byteorder::LittleEndian;
const NUM_BITS: u32 = 16;
const CAPACITY: u32 = 15;

View File

@@ -1,6 +1,6 @@
use super::multicore::Worker;
use bit_vec::{self, BitVec};
use ff::{Field, PrimeField, ScalarEngine};
use ff::{Endianness, Field, PrimeField, ScalarEngine};
use futures::Future;
use group::{CurveAffine, CurveProjective};
use std::io;
@@ -195,8 +195,18 @@ where
bases.skip(1)?;
}
} else {
let exp = exp >> skip;
let exp = exp & ((1 << c) - 1);
let mut exp = exp.into_repr();
<<G::Engine as ScalarEngine>::Fr as PrimeField>::ReprEndianness::toggle_little_endian(&mut exp);
let exp = exp
.as_ref()
.into_iter()
.map(|b| (0..8).map(move |i| (b >> i) & 1u8))
.flatten()
.skip(skip as usize)
.take(c as usize)
.enumerate()
.fold(0u64, |acc, (i, b)| acc + ((b as u64) << i));
if exp != 0 {
(&mut buckets[(exp - 1) as usize])