From 49f119fb033dac88165028b7117e3d23e9f469a8 Mon Sep 17 00:00:00 2001
From: Jack Grigg <jack@z.cash>
Date: Thu, 23 Apr 2020 17:32:04 +1200
Subject: [PATCH] ff: Remove PrimeFieldRepr trait

The ff::PrimeField::Repr associated type now has the minimal necessary
bounds, which can be satisfied by a newtype around a byte array.
---
 bellman/src/gadgets/boolean.rs                |    4 +-
 bellman/src/gadgets/num.rs                    |   13 +-
 bellman/src/gadgets/test/mod.rs               |    9 +-
 bellman/src/groth16/prover.rs                 |   20 +-
 bellman/src/groth16/tests/dummy_engine.rs     |   92 +-
 bellman/src/multiexp.rs                       |   22 +-
 ff/ff_derive/src/lib.rs                       |  642 ++++++----
 ff/src/lib.rs                                 |  148 +--
 group/src/lib.rs                              |   10 +-
 group/src/wnaf.rs                             |   13 +-
 pairing/benches/bls12_381/fq.rs               |  138 +--
 pairing/benches/bls12_381/fr.rs               |  138 +--
 pairing/src/bls12_381/ec.rs                   |  697 +++++------
 pairing/src/bls12_381/fq.rs                   |  866 ++++----------
 pairing/src/bls12_381/fq2.rs                  |  508 ++++----
 pairing/src/bls12_381/fr.rs                   |  607 ++--------
 pairing/src/bls12_381/tests/mod.rs            |   84 +-
 pairing/src/tests/field.rs                    |    2 +-
 pairing/src/tests/repr.rs                     |   87 +-
 zcash_client_backend/src/proto/mod.rs         |    6 +-
 zcash_client_backend/src/welding_rig.rs       |    9 +-
 zcash_primitives/src/jubjub/edwards.rs        |   22 +-
 zcash_primitives/src/jubjub/fs.rs             | 1044 +++++------------
 zcash_primitives/src/jubjub/montgomery.rs     |    2 +-
 zcash_primitives/src/keys.rs                  |   14 +-
 zcash_primitives/src/merkle_tree.rs           |    6 +-
 zcash_primitives/src/note_encryption.rs       |   55 +-
 zcash_primitives/src/primitives.rs            |    4 +-
 zcash_primitives/src/redjubjub.rs             |   12 +-
 zcash_primitives/src/sapling.rs               |   12 +-
 .../src/transaction/components.rs             |   20 +-
 zcash_primitives/src/transaction/sighash.rs   |    4 +-
 zcash_primitives/src/zip32.rs                 |   17 +-
 zcash_proofs/src/circuit/ecc.rs               |    4 +-
 zcash_proofs/src/circuit/sapling.rs           |    8 +-
 35 files changed, 1705 insertions(+), 3634 deletions(-)

diff --git a/bellman/src/gadgets/boolean.rs b/bellman/src/gadgets/boolean.rs
index f117681..2ccad51 100644
--- a/bellman/src/gadgets/boolean.rs
+++ b/bellman/src/gadgets/boolean.rs
@@ -313,12 +313,12 @@ pub fn field_into_allocated_bits_le<E: ScalarEngine, CS: ConstraintSystem<E>, F:
     // Deconstruct in big-endian bit order
     let values = match value {
         Some(ref value) => {
-            let mut field_char = BitIterator::<u64, _>::new(F::char());
+            let mut field_char = BitIterator::<u8, _>::new(F::char());
 
             let mut tmp = Vec::with_capacity(F::NUM_BITS as usize);
 
             let mut found_one = false;
-            for b in BitIterator::<u64, _>::new(value.into_repr()) {
+            for b in BitIterator::<u8, _>::new(value.into_repr()) {
                 // Skip leading bits
                 found_one |= field_char.next().unwrap();
                 if !found_one {
diff --git a/bellman/src/gadgets/num.rs b/bellman/src/gadgets/num.rs
index f8ce6d3..8f73663 100644
--- a/bellman/src/gadgets/num.rs
+++ b/bellman/src/gadgets/num.rs
@@ -1,6 +1,6 @@
 //! Gadgets representing numbers in the scalar field of the underlying curve.
 
-use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, ScalarEngine};
+use ff::{BitIterator, Field, PrimeField, ScalarEngine};
 use std::ops::{AddAssign, MulAssign};
 
 use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable};
@@ -103,11 +103,8 @@ impl<E: ScalarEngine> AllocatedNum<E> {
 
         // We want to ensure that the bit representation of a is
         // less than or equal to r - 1.
-        let mut a = self
-            .value
-            .map(|e| BitIterator::<u64, _>::new(e.into_repr()));
-        let mut b = E::Fr::char();
-        b.sub_noborrow(&1.into());
+        let mut a = self.value.map(|e| BitIterator::<u8, _>::new(e.into_repr()));
+        let b = (-E::Fr::one()).into_repr();
 
         let mut result = vec![];
 
@@ -117,7 +114,7 @@ impl<E: ScalarEngine> AllocatedNum<E> {
 
         let mut found_one = false;
         let mut i = 0;
-        for b in BitIterator::<u64, _>::new(b) {
+        for b in BitIterator::<u8, _>::new(b) {
             let a_bit = a.as_mut().map(|e| e.next().unwrap());
 
             // Skip over unset bits at the beginning
@@ -560,7 +557,7 @@ mod test {
 
             assert!(cs.is_satisfied());
 
-            for (b, a) in BitIterator::<u64, _>::new(r.into_repr())
+            for (b, a) in BitIterator::<u8, _>::new(r.into_repr())
                 .skip(1)
                 .zip(bits.iter().rev())
             {
diff --git a/bellman/src/gadgets/test/mod.rs b/bellman/src/gadgets/test/mod.rs
index a803acc..b082907 100644
--- a/bellman/src/gadgets/test/mod.rs
+++ b/bellman/src/gadgets/test/mod.rs
@@ -1,6 +1,6 @@
 //! Helpers for testing circuit implementations.
 
-use ff::{Field, PowVartime, PrimeField, PrimeFieldRepr, ScalarEngine};
+use ff::{Field, PowVartime, PrimeField, ScalarEngine};
 
 use crate::{ConstraintSystem, Index, LinearCombination, SynthesisError, Variable};
 
@@ -106,7 +106,12 @@ fn hash_lc<E: ScalarEngine>(terms: &[(Variable, E::Fr)], h: &mut Blake2sState) {
             }
         }
 
-        coeff.into_repr().write_be(&mut buf[9..]).unwrap();
+        // 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();
+        buf[9..].copy_from_slice(&coeff_be[..]);
 
         h.update(&buf);
     }
diff --git a/bellman/src/groth16/prover.rs b/bellman/src/groth16/prover.rs
index c31b4db..34abbb4 100644
--- a/bellman/src/groth16/prover.rs
+++ b/bellman/src/groth16/prover.rs
@@ -4,7 +4,7 @@ use std::sync::Arc;
 
 use futures::Future;
 
-use ff::{Field, PrimeField};
+use ff::Field;
 use group::{CurveAffine, CurveProjective};
 use pairing::Engine;
 
@@ -229,26 +229,14 @@ where
         let a_len = a.len() - 1;
         a.truncate(a_len);
         // TODO: parallelize if it's even helpful
-        let a = Arc::new(a.into_iter().map(|s| s.0.into_repr()).collect::<Vec<_>>());
+        let a = Arc::new(a.into_iter().map(|s| s.0).collect::<Vec<_>>());
 
         multiexp(&worker, params.get_h(a.len())?, FullDensity, a)
     };
 
     // TODO: parallelize if it's even helpful
-    let input_assignment = Arc::new(
-        prover
-            .input_assignment
-            .into_iter()
-            .map(|s| s.into_repr())
-            .collect::<Vec<_>>(),
-    );
-    let aux_assignment = Arc::new(
-        prover
-            .aux_assignment
-            .into_iter()
-            .map(|s| s.into_repr())
-            .collect::<Vec<_>>(),
-    );
+    let input_assignment = Arc::new(prover.input_assignment);
+    let aux_assignment = Arc::new(prover.aux_assignment);
 
     let l = multiexp(
         &worker,
diff --git a/bellman/src/groth16/tests/dummy_engine.rs b/bellman/src/groth16/tests/dummy_engine.rs
index 6d3ae73..69937ce 100644
--- a/bellman/src/groth16/tests/dummy_engine.rs
+++ b/bellman/src/groth16/tests/dummy_engine.rs
@@ -1,6 +1,4 @@
-use ff::{
-    Field, PowVartime, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, ScalarEngine, SqrtField,
-};
+use ff::{Field, PowVartime, PrimeField, ScalarEngine, SqrtField};
 use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError};
 use pairing::{Engine, PairingCurveAffine};
 
@@ -259,86 +257,35 @@ impl SqrtField for Fr {
 }
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub struct FrRepr([u64; 1]);
-
-impl Ord for FrRepr {
-    fn cmp(&self, other: &FrRepr) -> Ordering {
-        (self.0)[0].cmp(&(other.0)[0])
-    }
-}
-
-impl PartialOrd for FrRepr {
-    fn partial_cmp(&self, other: &FrRepr) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-impl fmt::Display for FrRepr {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
-        write!(f, "{}", (self.0)[0])
-    }
-}
-
-impl From<u64> for FrRepr {
-    fn from(v: u64) -> FrRepr {
-        FrRepr([v])
-    }
-}
+pub struct FrRepr([u8; 8]);
 
 impl From<Fr> for FrRepr {
     fn from(v: Fr) -> FrRepr {
-        FrRepr([(v.0).0 as u64])
+        FrRepr::from(&v)
     }
 }
 
-impl AsMut<[u64]> for FrRepr {
-    fn as_mut(&mut self) -> &mut [u64] {
+impl<'a> From<&'a Fr> for FrRepr {
+    fn from(v: &'a Fr) -> FrRepr {
+        FrRepr(((v.0).0 as u64).to_le_bytes())
+    }
+}
+
+impl AsMut<[u8]> for FrRepr {
+    fn as_mut(&mut self) -> &mut [u8] {
         &mut self.0[..]
     }
 }
 
-impl AsRef<[u64]> for FrRepr {
-    fn as_ref(&self) -> &[u64] {
+impl AsRef<[u8]> for FrRepr {
+    fn as_ref(&self) -> &[u8] {
         &self.0[..]
     }
 }
 
 impl Default for FrRepr {
     fn default() -> FrRepr {
-        FrRepr::from(0u64)
-    }
-}
-
-impl PrimeFieldRepr for FrRepr {
-    fn sub_noborrow(&mut self, other: &Self) {
-        self.0[0] = self.0[0].wrapping_sub(other.0[0]);
-    }
-    fn add_nocarry(&mut self, other: &Self) {
-        self.0[0] = self.0[0].wrapping_add(other.0[0]);
-    }
-    fn num_bits(&self) -> u32 {
-        64 - self.0[0].leading_zeros()
-    }
-    fn is_zero(&self) -> bool {
-        self.0[0] == 0
-    }
-    fn is_odd(&self) -> bool {
-        !self.is_even()
-    }
-    fn is_even(&self) -> bool {
-        self.0[0] % 2 == 0
-    }
-    fn div2(&mut self) {
-        self.shr(1)
-    }
-    fn shr(&mut self, amt: u32) {
-        self.0[0] >>= amt;
-    }
-    fn mul2(&mut self) {
-        self.shl(1)
-    }
-    fn shl(&mut self, amt: u32) {
-        self.0[0] <<= amt;
+        FrRepr([0; 8])
     }
 }
 
@@ -349,11 +296,12 @@ impl PrimeField for Fr {
     const CAPACITY: u32 = 15;
     const S: u32 = 10;
 
-    fn from_repr(repr: FrRepr) -> Result<Self, PrimeFieldDecodingError> {
-        if repr.0[0] >= (MODULUS_R.0 as u64) {
-            Err(PrimeFieldDecodingError::NotInField)
+    fn from_repr(repr: FrRepr) -> Option<Self> {
+        let v = u64::from_le_bytes(repr.0);
+        if v >= (MODULUS_R.0 as u64) {
+            None
         } else {
-            Ok(Fr(Wrapping(repr.0[0] as u32)))
+            Some(Fr(Wrapping(v as u32)))
         }
     }
 
@@ -464,7 +412,7 @@ impl CurveProjective for Fr {
         *self
     }
 
-    fn recommended_wnaf_for_scalar(_: &<Self::Scalar as PrimeField>::Repr) -> usize {
+    fn recommended_wnaf_for_scalar(_: &Self::Scalar) -> usize {
         3
     }
 
diff --git a/bellman/src/multiexp.rs b/bellman/src/multiexp.rs
index 0bc61ba..18f48bd 100644
--- a/bellman/src/multiexp.rs
+++ b/bellman/src/multiexp.rs
@@ -1,6 +1,6 @@
 use super::multicore::Worker;
 use bit_vec::{self, BitVec};
-use ff::{Field, PrimeField, PrimeFieldRepr, ScalarEngine};
+use ff::{Field, PrimeField, ScalarEngine};
 use futures::Future;
 use group::{CurveAffine, CurveProjective};
 use std::io;
@@ -154,7 +154,7 @@ fn multiexp_inner<Q, D, G, S>(
     pool: &Worker,
     bases: S,
     density_map: D,
-    exponents: Arc<Vec<<<G::Engine as ScalarEngine>::Fr as PrimeField>::Repr>>,
+    exponents: Arc<Vec<<G::Engine as ScalarEngine>::Fr>>,
     mut skip: u32,
     c: u32,
     handle_trivial: bool,
@@ -181,13 +181,12 @@ where
             // Create space for the buckets
             let mut buckets = vec![G::zero(); (1 << c) - 1];
 
-            let zero = <G::Engine as ScalarEngine>::Fr::zero().into_repr();
-            let one = <G::Engine as ScalarEngine>::Fr::one().into_repr();
+            let one = <G::Engine as ScalarEngine>::Fr::one();
 
             // Sort the bases into buckets
             for (&exp, density) in exponents.iter().zip(density_map.as_ref().iter()) {
                 if density {
-                    if exp == zero {
+                    if exp.is_zero() {
                         bases.skip(1)?;
                     } else if exp == one {
                         if handle_trivial {
@@ -196,9 +195,8 @@ where
                             bases.skip(1)?;
                         }
                     } else {
-                        let mut exp = exp;
-                        exp.shr(skip);
-                        let exp = exp.as_ref()[0] % (1 << c);
+                        let exp = exp >> skip;
+                        let exp = exp & ((1 << c) - 1);
 
                         if exp != 0 {
                             (&mut buckets[(exp - 1) as usize])
@@ -261,7 +259,7 @@ pub fn multiexp<Q, D, G, S>(
     pool: &Worker,
     bases: S,
     density_map: D,
-    exponents: Arc<Vec<<<G::Engine as ScalarEngine>::Fr as PrimeField>::Repr>>,
+    exponents: Arc<Vec<<G::Engine as ScalarEngine>::Fr>>,
 ) -> Box<dyn Future<Item = G, Error = SynthesisError>>
 where
     for<'a> &'a Q: QueryDensity,
@@ -290,14 +288,14 @@ where
 fn test_with_bls12() {
     fn naive_multiexp<G: CurveProjective>(
         bases: Arc<Vec<<G as CurveProjective>::Affine>>,
-        exponents: Arc<Vec<<G::Scalar as PrimeField>::Repr>>,
+        exponents: Arc<Vec<G::Scalar>>,
     ) -> G {
         assert_eq!(bases.len(), exponents.len());
 
         let mut acc = G::zero();
 
         for (base, exp) in bases.iter().zip(exponents.iter()) {
-            AddAssign::<&G>::add_assign(&mut acc, &base.mul(*exp));
+            AddAssign::<&G>::add_assign(&mut acc, &base.mul(exp.into_repr()));
         }
 
         acc
@@ -311,7 +309,7 @@ fn test_with_bls12() {
     let rng = &mut rand::thread_rng();
     let v = Arc::new(
         (0..SAMPLES)
-            .map(|_| <Bls12 as ScalarEngine>::Fr::random(rng).into_repr())
+            .map(|_| <Bls12 as ScalarEngine>::Fr::random(rng))
             .collect::<Vec<_>>(),
     );
     let g = Arc::new(
diff --git a/ff/ff_derive/src/lib.rs b/ff/ff_derive/src/lib.rs
index f5439c5..0a7db91 100644
--- a/ff/ff_derive/src/lib.rs
+++ b/ff/ff_derive/src/lib.rs
@@ -8,19 +8,105 @@ use num_integer::Integer;
 use num_traits::{One, ToPrimitive, Zero};
 use quote::quote;
 use quote::TokenStreamExt;
+use std::iter;
 use std::str::FromStr;
 
 mod pow_fixed;
 
-#[proc_macro_derive(PrimeField, attributes(PrimeFieldModulus, PrimeFieldGenerator))]
+enum ReprEndianness {
+    Big,
+    Little,
+}
+
+impl FromStr for ReprEndianness {
+    type Err = ();
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s {
+            "big" => Ok(ReprEndianness::Big),
+            "little" => Ok(ReprEndianness::Little),
+            _ => Err(()),
+        }
+    }
+}
+
+impl ReprEndianness {
+    fn from_repr(&self, name: &syn::Ident, limbs: usize) -> proc_macro2::TokenStream {
+        let read_repr = match self {
+            ReprEndianness::Big => quote! {
+                ::byteorder::BigEndian::read_u64_into(r.as_ref(), &mut inner[..]);
+                inner.reverse();
+            },
+            ReprEndianness::Little => quote! {
+                ::byteorder::LittleEndian::read_u64_into(r.as_ref(), &mut inner[..]);
+            },
+        };
+
+        quote! {
+            use ::byteorder::ByteOrder;
+
+            let r = {
+                let mut inner = [0u64; #limbs];
+                #read_repr
+                #name(inner)
+            };
+
+            if r.is_valid() {
+                Some(r * R2)
+            } else {
+                None
+            }
+        }
+    }
+
+    fn into_repr(
+        &self,
+        repr: &syn::Ident,
+        mont_reduce_self_params: &proc_macro2::TokenStream,
+        limbs: usize,
+    ) -> proc_macro2::TokenStream {
+        let bytes = limbs * 8;
+
+        let write_repr = match self {
+            ReprEndianness::Big => quote! {
+                r.0.reverse();
+                ::byteorder::BigEndian::write_u64_into(&r.0, &mut repr[..]);
+            },
+            ReprEndianness::Little => quote! {
+                ::byteorder::LittleEndian::write_u64_into(&r.0, &mut repr[..]);
+            },
+        };
+
+        quote! {
+            use ::byteorder::ByteOrder;
+
+            let mut r = *self;
+            r.mont_reduce(
+                #mont_reduce_self_params
+            );
+
+            let mut repr = [0u8; #bytes];
+            #write_repr
+            #repr(repr)
+        }
+    }
+
+    fn iter_be(&self) -> proc_macro2::TokenStream {
+        match self {
+            ReprEndianness::Big => quote! {self.0.iter()},
+            ReprEndianness::Little => quote! {self.0.iter().rev()},
+        }
+    }
+}
+
+#[proc_macro_derive(
+    PrimeField,
+    attributes(PrimeFieldModulus, PrimeFieldGenerator, PrimeFieldReprEndianness)
+)]
 pub fn prime_field(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
     // Parse the type definition
     let ast: syn::DeriveInput = syn::parse(input).unwrap();
 
-    // The struct we're deriving for is a wrapper around a "Repr" type we must construct.
-    let repr_ident = fetch_wrapped_ident(&ast.data)
-        .expect("PrimeField derive only operates over tuple structs of a single item");
-
     // We're given the modulus p of the prime field
     let modulus: BigUint = fetch_attr("PrimeFieldModulus", &ast.attrs)
         .expect("Please supply a PrimeFieldModulus attribute")
@@ -29,11 +115,18 @@ pub fn prime_field(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
 
     // We may be provided with a generator of p - 1 order. It is required that this generator be quadratic
     // nonresidue.
+    // TODO: Compute this ourselves.
     let generator: BigUint = fetch_attr("PrimeFieldGenerator", &ast.attrs)
         .expect("Please supply a PrimeFieldGenerator attribute")
         .parse()
         .expect("PrimeFieldGenerator should be a number");
 
+    // Field element representations may be in little-endian or big-endian.
+    let endianness = fetch_attr("PrimeFieldReprEndianness", &ast.attrs)
+        .expect("Please supply a PrimeFieldReprEndianness attribute")
+        .parse()
+        .expect("PrimeFieldReprEndianness should be 'big' or 'little'");
+
     // The arithmetic in this library only works if the modulus*2 is smaller than the backing
     // representation. Compute the number of limbs we need.
     let mut limbs = 1;
@@ -46,34 +139,146 @@ pub fn prime_field(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
         }
     }
 
+    // The struct we're deriving for must be a wrapper around `pub [u64; limbs]`.
+    if let Some(err) = validate_struct(&ast, limbs) {
+        return err.into();
+    }
+
+    // Generate the identifier for the "Repr" type we must construct.
+    let repr_ident = syn::Ident::new(
+        &format!("{}Repr", ast.ident),
+        proc_macro2::Span::call_site(),
+    );
+
     let mut gen = proc_macro2::TokenStream::new();
 
     let (constants_impl, sqrt_impl) =
         prime_field_constants_and_sqrt(&ast.ident, &repr_ident, &modulus, limbs, generator);
 
     gen.extend(constants_impl);
-    gen.extend(prime_field_repr_impl(&repr_ident, limbs));
-    gen.extend(prime_field_impl(&ast.ident, &repr_ident, &modulus, limbs));
+    gen.extend(prime_field_repr_impl(&repr_ident, &endianness, limbs * 8));
+    gen.extend(prime_field_impl(
+        &ast.ident,
+        &repr_ident,
+        &modulus,
+        &endianness,
+        limbs,
+    ));
     gen.extend(sqrt_impl);
 
     // Return the generated impl
     gen.into()
 }
 
-/// Fetches the ident being wrapped by the type we're deriving.
-fn fetch_wrapped_ident(body: &syn::Data) -> Option<syn::Ident> {
-    if let syn::Data::Struct(ref variant_data) = body {
-        if let syn::Fields::Unnamed(ref fields) = variant_data.fields {
-            if fields.unnamed.len() == 1 {
-                if let syn::Type::Path(ref path) = fields.unnamed[0].ty {
-                    if path.path.segments.len() == 1 {
-                        return Some(path.path.segments[0].ident.clone());
-                    }
-                }
-            }
+/// Checks that `body` contains `pub [u64; limbs]`.
+fn validate_struct(ast: &syn::DeriveInput, limbs: usize) -> Option<proc_macro2::TokenStream> {
+    // The body should be a struct.
+    let variant_data = match &ast.data {
+        syn::Data::Struct(x) => x,
+        _ => {
+            return Some(
+                syn::Error::new_spanned(ast, "PrimeField derive only works for structs.")
+                    .to_compile_error(),
+            )
         }
     };
 
+    // The struct should contain a single unnamed field.
+    let fields = match &variant_data.fields {
+        syn::Fields::Unnamed(x) if x.unnamed.len() == 1 => x,
+        _ => {
+            return Some(
+                syn::Error::new_spanned(
+                    &ast.ident,
+                    format!(
+                        "The struct must contain an array of limbs. Change this to `{}([u64; {}])`",
+                        ast.ident, limbs,
+                    ),
+                )
+                .to_compile_error(),
+            )
+        }
+    };
+    let field = &fields.unnamed[0];
+
+    // The field should be an array.
+    let arr = match &field.ty {
+        syn::Type::Array(x) => x,
+        _ => {
+            return Some(
+                syn::Error::new_spanned(
+                    field,
+                    format!(
+                        "The inner field must be an array of limbs. Change this to `[u64; {}]`",
+                        limbs,
+                    ),
+                )
+                .to_compile_error(),
+            )
+        }
+    };
+
+    // The array's element type should be `u64`.
+    if match arr.elem.as_ref() {
+        syn::Type::Path(path) => path
+            .path
+            .get_ident()
+            .map(|x| x.to_string() != "u64")
+            .unwrap_or(true),
+        _ => true,
+    } {
+        return Some(
+            syn::Error::new_spanned(
+                arr,
+                format!(
+                    "PrimeField derive requires 64-bit limbs. Change this to `[u64; {}]",
+                    limbs
+                ),
+            )
+            .to_compile_error(),
+        );
+    }
+
+    // The array's length should be a literal int equal to `limbs`.
+    let lit_int = match match &arr.len {
+        syn::Expr::Lit(expr_lit) => match &expr_lit.lit {
+            syn::Lit::Int(lit_int) => Some(lit_int),
+            _ => None,
+        },
+        _ => None,
+    } {
+        Some(x) => x,
+        _ => {
+            return Some(
+                syn::Error::new_spanned(
+                    arr,
+                    format!("To derive PrimeField, change this to `[u64; {}]`.", limbs),
+                )
+                .to_compile_error(),
+            )
+        }
+    };
+    if lit_int.base10_digits() != limbs.to_string() {
+        return Some(
+            syn::Error::new_spanned(
+                lit_int,
+                format!("The given modulus requires {} limbs.", limbs),
+            )
+            .to_compile_error(),
+        );
+    }
+
+    // The field should not be public.
+    match &field.vis {
+        syn::Visibility::Inherited => (),
+        _ => {
+            return Some(
+                syn::Error::new_spanned(&field.vis, "Field must not be public.").to_compile_error(),
+            )
+        }
+    }
+
+    // Valid!
     None
 }
 
@@ -102,18 +307,49 @@ fn fetch_attr(name: &str, attrs: &[syn::Attribute]) -> Option<String> {
     None
 }
 
-// Implement PrimeFieldRepr for the wrapped ident `repr` with `limbs` limbs.
-fn prime_field_repr_impl(repr: &syn::Ident, limbs: usize) -> proc_macro2::TokenStream {
+// Implement the wrapped ident `repr` with `bytes` bytes.
+fn prime_field_repr_impl(
+    repr: &syn::Ident,
+    endianness: &ReprEndianness,
+    bytes: usize,
+) -> proc_macro2::TokenStream {
+    let repr_iter_be = endianness.iter_be();
+
     quote! {
-        #[derive(Copy, Clone, PartialEq, Eq, Default)]
-        pub struct #repr(pub [u64; #limbs]);
+        #[derive(Copy, Clone)]
+        pub struct #repr(pub [u8; #bytes]);
+
+        impl ::subtle::ConstantTimeEq for #repr {
+            fn ct_eq(&self, other: &#repr) -> ::subtle::Choice {
+                self.0
+                    .iter()
+                    .zip(other.0.iter())
+                    .map(|(a, b)| a.ct_eq(b))
+                    .fold(1.into(), |acc, x| acc & x)
+            }
+        }
+
+        impl ::core::cmp::PartialEq for #repr {
+            fn eq(&self, other: &#repr) -> bool {
+                use ::subtle::ConstantTimeEq;
+                self.ct_eq(other).into()
+            }
+        }
+
+        impl ::core::cmp::Eq for #repr { }
+
+        impl ::core::default::Default for #repr {
+            fn default() -> #repr {
+                #repr([0u8; #bytes])
+            }
+        }
 
         impl ::core::fmt::Debug for #repr
         {
             fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
                 write!(f, "0x")?;
-                for i in self.0.iter().rev() {
-                    write!(f, "{:016x}", *i)?;
+                for i in #repr_iter_be {
+                    write!(f, "{:02x}", *i)?;
                 }
 
                 Ok(())
@@ -123,183 +359,27 @@ fn prime_field_repr_impl(repr: &syn::Ident, limbs: usize) -> proc_macro2::TokenS
         impl ::core::fmt::Display for #repr {
             fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
                 write!(f, "0x")?;
-                for i in self.0.iter().rev() {
-                    write!(f, "{:016x}", *i)?;
+                for i in #repr_iter_be {
+                    write!(f, "{:02x}", *i)?;
                 }
 
                 Ok(())
             }
         }
 
-        impl AsRef<[u64]> for #repr {
+        impl AsRef<[u8]> for #repr {
             #[inline(always)]
-            fn as_ref(&self) -> &[u64] {
+            fn as_ref(&self) -> &[u8] {
                 &self.0
             }
         }
 
-        impl AsMut<[u64]> for #repr {
+        impl AsMut<[u8]> for #repr {
             #[inline(always)]
-            fn as_mut(&mut self) -> &mut [u64] {
+            fn as_mut(&mut self) -> &mut [u8] {
                 &mut self.0
             }
         }
-
-        impl From<u64> for #repr {
-            #[inline(always)]
-            fn from(val: u64) -> #repr {
-                use core::default::Default;
-
-                let mut repr = Self::default();
-                repr.0[0] = val;
-                repr
-            }
-        }
-
-        impl Ord for #repr {
-            #[inline(always)]
-            fn cmp(&self, other: &#repr) -> ::core::cmp::Ordering {
-                for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) {
-                    if a < b {
-                        return ::core::cmp::Ordering::Less
-                    } else if a > b {
-                        return ::core::cmp::Ordering::Greater
-                    }
-                }
-
-                ::core::cmp::Ordering::Equal
-            }
-        }
-
-        impl PartialOrd for #repr {
-            #[inline(always)]
-            fn partial_cmp(&self, other: &#repr) -> Option<::core::cmp::Ordering> {
-                Some(self.cmp(other))
-            }
-        }
-
-        impl ::ff::PrimeFieldRepr for #repr {
-            #[inline(always)]
-            fn is_odd(&self) -> bool {
-                self.0[0] & 1 == 1
-            }
-
-            #[inline(always)]
-            fn is_even(&self) -> bool {
-                !self.is_odd()
-            }
-
-            #[inline(always)]
-            fn is_zero(&self) -> bool {
-                self.0.iter().all(|&e| e == 0)
-            }
-
-            #[inline(always)]
-            fn shr(&mut self, mut n: u32) {
-                if n as usize >= 64 * #limbs {
-                    *self = Self::from(0);
-                    return;
-                }
-
-                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;
-                    }
-                }
-            }
-
-            #[inline(always)]
-            fn div2(&mut self) {
-                let mut t = 0;
-                for i in self.0.iter_mut().rev() {
-                    let t2 = *i << 63;
-                    *i >>= 1;
-                    *i |= t;
-                    t = t2;
-                }
-            }
-
-            #[inline(always)]
-            fn mul2(&mut self) {
-                let mut last = 0;
-                for i in &mut self.0 {
-                    let tmp = *i >> 63;
-                    *i <<= 1;
-                    *i |= last;
-                    last = tmp;
-                }
-            }
-
-            #[inline(always)]
-            fn shl(&mut self, mut n: u32) {
-                if n as usize >= 64 * #limbs {
-                    *self = Self::from(0);
-                    return;
-                }
-
-                while n >= 64 {
-                    let mut t = 0;
-                    for i in &mut self.0 {
-                        ::core::mem::swap(&mut t, i);
-                    }
-                    n -= 64;
-                }
-
-                if n > 0 {
-                    let mut t = 0;
-                    for i in &mut self.0 {
-                        let t2 = *i >> (64 - n);
-                        *i <<= n;
-                        *i |= t;
-                        t = t2;
-                    }
-                }
-            }
-
-            #[inline(always)]
-            fn num_bits(&self) -> u32 {
-                let mut ret = (#limbs as u32) * 64;
-                for i in self.0.iter().rev() {
-                    let leading = i.leading_zeros();
-                    ret -= leading;
-                    if leading != 64 {
-                        break;
-                    }
-                }
-
-                ret
-            }
-
-            #[inline(always)]
-            fn add_nocarry(&mut self, other: &#repr) {
-                let mut carry = 0;
-
-                for (a, b) in self.0.iter_mut().zip(other.0.iter()) {
-                    *a = ::ff::adc(*a, *b, &mut carry);
-                }
-            }
-
-            #[inline(always)]
-            fn sub_noborrow(&mut self, other: &#repr) {
-                let mut borrow = 0;
-
-                for (a, b) in self.0.iter_mut().zip(other.0.iter()) {
-                    *a = ::ff::sbb(*a, *b, &mut borrow);
-                }
-            }
-        }
     }
 }
 
@@ -455,7 +535,7 @@ fn prime_field_constants_and_sqrt(
                     let mut b = x * &w;
 
                     // Initialize z as the 2^S root of unity.
-                    let mut z = #name(ROOT_OF_UNITY);
+                    let mut z = ROOT_OF_UNITY;
 
                     for max_v in (1..=S).rev() {
                         let mut k = 1;
@@ -494,6 +574,11 @@ fn prime_field_constants_and_sqrt(
     let r2 = biguint_to_u64_vec((&r * &r) % modulus, limbs);
 
     let r = biguint_to_u64_vec(r, limbs);
+    let modulus_repr = {
+        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);
 
     // Compute -m^-1 mod 2**64 by exponentiating by totient(2**64) - 1
@@ -507,7 +592,10 @@ fn prime_field_constants_and_sqrt(
     (
         quote! {
             /// This is the modulus m of the prime field
-            const MODULUS: #repr = #repr([#(#modulus,)*]);
+            const MODULUS: #repr = #repr([#(#modulus_repr,)*]);
+
+            /// This is the modulus m of the prime field in limb form
+            const MODULUS_LIMBS: #name = #name([#(#modulus,)*]);
 
             /// The number of bits needed to represent the modulus.
             const MODULUS_BITS: u32 = #modulus_num_bits;
@@ -517,23 +605,23 @@ fn prime_field_constants_and_sqrt(
             const REPR_SHAVE_BITS: u32 = #repr_shave_bits;
 
             /// 2^{limbs*64} mod m
-            const R: #repr = #repr(#r);
+            const R: #name = #name(#r);
 
             /// 2^{limbs*64*2} mod m
-            const R2: #repr = #repr(#r2);
+            const R2: #name = #name(#r2);
 
             /// -(m^{-1} mod m) mod m
             const INV: u64 = #inv;
 
             /// Multiplicative generator of `MODULUS` - 1 order, also quadratic
             /// nonresidue.
-            const GENERATOR: #repr = #repr(#generator);
+            const GENERATOR: #name = #name(#generator);
 
             /// 2^s * t = MODULUS - 1 with t odd
             const S: u32 = #s;
 
             /// 2^s root of unity computed by GENERATOR^t
-            const ROOT_OF_UNITY: #repr = #repr(#root_of_unity);
+            const ROOT_OF_UNITY: #name = #name(#root_of_unity);
         },
         sqrt_impl,
     )
@@ -544,6 +632,7 @@ fn prime_field_impl(
     name: &syn::Ident,
     repr: &syn::Ident,
     modulus: &BigUint,
+    endianness: &ReprEndianness,
     limbs: usize,
 ) -> proc_macro2::TokenStream {
     // Returns r{n} as an ident.
@@ -575,14 +664,14 @@ fn prime_field_impl(
                 gen.extend(quote! {
                     let k = #temp.wrapping_mul(INV);
                     let mut carry = 0;
-                    ::ff::mac_with_carry(#temp, k, MODULUS.0[0], &mut carry);
+                    ::ff::mac_with_carry(#temp, k, MODULUS_LIMBS.0[0], &mut carry);
                 });
             }
 
             for j in 1..limbs {
                 let temp = get_temp(i + j);
                 gen.extend(quote! {
-                    #temp = ::ff::mac_with_carry(#temp, k, MODULUS.0[#j], &mut carry);
+                    #temp = ::ff::mac_with_carry(#temp, k, MODULUS_LIMBS.0[#j], &mut carry);
                 });
             }
 
@@ -609,7 +698,7 @@ fn prime_field_impl(
             let temp = get_temp(limbs + i);
 
             gen.extend(quote! {
-                (self.0).0[#i] = #temp;
+                self.0[#i] = #temp;
             });
         }
 
@@ -628,11 +717,11 @@ fn prime_field_impl(
                 let temp = get_temp(i + j);
                 if i == 0 {
                     gen.extend(quote! {
-                        let #temp = ::ff::mac_with_carry(0, (#a.0).0[#i], (#a.0).0[#j], &mut carry);
+                        let #temp = ::ff::mac_with_carry(0, #a.0[#i], #a.0[#j], &mut carry);
                     });
                 } else {
-                    gen.extend(quote!{
-                        let #temp = ::ff::mac_with_carry(#temp, (#a.0).0[#i], (#a.0).0[#j], &mut carry);
+                    gen.extend(quote! {
+                        let #temp = ::ff::mac_with_carry(#temp, #a.0[#i], #a.0[#j], &mut carry);
                     });
                 }
             }
@@ -672,11 +761,11 @@ fn prime_field_impl(
             let temp1 = get_temp(i * 2 + 1);
             if i == 0 {
                 gen.extend(quote! {
-                    let #temp0 = ::ff::mac_with_carry(0, (#a.0).0[#i], (#a.0).0[#i], &mut carry);
+                    let #temp0 = ::ff::mac_with_carry(0, #a.0[#i], #a.0[#i], &mut carry);
                 });
             } else {
-                gen.extend(quote!{
-                    let #temp0 = ::ff::mac_with_carry(#temp0, (#a.0).0[#i], (#a.0).0[#i], &mut carry);
+                gen.extend(quote! {
+                    let #temp0 = ::ff::mac_with_carry(#temp0, #a.0[#i], #a.0[#i], &mut carry);
                 });
             }
 
@@ -717,11 +806,11 @@ fn prime_field_impl(
 
                 if i == 0 {
                     gen.extend(quote! {
-                        let #temp = ::ff::mac_with_carry(0, (#a.0).0[#i], (#b.0).0[#j], &mut carry);
+                        let #temp = ::ff::mac_with_carry(0, #a.0[#i], #b.0[#j], &mut carry);
                     });
                 } else {
-                    gen.extend(quote!{
-                        let #temp = ::ff::mac_with_carry(#temp, (#a.0).0[#i], (#b.0).0[#j], &mut carry);
+                    gen.extend(quote! {
+                        let #temp = ::ff::mac_with_carry(#temp, #a.0[#i], #b.0[#j], &mut carry);
                     });
                 }
             }
@@ -778,10 +867,10 @@ fn prime_field_impl(
     let invert_impl = inv_impl(quote! {self}, name, modulus);
     let montgomery_impl = mont_impl(limbs);
 
-    // (self.0).0[0].ct_eq(&(other.0).0[0]) & (self.0).0[1].ct_eq(&(other.0).0[1]) & ...
+    // self.0[0].ct_eq(&other.0[0]) & self.0[1].ct_eq(&other.0[1]) & ...
     let mut ct_eq_impl = proc_macro2::TokenStream::new();
     ct_eq_impl.append_separated(
-        (0..limbs).map(|i| quote! { (self.0).0[#i].ct_eq(&(other.0).0[#i]) }),
+        (0..limbs).map(|i| quote! { self.0[#i].ct_eq(&other.0[#i]) }),
         proc_macro2::Punct::new('&', proc_macro2::Spacing::Alone),
     );
 
@@ -790,7 +879,7 @@ fn prime_field_impl(
         let mut mont_reduce_params = proc_macro2::TokenStream::new();
         mont_reduce_params.append_separated(
             (0..limbs)
-                .map(|i| quote! { (#a.0).0[#i] })
+                .map(|i| quote! { #a.0[#i] })
                 .chain((0..limbs).map(|_| quote! {0})),
             proc_macro2::Punct::new(',', proc_macro2::Spacing::Alone),
         );
@@ -798,6 +887,10 @@ 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 from_repr_impl = endianness.from_repr(name, limbs);
+    let into_repr_impl = endianness.into_repr(repr, &mont_reduce_self_params, limbs);
 
     let top_limb_index = limbs - 1;
 
@@ -818,13 +911,14 @@ fn prime_field_impl(
 
         impl ::subtle::ConstantTimeEq for #name {
             fn ct_eq(&self, other: &#name) -> ::subtle::Choice {
-                #ct_eq_impl
+                self.into_repr().ct_eq(&other.into_repr())
             }
         }
 
         impl ::core::cmp::PartialEq for #name {
             fn eq(&self, other: &#name) -> bool {
-                self.0 == other.0
+                use ::subtle::ConstantTimeEq;
+                self.ct_eq(other).into()
             }
         }
 
@@ -841,7 +935,17 @@ fn prime_field_impl(
         impl Ord for #name {
             #[inline(always)]
             fn cmp(&self, other: &#name) -> ::core::cmp::Ordering {
-                self.into_repr().cmp(&other.into_repr())
+                let mut a = *self;
+                a.mont_reduce(
+                    #mont_reduce_self_params
+                );
+
+                let mut b = *other;
+                b.mont_reduce(
+                    #mont_reduce_other_params
+                );
+
+                a.cmp_native(&b)
             }
         }
 
@@ -863,7 +967,7 @@ fn prime_field_impl(
             fn from(val: u64) -> #name {
                 let mut raw = [0u64; #limbs];
                 raw[0] = val;
-                #name(#repr(raw)) * #name(R2)
+                #name(raw) * R2
             }
         }
 
@@ -873,13 +977,19 @@ fn prime_field_impl(
             }
         }
 
+        impl<'a> From<&'a #name> for #repr {
+            fn from(e: &'a #name) -> #repr {
+                e.into_repr()
+            }
+        }
+
         impl ::subtle::ConditionallySelectable for #name {
             fn conditional_select(a: &#name, b: &#name, choice: ::subtle::Choice) -> #name {
                 let mut res = [0u64; #limbs];
                 for i in 0..#limbs {
-                    res[i] = u64::conditional_select(&(a.0).0[i], &(b.0).0[i], choice);
+                    res[i] = u64::conditional_select(&a.0[i], &b.0[i], choice);
                 }
-                #name(#repr(res))
+                #name(res)
             }
         }
 
@@ -890,9 +1000,9 @@ fn prime_field_impl(
             fn neg(self) -> #name {
                 let mut ret = self;
                 if !ret.is_zero() {
-                    let mut tmp = MODULUS;
-                    tmp.sub_noborrow(&ret.0);
-                    ret.0 = tmp;
+                    let mut tmp = MODULUS_LIMBS;
+                    tmp.sub_noborrow(&ret);
+                    ret = tmp;
                 }
                 ret
             }
@@ -922,7 +1032,7 @@ fn prime_field_impl(
             #[inline]
             fn add_assign(&mut self, other: &#name) {
                 // This cannot exceed the backing capacity.
-                self.0.add_nocarry(&other.0);
+                self.add_nocarry(other);
 
                 // However, it may need to be reduced.
                 self.reduce();
@@ -960,11 +1070,11 @@ fn prime_field_impl(
             #[inline]
             fn sub_assign(&mut self, other: &#name) {
                 // If `other` is larger than `self`, we'll need to add the modulus to self first.
-                if other.0 > self.0 {
-                    self.0.add_nocarry(&MODULUS);
+                if other.cmp_native(self) == ::core::cmp::Ordering::Greater {
+                    self.add_nocarry(&MODULUS_LIMBS);
                 }
 
-                self.0.sub_noborrow(&other.0);
+                self.sub_noborrow(other);
             }
         }
 
@@ -1020,7 +1130,7 @@ fn prime_field_impl(
                     #mont_reduce_self_params
                 );
 
-                (self.0).0[0] & rhs
+                self.0[0] & rhs
             }
         }
 
@@ -1040,7 +1150,7 @@ fn prime_field_impl(
 
                 while n >= 64 {
                     let mut t = 0;
-                    for i in (self.0).0.iter_mut().rev() {
+                    for i in self.0.iter_mut().rev() {
                         ::core::mem::swap(&mut t, i);
                     }
                     n -= 64;
@@ -1048,7 +1158,7 @@ fn prime_field_impl(
 
                 if n > 0 {
                     let mut t = 0;
-                    for i in (self.0).0.iter_mut().rev() {
+                    for i in self.0.iter_mut().rev() {
                         let t2 = *i << (64 - n);
                         *i >>= n;
                         *i |= t;
@@ -1057,39 +1167,32 @@ fn prime_field_impl(
                 }
 
                 // Convert back to Montgomery representation
-                self * #name(R2)
+                self * R2
             }
         }
 
         impl ::ff::PrimeField for #name {
             type Repr = #repr;
 
-            fn from_repr(r: #repr) -> Result<#name, PrimeFieldDecodingError> {
-                let mut r = #name(r);
-                if r.is_valid() {
-                    r.mul_assign(&#name(R2));
-
-                    Ok(r)
-                } else {
-                    Err(PrimeFieldDecodingError::NotInField)
-                }
+            fn from_repr(r: #repr) -> Option<#name> {
+                #from_repr_impl
             }
 
             fn into_repr(&self) -> #repr {
+                #into_repr_impl
+            }
+
+            #[inline(always)]
+            fn is_odd(&self) -> bool {
                 let mut r = *self;
                 r.mont_reduce(
                     #mont_reduce_self_params
                 );
 
-                r.0
+                r.0[0] & 1 == 1
             }
 
-            #[inline(always)]
-            fn is_odd(&self) -> bool {
-                self.into_repr().is_odd()
-            }
-
-            fn char() -> #repr {
+            fn char() -> Self::Repr {
                 MODULUS
             }
 
@@ -1098,13 +1201,13 @@ fn prime_field_impl(
             const CAPACITY: u32 = Self::NUM_BITS - 1;
 
             fn multiplicative_generator() -> Self {
-                #name(GENERATOR)
+                GENERATOR
             }
 
             const S: u32 = S;
 
             fn root_of_unity() -> Self {
-                #name(ROOT_OF_UNITY)
+                ROOT_OF_UNITY
             }
         }
 
@@ -1117,7 +1220,7 @@ fn prime_field_impl(
                         for i in 0..#limbs {
                             repr[i] = rng.next_u64();
                         }
-                        #name(#repr(repr))
+                        #name(repr)
                     };
 
                     // Mask away the unused most-significant bits.
@@ -1131,17 +1234,17 @@ fn prime_field_impl(
 
             #[inline]
             fn zero() -> Self {
-                #name(#repr::from(0))
+                #name([0; #limbs])
             }
 
             #[inline]
             fn one() -> Self {
-                #name(R)
+                R
             }
 
             #[inline]
             fn is_zero(&self) -> bool {
-                self.0.is_zero()
+                self.0.iter().all(|&e| e == 0)
             }
 
             #[inline]
@@ -1149,7 +1252,13 @@ fn prime_field_impl(
                 let mut ret = *self;
 
                 // This cannot exceed the backing capacity.
-                ret.0.mul2();
+                let mut last = 0;
+                for i in &mut ret.0 {
+                    let tmp = *i >> 63;
+                    *i <<= 1;
+                    *i |= last;
+                    last = tmp;
+                }
 
                 // However, it may need to be reduced.
                 ret.reduce();
@@ -1174,11 +1283,46 @@ fn prime_field_impl(
         }
 
         impl #name {
+            /// Compares two elements in native representation. This is only used
+            /// internally.
+            #[inline(always)]
+            fn cmp_native(&self, other: &#name) -> ::core::cmp::Ordering {
+                for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) {
+                    if a < b {
+                        return ::core::cmp::Ordering::Less
+                    } else if a > b {
+                        return ::core::cmp::Ordering::Greater
+                    }
+                }
+
+                ::core::cmp::Ordering::Equal
+            }
+
             /// Determines if the element is really in the field. This is only used
             /// internally.
             #[inline(always)]
             fn is_valid(&self) -> bool {
-                self.0 < MODULUS
+                // The Ord impl calls `reduce`, which in turn calls `is_valid`, so we use
+                // this internal function to eliminate the cycle.
+                self.cmp_native(&MODULUS_LIMBS) == ::core::cmp::Ordering::Less
+            }
+
+            #[inline(always)]
+            fn add_nocarry(&mut self, other: &#name) {
+                let mut carry = 0;
+
+                for (a, b) in self.0.iter_mut().zip(other.0.iter()) {
+                    *a = ::ff::adc(*a, *b, &mut carry);
+                }
+            }
+
+            #[inline(always)]
+            fn sub_noborrow(&mut self, other: &#name) {
+                let mut borrow = 0;
+
+                for (a, b) in self.0.iter_mut().zip(other.0.iter()) {
+                    *a = ::ff::sbb(*a, *b, &mut borrow);
+                }
             }
 
             /// Subtracts the modulus from this element if this element is not in the
@@ -1186,7 +1330,7 @@ fn prime_field_impl(
             #[inline(always)]
             fn reduce(&mut self) {
                 if !self.is_valid() {
-                    self.0.sub_noborrow(&MODULUS);
+                    self.sub_noborrow(&MODULUS_LIMBS);
                 }
             }
 
diff --git a/ff/src/lib.rs b/ff/src/lib.rs
index 9a4028b..bb2994c 100644
--- a/ff/src/lib.rs
+++ b/ff/src/lib.rs
@@ -12,6 +12,7 @@ extern crate std;
 #[cfg(feature = "derive")]
 pub use ff_derive::*;
 
+use core::convert::TryFrom;
 use core::fmt;
 use core::marker::PhantomData;
 use core::ops::{Add, AddAssign, BitAnd, Mul, MulAssign, Neg, Shr, Sub, SubAssign};
@@ -130,139 +131,13 @@ pub trait SqrtField: Field {
     fn sqrt(&self) -> CtOption<Self>;
 }
 
-/// This trait represents a wrapper around a biginteger which can encode any element of a particular
-/// prime field. It is a smart wrapper around a sequence of `u64` limbs, least-significant digit
-/// first.
-pub trait PrimeFieldRepr:
-    Sized
-    + Copy
-    + Clone
-    + Eq
-    + Ord
-    + Send
-    + Sync
-    + Default
-    + fmt::Debug
-    + fmt::Display
-    + 'static
-    + AsRef<[u64]>
-    + AsMut<[u64]>
-    + From<u64>
-{
-    /// Subtract another represetation from this one.
-    fn sub_noborrow(&mut self, other: &Self);
-
-    /// Add another representation to this one.
-    fn add_nocarry(&mut self, other: &Self);
-
-    /// Compute the number of bits needed to encode this number. Always a
-    /// multiple of 64.
-    fn num_bits(&self) -> u32;
-
-    /// Returns true iff this number is zero.
-    fn is_zero(&self) -> bool;
-
-    /// Returns true iff this number is odd.
-    fn is_odd(&self) -> bool;
-
-    /// Returns true iff this number is even.
-    fn is_even(&self) -> bool;
-
-    /// Performs a rightwise bitshift of this number, effectively dividing
-    /// it by 2.
-    fn div2(&mut self);
-
-    /// Performs a rightwise bitshift of this number by some amount.
-    fn shr(&mut self, amt: u32);
-
-    /// Performs a leftwise bitshift of this number, effectively multiplying
-    /// it by 2. Overflow is ignored.
-    fn mul2(&mut self);
-
-    /// Performs a leftwise bitshift of this number by some amount.
-    fn shl(&mut self, amt: u32);
-
-    /// Writes this `PrimeFieldRepr` as a big endian integer.
-    #[cfg(feature = "std")]
-    fn write_be<W: Write>(&self, mut writer: W) -> io::Result<()> {
-        use byteorder::{BigEndian, WriteBytesExt};
-
-        for digit in self.as_ref().iter().rev() {
-            writer.write_u64::<BigEndian>(*digit)?;
-        }
-
-        Ok(())
-    }
-
-    /// Reads a big endian integer into this representation.
-    #[cfg(feature = "std")]
-    fn read_be<R: Read>(&mut self, mut reader: R) -> io::Result<()> {
-        use byteorder::{BigEndian, ReadBytesExt};
-
-        for digit in self.as_mut().iter_mut().rev() {
-            *digit = reader.read_u64::<BigEndian>()?;
-        }
-
-        Ok(())
-    }
-
-    /// Writes this `PrimeFieldRepr` as a little endian integer.
-    #[cfg(feature = "std")]
-    fn write_le<W: Write>(&self, mut writer: W) -> io::Result<()> {
-        use byteorder::{LittleEndian, WriteBytesExt};
-
-        for digit in self.as_ref().iter() {
-            writer.write_u64::<LittleEndian>(*digit)?;
-        }
-
-        Ok(())
-    }
-
-    /// Reads a little endian integer into this representation.
-    #[cfg(feature = "std")]
-    fn read_le<R: Read>(&mut self, mut reader: R) -> io::Result<()> {
-        use byteorder::{LittleEndian, ReadBytesExt};
-
-        for digit in self.as_mut().iter_mut() {
-            *digit = reader.read_u64::<LittleEndian>()?;
-        }
-
-        Ok(())
-    }
-}
-
-/// An error that may occur when trying to interpret a `PrimeFieldRepr` as a
-/// `PrimeField` element.
-#[derive(Debug)]
-pub enum PrimeFieldDecodingError {
-    /// The encoded value is not in the field
-    NotInField,
-}
-
-#[cfg(feature = "std")]
-impl std::error::Error for PrimeFieldDecodingError {
-    fn description(&self) -> &str {
-        match *self {
-            PrimeFieldDecodingError::NotInField => "not an element of the field",
-        }
-    }
-}
-
-impl fmt::Display for PrimeFieldDecodingError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
-        match *self {
-            PrimeFieldDecodingError::NotInField => write!(f, "not an element of the field"),
-        }
-    }
-}
-
 /// This represents an element of a prime field.
 pub trait PrimeField:
     Field + Ord + From<u64> + BitAnd<u64, Output = u64> + Shr<u32, Output = Self>
 {
-    /// The prime field can be converted back and forth into this biginteger
+    /// The prime field can be converted back and forth into this binary
     /// representation.
-    type Repr: PrimeFieldRepr + From<Self>;
+    type Repr: Default + AsRef<[u8]> + AsMut<[u8]> + From<Self> + for<'r> From<&'r Self>;
 
     /// Interpret a string of numbers as a (congruent) prime field element.
     /// Does not accept unnecessary leading zeroes or a blank string.
@@ -304,11 +179,20 @@ pub trait PrimeField:
         Some(res)
     }
 
-    /// Convert this prime field element into a biginteger representation.
-    fn from_repr(_: Self::Repr) -> Result<Self, PrimeFieldDecodingError>;
+    /// Attempts to convert a byte representation of a field element into an element of
+    /// 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`].
+    fn from_repr(_: Self::Repr) -> Option<Self>;
 
-    /// Convert a biginteger representation into a prime field element, if
-    /// the number is an element of the field.
+    /// 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.
     fn into_repr(&self) -> Self::Repr;
 
     /// Returns true iff this element is odd.
diff --git a/group/src/lib.rs b/group/src/lib.rs
index 3dd9bbd..8910494 100644
--- a/group/src/lib.rs
+++ b/group/src/lib.rs
@@ -1,7 +1,7 @@
 // Catch documentation errors caused by code changes.
 #![deny(intra_doc_link_resolution_failure)]
 
-use ff::{PrimeField, PrimeFieldDecodingError, ScalarEngine, SqrtField};
+use ff::{PrimeField, ScalarEngine, SqrtField};
 use rand::RngCore;
 use std::error::Error;
 use std::fmt;
@@ -82,7 +82,7 @@ pub trait CurveProjective:
 
     /// Recommends a wNAF window table size given a scalar. Always returns a number
     /// between 2 and 22, inclusive.
-    fn recommended_wnaf_for_scalar(scalar: &<Self::Scalar as PrimeField>::Repr) -> usize;
+    fn recommended_wnaf_for_scalar(scalar: &Self::Scalar) -> usize;
 
     /// Recommends a wNAF window size given the number of scalars you intend to multiply
     /// a base by. Always returns a number between 2 and 22, inclusive.
@@ -178,7 +178,7 @@ pub enum GroupDecodingError {
     /// The element is not part of the r-order subgroup.
     NotInSubgroup,
     /// One of the coordinates could not be decoded
-    CoordinateDecodingError(&'static str, PrimeFieldDecodingError),
+    CoordinateDecodingError(&'static str),
     /// The compression mode of the encoded element was not as expected
     UnexpectedCompressionMode,
     /// The encoding contained bits that should not have been set
@@ -202,8 +202,8 @@ impl Error for GroupDecodingError {
 impl fmt::Display for GroupDecodingError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
         match *self {
-            GroupDecodingError::CoordinateDecodingError(description, ref err) => {
-                write!(f, "{} decoding error: {}", description, err)
+            GroupDecodingError::CoordinateDecodingError(description) => {
+                write!(f, "{} decoding error", description)
             }
             _ => write!(f, "{}", self.description()),
         }
diff --git a/group/src/wnaf.rs b/group/src/wnaf.rs
index 2001101..261b301 100644
--- a/group/src/wnaf.rs
+++ b/group/src/wnaf.rs
@@ -1,3 +1,4 @@
+use byteorder::{ByteOrder, LittleEndian};
 use ff::PrimeField;
 use std::iter;
 
@@ -19,7 +20,7 @@ pub(crate) fn wnaf_table<G: CurveProjective>(table: &mut Vec<G>, mut base: G, wi
 
 /// Replaces the contents of `wnaf` with the w-NAF representation of a little-endian
 /// scalar.
-pub(crate) fn wnaf_form<S: AsRef<[u64]>>(wnaf: &mut Vec<i64>, c: S, window: usize) {
+pub(crate) fn wnaf_form<S: AsRef<[u8]>>(wnaf: &mut Vec<i64>, c: S, window: usize) {
     // Required by the NAF definition
     debug_assert!(window >= 2);
     // Required so that the NAF digits fit in i64
@@ -27,11 +28,11 @@ pub(crate) fn wnaf_form<S: AsRef<[u64]>>(wnaf: &mut Vec<i64>, c: S, window: usiz
 
     wnaf.truncate(0);
 
-    let u64_len = c.as_ref().len();
-    let bit_len = u64_len * 64;
+    let bit_len = c.as_ref().len() * 8;
+    let u64_len = (bit_len + 1) / 64;
 
     let mut c_u64 = vec![0u64; u64_len + 1];
-    c_u64[0..u64_len].copy_from_slice(c.as_ref());
+    LittleEndian::read_u64_into(c.as_ref(), &mut c_u64[0..u64_len]);
 
     let width = 1u64 << window;
     let window_mask = width - 1;
@@ -144,13 +145,11 @@ impl<G: CurveProjective> Wnaf<(), Vec<G>, Vec<i64>> {
         &mut self,
         scalar: &<G as CurveProjective>::Scalar,
     ) -> Wnaf<usize, &mut Vec<G>, &[i64]> {
-        let scalar = scalar.into_repr();
-
         // Compute the appropriate window size for the scalar.
         let window_size = G::recommended_wnaf_for_scalar(&scalar);
 
         // Compute the wNAF form of the scalar.
-        wnaf_form(&mut self.scalar, scalar, window_size);
+        wnaf_form(&mut self.scalar, scalar.into_repr(), window_size);
 
         // Return a Wnaf object that mutably borrows the base storage location, but
         // immutably borrows the computed wNAF form scalar location.
diff --git a/pairing/benches/bls12_381/fq.rs b/pairing/benches/bls12_381/fq.rs
index 244c161..3c43fdd 100644
--- a/pairing/benches/bls12_381/fq.rs
+++ b/pairing/benches/bls12_381/fq.rs
@@ -3,140 +3,9 @@ use rand_core::SeedableRng;
 use rand_xorshift::XorShiftRng;
 use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
 
-use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField};
+use ff::{Field, PrimeField, SqrtField};
 use pairing::bls12_381::*;
 
-fn bench_fq_repr_add_nocarry(c: &mut Criterion) {
-    const SAMPLES: usize = 1000;
-
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    let v: Vec<(FqRepr, FqRepr)> = (0..SAMPLES)
-        .map(|_| {
-            let mut tmp1 = Fq::random(&mut rng).into_repr();
-            let mut tmp2 = Fq::random(&mut rng).into_repr();
-            // Shave a few bits off to avoid overflow.
-            for _ in 0..3 {
-                tmp1.div2();
-                tmp2.div2();
-            }
-            (tmp1, tmp2)
-        })
-        .collect();
-
-    let mut count = 0;
-    c.bench_function("FqRepr::add_nocarry", |b| {
-        b.iter(|| {
-            let mut tmp = v[count].0;
-            tmp.add_nocarry(&v[count].1);
-            count = (count + 1) % SAMPLES;
-            tmp
-        })
-    });
-}
-
-fn bench_fq_repr_sub_noborrow(c: &mut Criterion) {
-    const SAMPLES: usize = 1000;
-
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    let v: Vec<(FqRepr, FqRepr)> = (0..SAMPLES)
-        .map(|_| {
-            let tmp1 = Fq::random(&mut rng).into_repr();
-            let mut tmp2 = tmp1;
-            // Ensure tmp2 is smaller than tmp1.
-            for _ in 0..10 {
-                tmp2.div2();
-            }
-            (tmp1, tmp2)
-        })
-        .collect();
-
-    let mut count = 0;
-    c.bench_function("FqRepr::sub_noborrow", |b| {
-        b.iter(|| {
-            let mut tmp = v[count].0;
-            tmp.sub_noborrow(&v[count].1);
-            count = (count + 1) % SAMPLES;
-            tmp
-        })
-    });
-}
-
-fn bench_fq_repr_num_bits(c: &mut Criterion) {
-    const SAMPLES: usize = 1000;
-
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    let v: Vec<FqRepr> = (0..SAMPLES)
-        .map(|_| Fq::random(&mut rng).into_repr())
-        .collect();
-
-    let mut count = 0;
-    c.bench_function("FqRepr::num_bits", |b| {
-        b.iter(|| {
-            let tmp = v[count].num_bits();
-            count = (count + 1) % SAMPLES;
-            tmp
-        })
-    });
-}
-
-fn bench_fq_repr_mul2(c: &mut Criterion) {
-    const SAMPLES: usize = 1000;
-
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    let v: Vec<FqRepr> = (0..SAMPLES)
-        .map(|_| Fq::random(&mut rng).into_repr())
-        .collect();
-
-    let mut count = 0;
-    c.bench_function("FqRepr::mul2", |b| {
-        b.iter(|| {
-            let mut tmp = v[count];
-            tmp.mul2();
-            count = (count + 1) % SAMPLES;
-            tmp
-        })
-    });
-}
-
-fn bench_fq_repr_div2(c: &mut Criterion) {
-    const SAMPLES: usize = 1000;
-
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    let v: Vec<FqRepr> = (0..SAMPLES)
-        .map(|_| Fq::random(&mut rng).into_repr())
-        .collect();
-
-    let mut count = 0;
-    c.bench_function("FqRepr::div2", |b| {
-        b.iter(|| {
-            let mut tmp = v[count];
-            tmp.div2();
-            count = (count + 1) % SAMPLES;
-            tmp
-        })
-    });
-}
-
 fn bench_fq_add_assign(c: &mut Criterion) {
     const SAMPLES: usize = 1000;
 
@@ -328,11 +197,6 @@ fn bench_fq_from_repr(c: &mut Criterion) {
 
 criterion_group!(
     benches,
-    bench_fq_repr_add_nocarry,
-    bench_fq_repr_sub_noborrow,
-    bench_fq_repr_num_bits,
-    bench_fq_repr_mul2,
-    bench_fq_repr_div2,
     bench_fq_add_assign,
     bench_fq_sub_assign,
     bench_fq_mul_assign,
diff --git a/pairing/benches/bls12_381/fr.rs b/pairing/benches/bls12_381/fr.rs
index d2dbc4c..33b3901 100644
--- a/pairing/benches/bls12_381/fr.rs
+++ b/pairing/benches/bls12_381/fr.rs
@@ -3,140 +3,9 @@ use rand_core::SeedableRng;
 use rand_xorshift::XorShiftRng;
 use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
 
-use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField};
+use ff::{Field, PrimeField, SqrtField};
 use pairing::bls12_381::*;
 
-fn bench_fr_repr_add_nocarry(c: &mut Criterion) {
-    const SAMPLES: usize = 1000;
-
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    let v: Vec<(FrRepr, FrRepr)> = (0..SAMPLES)
-        .map(|_| {
-            let mut tmp1 = Fr::random(&mut rng).into_repr();
-            let mut tmp2 = Fr::random(&mut rng).into_repr();
-            // Shave a few bits off to avoid overflow.
-            for _ in 0..3 {
-                tmp1.div2();
-                tmp2.div2();
-            }
-            (tmp1, tmp2)
-        })
-        .collect();
-
-    let mut count = 0;
-    c.bench_function("FrRepr::add_nocarry", |b| {
-        b.iter(|| {
-            let mut tmp = v[count].0;
-            tmp.add_nocarry(&v[count].1);
-            count = (count + 1) % SAMPLES;
-            tmp
-        })
-    });
-}
-
-fn bench_fr_repr_sub_noborrow(c: &mut Criterion) {
-    const SAMPLES: usize = 1000;
-
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    let v: Vec<(FrRepr, FrRepr)> = (0..SAMPLES)
-        .map(|_| {
-            let tmp1 = Fr::random(&mut rng).into_repr();
-            let mut tmp2 = tmp1;
-            // Ensure tmp2 is smaller than tmp1.
-            for _ in 0..10 {
-                tmp2.div2();
-            }
-            (tmp1, tmp2)
-        })
-        .collect();
-
-    let mut count = 0;
-    c.bench_function("FrRepr::sub_noborrow", |b| {
-        b.iter(|| {
-            let mut tmp = v[count].0;
-            tmp.sub_noborrow(&v[count].1);
-            count = (count + 1) % SAMPLES;
-            tmp
-        })
-    });
-}
-
-fn bench_fr_repr_num_bits(c: &mut Criterion) {
-    const SAMPLES: usize = 1000;
-
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    let v: Vec<FrRepr> = (0..SAMPLES)
-        .map(|_| Fr::random(&mut rng).into_repr())
-        .collect();
-
-    let mut count = 0;
-    c.bench_function("FrRepr::num_bits", |b| {
-        b.iter(|| {
-            let tmp = v[count].num_bits();
-            count = (count + 1) % SAMPLES;
-            tmp
-        })
-    });
-}
-
-fn bench_fr_repr_mul2(c: &mut Criterion) {
-    const SAMPLES: usize = 1000;
-
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    let v: Vec<FrRepr> = (0..SAMPLES)
-        .map(|_| Fr::random(&mut rng).into_repr())
-        .collect();
-
-    let mut count = 0;
-    c.bench_function("FrRepr::mul2", |b| {
-        b.iter(|| {
-            let mut tmp = v[count];
-            tmp.mul2();
-            count = (count + 1) % SAMPLES;
-            tmp
-        })
-    });
-}
-
-fn bench_fr_repr_div2(c: &mut Criterion) {
-    const SAMPLES: usize = 1000;
-
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    let v: Vec<FrRepr> = (0..SAMPLES)
-        .map(|_| Fr::random(&mut rng).into_repr())
-        .collect();
-
-    let mut count = 0;
-    c.bench_function("FrRepr::div2", |b| {
-        b.iter(|| {
-            let mut tmp = v[count];
-            tmp.div2();
-            count = (count + 1) % SAMPLES;
-            tmp
-        })
-    });
-}
-
 fn bench_fr_add_assign(c: &mut Criterion) {
     const SAMPLES: usize = 1000;
 
@@ -328,11 +197,6 @@ fn bench_fr_from_repr(c: &mut Criterion) {
 
 criterion_group!(
     benches,
-    bench_fr_repr_add_nocarry,
-    bench_fr_repr_sub_noborrow,
-    bench_fr_repr_num_bits,
-    bench_fr_repr_mul2,
-    bench_fr_repr_div2,
     bench_fr_add_assign,
     bench_fr_sub_assign,
     bench_fr_mul_assign,
diff --git a/pairing/src/bls12_381/ec.rs b/pairing/src/bls12_381/ec.rs
index 42bd91e..ef03797 100644
--- a/pairing/src/bls12_381/ec.rs
+++ b/pairing/src/bls12_381/ec.rs
@@ -183,8 +183,8 @@ macro_rules! curve_impl {
             }
 
             fn mul<S: Into<<Self::Scalar as PrimeField>::Repr>>(&self, by: S) -> $projective {
-                let bits = BitIterator::<u64, _>::new(by.into());
-                self.mul_bits_u64(bits)
+                let bits = BitIterator::<u8, _>::new(by.into());
+                self.mul_bits_u8(bits)
             }
 
             fn into_projective(&self) -> $projective {
@@ -666,7 +666,7 @@ macro_rules! curve_impl {
 
                 let mut found_one = false;
 
-                for i in BitIterator::<u64, _>::new(other.into()) {
+                for i in BitIterator::<u8, _>::new(other.into()) {
                     if found_one {
                         res.double();
                     } else {
@@ -685,8 +685,10 @@ macro_rules! curve_impl {
                 (*self).into()
             }
 
-            fn recommended_wnaf_for_scalar(scalar: &<Self::Scalar as PrimeField>::Repr) -> usize {
-                Self::empirical_recommended_wnaf_for_scalar(scalar)
+            fn recommended_wnaf_for_scalar(_: &Self::Scalar) -> usize {
+                Self::empirical_recommended_wnaf_for_scalar(
+                    <Self::Scalar as PrimeField>::NUM_BITS as usize,
+                )
             }
 
             fn recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize {
@@ -749,10 +751,10 @@ macro_rules! curve_impl {
 }
 
 pub mod g1 {
-    use super::super::{Bls12, Fq, Fq12, FqRepr, Fr, FrRepr};
+    use super::super::{Bls12, Fq, Fq12, FqRepr, Fr};
     use super::g2::G2Affine;
     use crate::{Engine, PairingCurveAffine};
-    use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField};
+    use ff::{BitIterator, Field, PrimeField, SqrtField};
     use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError};
     use rand_core::RngCore;
     use std::fmt;
@@ -842,22 +844,21 @@ pub mod g1 {
                 // Unset the three most significant bits.
                 copy[0] &= 0x1f;
 
-                let mut x = FqRepr([0; 6]);
-                let mut y = FqRepr([0; 6]);
-
-                {
-                    let mut reader = &copy[..];
-
-                    x.read_be(&mut reader).unwrap();
-                    y.read_be(&mut reader).unwrap();
+                fn copy_segment(s: &[u8], start: usize) -> [u8; 48] {
+                    let mut ret = [0; 48];
+                    ret.copy_from_slice(&s[start..start + 48]);
+                    ret
                 }
 
+                let x = FqRepr(copy_segment(&copy, 0));
+                let y = FqRepr(copy_segment(&copy, 48));
+
                 Ok(G1Affine {
-                    x: Fq::from_repr(x).map_err(|e| {
-                        GroupDecodingError::CoordinateDecodingError("x coordinate", e)
+                    x: Fq::from_repr(x).ok_or_else(|| {
+                        GroupDecodingError::CoordinateDecodingError("x coordinate")
                     })?,
-                    y: Fq::from_repr(y).map_err(|e| {
-                        GroupDecodingError::CoordinateDecodingError("y coordinate", e)
+                    y: Fq::from_repr(y).ok_or_else(|| {
+                        GroupDecodingError::CoordinateDecodingError("y coordinate")
                     })?,
                     infinity: false,
                 })
@@ -871,10 +872,8 @@ pub mod g1 {
                 // is at infinity.
                 res.0[0] |= 1 << 6;
             } else {
-                let mut writer = &mut res.0[..];
-
-                affine.x.into_repr().write_be(&mut writer).unwrap();
-                affine.y.into_repr().write_be(&mut writer).unwrap();
+                res.0[..48].copy_from_slice(&affine.x.into_repr().0);
+                res.0[48..].copy_from_slice(&affine.y.into_repr().0);
             }
 
             res
@@ -950,17 +949,9 @@ pub mod g1 {
                 // Unset the three most significant bits.
                 copy[0] &= 0x1f;
 
-                let mut x = FqRepr([0; 6]);
-
-                {
-                    let mut reader = &copy[..];
-
-                    x.read_be(&mut reader).unwrap();
-                }
-
                 // Interpret as Fq element.
-                let x = Fq::from_repr(x)
-                    .map_err(|e| GroupDecodingError::CoordinateDecodingError("x coordinate", e))?;
+                let x = Fq::from_repr(FqRepr(copy))
+                    .ok_or_else(|| GroupDecodingError::CoordinateDecodingError("x coordinate"))?;
 
                 let ret = G1Affine::get_point_from_x(x, greatest);
                 if ret.is_some().into() {
@@ -978,11 +969,7 @@ pub mod g1 {
                 // is at infinity.
                 res.0[0] |= 1 << 6;
             } else {
-                {
-                    let mut writer = &mut res.0[..];
-
-                    affine.x.into_repr().write_be(&mut writer).unwrap();
-                }
+                res.0 = affine.x.into_repr().0;
 
                 let negy = affine.y.neg();
 
@@ -1025,9 +1012,7 @@ pub mod g1 {
     }
 
     impl G1 {
-        fn empirical_recommended_wnaf_for_scalar(scalar: &FrRepr) -> usize {
-            let num_bits = scalar.num_bits() as usize;
-
+        fn empirical_recommended_wnaf_for_scalar(num_bits: usize) -> usize {
             if num_bits >= 130 {
                 4
             } else if num_bits >= 34 {
@@ -1082,13 +1067,11 @@ pub mod g1 {
             let y = rhs.sqrt();
             if y.is_some().into() {
                 let y = y.unwrap();
-                let yrepr = y.into_repr();
                 let negy = y.neg();
-                let negyrepr = negy.into_repr();
 
                 let p = G1Affine {
                     x,
-                    y: if yrepr < negyrepr { y } else { negy },
+                    y: if y < negy { y } else { negy },
                     infinity: false,
                 };
                 assert!(!p.is_in_correct_subgroup_assuming_on_curve());
@@ -1116,21 +1099,17 @@ pub mod g1 {
         {
             let p = G1Affine {
                 x: Fq::from_repr(FqRepr([
-                    0xc58d887b66c035dc,
-                    0x10cbfd301d553822,
-                    0xaf23e064f1131ee5,
-                    0x9fe83b1b4a5d648d,
-                    0xf583cc5a508f6a40,
-                    0xc3ad2aefde0bb13,
+                    0x0c, 0x3a, 0xd2, 0xae, 0xfd, 0xe0, 0xbb, 0x13, 0xf5, 0x83, 0xcc, 0x5a, 0x50,
+                    0x8f, 0x6a, 0x40, 0x9f, 0xe8, 0x3b, 0x1b, 0x4a, 0x5d, 0x64, 0x8d, 0xaf, 0x23,
+                    0xe0, 0x64, 0xf1, 0x13, 0x1e, 0xe5, 0x10, 0xcb, 0xfd, 0x30, 0x1d, 0x55, 0x38,
+                    0x22, 0xc5, 0x8d, 0x88, 0x7b, 0x66, 0xc0, 0x35, 0xdc,
                 ]))
                 .unwrap(),
                 y: Fq::from_repr(FqRepr([
-                    0x60aa6f9552f03aae,
-                    0xecd01d5181300d35,
-                    0x8af1cdb8aa8ce167,
-                    0xe760f57922998c9d,
-                    0x953703f5795a39e5,
-                    0xfe3ae0922df702c,
+                    0x0f, 0xe3, 0xae, 0x09, 0x22, 0xdf, 0x70, 0x2c, 0x95, 0x37, 0x03, 0xf5, 0x79,
+                    0x5a, 0x39, 0xe5, 0xe7, 0x60, 0xf5, 0x79, 0x22, 0x99, 0x8c, 0x9d, 0x8a, 0xf1,
+                    0xcd, 0xb8, 0xaa, 0x8c, 0xe1, 0x67, 0xec, 0xd0, 0x1d, 0x51, 0x81, 0x30, 0x0d,
+                    0x35, 0x60, 0xaa, 0x6f, 0x95, 0x52, 0xf0, 0x3a, 0xae,
                 ]))
                 .unwrap(),
                 infinity: false,
@@ -1143,21 +1122,17 @@ pub mod g1 {
         {
             let p = G1Affine {
                 x: Fq::from_repr(FqRepr([
-                    0xee6adf83511e15f5,
-                    0x92ddd328f27a4ba6,
-                    0xe305bd1ac65adba7,
-                    0xea034ee2928b30a8,
-                    0xbd8833dc7c79a7f7,
-                    0xe45c9f0c0438675,
+                    0x0e, 0x45, 0xc9, 0xf0, 0xc0, 0x43, 0x86, 0x75, 0xbd, 0x88, 0x33, 0xdc, 0x7c,
+                    0x79, 0xa7, 0xf7, 0xea, 0x03, 0x4e, 0xe2, 0x92, 0x8b, 0x30, 0xa8, 0xe3, 0x05,
+                    0xbd, 0x1a, 0xc6, 0x5a, 0xdb, 0xa7, 0x92, 0xdd, 0xd3, 0x28, 0xf2, 0x7a, 0x4b,
+                    0xa6, 0xee, 0x6a, 0xdf, 0x83, 0x51, 0x1e, 0x15, 0xf5,
                 ]))
                 .unwrap(),
                 y: Fq::from_repr(FqRepr([
-                    0x3b450eb1ab7b5dad,
-                    0xa65cb81e975e8675,
-                    0xaa548682b21726e5,
-                    0x753ddf21a2601d20,
-                    0x532d0b640bd3ff8b,
-                    0x118d2c543f031102,
+                    0x11, 0x8d, 0x2c, 0x54, 0x3f, 0x03, 0x11, 0x02, 0x53, 0x2d, 0x0b, 0x64, 0x0b,
+                    0xd3, 0xff, 0x8b, 0x75, 0x3d, 0xdf, 0x21, 0xa2, 0x60, 0x1d, 0x20, 0xaa, 0x54,
+                    0x86, 0x82, 0xb2, 0x17, 0x26, 0xe5, 0xa6, 0x5c, 0xb8, 0x1e, 0x97, 0x5e, 0x86,
+                    0x75, 0x3b, 0x45, 0x0e, 0xb1, 0xab, 0x7b, 0x5d, 0xad,
                 ]))
                 .unwrap(),
                 infinity: false,
@@ -1171,21 +1146,17 @@ pub mod g1 {
         {
             let p = G1Affine {
                 x: Fq::from_repr(FqRepr([
-                    0x76e1c971c6db8fe8,
-                    0xe37e1a610eff2f79,
-                    0x88ae9c499f46f0c0,
-                    0xf35de9ce0d6b4e84,
-                    0x265bddd23d1dec54,
-                    0x12a8778088458308,
+                    0x12, 0xa8, 0x77, 0x80, 0x88, 0x45, 0x83, 0x08, 0x26, 0x5b, 0xdd, 0xd2, 0x3d,
+                    0x1d, 0xec, 0x54, 0xf3, 0x5d, 0xe9, 0xce, 0x0d, 0x6b, 0x4e, 0x84, 0x88, 0xae,
+                    0x9c, 0x49, 0x9f, 0x46, 0xf0, 0xc0, 0xe3, 0x7e, 0x1a, 0x61, 0x0e, 0xff, 0x2f,
+                    0x79, 0x76, 0xe1, 0xc9, 0x71, 0xc6, 0xdb, 0x8f, 0xe8,
                 ]))
                 .unwrap(),
                 y: Fq::from_repr(FqRepr([
-                    0x8a22defa0d526256,
-                    0xc57ca55456fcb9ae,
-                    0x1ba194e89bab2610,
-                    0x921beef89d4f29df,
-                    0x5b6fda44ad85fa78,
-                    0xed74ab9f302cbe0,
+                    0x0e, 0xd7, 0x4a, 0xb9, 0xf3, 0x02, 0xcb, 0xe0, 0x5b, 0x6f, 0xda, 0x44, 0xad,
+                    0x85, 0xfa, 0x78, 0x92, 0x1b, 0xee, 0xf8, 0x9d, 0x4f, 0x29, 0xdf, 0x1b, 0xa1,
+                    0x94, 0xe8, 0x9b, 0xab, 0x26, 0x10, 0xc5, 0x7c, 0xa5, 0x54, 0x56, 0xfc, 0xb9,
+                    0xae, 0x8a, 0x22, 0xde, 0xfa, 0x0d, 0x52, 0x62, 0x56,
                 ]))
                 .unwrap(),
                 infinity: false,
@@ -1199,21 +1170,17 @@ pub mod g1 {
     fn test_g1_addition_correctness() {
         let mut p = G1 {
             x: Fq::from_repr(FqRepr([
-                0x47fd1f891d6e8bbf,
-                0x79a3b0448f31a2aa,
-                0x81f3339e5f9968f,
-                0x485e77d50a5df10d,
-                0x4c6fcac4b55fd479,
-                0x86ed4d9906fb064,
+                0x08, 0x6e, 0xd4, 0xd9, 0x90, 0x6f, 0xb0, 0x64, 0x4c, 0x6f, 0xca, 0xc4, 0xb5, 0x5f,
+                0xd4, 0x79, 0x48, 0x5e, 0x77, 0xd5, 0x0a, 0x5d, 0xf1, 0x0d, 0x08, 0x1f, 0x33, 0x39,
+                0xe5, 0xf9, 0x96, 0x8f, 0x79, 0xa3, 0xb0, 0x44, 0x8f, 0x31, 0xa2, 0xaa, 0x47, 0xfd,
+                0x1f, 0x89, 0x1d, 0x6e, 0x8b, 0xbf,
             ]))
             .unwrap(),
             y: Fq::from_repr(FqRepr([
-                0xd25ee6461538c65,
-                0x9f3bbb2ecd3719b9,
-                0xa06fd3f1e540910d,
-                0xcefca68333c35288,
-                0x570c8005f8573fa6,
-                0x152ca696fe034442,
+                0x15, 0x2c, 0xa6, 0x96, 0xfe, 0x03, 0x44, 0x42, 0x57, 0x0c, 0x80, 0x05, 0xf8, 0x57,
+                0x3f, 0xa6, 0xce, 0xfc, 0xa6, 0x83, 0x33, 0xc3, 0x52, 0x88, 0xa0, 0x6f, 0xd3, 0xf1,
+                0xe5, 0x40, 0x91, 0x0d, 0x9f, 0x3b, 0xbb, 0x2e, 0xcd, 0x37, 0x19, 0xb9, 0x0d, 0x25,
+                0xee, 0x64, 0x61, 0x53, 0x8c, 0x65,
             ]))
             .unwrap(),
             z: Fq::one(),
@@ -1221,21 +1188,17 @@ pub mod g1 {
 
         p.add_assign(&G1 {
             x: Fq::from_repr(FqRepr([
-                0xeec78f3096213cbf,
-                0xa12beb1fea1056e6,
-                0xc286c0211c40dd54,
-                0x5f44314ec5e3fb03,
-                0x24e8538737c6e675,
-                0x8abd623a594fba8,
+                0x08, 0xab, 0xd6, 0x23, 0xa5, 0x94, 0xfb, 0xa8, 0x24, 0xe8, 0x53, 0x87, 0x37, 0xc6,
+                0xe6, 0x75, 0x5f, 0x44, 0x31, 0x4e, 0xc5, 0xe3, 0xfb, 0x03, 0xc2, 0x86, 0xc0, 0x21,
+                0x1c, 0x40, 0xdd, 0x54, 0xa1, 0x2b, 0xeb, 0x1f, 0xea, 0x10, 0x56, 0xe6, 0xee, 0xc7,
+                0x8f, 0x30, 0x96, 0x21, 0x3c, 0xbf,
             ]))
             .unwrap(),
             y: Fq::from_repr(FqRepr([
-                0x6b0528f088bb7044,
-                0x2fdeb5c82917ff9e,
-                0x9a5181f2fac226ad,
-                0xd65104c6f95a872a,
-                0x1f2998a5a9c61253,
-                0xe74846154a9e44,
+                0x00, 0xe7, 0x48, 0x46, 0x15, 0x4a, 0x9e, 0x44, 0x1f, 0x29, 0x98, 0xa5, 0xa9, 0xc6,
+                0x12, 0x53, 0xd6, 0x51, 0x04, 0xc6, 0xf9, 0x5a, 0x87, 0x2a, 0x9a, 0x51, 0x81, 0xf2,
+                0xfa, 0xc2, 0x26, 0xad, 0x2f, 0xde, 0xb5, 0xc8, 0x29, 0x17, 0xff, 0x9e, 0x6b, 0x05,
+                0x28, 0xf0, 0x88, 0xbb, 0x70, 0x44,
             ]))
             .unwrap(),
             z: Fq::one(),
@@ -1247,21 +1210,17 @@ pub mod g1 {
             p,
             G1Affine {
                 x: Fq::from_repr(FqRepr([
-                    0x6dd3098f22235df,
-                    0xe865d221c8090260,
-                    0xeb96bb99fa50779f,
-                    0xc4f9a52a428e23bb,
-                    0xd178b28dd4f407ef,
-                    0x17fb8905e9183c69
+                    0x17, 0xfb, 0x89, 0x05, 0xe9, 0x18, 0x3c, 0x69, 0xd1, 0x78, 0xb2, 0x8d, 0xd4,
+                    0xf4, 0x07, 0xef, 0xc4, 0xf9, 0xa5, 0x2a, 0x42, 0x8e, 0x23, 0xbb, 0xeb, 0x96,
+                    0xbb, 0x99, 0xfa, 0x50, 0x77, 0x9f, 0xe8, 0x65, 0xd2, 0x21, 0xc8, 0x09, 0x02,
+                    0x60, 0x06, 0xdd, 0x30, 0x98, 0xf2, 0x22, 0x35, 0xdf,
                 ]))
                 .unwrap(),
                 y: Fq::from_repr(FqRepr([
-                    0xd0de9d65292b7710,
-                    0xf6a05f2bcf1d9ca7,
-                    0x1040e27012f20b64,
-                    0xeec8d1a5b7466c58,
-                    0x4bc362649dce6376,
-                    0x430cbdc5455b00a
+                    0x04, 0x30, 0xcb, 0xdc, 0x54, 0x55, 0xb0, 0x0a, 0x4b, 0xc3, 0x62, 0x64, 0x9d,
+                    0xce, 0x63, 0x76, 0xee, 0xc8, 0xd1, 0xa5, 0xb7, 0x46, 0x6c, 0x58, 0x10, 0x40,
+                    0xe2, 0x70, 0x12, 0xf2, 0x0b, 0x64, 0xf6, 0xa0, 0x5f, 0x2b, 0xcf, 0x1d, 0x9c,
+                    0xa7, 0xd0, 0xde, 0x9d, 0x65, 0x29, 0x2b, 0x77, 0x10,
                 ]))
                 .unwrap(),
                 infinity: false,
@@ -1273,21 +1232,17 @@ pub mod g1 {
     fn test_g1_doubling_correctness() {
         let mut p = G1 {
             x: Fq::from_repr(FqRepr([
-                0x47fd1f891d6e8bbf,
-                0x79a3b0448f31a2aa,
-                0x81f3339e5f9968f,
-                0x485e77d50a5df10d,
-                0x4c6fcac4b55fd479,
-                0x86ed4d9906fb064,
+                0x08, 0x6e, 0xd4, 0xd9, 0x90, 0x6f, 0xb0, 0x64, 0x4c, 0x6f, 0xca, 0xc4, 0xb5, 0x5f,
+                0xd4, 0x79, 0x48, 0x5e, 0x77, 0xd5, 0x0a, 0x5d, 0xf1, 0x0d, 0x08, 0x1f, 0x33, 0x39,
+                0xe5, 0xf9, 0x96, 0x8f, 0x79, 0xa3, 0xb0, 0x44, 0x8f, 0x31, 0xa2, 0xaa, 0x47, 0xfd,
+                0x1f, 0x89, 0x1d, 0x6e, 0x8b, 0xbf,
             ]))
             .unwrap(),
             y: Fq::from_repr(FqRepr([
-                0xd25ee6461538c65,
-                0x9f3bbb2ecd3719b9,
-                0xa06fd3f1e540910d,
-                0xcefca68333c35288,
-                0x570c8005f8573fa6,
-                0x152ca696fe034442,
+                0x15, 0x2c, 0xa6, 0x96, 0xfe, 0x03, 0x44, 0x42, 0x57, 0x0c, 0x80, 0x05, 0xf8, 0x57,
+                0x3f, 0xa6, 0xce, 0xfc, 0xa6, 0x83, 0x33, 0xc3, 0x52, 0x88, 0xa0, 0x6f, 0xd3, 0xf1,
+                0xe5, 0x40, 0x91, 0x0d, 0x9f, 0x3b, 0xbb, 0x2e, 0xcd, 0x37, 0x19, 0xb9, 0x0d, 0x25,
+                0xee, 0x64, 0x61, 0x53, 0x8c, 0x65,
             ]))
             .unwrap(),
             z: Fq::one(),
@@ -1301,21 +1256,17 @@ pub mod g1 {
             p,
             G1Affine {
                 x: Fq::from_repr(FqRepr([
-                    0xf939ddfe0ead7018,
-                    0x3b03942e732aecb,
-                    0xce0e9c38fdb11851,
-                    0x4b914c16687dcde0,
-                    0x66c8baf177d20533,
-                    0xaf960cff3d83833
+                    0x0a, 0xf9, 0x60, 0xcf, 0xf3, 0xd8, 0x38, 0x33, 0x66, 0xc8, 0xba, 0xf1, 0x77,
+                    0xd2, 0x05, 0x33, 0x4b, 0x91, 0x4c, 0x16, 0x68, 0x7d, 0xcd, 0xe0, 0xce, 0x0e,
+                    0x9c, 0x38, 0xfd, 0xb1, 0x18, 0x51, 0x03, 0xb0, 0x39, 0x42, 0xe7, 0x32, 0xae,
+                    0xcb, 0xf9, 0x39, 0xdd, 0xfe, 0x0e, 0xad, 0x70, 0x18,
                 ]))
                 .unwrap(),
                 y: Fq::from_repr(FqRepr([
-                    0x3f0675695f5177a8,
-                    0x2b6d82ae178a1ba0,
-                    0x9096380dd8e51b11,
-                    0x1771a65b60572f4e,
-                    0x8b547c1313b27555,
-                    0x135075589a687b1e
+                    0x13, 0x50, 0x75, 0x58, 0x9a, 0x68, 0x7b, 0x1e, 0x8b, 0x54, 0x7c, 0x13, 0x13,
+                    0xb2, 0x75, 0x55, 0x17, 0x71, 0xa6, 0x5b, 0x60, 0x57, 0x2f, 0x4e, 0x90, 0x96,
+                    0x38, 0x0d, 0xd8, 0xe5, 0x1b, 0x11, 0x2b, 0x6d, 0x82, 0xae, 0x17, 0x8a, 0x1b,
+                    0xa0, 0x3f, 0x06, 0x75, 0x69, 0x5f, 0x51, 0x77, 0xa8,
                 ]))
                 .unwrap(),
                 infinity: false,
@@ -1334,21 +1285,17 @@ pub mod g1 {
 
         let a = G1Affine {
             x: Fq::from_repr(FqRepr([
-                0xea431f2cc38fc94d,
-                0x3ad2354a07f5472b,
-                0xfe669f133f16c26a,
-                0x71ffa8021531705,
-                0x7418d484386d267,
-                0xd5108d8ff1fbd6,
+                0x00, 0xd5, 0x10, 0x8d, 0x8f, 0xf1, 0xfb, 0xd6, 0x07, 0x41, 0x8d, 0x48, 0x43, 0x86,
+                0xd2, 0x67, 0x07, 0x1f, 0xfa, 0x80, 0x21, 0x53, 0x17, 0x05, 0xfe, 0x66, 0x9f, 0x13,
+                0x3f, 0x16, 0xc2, 0x6a, 0x3a, 0xd2, 0x35, 0x4a, 0x07, 0xf5, 0x47, 0x2b, 0xea, 0x43,
+                0x1f, 0x2c, 0xc3, 0x8f, 0xc9, 0x4d,
             ]))
             .unwrap(),
             y: Fq::from_repr(FqRepr([
-                0xa776ccbfe9981766,
-                0x255632964ff40f4a,
-                0xc09744e650b00499,
-                0x520f74773e74c8c3,
-                0x484c8fc982008f0,
-                0xee2c3d922008cc6,
+                0x0e, 0xe2, 0xc3, 0xd9, 0x22, 0x00, 0x8c, 0xc6, 0x04, 0x84, 0xc8, 0xfc, 0x98, 0x20,
+                0x08, 0xf0, 0x52, 0x0f, 0x74, 0x77, 0x3e, 0x74, 0xc8, 0xc3, 0xc0, 0x97, 0x44, 0xe6,
+                0x50, 0xb0, 0x04, 0x99, 0x25, 0x56, 0x32, 0x96, 0x4f, 0xf4, 0x0f, 0x4a, 0xa7, 0x76,
+                0xcc, 0xbf, 0xe9, 0x98, 0x17, 0x66,
             ]))
             .unwrap(),
             infinity: false,
@@ -1356,21 +1303,17 @@ pub mod g1 {
 
         let b = G1Affine {
             x: Fq::from_repr(FqRepr([
-                0xe06cdb156b6356b6,
-                0xd9040b2d75448ad9,
-                0xe702f14bb0e2aca5,
-                0xc6e05201e5f83991,
-                0xf7c75910816f207c,
-                0x18d4043e78103106,
+                0x18, 0xd4, 0x04, 0x3e, 0x78, 0x10, 0x31, 0x06, 0xf7, 0xc7, 0x59, 0x10, 0x81, 0x6f,
+                0x20, 0x7c, 0xc6, 0xe0, 0x52, 0x01, 0xe5, 0xf8, 0x39, 0x91, 0xe7, 0x02, 0xf1, 0x4b,
+                0xb0, 0xe2, 0xac, 0xa5, 0xd9, 0x04, 0x0b, 0x2d, 0x75, 0x44, 0x8a, 0xd9, 0xe0, 0x6c,
+                0xdb, 0x15, 0x6b, 0x63, 0x56, 0xb6,
             ]))
             .unwrap(),
             y: Fq::from_repr(FqRepr([
-                0xa776ccbfe9981766,
-                0x255632964ff40f4a,
-                0xc09744e650b00499,
-                0x520f74773e74c8c3,
-                0x484c8fc982008f0,
-                0xee2c3d922008cc6,
+                0x0e, 0xe2, 0xc3, 0xd9, 0x22, 0x00, 0x8c, 0xc6, 0x04, 0x84, 0xc8, 0xfc, 0x98, 0x20,
+                0x08, 0xf0, 0x52, 0x0f, 0x74, 0x77, 0x3e, 0x74, 0xc8, 0xc3, 0xc0, 0x97, 0x44, 0xe6,
+                0x50, 0xb0, 0x04, 0x99, 0x25, 0x56, 0x32, 0x96, 0x4f, 0xf4, 0x0f, 0x4a, 0xa7, 0x76,
+                0xcc, 0xbf, 0xe9, 0x98, 0x17, 0x66,
             ]))
             .unwrap(),
             infinity: false,
@@ -1381,21 +1324,17 @@ pub mod g1 {
         // y = 1711275103908443722918766889652776216989264073722543507596490456144926139887096946237734327757134898380852225872709
         let c = G1Affine {
             x: Fq::from_repr(FqRepr([
-                0xef4f05bdd10c8aa8,
-                0xad5bf87341a2df9,
-                0x81c7424206b78714,
-                0x9676ff02ec39c227,
-                0x4c12c15d7e55b9f3,
-                0x57fd1e317db9bd,
+                0x00, 0x57, 0xfd, 0x1e, 0x31, 0x7d, 0xb9, 0xbd, 0x4c, 0x12, 0xc1, 0x5d, 0x7e, 0x55,
+                0xb9, 0xf3, 0x96, 0x76, 0xff, 0x02, 0xec, 0x39, 0xc2, 0x27, 0x81, 0xc7, 0x42, 0x42,
+                0x06, 0xb7, 0x87, 0x14, 0x0a, 0xd5, 0xbf, 0x87, 0x34, 0x1a, 0x2d, 0xf9, 0xef, 0x4f,
+                0x05, 0xbd, 0xd1, 0x0c, 0x8a, 0xa8,
             ]))
             .unwrap(),
             y: Fq::from_repr(FqRepr([
-                0x1288334016679345,
-                0xf955cd68615ff0b5,
-                0xa6998dbaa600f18a,
-                0x1267d70db51049fb,
-                0x4696deb9ab2ba3e7,
-                0xb1e4e11177f59d4,
+                0x0b, 0x1e, 0x4e, 0x11, 0x17, 0x7f, 0x59, 0xd4, 0x46, 0x96, 0xde, 0xb9, 0xab, 0x2b,
+                0xa3, 0xe7, 0x12, 0x67, 0xd7, 0x0d, 0xb5, 0x10, 0x49, 0xfb, 0xa6, 0x99, 0x8d, 0xba,
+                0xa6, 0x00, 0xf1, 0x8a, 0xf9, 0x55, 0xcd, 0x68, 0x61, 0x5f, 0xf0, 0xb5, 0x12, 0x88,
+                0x33, 0x40, 0x16, 0x67, 0x93, 0x45,
             ]))
             .unwrap(),
             infinity: false,
@@ -1424,10 +1363,10 @@ pub mod g1 {
 }
 
 pub mod g2 {
-    use super::super::{Bls12, Fq, Fq12, Fq2, FqRepr, Fr, FrRepr};
+    use super::super::{Bls12, Fq, Fq12, Fq2, FqRepr, Fr};
     use super::g1::G1Affine;
     use crate::{Engine, PairingCurveAffine};
-    use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField};
+    use ff::{BitIterator, Field, PrimeField, SqrtField};
     use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError};
     use rand_core::RngCore;
     use std::fmt;
@@ -1517,35 +1456,32 @@ pub mod g2 {
                 // Unset the three most significant bits.
                 copy[0] &= 0x1f;
 
-                let mut x_c0 = FqRepr([0; 6]);
-                let mut x_c1 = FqRepr([0; 6]);
-                let mut y_c0 = FqRepr([0; 6]);
-                let mut y_c1 = FqRepr([0; 6]);
-
-                {
-                    let mut reader = &copy[..];
-
-                    x_c1.read_be(&mut reader).unwrap();
-                    x_c0.read_be(&mut reader).unwrap();
-                    y_c1.read_be(&mut reader).unwrap();
-                    y_c0.read_be(&mut reader).unwrap();
+                fn copy_segment(s: &[u8], start: usize) -> [u8; 48] {
+                    let mut ret = [0; 48];
+                    ret.copy_from_slice(&s[start..start + 48]);
+                    ret
                 }
 
+                let x_c1 = FqRepr(copy_segment(&copy, 0));
+                let x_c0 = FqRepr(copy_segment(&copy, 48));
+                let y_c1 = FqRepr(copy_segment(&copy, 96));
+                let y_c0 = FqRepr(copy_segment(&copy, 144));
+
                 Ok(G2Affine {
                     x: Fq2 {
-                        c0: Fq::from_repr(x_c0).map_err(|e| {
-                            GroupDecodingError::CoordinateDecodingError("x coordinate (c0)", e)
+                        c0: Fq::from_repr(x_c0).ok_or_else(|| {
+                            GroupDecodingError::CoordinateDecodingError("x coordinate (c0)")
                         })?,
-                        c1: Fq::from_repr(x_c1).map_err(|e| {
-                            GroupDecodingError::CoordinateDecodingError("x coordinate (c1)", e)
+                        c1: Fq::from_repr(x_c1).ok_or_else(|| {
+                            GroupDecodingError::CoordinateDecodingError("x coordinate (c1)")
                         })?,
                     },
                     y: Fq2 {
-                        c0: Fq::from_repr(y_c0).map_err(|e| {
-                            GroupDecodingError::CoordinateDecodingError("y coordinate (c0)", e)
+                        c0: Fq::from_repr(y_c0).ok_or_else(|| {
+                            GroupDecodingError::CoordinateDecodingError("y coordinate (c0)")
                         })?,
-                        c1: Fq::from_repr(y_c1).map_err(|e| {
-                            GroupDecodingError::CoordinateDecodingError("y coordinate (c1)", e)
+                        c1: Fq::from_repr(y_c1).ok_or_else(|| {
+                            GroupDecodingError::CoordinateDecodingError("y coordinate (c1)")
                         })?,
                     },
                     infinity: false,
@@ -1560,12 +1496,10 @@ pub mod g2 {
                 // is at infinity.
                 res.0[0] |= 1 << 6;
             } else {
-                let mut writer = &mut res.0[..];
-
-                affine.x.c1.into_repr().write_be(&mut writer).unwrap();
-                affine.x.c0.into_repr().write_be(&mut writer).unwrap();
-                affine.y.c1.into_repr().write_be(&mut writer).unwrap();
-                affine.y.c0.into_repr().write_be(&mut writer).unwrap();
+                res.0[0..48].copy_from_slice(&affine.x.c1.into_repr().0);
+                res.0[48..96].copy_from_slice(&affine.x.c0.into_repr().0);
+                res.0[96..144].copy_from_slice(&affine.y.c1.into_repr().0);
+                res.0[144..192].copy_from_slice(&affine.y.c0.into_repr().0);
             }
 
             res
@@ -1641,23 +1575,22 @@ pub mod g2 {
                 // Unset the three most significant bits.
                 copy[0] &= 0x1f;
 
-                let mut x_c1 = FqRepr([0; 6]);
-                let mut x_c0 = FqRepr([0; 6]);
-
-                {
-                    let mut reader = &copy[..];
-
-                    x_c1.read_be(&mut reader).unwrap();
-                    x_c0.read_be(&mut reader).unwrap();
+                fn copy_segment(s: &[u8], start: usize) -> [u8; 48] {
+                    let mut ret = [0; 48];
+                    ret.copy_from_slice(&s[start..start + 48]);
+                    ret
                 }
 
+                let x_c1 = FqRepr(copy_segment(&copy, 0));
+                let x_c0 = FqRepr(copy_segment(&copy, 48));
+
                 // Interpret as Fq element.
                 let x = Fq2 {
-                    c0: Fq::from_repr(x_c0).map_err(|e| {
-                        GroupDecodingError::CoordinateDecodingError("x coordinate (c0)", e)
+                    c0: Fq::from_repr(x_c0).ok_or_else(|| {
+                        GroupDecodingError::CoordinateDecodingError("x coordinate (c0)")
                     })?,
-                    c1: Fq::from_repr(x_c1).map_err(|e| {
-                        GroupDecodingError::CoordinateDecodingError("x coordinate (c1)", e)
+                    c1: Fq::from_repr(x_c1).ok_or_else(|| {
+                        GroupDecodingError::CoordinateDecodingError("x coordinate (c1)")
                     })?,
                 };
 
@@ -1677,12 +1610,8 @@ pub mod g2 {
                 // is at infinity.
                 res.0[0] |= 1 << 6;
             } else {
-                {
-                    let mut writer = &mut res.0[..];
-
-                    affine.x.c1.into_repr().write_be(&mut writer).unwrap();
-                    affine.x.c0.into_repr().write_be(&mut writer).unwrap();
-                }
+                res.0[..48].copy_from_slice(&affine.x.c1.into_repr().0);
+                res.0[48..].copy_from_slice(&affine.x.c0.into_repr().0);
 
                 let negy = affine.y.neg();
 
@@ -1744,9 +1673,7 @@ pub mod g2 {
     }
 
     impl G2 {
-        fn empirical_recommended_wnaf_for_scalar(scalar: &FrRepr) -> usize {
-            let num_bits = scalar.num_bits() as usize;
-
+        fn empirical_recommended_wnaf_for_scalar(num_bits: usize) -> usize {
             if num_bits >= 103 {
                 4
             } else if num_bits >= 37 {
@@ -1827,41 +1754,33 @@ pub mod g2 {
             let p = G2Affine {
                 x: Fq2 {
                     c0: Fq::from_repr(FqRepr([
-                        0xa757072d9fa35ba9,
-                        0xae3fb2fb418f6e8a,
-                        0xc1598ec46faa0c7c,
-                        0x7a17a004747e3dbe,
-                        0xcc65406a7c2e5a73,
-                        0x10b8c03d64db4d0c,
+                        0x10, 0xb8, 0xc0, 0x3d, 0x64, 0xdb, 0x4d, 0x0c, 0xcc, 0x65, 0x40, 0x6a,
+                        0x7c, 0x2e, 0x5a, 0x73, 0x7a, 0x17, 0xa0, 0x04, 0x74, 0x7e, 0x3d, 0xbe,
+                        0xc1, 0x59, 0x8e, 0xc4, 0x6f, 0xaa, 0x0c, 0x7c, 0xae, 0x3f, 0xb2, 0xfb,
+                        0x41, 0x8f, 0x6e, 0x8a, 0xa7, 0x57, 0x07, 0x2d, 0x9f, 0xa3, 0x5b, 0xa9,
                     ]))
                     .unwrap(),
                     c1: Fq::from_repr(FqRepr([
-                        0xd30e70fe2f029778,
-                        0xda30772df0f5212e,
-                        0x5b47a9ff9a233a50,
-                        0xfb777e5b9b568608,
-                        0x789bac1fec71a2b9,
-                        0x1342f02e2da54405,
+                        0x13, 0x42, 0xf0, 0x2e, 0x2d, 0xa5, 0x44, 0x05, 0x78, 0x9b, 0xac, 0x1f,
+                        0xec, 0x71, 0xa2, 0xb9, 0xfb, 0x77, 0x7e, 0x5b, 0x9b, 0x56, 0x86, 0x08,
+                        0x5b, 0x47, 0xa9, 0xff, 0x9a, 0x23, 0x3a, 0x50, 0xda, 0x30, 0x77, 0x2d,
+                        0xf0, 0xf5, 0x21, 0x2e, 0xd3, 0x0e, 0x70, 0xfe, 0x2f, 0x02, 0x97, 0x78,
                     ]))
                     .unwrap(),
                 },
                 y: Fq2 {
                     c0: Fq::from_repr(FqRepr([
-                        0xfe0812043de54dca,
-                        0xe455171a3d47a646,
-                        0xa493f36bc20be98a,
-                        0x663015d9410eb608,
-                        0x78e82a79d829a544,
-                        0x40a00545bb3c1e,
+                        0x00, 0x40, 0xa0, 0x05, 0x45, 0xbb, 0x3c, 0x1e, 0x78, 0xe8, 0x2a, 0x79,
+                        0xd8, 0x29, 0xa5, 0x44, 0x66, 0x30, 0x15, 0xd9, 0x41, 0x0e, 0xb6, 0x08,
+                        0xa4, 0x93, 0xf3, 0x6b, 0xc2, 0x0b, 0xe9, 0x8a, 0xe4, 0x55, 0x17, 0x1a,
+                        0x3d, 0x47, 0xa6, 0x46, 0xfe, 0x08, 0x12, 0x04, 0x3d, 0xe5, 0x4d, 0xca,
                     ]))
                     .unwrap(),
                     c1: Fq::from_repr(FqRepr([
-                        0x4709802348e79377,
-                        0xb5ac4dc9204bcfbd,
-                        0xda361c97d02f42b2,
-                        0x15008b1dc399e8df,
-                        0x68128fd0548a3829,
-                        0x16a613db5c873aaa,
+                        0x16, 0xa6, 0x13, 0xdb, 0x5c, 0x87, 0x3a, 0xaa, 0x68, 0x12, 0x8f, 0xd0,
+                        0x54, 0x8a, 0x38, 0x29, 0x15, 0x00, 0x8b, 0x1d, 0xc3, 0x99, 0xe8, 0xdf,
+                        0xda, 0x36, 0x1c, 0x97, 0xd0, 0x2f, 0x42, 0xb2, 0xb5, 0xac, 0x4d, 0xc9,
+                        0x20, 0x4b, 0xcf, 0xbd, 0x47, 0x09, 0x80, 0x23, 0x48, 0xe7, 0x93, 0x77,
                     ]))
                     .unwrap(),
                 },
@@ -1876,41 +1795,33 @@ pub mod g2 {
             let p = G2Affine {
                 x: Fq2 {
                     c0: Fq::from_repr(FqRepr([
-                        0xf4fdfe95a705f917,
-                        0xc2914df688233238,
-                        0x37c6b12cca35a34b,
-                        0x41abba710d6c692c,
-                        0xffcc4b2b62ce8484,
-                        0x6993ec01b8934ed,
+                        0x06, 0x99, 0x3e, 0xc0, 0x1b, 0x89, 0x34, 0xed, 0xff, 0xcc, 0x4b, 0x2b,
+                        0x62, 0xce, 0x84, 0x84, 0x41, 0xab, 0xba, 0x71, 0x0d, 0x6c, 0x69, 0x2c,
+                        0x37, 0xc6, 0xb1, 0x2c, 0xca, 0x35, 0xa3, 0x4b, 0xc2, 0x91, 0x4d, 0xf6,
+                        0x88, 0x23, 0x32, 0x38, 0xf4, 0xfd, 0xfe, 0x95, 0xa7, 0x05, 0xf9, 0x17,
                     ]))
                     .unwrap(),
                     c1: Fq::from_repr(FqRepr([
-                        0xb94e92d5f874e26,
-                        0x44516408bc115d95,
-                        0xe93946b290caa591,
-                        0xa5a0c2b7131f3555,
-                        0x83800965822367e7,
-                        0x10cf1d3ad8d90bfa,
+                        0x10, 0xcf, 0x1d, 0x3a, 0xd8, 0xd9, 0x0b, 0xfa, 0x83, 0x80, 0x09, 0x65,
+                        0x82, 0x23, 0x67, 0xe7, 0xa5, 0xa0, 0xc2, 0xb7, 0x13, 0x1f, 0x35, 0x55,
+                        0xe9, 0x39, 0x46, 0xb2, 0x90, 0xca, 0xa5, 0x91, 0x44, 0x51, 0x64, 0x08,
+                        0xbc, 0x11, 0x5d, 0x95, 0x0b, 0x94, 0xe9, 0x2d, 0x5f, 0x87, 0x4e, 0x26,
                     ]))
                     .unwrap(),
                 },
                 y: Fq2 {
                     c0: Fq::from_repr(FqRepr([
-                        0xbf00334c79701d97,
-                        0x4fe714f9ff204f9a,
-                        0xab70b28002f3d825,
-                        0x5a9171720e73eb51,
-                        0x38eb4fd8d658adb7,
-                        0xb649051bbc1164d,
+                        0x0b, 0x64, 0x90, 0x51, 0xbb, 0xc1, 0x16, 0x4d, 0x38, 0xeb, 0x4f, 0xd8,
+                        0xd6, 0x58, 0xad, 0xb7, 0x5a, 0x91, 0x71, 0x72, 0x0e, 0x73, 0xeb, 0x51,
+                        0xab, 0x70, 0xb2, 0x80, 0x02, 0xf3, 0xd8, 0x25, 0x4f, 0xe7, 0x14, 0xf9,
+                        0xff, 0x20, 0x4f, 0x9a, 0xbf, 0x00, 0x33, 0x4c, 0x79, 0x70, 0x1d, 0x97,
                     ]))
                     .unwrap(),
                     c1: Fq::from_repr(FqRepr([
-                        0x9225814253d7df75,
-                        0xc196c2513477f887,
-                        0xe05e2fbd15a804e0,
-                        0x55f2b8efad953e04,
-                        0x7379345eda55265e,
-                        0x377f2e6208fd4cb,
+                        0x03, 0x77, 0xf2, 0xe6, 0x20, 0x8f, 0xd4, 0xcb, 0x73, 0x79, 0x34, 0x5e,
+                        0xda, 0x55, 0x26, 0x5e, 0x55, 0xf2, 0xb8, 0xef, 0xad, 0x95, 0x3e, 0x04,
+                        0xe0, 0x5e, 0x2f, 0xbd, 0x15, 0xa8, 0x04, 0xe0, 0xc1, 0x96, 0xc2, 0x51,
+                        0x34, 0x77, 0xf8, 0x87, 0x92, 0x25, 0x81, 0x42, 0x53, 0xd7, 0xdf, 0x75,
                     ]))
                     .unwrap(),
                 },
@@ -1926,41 +1837,33 @@ pub mod g2 {
             let p = G2Affine {
                 x: Fq2 {
                     c0: Fq::from_repr(FqRepr([
-                        0x262cea73ea1906c,
-                        0x2f08540770fabd6,
-                        0x4ceb92d0a76057be,
-                        0x2199bc19c48c393d,
-                        0x4a151b732a6075bf,
-                        0x17762a3b9108c4a7,
+                        0x17, 0x76, 0x2a, 0x3b, 0x91, 0x08, 0xc4, 0xa7, 0x4a, 0x15, 0x1b, 0x73,
+                        0x2a, 0x60, 0x75, 0xbf, 0x21, 0x99, 0xbc, 0x19, 0xc4, 0x8c, 0x39, 0x3d,
+                        0x4c, 0xeb, 0x92, 0xd0, 0xa7, 0x60, 0x57, 0xbe, 0x02, 0xf0, 0x85, 0x40,
+                        0x77, 0x0f, 0xab, 0xd6, 0x02, 0x62, 0xce, 0xa7, 0x3e, 0xa1, 0x90, 0x6c,
                     ]))
                     .unwrap(),
                     c1: Fq::from_repr(FqRepr([
-                        0x26f461e944bbd3d1,
-                        0x298f3189a9cf6ed6,
-                        0x74328ad8bc2aa150,
-                        0x7e147f3f9e6e241,
-                        0x72a9b63583963fff,
-                        0x158b0083c000462,
+                        0x01, 0x58, 0xb0, 0x08, 0x3c, 0x00, 0x04, 0x62, 0x72, 0xa9, 0xb6, 0x35,
+                        0x83, 0x96, 0x3f, 0xff, 0x07, 0xe1, 0x47, 0xf3, 0xf9, 0xe6, 0xe2, 0x41,
+                        0x74, 0x32, 0x8a, 0xd8, 0xbc, 0x2a, 0xa1, 0x50, 0x29, 0x8f, 0x31, 0x89,
+                        0xa9, 0xcf, 0x6e, 0xd6, 0x26, 0xf4, 0x61, 0xe9, 0x44, 0xbb, 0xd3, 0xd1,
                     ]))
                     .unwrap(),
                 },
                 y: Fq2 {
                     c0: Fq::from_repr(FqRepr([
-                        0x91fb0b225ecf103b,
-                        0x55d42edc1dc46ba0,
-                        0x43939b11997b1943,
-                        0x68cad19430706b4d,
-                        0x3ccfb97b924dcea8,
-                        0x1660f93434588f8d,
+                        0x16, 0x60, 0xf9, 0x34, 0x34, 0x58, 0x8f, 0x8d, 0x3c, 0xcf, 0xb9, 0x7b,
+                        0x92, 0x4d, 0xce, 0xa8, 0x68, 0xca, 0xd1, 0x94, 0x30, 0x70, 0x6b, 0x4d,
+                        0x43, 0x93, 0x9b, 0x11, 0x99, 0x7b, 0x19, 0x43, 0x55, 0xd4, 0x2e, 0xdc,
+                        0x1d, 0xc4, 0x6b, 0xa0, 0x91, 0xfb, 0x0b, 0x22, 0x5e, 0xcf, 0x10, 0x3b,
                     ]))
                     .unwrap(),
                     c1: Fq::from_repr(FqRepr([
-                        0xaaed3985b6dcb9c7,
-                        0xc1e985d6d898d9f4,
-                        0x618bd2ac3271ac42,
-                        0x3940a2dbb914b529,
-                        0xbeb88137cf34f3e7,
-                        0x1699ee577c61b694,
+                        0x16, 0x99, 0xee, 0x57, 0x7c, 0x61, 0xb6, 0x94, 0xbe, 0xb8, 0x81, 0x37,
+                        0xcf, 0x34, 0xf3, 0xe7, 0x39, 0x40, 0xa2, 0xdb, 0xb9, 0x14, 0xb5, 0x29,
+                        0x61, 0x8b, 0xd2, 0xac, 0x32, 0x71, 0xac, 0x42, 0xc1, 0xe9, 0x85, 0xd6,
+                        0xd8, 0x98, 0xd9, 0xf4, 0xaa, 0xed, 0x39, 0x85, 0xb6, 0xdc, 0xb9, 0xc7,
                     ]))
                     .unwrap(),
                 },
@@ -1976,41 +1879,33 @@ pub mod g2 {
         let mut p = G2 {
             x: Fq2 {
                 c0: Fq::from_repr(FqRepr([
-                    0x6c994cc1e303094e,
-                    0xf034642d2c9e85bd,
-                    0x275094f1352123a9,
-                    0x72556c999f3707ac,
-                    0x4617f2e6774e9711,
-                    0x100b2fe5bffe030b,
+                    0x10, 0x0b, 0x2f, 0xe5, 0xbf, 0xfe, 0x03, 0x0b, 0x46, 0x17, 0xf2, 0xe6, 0x77,
+                    0x4e, 0x97, 0x11, 0x72, 0x55, 0x6c, 0x99, 0x9f, 0x37, 0x07, 0xac, 0x27, 0x50,
+                    0x94, 0xf1, 0x35, 0x21, 0x23, 0xa9, 0xf0, 0x34, 0x64, 0x2d, 0x2c, 0x9e, 0x85,
+                    0xbd, 0x6c, 0x99, 0x4c, 0xc1, 0xe3, 0x03, 0x09, 0x4e,
                 ]))
                 .unwrap(),
                 c1: Fq::from_repr(FqRepr([
-                    0x7a33555977ec608,
-                    0xe23039d1fe9c0881,
-                    0x19ce4678aed4fcb5,
-                    0x4637c4f417667e2e,
-                    0x93ebe7c3e41f6acc,
-                    0xde884f89a9a371b,
+                    0x0d, 0xe8, 0x84, 0xf8, 0x9a, 0x9a, 0x37, 0x1b, 0x93, 0xeb, 0xe7, 0xc3, 0xe4,
+                    0x1f, 0x6a, 0xcc, 0x46, 0x37, 0xc4, 0xf4, 0x17, 0x66, 0x7e, 0x2e, 0x19, 0xce,
+                    0x46, 0x78, 0xae, 0xd4, 0xfc, 0xb5, 0xe2, 0x30, 0x39, 0xd1, 0xfe, 0x9c, 0x08,
+                    0x81, 0x07, 0xa3, 0x35, 0x55, 0x97, 0x7e, 0xc6, 0x08,
                 ]))
                 .unwrap(),
             },
             y: Fq2 {
                 c0: Fq::from_repr(FqRepr([
-                    0xe073119472e1eb62,
-                    0x44fb3391fe3c9c30,
-                    0xaa9b066d74694006,
-                    0x25fd427b4122f231,
-                    0xd83112aace35cae,
-                    0x191b2432407cbb7f,
+                    0x19, 0x1b, 0x24, 0x32, 0x40, 0x7c, 0xbb, 0x7f, 0x0d, 0x83, 0x11, 0x2a, 0xac,
+                    0xe3, 0x5c, 0xae, 0x25, 0xfd, 0x42, 0x7b, 0x41, 0x22, 0xf2, 0x31, 0xaa, 0x9b,
+                    0x06, 0x6d, 0x74, 0x69, 0x40, 0x06, 0x44, 0xfb, 0x33, 0x91, 0xfe, 0x3c, 0x9c,
+                    0x30, 0xe0, 0x73, 0x11, 0x94, 0x72, 0xe1, 0xeb, 0x62,
                 ]))
                 .unwrap(),
                 c1: Fq::from_repr(FqRepr([
-                    0xf68ae82fe97662f5,
-                    0xe986057068b50b7d,
-                    0x96c30f0411590b48,
-                    0x9eaa6d19de569196,
-                    0xf6a03d31e2ec2183,
-                    0x3bdafaf7ca9b39b,
+                    0x03, 0xbd, 0xaf, 0xaf, 0x7c, 0xa9, 0xb3, 0x9b, 0xf6, 0xa0, 0x3d, 0x31, 0xe2,
+                    0xec, 0x21, 0x83, 0x9e, 0xaa, 0x6d, 0x19, 0xde, 0x56, 0x91, 0x96, 0x96, 0xc3,
+                    0x0f, 0x04, 0x11, 0x59, 0x0b, 0x48, 0xe9, 0x86, 0x05, 0x70, 0x68, 0xb5, 0x0b,
+                    0x7d, 0xf6, 0x8a, 0xe8, 0x2f, 0xe9, 0x76, 0x62, 0xf5,
                 ]))
                 .unwrap(),
             },
@@ -2020,41 +1915,33 @@ pub mod g2 {
         p.add_assign(&G2 {
             x: Fq2 {
                 c0: Fq::from_repr(FqRepr([
-                    0xa8c763d25910bdd3,
-                    0x408777b30ca3add4,
-                    0x6115fcc12e2769e,
-                    0x8e73a96b329ad190,
-                    0x27c546f75ee1f3ab,
-                    0xa33d27add5e7e82,
+                    0x0a, 0x33, 0xd2, 0x7a, 0xdd, 0x5e, 0x7e, 0x82, 0x27, 0xc5, 0x46, 0xf7, 0x5e,
+                    0xe1, 0xf3, 0xab, 0x8e, 0x73, 0xa9, 0x6b, 0x32, 0x9a, 0xd1, 0x90, 0x06, 0x11,
+                    0x5f, 0xcc, 0x12, 0xe2, 0x76, 0x9e, 0x40, 0x87, 0x77, 0xb3, 0x0c, 0xa3, 0xad,
+                    0xd4, 0xa8, 0xc7, 0x63, 0xd2, 0x59, 0x10, 0xbd, 0xd3,
                 ]))
                 .unwrap(),
                 c1: Fq::from_repr(FqRepr([
-                    0x93b1ebcd54870dfe,
-                    0xf1578300e1342e11,
-                    0x8270dca3a912407b,
-                    0x2089faf462438296,
-                    0x828e5848cd48ea66,
-                    0x141ecbac1deb038b,
+                    0x14, 0x1e, 0xcb, 0xac, 0x1d, 0xeb, 0x03, 0x8b, 0x82, 0x8e, 0x58, 0x48, 0xcd,
+                    0x48, 0xea, 0x66, 0x20, 0x89, 0xfa, 0xf4, 0x62, 0x43, 0x82, 0x96, 0x82, 0x70,
+                    0xdc, 0xa3, 0xa9, 0x12, 0x40, 0x7b, 0xf1, 0x57, 0x83, 0x00, 0xe1, 0x34, 0x2e,
+                    0x11, 0x93, 0xb1, 0xeb, 0xcd, 0x54, 0x87, 0x0d, 0xfe,
                 ]))
                 .unwrap(),
             },
             y: Fq2 {
                 c0: Fq::from_repr(FqRepr([
-                    0xf5d2c28857229c3f,
-                    0x8c1574228757ca23,
-                    0xe8d8102175f5dc19,
-                    0x2767032fc37cc31d,
-                    0xd5ee2aba84fd10fe,
-                    0x16576ccd3dd0a4e8,
+                    0x16, 0x57, 0x6c, 0xcd, 0x3d, 0xd0, 0xa4, 0xe8, 0xd5, 0xee, 0x2a, 0xba, 0x84,
+                    0xfd, 0x10, 0xfe, 0x27, 0x67, 0x03, 0x2f, 0xc3, 0x7c, 0xc3, 0x1d, 0xe8, 0xd8,
+                    0x10, 0x21, 0x75, 0xf5, 0xdc, 0x19, 0x8c, 0x15, 0x74, 0x22, 0x87, 0x57, 0xca,
+                    0x23, 0xf5, 0xd2, 0xc2, 0x88, 0x57, 0x22, 0x9c, 0x3f,
                 ]))
                 .unwrap(),
                 c1: Fq::from_repr(FqRepr([
-                    0x4da9b6f6a96d1dd2,
-                    0x9657f7da77f1650e,
-                    0xbc150712f9ffe6da,
-                    0x31898db63f87363a,
-                    0xabab040ddbd097cc,
-                    0x11ad236b9ba02990,
+                    0x11, 0xad, 0x23, 0x6b, 0x9b, 0xa0, 0x29, 0x90, 0xab, 0xab, 0x04, 0x0d, 0xdb,
+                    0xd0, 0x97, 0xcc, 0x31, 0x89, 0x8d, 0xb6, 0x3f, 0x87, 0x36, 0x3a, 0xbc, 0x15,
+                    0x07, 0x12, 0xf9, 0xff, 0xe6, 0xda, 0x96, 0x57, 0xf7, 0xda, 0x77, 0xf1, 0x65,
+                    0x0e, 0x4d, 0xa9, 0xb6, 0xf6, 0xa9, 0x6d, 0x1d, 0xd2,
                 ]))
                 .unwrap(),
             },
@@ -2068,41 +1955,33 @@ pub mod g2 {
             G2Affine {
                 x: Fq2 {
                     c0: Fq::from_repr(FqRepr([
-                        0xcde7ee8a3f2ac8af,
-                        0xfc642eb35975b069,
-                        0xa7de72b7dd0e64b7,
-                        0xf1273e6406eef9cc,
-                        0xababd760ff05cb92,
-                        0xd7c20456617e89
+                        0x00, 0xd7, 0xc2, 0x04, 0x56, 0x61, 0x7e, 0x89, 0xab, 0xab, 0xd7, 0x60,
+                        0xff, 0x05, 0xcb, 0x92, 0xf1, 0x27, 0x3e, 0x64, 0x06, 0xee, 0xf9, 0xcc,
+                        0xa7, 0xde, 0x72, 0xb7, 0xdd, 0x0e, 0x64, 0xb7, 0xfc, 0x64, 0x2e, 0xb3,
+                        0x59, 0x75, 0xb0, 0x69, 0xcd, 0xe7, 0xee, 0x8a, 0x3f, 0x2a, 0xc8, 0xaf,
                     ]))
                     .unwrap(),
                     c1: Fq::from_repr(FqRepr([
-                        0xd1a50b8572cbd2b8,
-                        0x238f0ac6119d07df,
-                        0x4dbe924fe5fd6ac2,
-                        0x8b203284c51edf6b,
-                        0xc8a0b730bbb21f5e,
-                        0x1a3b59d29a31274
+                        0x01, 0xa3, 0xb5, 0x9d, 0x29, 0xa3, 0x12, 0x74, 0xc8, 0xa0, 0xb7, 0x30,
+                        0xbb, 0xb2, 0x1f, 0x5e, 0x8b, 0x20, 0x32, 0x84, 0xc5, 0x1e, 0xdf, 0x6b,
+                        0x4d, 0xbe, 0x92, 0x4f, 0xe5, 0xfd, 0x6a, 0xc2, 0x23, 0x8f, 0x0a, 0xc6,
+                        0x11, 0x9d, 0x07, 0xdf, 0xd1, 0xa5, 0x0b, 0x85, 0x72, 0xcb, 0xd2, 0xb8,
                     ]))
                     .unwrap(),
                 },
                 y: Fq2 {
                     c0: Fq::from_repr(FqRepr([
-                        0x9e709e78a8eaa4c9,
-                        0xd30921c93ec342f4,
-                        0x6d1ef332486f5e34,
-                        0x64528ab3863633dc,
-                        0x159384333d7cba97,
-                        0x4cb84741f3cafe8
+                        0x04, 0xcb, 0x84, 0x74, 0x1f, 0x3c, 0xaf, 0xe8, 0x15, 0x93, 0x84, 0x33,
+                        0x3d, 0x7c, 0xba, 0x97, 0x64, 0x52, 0x8a, 0xb3, 0x86, 0x36, 0x33, 0xdc,
+                        0x6d, 0x1e, 0xf3, 0x32, 0x48, 0x6f, 0x5e, 0x34, 0xd3, 0x09, 0x21, 0xc9,
+                        0x3e, 0xc3, 0x42, 0xf4, 0x9e, 0x70, 0x9e, 0x78, 0xa8, 0xea, 0xa4, 0xc9,
                     ]))
                     .unwrap(),
                     c1: Fq::from_repr(FqRepr([
-                        0x242af0dc3640e1a4,
-                        0xe90a73ad65c66919,
-                        0x2bd7ca7f4346f9ec,
-                        0x38528f92b689644d,
-                        0xb6884deec59fb21f,
-                        0x3c075d3ec52ba90
+                        0x03, 0xc0, 0x75, 0xd3, 0xec, 0x52, 0xba, 0x90, 0xb6, 0x88, 0x4d, 0xee,
+                        0xc5, 0x9f, 0xb2, 0x1f, 0x38, 0x52, 0x8f, 0x92, 0xb6, 0x89, 0x64, 0x4d,
+                        0x2b, 0xd7, 0xca, 0x7f, 0x43, 0x46, 0xf9, 0xec, 0xe9, 0x0a, 0x73, 0xad,
+                        0x65, 0xc6, 0x69, 0x19, 0x24, 0x2a, 0xf0, 0xdc, 0x36, 0x40, 0xe1, 0xa4,
                     ]))
                     .unwrap(),
                 },
@@ -2116,41 +1995,33 @@ pub mod g2 {
         let mut p = G2 {
             x: Fq2 {
                 c0: Fq::from_repr(FqRepr([
-                    0x6c994cc1e303094e,
-                    0xf034642d2c9e85bd,
-                    0x275094f1352123a9,
-                    0x72556c999f3707ac,
-                    0x4617f2e6774e9711,
-                    0x100b2fe5bffe030b,
+                    0x10, 0x0b, 0x2f, 0xe5, 0xbf, 0xfe, 0x03, 0x0b, 0x46, 0x17, 0xf2, 0xe6, 0x77,
+                    0x4e, 0x97, 0x11, 0x72, 0x55, 0x6c, 0x99, 0x9f, 0x37, 0x07, 0xac, 0x27, 0x50,
+                    0x94, 0xf1, 0x35, 0x21, 0x23, 0xa9, 0xf0, 0x34, 0x64, 0x2d, 0x2c, 0x9e, 0x85,
+                    0xbd, 0x6c, 0x99, 0x4c, 0xc1, 0xe3, 0x03, 0x09, 0x4e,
                 ]))
                 .unwrap(),
                 c1: Fq::from_repr(FqRepr([
-                    0x7a33555977ec608,
-                    0xe23039d1fe9c0881,
-                    0x19ce4678aed4fcb5,
-                    0x4637c4f417667e2e,
-                    0x93ebe7c3e41f6acc,
-                    0xde884f89a9a371b,
+                    0x0d, 0xe8, 0x84, 0xf8, 0x9a, 0x9a, 0x37, 0x1b, 0x93, 0xeb, 0xe7, 0xc3, 0xe4,
+                    0x1f, 0x6a, 0xcc, 0x46, 0x37, 0xc4, 0xf4, 0x17, 0x66, 0x7e, 0x2e, 0x19, 0xce,
+                    0x46, 0x78, 0xae, 0xd4, 0xfc, 0xb5, 0xe2, 0x30, 0x39, 0xd1, 0xfe, 0x9c, 0x08,
+                    0x81, 0x07, 0xa3, 0x35, 0x55, 0x97, 0x7e, 0xc6, 0x08,
                 ]))
                 .unwrap(),
             },
             y: Fq2 {
                 c0: Fq::from_repr(FqRepr([
-                    0xe073119472e1eb62,
-                    0x44fb3391fe3c9c30,
-                    0xaa9b066d74694006,
-                    0x25fd427b4122f231,
-                    0xd83112aace35cae,
-                    0x191b2432407cbb7f,
+                    0x19, 0x1b, 0x24, 0x32, 0x40, 0x7c, 0xbb, 0x7f, 0x0d, 0x83, 0x11, 0x2a, 0xac,
+                    0xe3, 0x5c, 0xae, 0x25, 0xfd, 0x42, 0x7b, 0x41, 0x22, 0xf2, 0x31, 0xaa, 0x9b,
+                    0x06, 0x6d, 0x74, 0x69, 0x40, 0x06, 0x44, 0xfb, 0x33, 0x91, 0xfe, 0x3c, 0x9c,
+                    0x30, 0xe0, 0x73, 0x11, 0x94, 0x72, 0xe1, 0xeb, 0x62,
                 ]))
                 .unwrap(),
                 c1: Fq::from_repr(FqRepr([
-                    0xf68ae82fe97662f5,
-                    0xe986057068b50b7d,
-                    0x96c30f0411590b48,
-                    0x9eaa6d19de569196,
-                    0xf6a03d31e2ec2183,
-                    0x3bdafaf7ca9b39b,
+                    0x03, 0xbd, 0xaf, 0xaf, 0x7c, 0xa9, 0xb3, 0x9b, 0xf6, 0xa0, 0x3d, 0x31, 0xe2,
+                    0xec, 0x21, 0x83, 0x9e, 0xaa, 0x6d, 0x19, 0xde, 0x56, 0x91, 0x96, 0x96, 0xc3,
+                    0x0f, 0x04, 0x11, 0x59, 0x0b, 0x48, 0xe9, 0x86, 0x05, 0x70, 0x68, 0xb5, 0x0b,
+                    0x7d, 0xf6, 0x8a, 0xe8, 0x2f, 0xe9, 0x76, 0x62, 0xf5,
                 ]))
                 .unwrap(),
             },
@@ -2166,41 +2037,33 @@ pub mod g2 {
             G2Affine {
                 x: Fq2 {
                     c0: Fq::from_repr(FqRepr([
-                        0x91ccb1292727c404,
-                        0x91a6cb182438fad7,
-                        0x116aee59434de902,
-                        0xbcedcfce1e52d986,
-                        0x9755d4a3926e9862,
-                        0x18bab73760fd8024
+                        0x18, 0xba, 0xb7, 0x37, 0x60, 0xfd, 0x80, 0x24, 0x97, 0x55, 0xd4, 0xa3,
+                        0x92, 0x6e, 0x98, 0x62, 0xbc, 0xed, 0xcf, 0xce, 0x1e, 0x52, 0xd9, 0x86,
+                        0x11, 0x6a, 0xee, 0x59, 0x43, 0x4d, 0xe9, 0x02, 0x91, 0xa6, 0xcb, 0x18,
+                        0x24, 0x38, 0xfa, 0xd7, 0x91, 0xcc, 0xb1, 0x29, 0x27, 0x27, 0xc4, 0x04,
                     ]))
                     .unwrap(),
                     c1: Fq::from_repr(FqRepr([
-                        0x4e7c5e0a2ae5b99e,
-                        0x96e582a27f028961,
-                        0xc74d1cf4ef2d5926,
-                        0xeb0cf5e610ef4fe7,
-                        0x7b4c2bae8db6e70b,
-                        0xf136e43909fca0
+                        0x00, 0xf1, 0x36, 0xe4, 0x39, 0x09, 0xfc, 0xa0, 0x7b, 0x4c, 0x2b, 0xae,
+                        0x8d, 0xb6, 0xe7, 0x0b, 0xeb, 0x0c, 0xf5, 0xe6, 0x10, 0xef, 0x4f, 0xe7,
+                        0xc7, 0x4d, 0x1c, 0xf4, 0xef, 0x2d, 0x59, 0x26, 0x96, 0xe5, 0x82, 0xa2,
+                        0x7f, 0x02, 0x89, 0x61, 0x4e, 0x7c, 0x5e, 0x0a, 0x2a, 0xe5, 0xb9, 0x9e,
                     ]))
                     .unwrap(),
                 },
                 y: Fq2 {
                     c0: Fq::from_repr(FqRepr([
-                        0x954d4466ab13e58,
-                        0x3ee42eec614cf890,
-                        0x853bb1d28877577e,
-                        0xa5a2a51f7fde787b,
-                        0x8b92866bc6384188,
-                        0x81a53fe531d64ef
+                        0x08, 0x1a, 0x53, 0xfe, 0x53, 0x1d, 0x64, 0xef, 0x8b, 0x92, 0x86, 0x6b,
+                        0xc6, 0x38, 0x41, 0x88, 0xa5, 0xa2, 0xa5, 0x1f, 0x7f, 0xde, 0x78, 0x7b,
+                        0x85, 0x3b, 0xb1, 0xd2, 0x88, 0x77, 0x57, 0x7e, 0x3e, 0xe4, 0x2e, 0xec,
+                        0x61, 0x4c, 0xf8, 0x90, 0x09, 0x54, 0xd4, 0x46, 0x6a, 0xb1, 0x3e, 0x58,
                     ]))
                     .unwrap(),
                     c1: Fq::from_repr(FqRepr([
-                        0x4c5d607666239b34,
-                        0xeddb5f48304d14b3,
-                        0x337167ee6e8e3cb6,
-                        0xb271f52f12ead742,
-                        0x244e6c2015c83348,
-                        0x19e2deae6eb9b441
+                        0x19, 0xe2, 0xde, 0xae, 0x6e, 0xb9, 0xb4, 0x41, 0x24, 0x4e, 0x6c, 0x20,
+                        0x15, 0xc8, 0x33, 0x48, 0xb2, 0x71, 0xf5, 0x2f, 0x12, 0xea, 0xd7, 0x42,
+                        0x33, 0x71, 0x67, 0xee, 0x6e, 0x8e, 0x3c, 0xb6, 0xed, 0xdb, 0x5f, 0x48,
+                        0x30, 0x4d, 0x14, 0xb3, 0x4c, 0x5d, 0x60, 0x76, 0x66, 0x23, 0x9b, 0x34,
                     ]))
                     .unwrap(),
                 },
diff --git a/pairing/src/bls12_381/fq.rs b/pairing/src/bls12_381/fq.rs
index f9caf5e..fa236ff 100644
--- a/pairing/src/bls12_381/fq.rs
+++ b/pairing/src/bls12_381/fq.rs
@@ -1,5 +1,5 @@
 use super::fq2::Fq2;
-use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr};
+use ff::{Field, PrimeField};
 use std::ops::{AddAssign, MulAssign, SubAssign};
 
 #[cfg(test)]
@@ -8,14 +8,14 @@ use ff::PowVartime;
 use std::ops::Neg;
 
 // B coefficient of BLS12-381 curve, 4.
-pub const B_COEFF: Fq = Fq(FqRepr([
+pub const B_COEFF: Fq = Fq([
     0xaa270000000cfff3,
     0x53cc0032fc34000a,
     0x478fe97a6b0a807f,
     0xb1d37ebee6ba24d7,
     0x8ec9733bbf78ab2f,
     0x9d645513d83de7e,
-]));
+]);
 
 // The generators of G1/G2 are computed by finding the lexicographically smallest valid x coordinate,
 // and its lexicographically smallest y coordinate and multiplying it by the cofactor such that the
@@ -24,228 +24,228 @@ pub const B_COEFF: Fq = Fq(FqRepr([
 // Generator of G1
 // x = 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507
 // y = 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569
-pub const G1_GENERATOR_X: Fq = Fq(FqRepr([
+pub const G1_GENERATOR_X: Fq = Fq([
     0x5cb38790fd530c16,
     0x7817fc679976fff5,
     0x154f95c7143ba1c1,
     0xf0ae6acdf3d0e747,
     0xedce6ecc21dbf440,
     0x120177419e0bfb75,
-]));
-pub const G1_GENERATOR_Y: Fq = Fq(FqRepr([
+]);
+pub const G1_GENERATOR_Y: Fq = Fq([
     0xbaac93d50ce72271,
     0x8c22631a7918fd8e,
     0xdd595f13570725ce,
     0x51ac582950405194,
     0xe1c8c3fad0059c0,
     0xbbc3efc5008a26a,
-]));
+]);
 
 // Generator of G2
 // x = 3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758*u + 352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160
 // y = 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582*u + 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905
-pub const G2_GENERATOR_X_C0: Fq = Fq(FqRepr([
+pub const G2_GENERATOR_X_C0: Fq = Fq([
     0xf5f28fa202940a10,
     0xb3f5fb2687b4961a,
     0xa1a893b53e2ae580,
     0x9894999d1a3caee9,
     0x6f67b7631863366b,
     0x58191924350bcd7,
-]));
-pub const G2_GENERATOR_X_C1: Fq = Fq(FqRepr([
+]);
+pub const G2_GENERATOR_X_C1: Fq = Fq([
     0xa5a9c0759e23f606,
     0xaaa0c59dbccd60c3,
     0x3bb17e18e2867806,
     0x1b1ab6cc8541b367,
     0xc2b6ed0ef2158547,
     0x11922a097360edf3,
-]));
-pub const G2_GENERATOR_Y_C0: Fq = Fq(FqRepr([
+]);
+pub const G2_GENERATOR_Y_C0: Fq = Fq([
     0x4c730af860494c4a,
     0x597cfa1f5e369c5a,
     0xe7e6856caa0a635a,
     0xbbefb5e96e0d495f,
     0x7d3a975f0ef25a2,
     0x83fd8e7e80dae5,
-]));
-pub const G2_GENERATOR_Y_C1: Fq = Fq(FqRepr([
+]);
+pub const G2_GENERATOR_Y_C1: Fq = Fq([
     0xadc0fc92df64b05d,
     0x18aa270a2b1461dc,
     0x86adac6a3be4eba0,
     0x79495c4ec93da33a,
     0xe7175850a43ccaed,
     0xb2bc2a163de1bf2,
-]));
+]);
 
 // Coefficients for the Frobenius automorphism.
 pub const FROBENIUS_COEFF_FQ2_C1: [Fq; 2] = [
     // Fq(-1)**(((q^0) - 1) / 2)
-    Fq(FqRepr([
+    Fq([
         0x760900000002fffd,
         0xebf4000bc40c0002,
         0x5f48985753c758ba,
         0x77ce585370525745,
         0x5c071a97a256ec6d,
         0x15f65ec3fa80e493,
-    ])),
+    ]),
     // Fq(-1)**(((q^1) - 1) / 2)
-    Fq(FqRepr([
+    Fq([
         0x43f5fffffffcaaae,
         0x32b7fff2ed47fffd,
         0x7e83a49a2e99d69,
         0xeca8f3318332bb7a,
         0xef148d1ea0f4c069,
         0x40ab3263eff0206,
-    ])),
+    ]),
 ];
 
 pub const FROBENIUS_COEFF_FQ6_C1: [Fq2; 6] = [
     // Fq2(u + 1)**(((q^0) - 1) / 3)
     Fq2 {
-        c0: Fq(FqRepr([
+        c0: Fq([
             0x760900000002fffd,
             0xebf4000bc40c0002,
             0x5f48985753c758ba,
             0x77ce585370525745,
             0x5c071a97a256ec6d,
             0x15f65ec3fa80e493,
-        ])),
-        c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])),
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
     },
     // Fq2(u + 1)**(((q^1) - 1) / 3)
     Fq2 {
-        c0: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])),
-        c1: Fq(FqRepr([
+        c0: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
+        c1: Fq([
             0xcd03c9e48671f071,
             0x5dab22461fcda5d2,
             0x587042afd3851b95,
             0x8eb60ebe01bacb9e,
             0x3f97d6e83d050d2,
             0x18f0206554638741,
-        ])),
+        ]),
     },
     // Fq2(u + 1)**(((q^2) - 1) / 3)
     Fq2 {
-        c0: Fq(FqRepr([
+        c0: Fq([
             0x30f1361b798a64e8,
             0xf3b8ddab7ece5a2a,
             0x16a8ca3ac61577f7,
             0xc26a2ff874fd029b,
             0x3636b76660701c6e,
             0x51ba4ab241b6160,
-        ])),
-        c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])),
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
     },
     // Fq2(u + 1)**(((q^3) - 1) / 3)
     Fq2 {
-        c0: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])),
-        c1: Fq(FqRepr([
+        c0: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
+        c1: Fq([
             0x760900000002fffd,
             0xebf4000bc40c0002,
             0x5f48985753c758ba,
             0x77ce585370525745,
             0x5c071a97a256ec6d,
             0x15f65ec3fa80e493,
-        ])),
+        ]),
     },
     // Fq2(u + 1)**(((q^4) - 1) / 3)
     Fq2 {
-        c0: Fq(FqRepr([
+        c0: Fq([
             0xcd03c9e48671f071,
             0x5dab22461fcda5d2,
             0x587042afd3851b95,
             0x8eb60ebe01bacb9e,
             0x3f97d6e83d050d2,
             0x18f0206554638741,
-        ])),
-        c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])),
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
     },
     // Fq2(u + 1)**(((q^5) - 1) / 3)
     Fq2 {
-        c0: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])),
-        c1: Fq(FqRepr([
+        c0: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
+        c1: Fq([
             0x30f1361b798a64e8,
             0xf3b8ddab7ece5a2a,
             0x16a8ca3ac61577f7,
             0xc26a2ff874fd029b,
             0x3636b76660701c6e,
             0x51ba4ab241b6160,
-        ])),
+        ]),
     },
 ];
 
 pub const FROBENIUS_COEFF_FQ6_C2: [Fq2; 6] = [
     // Fq2(u + 1)**(((2q^0) - 2) / 3)
     Fq2 {
-        c0: Fq(FqRepr([
+        c0: Fq([
             0x760900000002fffd,
             0xebf4000bc40c0002,
             0x5f48985753c758ba,
             0x77ce585370525745,
             0x5c071a97a256ec6d,
             0x15f65ec3fa80e493,
-        ])),
-        c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])),
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
     },
     // Fq2(u + 1)**(((2q^1) - 2) / 3)
     Fq2 {
-        c0: Fq(FqRepr([
+        c0: Fq([
             0x890dc9e4867545c3,
             0x2af322533285a5d5,
             0x50880866309b7e2c,
             0xa20d1b8c7e881024,
             0x14e4f04fe2db9068,
             0x14e56d3f1564853a,
-        ])),
-        c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])),
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
     },
     // Fq2(u + 1)**(((2q^2) - 2) / 3)
     Fq2 {
-        c0: Fq(FqRepr([
+        c0: Fq([
             0xcd03c9e48671f071,
             0x5dab22461fcda5d2,
             0x587042afd3851b95,
             0x8eb60ebe01bacb9e,
             0x3f97d6e83d050d2,
             0x18f0206554638741,
-        ])),
-        c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])),
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
     },
     // Fq2(u + 1)**(((2q^3) - 2) / 3)
     Fq2 {
-        c0: Fq(FqRepr([
+        c0: Fq([
             0x43f5fffffffcaaae,
             0x32b7fff2ed47fffd,
             0x7e83a49a2e99d69,
             0xeca8f3318332bb7a,
             0xef148d1ea0f4c069,
             0x40ab3263eff0206,
-        ])),
-        c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])),
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
     },
     // Fq2(u + 1)**(((2q^4) - 2) / 3)
     Fq2 {
-        c0: Fq(FqRepr([
+        c0: Fq([
             0x30f1361b798a64e8,
             0xf3b8ddab7ece5a2a,
             0x16a8ca3ac61577f7,
             0xc26a2ff874fd029b,
             0x3636b76660701c6e,
             0x51ba4ab241b6160,
-        ])),
-        c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])),
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
     },
     // Fq2(u + 1)**(((2q^5) - 2) / 3)
     Fq2 {
-        c0: Fq(FqRepr([
+        c0: Fq([
             0xecfb361b798dba3a,
             0xc100ddb891865a2c,
             0xec08ff1232bda8e,
             0xd5c13cc6f1ca4721,
             0x47222a47bf7b5c04,
             0x110f184e51c5f59,
-        ])),
-        c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])),
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
     },
 ];
 
@@ -253,206 +253,207 @@ pub const FROBENIUS_COEFF_FQ6_C2: [Fq2; 6] = [
 pub const FROBENIUS_COEFF_FQ12_C1: [Fq2; 12] = [
     // Fq2(u + 1)**(((q^0) - 1) / 6)
     Fq2 {
-        c0: Fq(FqRepr([
+        c0: Fq([
             0x760900000002fffd,
             0xebf4000bc40c0002,
             0x5f48985753c758ba,
             0x77ce585370525745,
             0x5c071a97a256ec6d,
             0x15f65ec3fa80e493,
-        ])),
-        c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])),
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
     },
     // Fq2(u + 1)**(((q^1) - 1) / 6)
     Fq2 {
-        c0: Fq(FqRepr([
+        c0: Fq([
             0x7089552b319d465,
             0xc6695f92b50a8313,
             0x97e83cccd117228f,
             0xa35baecab2dc29ee,
             0x1ce393ea5daace4d,
             0x8f2220fb0fb66eb,
-        ])),
-        c1: Fq(FqRepr([
+        ]),
+        c1: Fq([
             0xb2f66aad4ce5d646,
             0x5842a06bfc497cec,
             0xcf4895d42599d394,
             0xc11b9cba40a8e8d0,
             0x2e3813cbe5a0de89,
             0x110eefda88847faf,
-        ])),
+        ]),
     },
     // Fq2(u + 1)**(((q^2) - 1) / 6)
     Fq2 {
-        c0: Fq(FqRepr([
+        c0: Fq([
             0xecfb361b798dba3a,
             0xc100ddb891865a2c,
             0xec08ff1232bda8e,
             0xd5c13cc6f1ca4721,
             0x47222a47bf7b5c04,
             0x110f184e51c5f59,
-        ])),
-        c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])),
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
     },
     // Fq2(u + 1)**(((q^3) - 1) / 6)
     Fq2 {
-        c0: Fq(FqRepr([
+        c0: Fq([
             0x3e2f585da55c9ad1,
             0x4294213d86c18183,
             0x382844c88b623732,
             0x92ad2afd19103e18,
             0x1d794e4fac7cf0b9,
             0xbd592fc7d825ec8,
-        ])),
-        c1: Fq(FqRepr([
+        ]),
+        c1: Fq([
             0x7bcfa7a25aa30fda,
             0xdc17dec12a927e7c,
             0x2f088dd86b4ebef1,
             0xd1ca2087da74d4a7,
             0x2da2596696cebc1d,
             0xe2b7eedbbfd87d2,
-        ])),
+        ]),
     },
     // Fq2(u + 1)**(((q^4) - 1) / 6)
     Fq2 {
-        c0: Fq(FqRepr([
+        c0: Fq([
             0x30f1361b798a64e8,
             0xf3b8ddab7ece5a2a,
             0x16a8ca3ac61577f7,
             0xc26a2ff874fd029b,
             0x3636b76660701c6e,
             0x51ba4ab241b6160,
-        ])),
-        c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])),
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
     },
     // Fq2(u + 1)**(((q^5) - 1) / 6)
     Fq2 {
-        c0: Fq(FqRepr([
+        c0: Fq([
             0x3726c30af242c66c,
             0x7c2ac1aad1b6fe70,
             0xa04007fbba4b14a2,
             0xef517c3266341429,
             0x95ba654ed2226b,
             0x2e370eccc86f7dd,
-        ])),
-        c1: Fq(FqRepr([
+        ]),
+        c1: Fq([
             0x82d83cf50dbce43f,
             0xa2813e53df9d018f,
             0xc6f0caa53c65e181,
             0x7525cf528d50fe95,
             0x4a85ed50f4798a6b,
             0x171da0fd6cf8eebd,
-        ])),
+        ]),
     },
     // Fq2(u + 1)**(((q^6) - 1) / 6)
     Fq2 {
-        c0: Fq(FqRepr([
+        c0: Fq([
             0x43f5fffffffcaaae,
             0x32b7fff2ed47fffd,
             0x7e83a49a2e99d69,
             0xeca8f3318332bb7a,
             0xef148d1ea0f4c069,
             0x40ab3263eff0206,
-        ])),
-        c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])),
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
     },
     // Fq2(u + 1)**(((q^7) - 1) / 6)
     Fq2 {
-        c0: Fq(FqRepr([
+        c0: Fq([
             0xb2f66aad4ce5d646,
             0x5842a06bfc497cec,
             0xcf4895d42599d394,
             0xc11b9cba40a8e8d0,
             0x2e3813cbe5a0de89,
             0x110eefda88847faf,
-        ])),
-        c1: Fq(FqRepr([
+        ]),
+        c1: Fq([
             0x7089552b319d465,
             0xc6695f92b50a8313,
             0x97e83cccd117228f,
             0xa35baecab2dc29ee,
             0x1ce393ea5daace4d,
             0x8f2220fb0fb66eb,
-        ])),
+        ]),
     },
     // Fq2(u + 1)**(((q^8) - 1) / 6)
     Fq2 {
-        c0: Fq(FqRepr([
+        c0: Fq([
             0xcd03c9e48671f071,
             0x5dab22461fcda5d2,
             0x587042afd3851b95,
             0x8eb60ebe01bacb9e,
             0x3f97d6e83d050d2,
             0x18f0206554638741,
-        ])),
-        c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])),
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
     },
     // Fq2(u + 1)**(((q^9) - 1) / 6)
     Fq2 {
-        c0: Fq(FqRepr([
+        c0: Fq([
             0x7bcfa7a25aa30fda,
             0xdc17dec12a927e7c,
             0x2f088dd86b4ebef1,
             0xd1ca2087da74d4a7,
             0x2da2596696cebc1d,
             0xe2b7eedbbfd87d2,
-        ])),
-        c1: Fq(FqRepr([
+        ]),
+        c1: Fq([
             0x3e2f585da55c9ad1,
             0x4294213d86c18183,
             0x382844c88b623732,
             0x92ad2afd19103e18,
             0x1d794e4fac7cf0b9,
             0xbd592fc7d825ec8,
-        ])),
+        ]),
     },
     // Fq2(u + 1)**(((q^10) - 1) / 6)
     Fq2 {
-        c0: Fq(FqRepr([
+        c0: Fq([
             0x890dc9e4867545c3,
             0x2af322533285a5d5,
             0x50880866309b7e2c,
             0xa20d1b8c7e881024,
             0x14e4f04fe2db9068,
             0x14e56d3f1564853a,
-        ])),
-        c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x0])),
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0, 0x0, 0x0]),
     },
     // Fq2(u + 1)**(((q^11) - 1) / 6)
     Fq2 {
-        c0: Fq(FqRepr([
+        c0: Fq([
             0x82d83cf50dbce43f,
             0xa2813e53df9d018f,
             0xc6f0caa53c65e181,
             0x7525cf528d50fe95,
             0x4a85ed50f4798a6b,
             0x171da0fd6cf8eebd,
-        ])),
-        c1: Fq(FqRepr([
+        ]),
+        c1: Fq([
             0x3726c30af242c66c,
             0x7c2ac1aad1b6fe70,
             0xa04007fbba4b14a2,
             0xef517c3266341429,
             0x95ba654ed2226b,
             0x2e370eccc86f7dd,
-        ])),
+        ]),
     },
 ];
 
 // -((2**384) mod q) mod q
-pub const NEGATIVE_ONE: Fq = Fq(FqRepr([
+pub const NEGATIVE_ONE: Fq = Fq([
     0x43f5fffffffcaaae,
     0x32b7fff2ed47fffd,
     0x7e83a49a2e99d69,
     0xeca8f3318332bb7a,
     0xef148d1ea0f4c069,
     0x40ab3263eff0206,
-]));
+]);
 
 #[derive(PrimeField)]
 #[PrimeFieldModulus = "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787"]
 #[PrimeFieldGenerator = "2"]
-pub struct Fq(FqRepr);
+#[PrimeFieldReprEndianness = "big"]
+pub struct Fq([u64; 6]);
 
 #[test]
 fn test_b_coeff() {
@@ -1182,428 +1183,30 @@ use rand_core::SeedableRng;
 #[cfg(test)]
 use rand_xorshift::XorShiftRng;
 
-#[test]
-fn test_fq_repr_ordering() {
-    use std::cmp::Ordering;
-
-    fn assert_equality(a: FqRepr, b: FqRepr) {
-        assert_eq!(a, b);
-        assert!(a.cmp(&b) == Ordering::Equal);
-    }
-
-    fn assert_lt(a: FqRepr, b: FqRepr) {
-        assert!(a < b);
-        assert!(b > a);
-    }
-
-    assert_equality(
-        FqRepr([9999, 9999, 9999, 9999, 9999, 9999]),
-        FqRepr([9999, 9999, 9999, 9999, 9999, 9999]),
-    );
-    assert_equality(
-        FqRepr([9999, 9998, 9999, 9999, 9999, 9999]),
-        FqRepr([9999, 9998, 9999, 9999, 9999, 9999]),
-    );
-    assert_equality(
-        FqRepr([9999, 9999, 9999, 9997, 9999, 9999]),
-        FqRepr([9999, 9999, 9999, 9997, 9999, 9999]),
-    );
-    assert_lt(
-        FqRepr([9999, 9999, 9999, 9997, 9999, 9998]),
-        FqRepr([9999, 9999, 9999, 9997, 9999, 9999]),
-    );
-    assert_lt(
-        FqRepr([9999, 9999, 9999, 9997, 9998, 9999]),
-        FqRepr([9999, 9999, 9999, 9997, 9999, 9999]),
-    );
-    assert_lt(
-        FqRepr([9, 9999, 9999, 9997, 9998, 9999]),
-        FqRepr([9999, 9999, 9999, 9997, 9999, 9999]),
-    );
-}
-
-#[test]
-fn test_fq_repr_from() {
-    assert_eq!(FqRepr::from(100), FqRepr([100, 0, 0, 0, 0, 0]));
-}
-
-#[test]
-fn test_fq_repr_is_odd() {
-    assert!(!FqRepr::from(0).is_odd());
-    assert!(FqRepr::from(0).is_even());
-    assert!(FqRepr::from(1).is_odd());
-    assert!(!FqRepr::from(1).is_even());
-    assert!(!FqRepr::from(324834872).is_odd());
-    assert!(FqRepr::from(324834872).is_even());
-    assert!(FqRepr::from(324834873).is_odd());
-    assert!(!FqRepr::from(324834873).is_even());
-}
-
-#[test]
-fn test_fq_repr_is_zero() {
-    assert!(FqRepr::from(0).is_zero());
-    assert!(!FqRepr::from(1).is_zero());
-    assert!(!FqRepr([0, 0, 0, 0, 1, 0]).is_zero());
-}
-
-#[test]
-fn test_fq_repr_div2() {
-    let mut a = FqRepr([
-        0x8b0ad39f8dd7482a,
-        0x147221c9a7178b69,
-        0x54764cb08d8a6aa0,
-        0x8519d708e1d83041,
-        0x41f82777bd13fdb,
-        0xf43944578f9b771b,
-    ]);
-    a.div2();
-    assert_eq!(
-        a,
-        FqRepr([
-            0xc58569cfc6eba415,
-            0xa3910e4d38bc5b4,
-            0xaa3b265846c53550,
-            0xc28ceb8470ec1820,
-            0x820fc13bbde89fed,
-            0x7a1ca22bc7cdbb8d
-        ])
-    );
-    for _ in 0..10 {
-        a.div2();
-    }
-    assert_eq!(
-        a,
-        FqRepr([
-            0x6d31615a73f1bae9,
-            0x54028e443934e2f1,
-            0x82a8ec99611b14d,
-            0xfb70a33ae11c3b06,
-            0xe36083f04eef7a27,
-            0x1e87288af1f36e
-        ])
-    );
-    for _ in 0..300 {
-        a.div2();
-    }
-    assert_eq!(a, FqRepr([0x7288af1f36ee3608, 0x1e8, 0x0, 0x0, 0x0, 0x0]));
-    for _ in 0..50 {
-        a.div2();
-    }
-    assert_eq!(a, FqRepr([0x7a1ca2, 0x0, 0x0, 0x0, 0x0, 0x0]));
-    for _ in 0..22 {
-        a.div2();
-    }
-    assert_eq!(a, FqRepr([0x1, 0x0, 0x0, 0x0, 0x0, 0x0]));
-    a.div2();
-    assert!(a.is_zero());
-}
-
-#[test]
-fn test_fq_repr_shr() {
-    let mut a = FqRepr([
-        0xaa5cdd6172847ffd,
-        0x43242c06aed55287,
-        0x9ddd5b312f3dd104,
-        0xc5541fd48046b7e7,
-        0x16080cf4071e0b05,
-        0x1225f2901aea514e,
-    ]);
-    a.shr(0);
-    assert_eq!(
-        a,
-        FqRepr([
-            0xaa5cdd6172847ffd,
-            0x43242c06aed55287,
-            0x9ddd5b312f3dd104,
-            0xc5541fd48046b7e7,
-            0x16080cf4071e0b05,
-            0x1225f2901aea514e
-        ])
-    );
-    a.shr(1);
-    assert_eq!(
-        a,
-        FqRepr([
-            0xd52e6eb0b9423ffe,
-            0x21921603576aa943,
-            0xceeead98979ee882,
-            0xe2aa0fea40235bf3,
-            0xb04067a038f0582,
-            0x912f9480d7528a7
-        ])
-    );
-    a.shr(50);
-    assert_eq!(
-        a,
-        FqRepr([
-            0x8580d5daaa50f54b,
-            0xab6625e7ba208864,
-            0x83fa9008d6fcf3bb,
-            0x19e80e3c160b8aa,
-            0xbe52035d4a29c2c1,
-            0x244
-        ])
-    );
-    a.shr(130);
-    assert_eq!(
-        a,
-        FqRepr([
-            0xa0fea40235bf3cee,
-            0x4067a038f0582e2a,
-            0x2f9480d7528a70b0,
-            0x91,
-            0x0,
-            0x0
-        ])
-    );
-    a.shr(64);
-    assert_eq!(
-        a,
-        FqRepr([0x4067a038f0582e2a, 0x2f9480d7528a70b0, 0x91, 0x0, 0x0, 0x0])
-    );
-}
-
-#[test]
-fn test_fq_repr_mul2() {
-    let mut a = FqRepr::from(23712937547);
-    a.mul2();
-    assert_eq!(a, FqRepr([0xb0acd6c96, 0x0, 0x0, 0x0, 0x0, 0x0]));
-    for _ in 0..60 {
-        a.mul2();
-    }
-    assert_eq!(
-        a,
-        FqRepr([0x6000000000000000, 0xb0acd6c9, 0x0, 0x0, 0x0, 0x0])
-    );
-    for _ in 0..300 {
-        a.mul2();
-    }
-    assert_eq!(a, FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0xcd6c960000000000]));
-    for _ in 0..17 {
-        a.mul2();
-    }
-    assert_eq!(a, FqRepr([0x0, 0x0, 0x0, 0x0, 0x0, 0x2c00000000000000]));
-    for _ in 0..6 {
-        a.mul2();
-    }
-    assert!(a.is_zero());
-}
-
-#[test]
-fn test_fq_repr_num_bits() {
-    let mut a = FqRepr::from(0);
-    assert_eq!(0, a.num_bits());
-    a = FqRepr::from(1);
-    for i in 1..385 {
-        assert_eq!(i, a.num_bits());
-        a.mul2();
-    }
-    assert_eq!(0, a.num_bits());
-}
-
-#[test]
-fn test_fq_repr_sub_noborrow() {
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    let mut t = FqRepr([
-        0x827a4a08041ebd9,
-        0x3c239f3dcc8f0d6b,
-        0x9ab46a912d555364,
-        0x196936b17b43910b,
-        0xad0eb3948a5c34fd,
-        0xd56f7b5ab8b5ce8,
-    ]);
-    t.sub_noborrow(&FqRepr([
-        0xc7867917187ca02b,
-        0x5d75679d4911ffef,
-        0x8c5b3e48b1a71c15,
-        0x6a427ae846fd66aa,
-        0x7a37e7265ee1eaf9,
-        0x7c0577a26f59d5,
-    ]));
-    assert!(
-        t == FqRepr([
-            0x40a12b8967c54bae,
-            0xdeae37a0837d0d7b,
-            0xe592c487bae374e,
-            0xaf26bbc934462a61,
-            0x32d6cc6e2b7a4a03,
-            0xcdaf23e091c0313
-        ])
-    );
-
-    for _ in 0..1000 {
-        let mut a = Fq::random(&mut rng).into_repr();
-        a.0[5] >>= 30;
-        let mut b = a;
-        for _ in 0..10 {
-            b.mul2();
-        }
-        let mut c = b;
-        for _ in 0..10 {
-            c.mul2();
-        }
-
-        assert!(a < b);
-        assert!(b < c);
-
-        let mut csub_ba = c;
-        csub_ba.sub_noborrow(&b);
-        csub_ba.sub_noborrow(&a);
-
-        let mut csub_ab = c;
-        csub_ab.sub_noborrow(&a);
-        csub_ab.sub_noborrow(&b);
-
-        assert_eq!(csub_ab, csub_ba);
-    }
-
-    // Subtracting q+1 from q should produce -1 (mod 2**384)
-    let mut qplusone = FqRepr([
-        0xb9feffffffffaaab,
-        0x1eabfffeb153ffff,
-        0x6730d2a0f6b0f624,
-        0x64774b84f38512bf,
-        0x4b1ba7b6434bacd7,
-        0x1a0111ea397fe69a,
-    ]);
-    qplusone.sub_noborrow(&FqRepr([
-        0xb9feffffffffaaac,
-        0x1eabfffeb153ffff,
-        0x6730d2a0f6b0f624,
-        0x64774b84f38512bf,
-        0x4b1ba7b6434bacd7,
-        0x1a0111ea397fe69a,
-    ]));
-    assert_eq!(
-        qplusone,
-        FqRepr([
-            0xffffffffffffffff,
-            0xffffffffffffffff,
-            0xffffffffffffffff,
-            0xffffffffffffffff,
-            0xffffffffffffffff,
-            0xffffffffffffffff
-        ])
-    );
-}
-
-#[test]
-fn test_fq_repr_add_nocarry() {
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    let mut t = FqRepr([
-        0x827a4a08041ebd9,
-        0x3c239f3dcc8f0d6b,
-        0x9ab46a912d555364,
-        0x196936b17b43910b,
-        0xad0eb3948a5c34fd,
-        0xd56f7b5ab8b5ce8,
-    ]);
-    t.add_nocarry(&FqRepr([
-        0xc7867917187ca02b,
-        0x5d75679d4911ffef,
-        0x8c5b3e48b1a71c15,
-        0x6a427ae846fd66aa,
-        0x7a37e7265ee1eaf9,
-        0x7c0577a26f59d5,
-    ]));
-    assert!(
-        t == FqRepr([
-            0xcfae1db798be8c04,
-            0x999906db15a10d5a,
-            0x270fa8d9defc6f79,
-            0x83abb199c240f7b6,
-            0x27469abae93e1ff6,
-            0xdd2fd2d4dfab6be
-        ])
-    );
-
-    // Test for the associativity of addition.
-    for _ in 0..1000 {
-        let mut a = Fq::random(&mut rng).into_repr();
-        let mut b = Fq::random(&mut rng).into_repr();
-        let mut c = Fq::random(&mut rng).into_repr();
-
-        // Unset the first few bits, so that overflow won't occur.
-        a.0[5] >>= 3;
-        b.0[5] >>= 3;
-        c.0[5] >>= 3;
-
-        let mut abc = a;
-        abc.add_nocarry(&b);
-        abc.add_nocarry(&c);
-
-        let mut acb = a;
-        acb.add_nocarry(&c);
-        acb.add_nocarry(&b);
-
-        let mut bac = b;
-        bac.add_nocarry(&a);
-        bac.add_nocarry(&c);
-
-        let mut bca = b;
-        bca.add_nocarry(&c);
-        bca.add_nocarry(&a);
-
-        let mut cab = c;
-        cab.add_nocarry(&a);
-        cab.add_nocarry(&b);
-
-        let mut cba = c;
-        cba.add_nocarry(&b);
-        cba.add_nocarry(&a);
-
-        assert_eq!(abc, acb);
-        assert_eq!(abc, bac);
-        assert_eq!(abc, bca);
-        assert_eq!(abc, cab);
-        assert_eq!(abc, cba);
-    }
-
-    // Adding 1 to (2^384 - 1) should produce zero
-    let mut x = FqRepr([
-        0xffffffffffffffff,
-        0xffffffffffffffff,
-        0xffffffffffffffff,
-        0xffffffffffffffff,
-        0xffffffffffffffff,
-        0xffffffffffffffff,
-    ]);
-    x.add_nocarry(&FqRepr::from(1));
-    assert!(x.is_zero());
-}
-
 #[test]
 fn test_fq_is_valid() {
-    let mut a = Fq(MODULUS);
+    let mut a = MODULUS_LIMBS;
     assert!(!a.is_valid());
-    a.0.sub_noborrow(&FqRepr::from(1));
+    a.sub_noborrow(&Fq([1, 0, 0, 0, 0, 0]));
     assert!(a.is_valid());
     assert!(Fq::from(0).is_valid());
-    assert!(Fq(FqRepr([
+    assert!(Fq([
         0xdf4671abd14dab3e,
         0xe2dc0c9f534fbd33,
         0x31ca6c880cc444a6,
         0x257a67e70ef33359,
         0xf9b29e493f899b36,
         0x17c8be1800b9f059
-    ]))
+    ])
     .is_valid());
-    assert!(!Fq(FqRepr([
+    assert!(!Fq([
         0xffffffffffffffff,
         0xffffffffffffffff,
         0xffffffffffffffff,
         0xffffffffffffffff,
         0xffffffffffffffff,
         0xffffffffffffffff
-    ]))
+    ])
     .is_valid());
 
     let mut rng = XorShiftRng::from_seed([
@@ -1621,103 +1224,103 @@ fn test_fq_is_valid() {
 fn test_fq_add_assign() {
     {
         // Random number
-        let mut tmp = Fq(FqRepr([
+        let mut tmp = Fq([
             0x624434821df92b69,
             0x503260c04fd2e2ea,
             0xd9df726e0d16e8ce,
             0xfbcb39adfd5dfaeb,
             0x86b8a22b0c88b112,
             0x165a2ed809e4201b,
-        ]));
+        ]);
         assert!(tmp.is_valid());
         // Test that adding zero has no effect.
-        tmp.add_assign(&Fq(FqRepr::from(0)));
+        tmp.add_assign(&Fq([0, 0, 0, 0, 0, 0]));
         assert_eq!(
             tmp,
-            Fq(FqRepr([
+            Fq([
                 0x624434821df92b69,
                 0x503260c04fd2e2ea,
                 0xd9df726e0d16e8ce,
                 0xfbcb39adfd5dfaeb,
                 0x86b8a22b0c88b112,
                 0x165a2ed809e4201b
-            ]))
+            ])
         );
         // Add one and test for the result.
-        tmp.add_assign(&Fq(FqRepr::from(1)));
+        tmp.add_assign(&Fq([1, 0, 0, 0, 0, 0]));
         assert_eq!(
             tmp,
-            Fq(FqRepr([
+            Fq([
                 0x624434821df92b6a,
                 0x503260c04fd2e2ea,
                 0xd9df726e0d16e8ce,
                 0xfbcb39adfd5dfaeb,
                 0x86b8a22b0c88b112,
                 0x165a2ed809e4201b
-            ]))
+            ])
         );
         // Add another random number that exercises the reduction.
-        tmp.add_assign(&Fq(FqRepr([
+        tmp.add_assign(&Fq([
             0x374d8f8ea7a648d8,
             0xe318bb0ebb8bfa9b,
             0x613d996f0a95b400,
             0x9fac233cb7e4fef1,
             0x67e47552d253c52,
             0x5c31b227edf25da,
-        ])));
+        ]));
         assert_eq!(
             tmp,
-            Fq(FqRepr([
+            Fq([
                 0xdf92c410c59fc997,
                 0x149f1bd05a0add85,
                 0xd3ec393c20fba6ab,
                 0x37001165c1bde71d,
                 0x421b41c9f662408e,
                 0x21c38104f435f5b
-            ]))
+            ])
         );
         // Add one to (q - 1) and test for the result.
-        tmp = Fq(FqRepr([
+        tmp = Fq([
             0xb9feffffffffaaaa,
             0x1eabfffeb153ffff,
             0x6730d2a0f6b0f624,
             0x64774b84f38512bf,
             0x4b1ba7b6434bacd7,
             0x1a0111ea397fe69a,
-        ]));
-        tmp.add_assign(&Fq(FqRepr::from(1)));
-        assert!(tmp.0.is_zero());
+        ]);
+        tmp.add_assign(&Fq([1, 0, 0, 0, 0, 0]));
+        assert!(tmp.is_zero());
         // Add a random number to another one such that the result is q - 1
-        tmp = Fq(FqRepr([
+        tmp = Fq([
             0x531221a410efc95b,
             0x72819306027e9717,
             0x5ecefb937068b746,
             0x97de59cd6feaefd7,
             0xdc35c51158644588,
             0xb2d176c04f2100,
-        ]));
-        tmp.add_assign(&Fq(FqRepr([
+        ]);
+        tmp.add_assign(&Fq([
             0x66ecde5bef0fe14f,
             0xac2a6cf8aed568e8,
             0x861d70d86483edd,
             0xcc98f1b7839a22e8,
             0x6ee5e2a4eae7674e,
             0x194e40737930c599,
-        ])));
+        ]));
         assert_eq!(
             tmp,
-            Fq(FqRepr([
+            Fq([
                 0xb9feffffffffaaaa,
                 0x1eabfffeb153ffff,
                 0x6730d2a0f6b0f624,
                 0x64774b84f38512bf,
                 0x4b1ba7b6434bacd7,
                 0x1a0111ea397fe69a
-            ]))
+            ])
         );
         // Add one to the result and test for it.
-        tmp.add_assign(&Fq(FqRepr::from(1)));
-        assert!(tmp.0.is_zero());
+        tmp.add_assign(&Fq([1, 0, 0, 0, 0, 0]));
+        assert!(tmp.is_zero());
     }
 
     // Test associativity
@@ -1751,87 +1354,87 @@ fn test_fq_add_assign() {
 fn test_fq_sub_assign() {
     {
         // Test arbitrary subtraction that tests reduction.
-        let mut tmp = Fq(FqRepr([
+        let mut tmp = Fq([
             0x531221a410efc95b,
             0x72819306027e9717,
             0x5ecefb937068b746,
             0x97de59cd6feaefd7,
             0xdc35c51158644588,
             0xb2d176c04f2100,
-        ]));
-        tmp.sub_assign(&Fq(FqRepr([
+        ]);
+        tmp.sub_assign(&Fq([
             0x98910d20877e4ada,
             0x940c983013f4b8ba,
             0xf677dc9b8345ba33,
             0xbef2ce6b7f577eba,
             0xe1ae288ac3222c44,
             0x5968bb602790806,
-        ])));
+        ]));
         assert_eq!(
             tmp,
-            Fq(FqRepr([
+            Fq([
                 0x748014838971292c,
                 0xfd20fad49fddde5c,
                 0xcf87f198e3d3f336,
                 0x3d62d6e6e41883db,
                 0x45a3443cd88dc61b,
                 0x151d57aaf755ff94
-            ]))
+            ])
         );
 
         // Test the opposite subtraction which doesn't test reduction.
-        tmp = Fq(FqRepr([
+        tmp = Fq([
             0x98910d20877e4ada,
             0x940c983013f4b8ba,
             0xf677dc9b8345ba33,
             0xbef2ce6b7f577eba,
             0xe1ae288ac3222c44,
             0x5968bb602790806,
-        ]));
-        tmp.sub_assign(&Fq(FqRepr([
+        ]);
+        tmp.sub_assign(&Fq([
             0x531221a410efc95b,
             0x72819306027e9717,
             0x5ecefb937068b746,
             0x97de59cd6feaefd7,
             0xdc35c51158644588,
             0xb2d176c04f2100,
-        ])));
+        ]));
         assert_eq!(
             tmp,
-            Fq(FqRepr([
+            Fq([
                 0x457eeb7c768e817f,
                 0x218b052a117621a3,
                 0x97a8e10812dd02ed,
                 0x2714749e0f6c8ee3,
                 0x57863796abde6bc,
                 0x4e3ba3f4229e706
-            ]))
+            ])
         );
 
         // Test for sensible results with zero
-        tmp = Fq(FqRepr::from(0));
-        tmp.sub_assign(&Fq(FqRepr::from(0)));
+        tmp = Fq::zero();
+        tmp.sub_assign(&Fq::zero());
         assert!(tmp.is_zero());
 
-        tmp = Fq(FqRepr([
+        tmp = Fq([
             0x98910d20877e4ada,
             0x940c983013f4b8ba,
             0xf677dc9b8345ba33,
             0xbef2ce6b7f577eba,
             0xe1ae288ac3222c44,
             0x5968bb602790806,
-        ]));
-        tmp.sub_assign(&Fq(FqRepr::from(0)));
+        ]);
+        tmp.sub_assign(&Fq::zero());
         assert_eq!(
             tmp,
-            Fq(FqRepr([
+            Fq([
                 0x98910d20877e4ada,
                 0x940c983013f4b8ba,
                 0xf677dc9b8345ba33,
                 0xbef2ce6b7f577eba,
                 0xe1ae288ac3222c44,
                 0x5968bb602790806
-            ]))
+            ])
         );
     }
 
@@ -1858,31 +1461,31 @@ fn test_fq_sub_assign() {
 
 #[test]
 fn test_fq_mul_assign() {
-    let mut tmp = Fq(FqRepr([
+    let mut tmp = Fq([
         0xcc6200000020aa8a,
         0x422800801dd8001a,
         0x7f4f5e619041c62c,
         0x8a55171ac70ed2ba,
         0x3f69cc3a3d07d58b,
         0xb972455fd09b8ef,
-    ]));
-    tmp.mul_assign(&Fq(FqRepr([
+    ]);
+    tmp.mul_assign(&Fq([
         0x329300000030ffcf,
         0x633c00c02cc40028,
         0xbef70d925862a942,
         0x4f7fa2a82a963c17,
         0xdf1eb2575b8bc051,
         0x1162b680fb8e9566,
-    ])));
+    ]));
     assert!(
-        tmp == Fq(FqRepr([
+        tmp == Fq([
             0x9dc4000001ebfe14,
             0x2850078997b00193,
             0xa8197f1abb4d7bf,
             0xc0309573f4bfe871,
             0xf48d0923ffaf7620,
             0x11d4b58c7a926e66
-        ]))
+        ])
     );
 
     let mut rng = XorShiftRng::from_seed([
@@ -1934,96 +1537,82 @@ fn test_fq_mul_assign() {
 #[test]
 fn test_fq_shr() {
     let mut a = Fq::from_repr(FqRepr([
-        0xaa5cdd6172847ffd,
-        0x43242c06aed55287,
-        0x9ddd5b312f3dd104,
-        0xc5541fd48046b7e7,
-        0x16080cf4071e0b05,
-        0x1225f2901aea514e,
+        0x12, 0x25, 0xf2, 0x90, 0x1a, 0xea, 0x51, 0x4e, 0x16, 0x08, 0x0c, 0xf4, 0x07, 0x1e, 0x0b,
+        0x05, 0xc5, 0x54, 0x1f, 0xd4, 0x80, 0x46, 0xb7, 0xe7, 0x9d, 0xdd, 0x5b, 0x31, 0x2f, 0x3d,
+        0xd1, 0x04, 0x43, 0x24, 0x2c, 0x06, 0xae, 0xd5, 0x52, 0x87, 0xaa, 0x5c, 0xdd, 0x61, 0x72,
+        0x84, 0x7f, 0xfd,
     ]))
     .unwrap();
     a = a >> 0;
     assert_eq!(
         a.into_repr(),
         FqRepr([
-            0xaa5cdd6172847ffd,
-            0x43242c06aed55287,
-            0x9ddd5b312f3dd104,
-            0xc5541fd48046b7e7,
-            0x16080cf4071e0b05,
-            0x1225f2901aea514e,
+            0x12, 0x25, 0xf2, 0x90, 0x1a, 0xea, 0x51, 0x4e, 0x16, 0x08, 0x0c, 0xf4, 0x07, 0x1e,
+            0x0b, 0x05, 0xc5, 0x54, 0x1f, 0xd4, 0x80, 0x46, 0xb7, 0xe7, 0x9d, 0xdd, 0x5b, 0x31,
+            0x2f, 0x3d, 0xd1, 0x04, 0x43, 0x24, 0x2c, 0x06, 0xae, 0xd5, 0x52, 0x87, 0xaa, 0x5c,
+            0xdd, 0x61, 0x72, 0x84, 0x7f, 0xfd,
         ])
     );
     a = a >> 1;
     assert_eq!(
         a.into_repr(),
         FqRepr([
-            0xd52e6eb0b9423ffe,
-            0x21921603576aa943,
-            0xceeead98979ee882,
-            0xe2aa0fea40235bf3,
-            0x0b04067a038f0582,
-            0x0912f9480d7528a7,
+            0x09, 0x12, 0xf9, 0x48, 0x0d, 0x75, 0x28, 0xa7, 0x0b, 0x04, 0x06, 0x7a, 0x03, 0x8f,
+            0x05, 0x82, 0xe2, 0xaa, 0x0f, 0xea, 0x40, 0x23, 0x5b, 0xf3, 0xce, 0xee, 0xad, 0x98,
+            0x97, 0x9e, 0xe8, 0x82, 0x21, 0x92, 0x16, 0x03, 0x57, 0x6a, 0xa9, 0x43, 0xd5, 0x2e,
+            0x6e, 0xb0, 0xb9, 0x42, 0x3f, 0xfe,
         ])
     );
     a = a >> 50;
     assert_eq!(
         a.into_repr(),
         FqRepr([
-            0x8580d5daaa50f54b,
-            0xab6625e7ba208864,
-            0x83fa9008d6fcf3bb,
-            0x019e80e3c160b8aa,
-            0xbe52035d4a29c2c1,
-            0x0000000000000244,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x44, 0xbe, 0x52, 0x03, 0x5d, 0x4a, 0x29,
+            0xc2, 0xc1, 0x01, 0x9e, 0x80, 0xe3, 0xc1, 0x60, 0xb8, 0xaa, 0x83, 0xfa, 0x90, 0x08,
+            0xd6, 0xfc, 0xf3, 0xbb, 0xab, 0x66, 0x25, 0xe7, 0xba, 0x20, 0x88, 0x64, 0x85, 0x80,
+            0xd5, 0xda, 0xaa, 0x50, 0xf5, 0x4b,
         ])
     );
     a = a >> 130;
     assert_eq!(
         a.into_repr(),
         FqRepr([
-            0xa0fea40235bf3cee,
-            0x4067a038f0582e2a,
-            0x2f9480d7528a70b0,
-            0x0000000000000091,
-            0x0000000000000000,
-            0x0000000000000000,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x2f, 0x94, 0x80, 0xd7,
+            0x52, 0x8a, 0x70, 0xb0, 0x40, 0x67, 0xa0, 0x38, 0xf0, 0x58, 0x2e, 0x2a, 0xa0, 0xfe,
+            0xa4, 0x02, 0x35, 0xbf, 0x3c, 0xee,
         ])
     );
     a = a >> 64;
     assert_eq!(
         a.into_repr(),
         FqRepr([
-            0x4067a038f0582e2a,
-            0x2f9480d7528a70b0,
-            0x0000000000000091,
-            0x0000000000000000,
-            0x0000000000000000,
-            0x0000000000000000,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x91, 0x2f, 0x94, 0x80, 0xd7, 0x52, 0x8a, 0x70, 0xb0, 0x40, 0x67,
+            0xa0, 0x38, 0xf0, 0x58, 0x2e, 0x2a,
         ])
     );
 }
 
 #[test]
 fn test_fq_squaring() {
-    let a = Fq(FqRepr([
+    let a = Fq([
         0xffffffffffffffff,
         0xffffffffffffffff,
         0xffffffffffffffff,
         0xffffffffffffffff,
         0xffffffffffffffff,
         0x19ffffffffffffff,
-    ]));
+    ]);
     assert!(a.is_valid());
     assert_eq!(
         a.square(),
         Fq::from_repr(FqRepr([
-            0x1cfb28fe7dfbbb86,
-            0x24cbe1731577a59,
-            0xcce1d4edc120e66e,
-            0xdc05c659b4e15b27,
-            0x79361e5a802c6a23,
-            0x24bcbe5d51b9a6f
+            0x02, 0x4b, 0xcb, 0xe5, 0xd5, 0x1b, 0x9a, 0x6f, 0x79, 0x36, 0x1e, 0x5a, 0x80, 0x2c,
+            0x6a, 0x23, 0xdc, 0x05, 0xc6, 0x59, 0xb4, 0xe1, 0x5b, 0x27, 0xcc, 0xe1, 0xd4, 0xed,
+            0xc1, 0x20, 0xe6, 0x6e, 0x02, 0x4c, 0xbe, 0x17, 0x31, 0x57, 0x7a, 0x59, 0x1c, 0xfb,
+            0x28, 0xfe, 0x7d, 0xfb, 0xbb, 0x86,
         ]))
         .unwrap()
     );
@@ -2161,50 +1750,42 @@ fn test_fq_sqrt() {
 fn test_fq_from_into_repr() {
     // q + 1 should not be in the field
     assert!(Fq::from_repr(FqRepr([
-        0xb9feffffffffaaac,
-        0x1eabfffeb153ffff,
-        0x6730d2a0f6b0f624,
-        0x64774b84f38512bf,
-        0x4b1ba7b6434bacd7,
-        0x1a0111ea397fe69a
+        0x1a, 0x01, 0x11, 0xea, 0x39, 0x7f, 0xe6, 0x9a, 0x4b, 0x1b, 0xa7, 0xb6, 0x43, 0x4b, 0xac,
+        0xd7, 0x64, 0x77, 0x4b, 0x84, 0xf3, 0x85, 0x12, 0xbf, 0x67, 0x30, 0xd2, 0xa0, 0xf6, 0xb0,
+        0xf6, 0x24, 0x1e, 0xab, 0xff, 0xfe, 0xb1, 0x53, 0xff, 0xff, 0xb9, 0xfe, 0xff, 0xff, 0xff,
+        0xff, 0xaa, 0xac,
     ]))
-    .is_err());
+    .is_none());
 
     // q should not be in the field
-    assert!(Fq::from_repr(Fq::char()).is_err());
+    assert!(Fq::from_repr(Fq::char()).is_none());
 
     // Multiply some arbitrary representations to see if the result is as expected.
     let a = FqRepr([
-        0x4a49dad4ff6cde2d,
-        0xac62a82a8f51cd50,
-        0x2b1f41ab9f36d640,
-        0x908a387f480735f1,
-        0xae30740c08a875d7,
-        0x6c80918a365ef78,
+        0x06, 0xc8, 0x09, 0x18, 0xa3, 0x65, 0xef, 0x78, 0xae, 0x30, 0x74, 0x0c, 0x08, 0xa8, 0x75,
+        0xd7, 0x90, 0x8a, 0x38, 0x7f, 0x48, 0x07, 0x35, 0xf1, 0x2b, 0x1f, 0x41, 0xab, 0x9f, 0x36,
+        0xd6, 0x40, 0xac, 0x62, 0xa8, 0x2a, 0x8f, 0x51, 0xcd, 0x50, 0x4a, 0x49, 0xda, 0xd4, 0xff,
+        0x6c, 0xde, 0x2d,
     ]);
     let mut a_fq = Fq::from_repr(a).unwrap();
     let b = FqRepr([
-        0xbba57917c32f0cf0,
-        0xe7f878cf87f05e5d,
-        0x9498b4292fd27459,
-        0xd59fd94ee4572cfa,
-        0x1f607186d5bb0059,
-        0xb13955f5ac7f6a3,
+        0x0b, 0x13, 0x95, 0x5f, 0x5a, 0xc7, 0xf6, 0xa3, 0x1f, 0x60, 0x71, 0x86, 0xd5, 0xbb, 0x00,
+        0x59, 0xd5, 0x9f, 0xd9, 0x4e, 0xe4, 0x57, 0x2c, 0xfa, 0x94, 0x98, 0xb4, 0x29, 0x2f, 0xd2,
+        0x74, 0x59, 0xe7, 0xf8, 0x78, 0xcf, 0x87, 0xf0, 0x5e, 0x5d, 0xbb, 0xa5, 0x79, 0x17, 0xc3,
+        0x2f, 0x0c, 0xf0,
     ]);
     let b_fq = Fq::from_repr(b).unwrap();
     let c = FqRepr([
-        0xf5f70713b717914c,
-        0x355ea5ac64cbbab1,
-        0xce60dd43417ec960,
-        0xf16b9d77b0ad7d10,
-        0xa44c204c1de7cdb7,
-        0x1684487772bc9a5a,
+        0x16, 0x84, 0x48, 0x77, 0x72, 0xbc, 0x9a, 0x5a, 0xa4, 0x4c, 0x20, 0x4c, 0x1d, 0xe7, 0xcd,
+        0xb7, 0xf1, 0x6b, 0x9d, 0x77, 0xb0, 0xad, 0x7d, 0x10, 0xce, 0x60, 0xdd, 0x43, 0x41, 0x7e,
+        0xc9, 0x60, 0x35, 0x5e, 0xa5, 0xac, 0x64, 0xcb, 0xba, 0xb1, 0xf5, 0xf7, 0x07, 0x13, 0xb7,
+        0x17, 0x91, 0x4c,
     ]);
     a_fq.mul_assign(&b_fq);
     assert_eq!(a_fq.into_repr(), c);
 
     // Zero should be in the field.
-    assert!(Fq::from_repr(FqRepr::from(0)).unwrap().is_zero());
+    assert!(Fq::from_repr(FqRepr([0; 48])).unwrap().is_zero());
 
     let mut rng = XorShiftRng::from_seed([
         0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
@@ -2223,34 +1804,24 @@ fn test_fq_from_into_repr() {
     }
 }
 
-#[test]
-fn test_fq_repr_display() {
-    assert_eq!(
-        format!("{}", FqRepr([0xa956babf9301ea24, 0x39a8f184f3535c7b, 0xb38d35b3f6779585, 0x676cc4eef4c46f2c, 0xb1d4aad87651e694, 0x1947f0d5f4fe325a])),
-        "0x1947f0d5f4fe325ab1d4aad87651e694676cc4eef4c46f2cb38d35b3f677958539a8f184f3535c7ba956babf9301ea24".to_string()
-    );
-    assert_eq!(
-        format!("{}", FqRepr([0xb4171485fd8622dd, 0x864229a6edec7ec5, 0xc57f7bdcf8dfb707, 0x6db7ff0ecea4584a, 0xf8d8578c4a57132d, 0x6eb66d42d9fcaaa])),
-        "0x06eb66d42d9fcaaaf8d8578c4a57132d6db7ff0ecea4584ac57f7bdcf8dfb707864229a6edec7ec5b4171485fd8622dd".to_string()
-    );
-    assert_eq!(
-        format!("{}", FqRepr([0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff])),
-        "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".to_string()
-    );
-    assert_eq!(
-        format!("{}", FqRepr([0, 0, 0, 0, 0, 0])),
-        "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".to_string()
-    );
-}
-
 #[test]
 fn test_fq_display() {
     assert_eq!(
-        format!("{}", Fq::from_repr(FqRepr([0xa956babf9301ea24, 0x39a8f184f3535c7b, 0xb38d35b3f6779585, 0x676cc4eef4c46f2c, 0xb1d4aad87651e694, 0x1947f0d5f4fe325a])).unwrap()),
+        format!("{}", Fq::from_repr(FqRepr([
+            0x19, 0x47, 0xf0, 0xd5, 0xf4, 0xfe, 0x32, 0x5a, 0xb1, 0xd4, 0xaa, 0xd8, 0x76, 0x51,
+            0xe6, 0x94, 0x67, 0x6c, 0xc4, 0xee, 0xf4, 0xc4, 0x6f, 0x2c, 0xb3, 0x8d, 0x35, 0xb3,
+            0xf6, 0x77, 0x95, 0x85, 0x39, 0xa8, 0xf1, 0x84, 0xf3, 0x53, 0x5c, 0x7b, 0xa9, 0x56,
+            0xba, 0xbf, 0x93, 0x01, 0xea, 0x24,
+        ])).unwrap()),
         "Fq(0x1947f0d5f4fe325ab1d4aad87651e694676cc4eef4c46f2cb38d35b3f677958539a8f184f3535c7ba956babf9301ea24)".to_string()
     );
     assert_eq!(
-        format!("{}", Fq::from_repr(FqRepr([0xe28e79396ac2bbf8, 0x413f6f7f06ea87eb, 0xa4b62af4a792a689, 0xb7f89f88f59c1dc5, 0x9a551859b1e43a9a, 0x6c9f5a1060de974])).unwrap()),
+        format!("{}", Fq::from_repr(FqRepr([
+            0x06, 0xc9, 0xf5, 0xa1, 0x06, 0x0d, 0xe9, 0x74, 0x9a, 0x55, 0x18, 0x59, 0xb1, 0xe4,
+            0x3a, 0x9a, 0xb7, 0xf8, 0x9f, 0x88, 0xf5, 0x9c, 0x1d, 0xc5, 0xa4, 0xb6, 0x2a, 0xf4,
+            0xa7, 0x92, 0xa6, 0x89, 0x41, 0x3f, 0x6f, 0x7f, 0x06, 0xea, 0x87, 0xeb, 0xe2, 0x8e,
+            0x79, 0x39, 0x6a, 0xc2, 0xbb, 0xf8,
+        ])).unwrap()),
         "Fq(0x06c9f5a1060de9749a551859b1e43a9ab7f89f88f59c1dc5a4b62af4a792a689413f6f7f06ea87ebe28e79396ac2bbf8)".to_string()
     );
 }
@@ -2304,8 +1875,7 @@ fn fq_field_tests() {
 
 #[test]
 fn test_fq_ordering() {
-    // FqRepr's ordering is well-tested, but we still need to make sure the Fq
-    // elements aren't being compared in Montgomery form.
+    // We need to make sure the Fq elements aren't being compared in Montgomery form.
     for i in 0..100 {
         assert!(Fq::from(i + 1) > Fq::from(i));
     }
diff --git a/pairing/src/bls12_381/fq2.rs b/pairing/src/bls12_381/fq2.rs
index 6e62307..dd5b751 100644
--- a/pairing/src/bls12_381/fq2.rs
+++ b/pairing/src/bls12_381/fq2.rs
@@ -302,6 +302,11 @@ impl SqrtField for Fq2 {
     }
 }
 
+#[cfg(test)]
+use super::fq::FqRepr;
+#[cfg(test)]
+use ff::PrimeField;
+
 #[test]
 fn test_fq2_ordering() {
     let mut a = Fq2 {
@@ -353,9 +358,6 @@ fn test_fq2_basics() {
 
 #[test]
 fn test_fq2_squaring() {
-    use super::fq::FqRepr;
-    use ff::PrimeField;
-
     let a = Fq2 {
         c0: Fq::one(),
         c1: Fq::one(),
@@ -381,21 +383,17 @@ fn test_fq2_squaring() {
 
     let a = Fq2 {
         c0: Fq::from_repr(FqRepr([
-            0x9c2c6309bbf8b598,
-            0x4eef5c946536f602,
-            0x90e34aab6fb6a6bd,
-            0xf7f295a94e58ae7c,
-            0x41b76dcc1c3fbe5e,
-            0x7080c5fa1d8e042,
+            0x07, 0x08, 0x0c, 0x5f, 0xa1, 0xd8, 0xe0, 0x42, 0x41, 0xb7, 0x6d, 0xcc, 0x1c, 0x3f,
+            0xbe, 0x5e, 0xf7, 0xf2, 0x95, 0xa9, 0x4e, 0x58, 0xae, 0x7c, 0x90, 0xe3, 0x4a, 0xab,
+            0x6f, 0xb6, 0xa6, 0xbd, 0x4e, 0xef, 0x5c, 0x94, 0x65, 0x36, 0xf6, 0x02, 0x9c, 0x2c,
+            0x63, 0x09, 0xbb, 0xf8, 0xb5, 0x98,
         ]))
         .unwrap(),
         c1: Fq::from_repr(FqRepr([
-            0x38f473b3c870a4ab,
-            0x6ad3291177c8c7e5,
-            0xdac5a4c911a4353e,
-            0xbfb99020604137a0,
-            0xfc58a7b7be815407,
-            0x10d1615e75250a21,
+            0x10, 0xd1, 0x61, 0x5e, 0x75, 0x25, 0x0a, 0x21, 0xfc, 0x58, 0xa7, 0xb7, 0xbe, 0x81,
+            0x54, 0x07, 0xbf, 0xb9, 0x90, 0x20, 0x60, 0x41, 0x37, 0xa0, 0xda, 0xc5, 0xa4, 0xc9,
+            0x11, 0xa4, 0x35, 0x3e, 0x6a, 0xd3, 0x29, 0x11, 0x77, 0xc8, 0xc7, 0xe5, 0x38, 0xf4,
+            0x73, 0xb3, 0xc8, 0x70, 0xa4, 0xab,
         ]))
         .unwrap(),
     };
@@ -403,21 +401,17 @@ fn test_fq2_squaring() {
         a.square(),
         Fq2 {
             c0: Fq::from_repr(FqRepr([
-                0xf262c28c538bcf68,
-                0xb9f2a66eae1073ba,
-                0xdc46ab8fad67ae0,
-                0xcb674157618da176,
-                0x4cf17b5893c3d327,
-                0x7eac81369c43361
+                0x07, 0xea, 0xc8, 0x13, 0x69, 0xc4, 0x33, 0x61, 0x4c, 0xf1, 0x7b, 0x58, 0x93, 0xc3,
+                0xd3, 0x27, 0xcb, 0x67, 0x41, 0x57, 0x61, 0x8d, 0xa1, 0x76, 0x0d, 0xc4, 0x6a, 0xb8,
+                0xfa, 0xd6, 0x7a, 0xe0, 0xb9, 0xf2, 0xa6, 0x6e, 0xae, 0x10, 0x73, 0xba, 0xf2, 0x62,
+                0xc2, 0x8c, 0x53, 0x8b, 0xcf, 0x68,
             ]))
             .unwrap(),
             c1: Fq::from_repr(FqRepr([
-                0xc1579cf58e980cf8,
-                0xa23eb7e12dd54d98,
-                0xe75138bce4cec7aa,
-                0x38d0d7275a9689e1,
-                0x739c983042779a65,
-                0x1542a61c8a8db994
+                0x15, 0x42, 0xa6, 0x1c, 0x8a, 0x8d, 0xb9, 0x94, 0x73, 0x9c, 0x98, 0x30, 0x42, 0x77,
+                0x9a, 0x65, 0x38, 0xd0, 0xd7, 0x27, 0x5a, 0x96, 0x89, 0xe1, 0xe7, 0x51, 0x38, 0xbc,
+                0xe4, 0xce, 0xc7, 0xaa, 0xa2, 0x3e, 0xb7, 0xe1, 0x2d, 0xd5, 0x4d, 0x98, 0xc1, 0x57,
+                0x9c, 0xf5, 0x8e, 0x98, 0x0c, 0xf8,
             ]))
             .unwrap(),
         }
@@ -431,41 +425,33 @@ fn test_fq2_mul() {
 
     let mut a = Fq2 {
         c0: Fq::from_repr(FqRepr([
-            0x85c9f989e1461f03,
-            0xa2e33c333449a1d6,
-            0x41e461154a7354a3,
-            0x9ee53e7e84d7532e,
-            0x1c202d8ed97afb45,
-            0x51d3f9253e2516f,
+            0x05, 0x1d, 0x3f, 0x92, 0x53, 0xe2, 0x51, 0x6f, 0x1c, 0x20, 0x2d, 0x8e, 0xd9, 0x7a,
+            0xfb, 0x45, 0x9e, 0xe5, 0x3e, 0x7e, 0x84, 0xd7, 0x53, 0x2e, 0x41, 0xe4, 0x61, 0x15,
+            0x4a, 0x73, 0x54, 0xa3, 0xa2, 0xe3, 0x3c, 0x33, 0x34, 0x49, 0xa1, 0xd6, 0x85, 0xc9,
+            0xf9, 0x89, 0xe1, 0x46, 0x1f, 0x03,
         ]))
         .unwrap(),
         c1: Fq::from_repr(FqRepr([
-            0xa7348a8b511aedcf,
-            0x143c215d8176b319,
-            0x4cc48081c09b8903,
-            0x9533e4a9a5158be,
-            0x7a5e1ecb676d65f9,
-            0x180c3ee46656b008,
+            0x18, 0x0c, 0x3e, 0xe4, 0x66, 0x56, 0xb0, 0x08, 0x7a, 0x5e, 0x1e, 0xcb, 0x67, 0x6d,
+            0x65, 0xf9, 0x09, 0x53, 0x3e, 0x4a, 0x9a, 0x51, 0x58, 0xbe, 0x4c, 0xc4, 0x80, 0x81,
+            0xc0, 0x9b, 0x89, 0x03, 0x14, 0x3c, 0x21, 0x5d, 0x81, 0x76, 0xb3, 0x19, 0xa7, 0x34,
+            0x8a, 0x8b, 0x51, 0x1a, 0xed, 0xcf,
         ]))
         .unwrap(),
     };
     a.mul_assign(&Fq2 {
         c0: Fq::from_repr(FqRepr([
-            0xe21f9169805f537e,
-            0xfc87e62e179c285d,
-            0x27ece175be07a531,
-            0xcd460f9f0c23e430,
-            0x6c9110292bfa409,
-            0x2c93a72eb8af83e,
+            0x02, 0xc9, 0x3a, 0x72, 0xeb, 0x8a, 0xf8, 0x3e, 0x06, 0xc9, 0x11, 0x02, 0x92, 0xbf,
+            0xa4, 0x09, 0xcd, 0x46, 0x0f, 0x9f, 0x0c, 0x23, 0xe4, 0x30, 0x27, 0xec, 0xe1, 0x75,
+            0xbe, 0x07, 0xa5, 0x31, 0xfc, 0x87, 0xe6, 0x2e, 0x17, 0x9c, 0x28, 0x5d, 0xe2, 0x1f,
+            0x91, 0x69, 0x80, 0x5f, 0x53, 0x7e,
         ]))
         .unwrap(),
         c1: Fq::from_repr(FqRepr([
-            0x4b1c3f936d8992d4,
-            0x1d2a72916dba4c8a,
-            0x8871c508658d1e5f,
-            0x57a06d3135a752ae,
-            0x634cd3c6c565096d,
-            0x19e17334d4e93558,
+            0x19, 0xe1, 0x73, 0x34, 0xd4, 0xe9, 0x35, 0x58, 0x63, 0x4c, 0xd3, 0xc6, 0xc5, 0x65,
+            0x09, 0x6d, 0x57, 0xa0, 0x6d, 0x31, 0x35, 0xa7, 0x52, 0xae, 0x88, 0x71, 0xc5, 0x08,
+            0x65, 0x8d, 0x1e, 0x5f, 0x1d, 0x2a, 0x72, 0x91, 0x6d, 0xba, 0x4c, 0x8a, 0x4b, 0x1c,
+            0x3f, 0x93, 0x6d, 0x89, 0x92, 0xd4,
         ]))
         .unwrap(),
     });
@@ -473,21 +459,17 @@ fn test_fq2_mul() {
         a,
         Fq2 {
             c0: Fq::from_repr(FqRepr([
-                0x95b5127e6360c7e4,
-                0xde29c31a19a6937e,
-                0xf61a96dacf5a39bc,
-                0x5511fe4d84ee5f78,
-                0x5310a202d92f9963,
-                0x1751afbe166e5399
+                0x17, 0x51, 0xaf, 0xbe, 0x16, 0x6e, 0x53, 0x99, 0x53, 0x10, 0xa2, 0x02, 0xd9, 0x2f,
+                0x99, 0x63, 0x55, 0x11, 0xfe, 0x4d, 0x84, 0xee, 0x5f, 0x78, 0xf6, 0x1a, 0x96, 0xda,
+                0xcf, 0x5a, 0x39, 0xbc, 0xde, 0x29, 0xc3, 0x1a, 0x19, 0xa6, 0x93, 0x7e, 0x95, 0xb5,
+                0x12, 0x7e, 0x63, 0x60, 0xc7, 0xe4,
             ]))
             .unwrap(),
             c1: Fq::from_repr(FqRepr([
-                0x84af0e1bd630117a,
-                0x6c63cd4da2c2aa7,
-                0x5ba6e5430e883d40,
-                0xc975106579c275ee,
-                0x33a9ac82ce4c5083,
-                0x1ef1a36c201589d
+                0x01, 0xef, 0x1a, 0x36, 0xc2, 0x01, 0x58, 0x9d, 0x33, 0xa9, 0xac, 0x82, 0xce, 0x4c,
+                0x50, 0x83, 0xc9, 0x75, 0x10, 0x65, 0x79, 0xc2, 0x75, 0xee, 0x5b, 0xa6, 0xe5, 0x43,
+                0x0e, 0x88, 0x3d, 0x40, 0x06, 0xc6, 0x3c, 0xd4, 0xda, 0x2c, 0x2a, 0xa7, 0x84, 0xaf,
+                0x0e, 0x1b, 0xd6, 0x30, 0x11, 0x7a,
             ]))
             .unwrap(),
         }
@@ -503,21 +485,17 @@ fn test_fq2_invert() {
 
     let a = Fq2 {
         c0: Fq::from_repr(FqRepr([
-            0x85c9f989e1461f03,
-            0xa2e33c333449a1d6,
-            0x41e461154a7354a3,
-            0x9ee53e7e84d7532e,
-            0x1c202d8ed97afb45,
-            0x51d3f9253e2516f,
+            0x05, 0x1d, 0x3f, 0x92, 0x53, 0xe2, 0x51, 0x6f, 0x1c, 0x20, 0x2d, 0x8e, 0xd9, 0x7a,
+            0xfb, 0x45, 0x9e, 0xe5, 0x3e, 0x7e, 0x84, 0xd7, 0x53, 0x2e, 0x41, 0xe4, 0x61, 0x15,
+            0x4a, 0x73, 0x54, 0xa3, 0xa2, 0xe3, 0x3c, 0x33, 0x34, 0x49, 0xa1, 0xd6, 0x85, 0xc9,
+            0xf9, 0x89, 0xe1, 0x46, 0x1f, 0x03,
         ]))
         .unwrap(),
         c1: Fq::from_repr(FqRepr([
-            0xa7348a8b511aedcf,
-            0x143c215d8176b319,
-            0x4cc48081c09b8903,
-            0x9533e4a9a5158be,
-            0x7a5e1ecb676d65f9,
-            0x180c3ee46656b008,
+            0x18, 0x0c, 0x3e, 0xe4, 0x66, 0x56, 0xb0, 0x08, 0x7a, 0x5e, 0x1e, 0xcb, 0x67, 0x6d,
+            0x65, 0xf9, 0x09, 0x53, 0x3e, 0x4a, 0x9a, 0x51, 0x58, 0xbe, 0x4c, 0xc4, 0x80, 0x81,
+            0xc0, 0x9b, 0x89, 0x03, 0x14, 0x3c, 0x21, 0x5d, 0x81, 0x76, 0xb3, 0x19, 0xa7, 0x34,
+            0x8a, 0x8b, 0x51, 0x1a, 0xed, 0xcf,
         ]))
         .unwrap(),
     };
@@ -526,21 +504,17 @@ fn test_fq2_invert() {
         a,
         Fq2 {
             c0: Fq::from_repr(FqRepr([
-                0x70300f9bcb9e594,
-                0xe5ecda5fdafddbb2,
-                0x64bef617d2915a8f,
-                0xdfba703293941c30,
-                0xa6c3d8f9586f2636,
-                0x1351ef01941b70c4
+                0x13, 0x51, 0xef, 0x01, 0x94, 0x1b, 0x70, 0xc4, 0xa6, 0xc3, 0xd8, 0xf9, 0x58, 0x6f,
+                0x26, 0x36, 0xdf, 0xba, 0x70, 0x32, 0x93, 0x94, 0x1c, 0x30, 0x64, 0xbe, 0xf6, 0x17,
+                0xd2, 0x91, 0x5a, 0x8f, 0xe5, 0xec, 0xda, 0x5f, 0xda, 0xfd, 0xdb, 0xb2, 0x07, 0x03,
+                0x00, 0xf9, 0xbc, 0xb9, 0xe5, 0x94,
             ]))
             .unwrap(),
             c1: Fq::from_repr(FqRepr([
-                0x8c39fd76a8312cb4,
-                0x15d7b6b95defbff0,
-                0x947143f89faedee9,
-                0xcbf651a0f367afb2,
-                0xdf4e54f0d3ef15a6,
-                0x103bdf241afb0019
+                0x10, 0x3b, 0xdf, 0x24, 0x1a, 0xfb, 0x00, 0x19, 0xdf, 0x4e, 0x54, 0xf0, 0xd3, 0xef,
+                0x15, 0xa6, 0xcb, 0xf6, 0x51, 0xa0, 0xf3, 0x67, 0xaf, 0xb2, 0x94, 0x71, 0x43, 0xf8,
+                0x9f, 0xae, 0xde, 0xe9, 0x15, 0xd7, 0xb6, 0xb9, 0x5d, 0xef, 0xbf, 0xf0, 0x8c, 0x39,
+                0xfd, 0x76, 0xa8, 0x31, 0x2c, 0xb4,
             ]))
             .unwrap(),
         }
@@ -554,41 +528,33 @@ fn test_fq2_addition() {
 
     let mut a = Fq2 {
         c0: Fq::from_repr(FqRepr([
-            0x2d0078036923ffc7,
-            0x11e59ea221a3b6d2,
-            0x8b1a52e0a90f59ed,
-            0xb966ce3bc2108b13,
-            0xccc649c4b9532bf3,
-            0xf8d295b2ded9dc,
+            0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
+            0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
+            0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
+            0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
         ]))
         .unwrap(),
         c1: Fq::from_repr(FqRepr([
-            0x977df6efcdaee0db,
-            0x946ae52d684fa7ed,
-            0xbe203411c66fb3a5,
-            0xb3f8afc0ee248cad,
-            0x4e464dea5bcfd41e,
-            0x12d1137b8a6a837,
+            0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf,
+            0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11,
+            0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d,
+            0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb,
         ]))
         .unwrap(),
     };
     a.add_assign(&Fq2 {
         c0: Fq::from_repr(FqRepr([
-            0x619a02d78dc70ef2,
-            0xb93adfc9119e33e8,
-            0x4bf0b99a9f0dca12,
-            0x3b88899a42a6318f,
-            0x986a4a62fa82a49d,
-            0x13ce433fa26027f5,
+            0x13, 0xce, 0x43, 0x3f, 0xa2, 0x60, 0x27, 0xf5, 0x98, 0x6a, 0x4a, 0x62, 0xfa, 0x82,
+            0xa4, 0x9d, 0x3b, 0x88, 0x89, 0x9a, 0x42, 0xa6, 0x31, 0x8f, 0x4b, 0xf0, 0xb9, 0x9a,
+            0x9f, 0x0d, 0xca, 0x12, 0xb9, 0x3a, 0xdf, 0xc9, 0x11, 0x9e, 0x33, 0xe8, 0x61, 0x9a,
+            0x02, 0xd7, 0x8d, 0xc7, 0x0e, 0xf2,
         ]))
         .unwrap(),
         c1: Fq::from_repr(FqRepr([
-            0x66323bf80b58b9b9,
-            0xa1379b6facf6e596,
-            0x402aef1fb797e32f,
-            0x2236f55246d0d44d,
-            0x4c8c1800eb104566,
-            0x11d6e20e986c2085,
+            0x11, 0xd6, 0xe2, 0x0e, 0x98, 0x6c, 0x20, 0x85, 0x4c, 0x8c, 0x18, 0x00, 0xeb, 0x10,
+            0x45, 0x66, 0x22, 0x36, 0xf5, 0x52, 0x46, 0xd0, 0xd4, 0x4d, 0x40, 0x2a, 0xef, 0x1f,
+            0xb7, 0x97, 0xe3, 0x2f, 0xa1, 0x37, 0x9b, 0x6f, 0xac, 0xf6, 0xe5, 0x96, 0x66, 0x32,
+            0x3b, 0xf8, 0x0b, 0x58, 0xb9, 0xb9,
         ]))
         .unwrap(),
     });
@@ -596,21 +562,17 @@ fn test_fq2_addition() {
         a,
         Fq2 {
             c0: Fq::from_repr(FqRepr([
-                0x8e9a7adaf6eb0eb9,
-                0xcb207e6b3341eaba,
-                0xd70b0c7b481d23ff,
-                0xf4ef57d604b6bca2,
-                0x65309427b3d5d090,
-                0x14c715d5553f01d2
+                0x14, 0xc7, 0x15, 0xd5, 0x55, 0x3f, 0x01, 0xd2, 0x65, 0x30, 0x94, 0x27, 0xb3, 0xd5,
+                0xd0, 0x90, 0xf4, 0xef, 0x57, 0xd6, 0x04, 0xb6, 0xbc, 0xa2, 0xd7, 0x0b, 0x0c, 0x7b,
+                0x48, 0x1d, 0x23, 0xff, 0xcb, 0x20, 0x7e, 0x6b, 0x33, 0x41, 0xea, 0xba, 0x8e, 0x9a,
+                0x7a, 0xda, 0xf6, 0xeb, 0x0e, 0xb9,
             ]))
             .unwrap(),
             c1: Fq::from_repr(FqRepr([
-                0xfdb032e7d9079a94,
-                0x35a2809d15468d83,
-                0xfe4b23317e0796d5,
-                0xd62fa51334f560fa,
-                0x9ad265eb46e01984,
-                0x1303f3465112c8bc
+                0x13, 0x03, 0xf3, 0x46, 0x51, 0x12, 0xc8, 0xbc, 0x9a, 0xd2, 0x65, 0xeb, 0x46, 0xe0,
+                0x19, 0x84, 0xd6, 0x2f, 0xa5, 0x13, 0x34, 0xf5, 0x60, 0xfa, 0xfe, 0x4b, 0x23, 0x31,
+                0x7e, 0x07, 0x96, 0xd5, 0x35, 0xa2, 0x80, 0x9d, 0x15, 0x46, 0x8d, 0x83, 0xfd, 0xb0,
+                0x32, 0xe7, 0xd9, 0x07, 0x9a, 0x94,
             ]))
             .unwrap(),
         }
@@ -624,41 +586,33 @@ fn test_fq2_subtraction() {
 
     let mut a = Fq2 {
         c0: Fq::from_repr(FqRepr([
-            0x2d0078036923ffc7,
-            0x11e59ea221a3b6d2,
-            0x8b1a52e0a90f59ed,
-            0xb966ce3bc2108b13,
-            0xccc649c4b9532bf3,
-            0xf8d295b2ded9dc,
+            0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
+            0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
+            0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
+            0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
         ]))
         .unwrap(),
         c1: Fq::from_repr(FqRepr([
-            0x977df6efcdaee0db,
-            0x946ae52d684fa7ed,
-            0xbe203411c66fb3a5,
-            0xb3f8afc0ee248cad,
-            0x4e464dea5bcfd41e,
-            0x12d1137b8a6a837,
+            0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf,
+            0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11,
+            0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d,
+            0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb,
         ]))
         .unwrap(),
     };
     a.sub_assign(&Fq2 {
         c0: Fq::from_repr(FqRepr([
-            0x619a02d78dc70ef2,
-            0xb93adfc9119e33e8,
-            0x4bf0b99a9f0dca12,
-            0x3b88899a42a6318f,
-            0x986a4a62fa82a49d,
-            0x13ce433fa26027f5,
+            0x13, 0xce, 0x43, 0x3f, 0xa2, 0x60, 0x27, 0xf5, 0x98, 0x6a, 0x4a, 0x62, 0xfa, 0x82,
+            0xa4, 0x9d, 0x3b, 0x88, 0x89, 0x9a, 0x42, 0xa6, 0x31, 0x8f, 0x4b, 0xf0, 0xb9, 0x9a,
+            0x9f, 0x0d, 0xca, 0x12, 0xb9, 0x3a, 0xdf, 0xc9, 0x11, 0x9e, 0x33, 0xe8, 0x61, 0x9a,
+            0x02, 0xd7, 0x8d, 0xc7, 0x0e, 0xf2,
         ]))
         .unwrap(),
         c1: Fq::from_repr(FqRepr([
-            0x66323bf80b58b9b9,
-            0xa1379b6facf6e596,
-            0x402aef1fb797e32f,
-            0x2236f55246d0d44d,
-            0x4c8c1800eb104566,
-            0x11d6e20e986c2085,
+            0x11, 0xd6, 0xe2, 0x0e, 0x98, 0x6c, 0x20, 0x85, 0x4c, 0x8c, 0x18, 0x00, 0xeb, 0x10,
+            0x45, 0x66, 0x22, 0x36, 0xf5, 0x52, 0x46, 0xd0, 0xd4, 0x4d, 0x40, 0x2a, 0xef, 0x1f,
+            0xb7, 0x97, 0xe3, 0x2f, 0xa1, 0x37, 0x9b, 0x6f, 0xac, 0xf6, 0xe5, 0x96, 0x66, 0x32,
+            0x3b, 0xf8, 0x0b, 0x58, 0xb9, 0xb9,
         ]))
         .unwrap(),
     });
@@ -666,21 +620,17 @@ fn test_fq2_subtraction() {
         a,
         Fq2 {
             c0: Fq::from_repr(FqRepr([
-                0x8565752bdb5c9b80,
-                0x7756bed7c15982e9,
-                0xa65a6be700b285fe,
-                0xe255902672ef6c43,
-                0x7f77a718021c342d,
-                0x72ba14049fe9881
+                0x07, 0x2b, 0xa1, 0x40, 0x49, 0xfe, 0x98, 0x81, 0x7f, 0x77, 0xa7, 0x18, 0x02, 0x1c,
+                0x34, 0x2d, 0xe2, 0x55, 0x90, 0x26, 0x72, 0xef, 0x6c, 0x43, 0xa6, 0x5a, 0x6b, 0xe7,
+                0x00, 0xb2, 0x85, 0xfe, 0x77, 0x56, 0xbe, 0xd7, 0xc1, 0x59, 0x82, 0xe9, 0x85, 0x65,
+                0x75, 0x2b, 0xdb, 0x5c, 0x9b, 0x80,
             ]))
             .unwrap(),
             c1: Fq::from_repr(FqRepr([
-                0xeb4abaf7c255d1cd,
-                0x11df49bc6cacc256,
-                0xe52617930588c69a,
-                0xf63905f39ad8cb1f,
-                0x4cd5dd9fb40b3b8f,
-                0x957411359ba6e4c
+                0x09, 0x57, 0x41, 0x13, 0x59, 0xba, 0x6e, 0x4c, 0x4c, 0xd5, 0xdd, 0x9f, 0xb4, 0x0b,
+                0x3b, 0x8f, 0xf6, 0x39, 0x05, 0xf3, 0x9a, 0xd8, 0xcb, 0x1f, 0xe5, 0x26, 0x17, 0x93,
+                0x05, 0x88, 0xc6, 0x9a, 0x11, 0xdf, 0x49, 0xbc, 0x6c, 0xac, 0xc2, 0x56, 0xeb, 0x4a,
+                0xba, 0xf7, 0xc2, 0x55, 0xd1, 0xcd,
             ]))
             .unwrap(),
         }
@@ -694,21 +644,17 @@ fn test_fq2_negation() {
 
     let a = Fq2 {
         c0: Fq::from_repr(FqRepr([
-            0x2d0078036923ffc7,
-            0x11e59ea221a3b6d2,
-            0x8b1a52e0a90f59ed,
-            0xb966ce3bc2108b13,
-            0xccc649c4b9532bf3,
-            0xf8d295b2ded9dc,
+            0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
+            0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
+            0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
+            0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
         ]))
         .unwrap(),
         c1: Fq::from_repr(FqRepr([
-            0x977df6efcdaee0db,
-            0x946ae52d684fa7ed,
-            0xbe203411c66fb3a5,
-            0xb3f8afc0ee248cad,
-            0x4e464dea5bcfd41e,
-            0x12d1137b8a6a837,
+            0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf,
+            0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11,
+            0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d,
+            0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb,
         ]))
         .unwrap(),
     }
@@ -717,21 +663,17 @@ fn test_fq2_negation() {
         a,
         Fq2 {
             c0: Fq::from_repr(FqRepr([
-                0x8cfe87fc96dbaae4,
-                0xcc6615c8fb0492d,
-                0xdc167fc04da19c37,
-                0xab107d49317487ab,
-                0x7e555df189f880e3,
-                0x19083f5486a10cbd
+                0x19, 0x08, 0x3f, 0x54, 0x86, 0xa1, 0x0c, 0xbd, 0x7e, 0x55, 0x5d, 0xf1, 0x89, 0xf8,
+                0x80, 0xe3, 0xab, 0x10, 0x7d, 0x49, 0x31, 0x74, 0x87, 0xab, 0xdc, 0x16, 0x7f, 0xc0,
+                0x4d, 0xa1, 0x9c, 0x37, 0x0c, 0xc6, 0x61, 0x5c, 0x8f, 0xb0, 0x49, 0x2d, 0x8c, 0xfe,
+                0x87, 0xfc, 0x96, 0xdb, 0xaa, 0xe4,
             ]))
             .unwrap(),
             c1: Fq::from_repr(FqRepr([
-                0x228109103250c9d0,
-                0x8a411ad149045812,
-                0xa9109e8f3041427e,
-                0xb07e9bc405608611,
-                0xfcd559cbe77bd8b8,
-                0x18d400b280d93e62
+                0x18, 0xd4, 0x00, 0xb2, 0x80, 0xd9, 0x3e, 0x62, 0xfc, 0xd5, 0x59, 0xcb, 0xe7, 0x7b,
+                0xd8, 0xb8, 0xb0, 0x7e, 0x9b, 0xc4, 0x05, 0x60, 0x86, 0x11, 0xa9, 0x10, 0x9e, 0x8f,
+                0x30, 0x41, 0x42, 0x7e, 0x8a, 0x41, 0x1a, 0xd1, 0x49, 0x04, 0x58, 0x12, 0x22, 0x81,
+                0x09, 0x10, 0x32, 0x50, 0xc9, 0xd0,
             ]))
             .unwrap(),
         }
@@ -745,21 +687,17 @@ fn test_fq2_doubling() {
 
     let a = Fq2 {
         c0: Fq::from_repr(FqRepr([
-            0x2d0078036923ffc7,
-            0x11e59ea221a3b6d2,
-            0x8b1a52e0a90f59ed,
-            0xb966ce3bc2108b13,
-            0xccc649c4b9532bf3,
-            0xf8d295b2ded9dc,
+            0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
+            0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
+            0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
+            0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
         ]))
         .unwrap(),
         c1: Fq::from_repr(FqRepr([
-            0x977df6efcdaee0db,
-            0x946ae52d684fa7ed,
-            0xbe203411c66fb3a5,
-            0xb3f8afc0ee248cad,
-            0x4e464dea5bcfd41e,
-            0x12d1137b8a6a837,
+            0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf,
+            0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11,
+            0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d,
+            0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb,
         ]))
         .unwrap(),
     };
@@ -767,21 +705,17 @@ fn test_fq2_doubling() {
         a.double(),
         Fq2 {
             c0: Fq::from_repr(FqRepr([
-                0x5a00f006d247ff8e,
-                0x23cb3d4443476da4,
-                0x1634a5c1521eb3da,
-                0x72cd9c7784211627,
-                0x998c938972a657e7,
-                0x1f1a52b65bdb3b9
+                0x01, 0xf1, 0xa5, 0x2b, 0x65, 0xbd, 0xb3, 0xb9, 0x99, 0x8c, 0x93, 0x89, 0x72, 0xa6,
+                0x57, 0xe7, 0x72, 0xcd, 0x9c, 0x77, 0x84, 0x21, 0x16, 0x27, 0x16, 0x34, 0xa5, 0xc1,
+                0x52, 0x1e, 0xb3, 0xda, 0x23, 0xcb, 0x3d, 0x44, 0x43, 0x47, 0x6d, 0xa4, 0x5a, 0x00,
+                0xf0, 0x06, 0xd2, 0x47, 0xff, 0x8e,
             ]))
             .unwrap(),
             c1: Fq::from_repr(FqRepr([
-                0x2efbeddf9b5dc1b6,
-                0x28d5ca5ad09f4fdb,
-                0x7c4068238cdf674b,
-                0x67f15f81dc49195b,
-                0x9c8c9bd4b79fa83d,
-                0x25a226f714d506e
+                0x02, 0x5a, 0x22, 0x6f, 0x71, 0x4d, 0x50, 0x6e, 0x9c, 0x8c, 0x9b, 0xd4, 0xb7, 0x9f,
+                0xa8, 0x3d, 0x67, 0xf1, 0x5f, 0x81, 0xdc, 0x49, 0x19, 0x5b, 0x7c, 0x40, 0x68, 0x23,
+                0x8c, 0xdf, 0x67, 0x4b, 0x28, 0xd5, 0xca, 0x5a, 0xd0, 0x9f, 0x4f, 0xdb, 0x2e, 0xfb,
+                0xed, 0xdf, 0x9b, 0x5d, 0xc1, 0xb6,
             ]))
             .unwrap(),
         }
@@ -795,21 +729,17 @@ fn test_fq2_frobenius_map() {
 
     let mut a = Fq2 {
         c0: Fq::from_repr(FqRepr([
-            0x2d0078036923ffc7,
-            0x11e59ea221a3b6d2,
-            0x8b1a52e0a90f59ed,
-            0xb966ce3bc2108b13,
-            0xccc649c4b9532bf3,
-            0xf8d295b2ded9dc,
+            0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
+            0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
+            0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
+            0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
         ]))
         .unwrap(),
         c1: Fq::from_repr(FqRepr([
-            0x977df6efcdaee0db,
-            0x946ae52d684fa7ed,
-            0xbe203411c66fb3a5,
-            0xb3f8afc0ee248cad,
-            0x4e464dea5bcfd41e,
-            0x12d1137b8a6a837,
+            0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf,
+            0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11,
+            0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d,
+            0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb,
         ]))
         .unwrap(),
     };
@@ -818,21 +748,17 @@ fn test_fq2_frobenius_map() {
         a,
         Fq2 {
             c0: Fq::from_repr(FqRepr([
-                0x2d0078036923ffc7,
-                0x11e59ea221a3b6d2,
-                0x8b1a52e0a90f59ed,
-                0xb966ce3bc2108b13,
-                0xccc649c4b9532bf3,
-                0xf8d295b2ded9dc
+                0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
+                0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
+                0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
+                0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
             ]))
             .unwrap(),
             c1: Fq::from_repr(FqRepr([
-                0x977df6efcdaee0db,
-                0x946ae52d684fa7ed,
-                0xbe203411c66fb3a5,
-                0xb3f8afc0ee248cad,
-                0x4e464dea5bcfd41e,
-                0x12d1137b8a6a837
+                0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf,
+                0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11,
+                0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d,
+                0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb,
             ]))
             .unwrap(),
         }
@@ -842,21 +768,17 @@ fn test_fq2_frobenius_map() {
         a,
         Fq2 {
             c0: Fq::from_repr(FqRepr([
-                0x2d0078036923ffc7,
-                0x11e59ea221a3b6d2,
-                0x8b1a52e0a90f59ed,
-                0xb966ce3bc2108b13,
-                0xccc649c4b9532bf3,
-                0xf8d295b2ded9dc
+                0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
+                0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
+                0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
+                0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
             ]))
             .unwrap(),
             c1: Fq::from_repr(FqRepr([
-                0x228109103250c9d0,
-                0x8a411ad149045812,
-                0xa9109e8f3041427e,
-                0xb07e9bc405608611,
-                0xfcd559cbe77bd8b8,
-                0x18d400b280d93e62
+                0x18, 0xd4, 0x00, 0xb2, 0x80, 0xd9, 0x3e, 0x62, 0xfc, 0xd5, 0x59, 0xcb, 0xe7, 0x7b,
+                0xd8, 0xb8, 0xb0, 0x7e, 0x9b, 0xc4, 0x05, 0x60, 0x86, 0x11, 0xa9, 0x10, 0x9e, 0x8f,
+                0x30, 0x41, 0x42, 0x7e, 0x8a, 0x41, 0x1a, 0xd1, 0x49, 0x04, 0x58, 0x12, 0x22, 0x81,
+                0x09, 0x10, 0x32, 0x50, 0xc9, 0xd0,
             ]))
             .unwrap(),
         }
@@ -866,21 +788,17 @@ fn test_fq2_frobenius_map() {
         a,
         Fq2 {
             c0: Fq::from_repr(FqRepr([
-                0x2d0078036923ffc7,
-                0x11e59ea221a3b6d2,
-                0x8b1a52e0a90f59ed,
-                0xb966ce3bc2108b13,
-                0xccc649c4b9532bf3,
-                0xf8d295b2ded9dc
+                0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
+                0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
+                0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
+                0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
             ]))
             .unwrap(),
             c1: Fq::from_repr(FqRepr([
-                0x977df6efcdaee0db,
-                0x946ae52d684fa7ed,
-                0xbe203411c66fb3a5,
-                0xb3f8afc0ee248cad,
-                0x4e464dea5bcfd41e,
-                0x12d1137b8a6a837
+                0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf,
+                0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11,
+                0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d,
+                0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb,
             ]))
             .unwrap(),
         }
@@ -890,21 +808,17 @@ fn test_fq2_frobenius_map() {
         a,
         Fq2 {
             c0: Fq::from_repr(FqRepr([
-                0x2d0078036923ffc7,
-                0x11e59ea221a3b6d2,
-                0x8b1a52e0a90f59ed,
-                0xb966ce3bc2108b13,
-                0xccc649c4b9532bf3,
-                0xf8d295b2ded9dc
+                0x00, 0xf8, 0xd2, 0x95, 0xb2, 0xde, 0xd9, 0xdc, 0xcc, 0xc6, 0x49, 0xc4, 0xb9, 0x53,
+                0x2b, 0xf3, 0xb9, 0x66, 0xce, 0x3b, 0xc2, 0x10, 0x8b, 0x13, 0x8b, 0x1a, 0x52, 0xe0,
+                0xa9, 0x0f, 0x59, 0xed, 0x11, 0xe5, 0x9e, 0xa2, 0x21, 0xa3, 0xb6, 0xd2, 0x2d, 0x00,
+                0x78, 0x03, 0x69, 0x23, 0xff, 0xc7,
             ]))
             .unwrap(),
             c1: Fq::from_repr(FqRepr([
-                0x977df6efcdaee0db,
-                0x946ae52d684fa7ed,
-                0xbe203411c66fb3a5,
-                0xb3f8afc0ee248cad,
-                0x4e464dea5bcfd41e,
-                0x12d1137b8a6a837
+                0x01, 0x2d, 0x11, 0x37, 0xb8, 0xa6, 0xa8, 0x37, 0x4e, 0x46, 0x4d, 0xea, 0x5b, 0xcf,
+                0xd4, 0x1e, 0xb3, 0xf8, 0xaf, 0xc0, 0xee, 0x24, 0x8c, 0xad, 0xbe, 0x20, 0x34, 0x11,
+                0xc6, 0x6f, 0xb3, 0xa5, 0x94, 0x6a, 0xe5, 0x2d, 0x68, 0x4f, 0xa7, 0xed, 0x97, 0x7d,
+                0xf6, 0xef, 0xcd, 0xae, 0xe0, 0xdb,
             ]))
             .unwrap(),
         }
@@ -919,21 +833,17 @@ fn test_fq2_sqrt() {
     assert_eq!(
         Fq2 {
             c0: Fq::from_repr(FqRepr([
-                0x476b4c309720e227,
-                0x34c2d04faffdab6,
-                0xa57e6fc1bab51fd9,
-                0xdb4a116b5bf74aa1,
-                0x1e58b2159dfe10e2,
-                0x7ca7da1f13606ac
+                0x07, 0xca, 0x7d, 0xa1, 0xf1, 0x36, 0x06, 0xac, 0x1e, 0x58, 0xb2, 0x15, 0x9d, 0xfe,
+                0x10, 0xe2, 0xdb, 0x4a, 0x11, 0x6b, 0x5b, 0xf7, 0x4a, 0xa1, 0xa5, 0x7e, 0x6f, 0xc1,
+                0xba, 0xb5, 0x1f, 0xd9, 0x03, 0x4c, 0x2d, 0x04, 0xfa, 0xff, 0xda, 0xb6, 0x47, 0x6b,
+                0x4c, 0x30, 0x97, 0x20, 0xe2, 0x27,
             ]))
             .unwrap(),
             c1: Fq::from_repr(FqRepr([
-                0xfa8de88b7516d2c3,
-                0x371a75ed14f41629,
-                0x4cec2dca577a3eb6,
-                0x212611bca4e99121,
-                0x8ee5394d77afb3d,
-                0xec92336650e49d5
+                0x0e, 0xc9, 0x23, 0x36, 0x65, 0x0e, 0x49, 0xd5, 0x08, 0xee, 0x53, 0x94, 0xd7, 0x7a,
+                0xfb, 0x3d, 0x21, 0x26, 0x11, 0xbc, 0xa4, 0xe9, 0x91, 0x21, 0x4c, 0xec, 0x2d, 0xca,
+                0x57, 0x7a, 0x3e, 0xb6, 0x37, 0x1a, 0x75, 0xed, 0x14, 0xf4, 0x16, 0x29, 0xfa, 0x8d,
+                0xe8, 0x8b, 0x75, 0x16, 0xd2, 0xc3,
             ]))
             .unwrap(),
         }
@@ -941,21 +851,17 @@ fn test_fq2_sqrt() {
         .unwrap(),
         Fq2 {
             c0: Fq::from_repr(FqRepr([
-                0x40b299b2704258c5,
-                0x6ef7de92e8c68b63,
-                0x6d2ddbe552203e82,
-                0x8d7f1f723d02c1d3,
-                0x881b3e01b611c070,
-                0x10f6963bbad2ebc5
+                0x10, 0xf6, 0x96, 0x3b, 0xba, 0xd2, 0xeb, 0xc5, 0x88, 0x1b, 0x3e, 0x01, 0xb6, 0x11,
+                0xc0, 0x70, 0x8d, 0x7f, 0x1f, 0x72, 0x3d, 0x02, 0xc1, 0xd3, 0x6d, 0x2d, 0xdb, 0xe5,
+                0x52, 0x20, 0x3e, 0x82, 0x6e, 0xf7, 0xde, 0x92, 0xe8, 0xc6, 0x8b, 0x63, 0x40, 0xb2,
+                0x99, 0xb2, 0x70, 0x42, 0x58, 0xc5,
             ]))
             .unwrap(),
             c1: Fq::from_repr(FqRepr([
-                0xc099534fc209e752,
-                0x7670594665676447,
-                0x28a20faed211efe7,
-                0x6b852aeaf2afcb1b,
-                0xa4c93b08105d71a9,
-                0x8d7cfff94216330
+                0x08, 0xd7, 0xcf, 0xff, 0x94, 0x21, 0x63, 0x30, 0xa4, 0xc9, 0x3b, 0x08, 0x10, 0x5d,
+                0x71, 0xa9, 0x6b, 0x85, 0x2a, 0xea, 0xf2, 0xaf, 0xcb, 0x1b, 0x28, 0xa2, 0x0f, 0xae,
+                0xd2, 0x11, 0xef, 0xe7, 0x76, 0x70, 0x59, 0x46, 0x65, 0x67, 0x64, 0x47, 0xc0, 0x99,
+                0x53, 0x4f, 0xc2, 0x09, 0xe7, 0x52,
             ]))
             .unwrap(),
         }
@@ -964,12 +870,10 @@ fn test_fq2_sqrt() {
     assert_eq!(
         Fq2 {
             c0: Fq::from_repr(FqRepr([
-                0xb9f78429d1517a6b,
-                0x1eabfffeb153ffff,
-                0x6730d2a0f6b0f624,
-                0x64774b84f38512bf,
-                0x4b1ba7b6434bacd7,
-                0x1a0111ea397fe69a
+                0x1a, 0x01, 0x11, 0xea, 0x39, 0x7f, 0xe6, 0x9a, 0x4b, 0x1b, 0xa7, 0xb6, 0x43, 0x4b,
+                0xac, 0xd7, 0x64, 0x77, 0x4b, 0x84, 0xf3, 0x85, 0x12, 0xbf, 0x67, 0x30, 0xd2, 0xa0,
+                0xf6, 0xb0, 0xf6, 0x24, 0x1e, 0xab, 0xff, 0xfe, 0xb1, 0x53, 0xff, 0xff, 0xb9, 0xf7,
+                0x84, 0x29, 0xd1, 0x51, 0x7a, 0x6b,
             ]))
             .unwrap(),
             c1: Fq::zero(),
@@ -979,12 +883,10 @@ fn test_fq2_sqrt() {
         Fq2 {
             c0: Fq::zero(),
             c1: Fq::from_repr(FqRepr([
-                0xb9fefffffd4357a3,
-                0x1eabfffeb153ffff,
-                0x6730d2a0f6b0f624,
-                0x64774b84f38512bf,
-                0x4b1ba7b6434bacd7,
-                0x1a0111ea397fe69a
+                0x1a, 0x01, 0x11, 0xea, 0x39, 0x7f, 0xe6, 0x9a, 0x4b, 0x1b, 0xa7, 0xb6, 0x43, 0x4b,
+                0xac, 0xd7, 0x64, 0x77, 0x4b, 0x84, 0xf3, 0x85, 0x12, 0xbf, 0x67, 0x30, 0xd2, 0xa0,
+                0xf6, 0xb0, 0xf6, 0x24, 0x1e, 0xab, 0xff, 0xfe, 0xb1, 0x53, 0xff, 0xff, 0xb9, 0xfe,
+                0xff, 0xff, 0xfd, 0x43, 0x57, 0xa3,
             ]))
             .unwrap(),
         }
diff --git a/pairing/src/bls12_381/fr.rs b/pairing/src/bls12_381/fr.rs
index 6bfb175..4a153ad 100644
--- a/pairing/src/bls12_381/fr.rs
+++ b/pairing/src/bls12_381/fr.rs
@@ -1,10 +1,11 @@
-use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr};
+use ff::{Field, PrimeField};
 use std::ops::{AddAssign, MulAssign, SubAssign};
 
 #[derive(PrimeField)]
 #[PrimeFieldModulus = "52435875175126190479447740508185965837690552500527637822603658699938581184513"]
 #[PrimeFieldGenerator = "7"]
-pub struct Fr(FrRepr);
+#[PrimeFieldReprEndianness = "little"]
+pub struct Fr([u64; 4]);
 
 #[cfg(test)]
 use ff::PowVartime;
@@ -15,373 +16,26 @@ use rand_xorshift::XorShiftRng;
 #[cfg(test)]
 use std::ops::Neg;
 
-#[test]
-fn test_fr_repr_ordering() {
-    fn assert_equality(a: FrRepr, b: FrRepr) {
-        assert_eq!(a, b);
-        assert!(a.cmp(&b) == ::std::cmp::Ordering::Equal);
-    }
-
-    fn assert_lt(a: FrRepr, b: FrRepr) {
-        assert!(a < b);
-        assert!(b > a);
-    }
-
-    assert_equality(
-        FrRepr([9999, 9999, 9999, 9999]),
-        FrRepr([9999, 9999, 9999, 9999]),
-    );
-    assert_equality(
-        FrRepr([9999, 9998, 9999, 9999]),
-        FrRepr([9999, 9998, 9999, 9999]),
-    );
-    assert_equality(
-        FrRepr([9999, 9999, 9999, 9997]),
-        FrRepr([9999, 9999, 9999, 9997]),
-    );
-    assert_lt(
-        FrRepr([9999, 9997, 9999, 9998]),
-        FrRepr([9999, 9997, 9999, 9999]),
-    );
-    assert_lt(
-        FrRepr([9999, 9997, 9998, 9999]),
-        FrRepr([9999, 9997, 9999, 9999]),
-    );
-    assert_lt(
-        FrRepr([9, 9999, 9999, 9997]),
-        FrRepr([9999, 9999, 9999, 9997]),
-    );
-}
-
-#[test]
-fn test_fr_repr_from() {
-    assert_eq!(FrRepr::from(100), FrRepr([100, 0, 0, 0]));
-}
-
-#[test]
-fn test_fr_repr_is_odd() {
-    assert!(!FrRepr::from(0).is_odd());
-    assert!(FrRepr::from(0).is_even());
-    assert!(FrRepr::from(1).is_odd());
-    assert!(!FrRepr::from(1).is_even());
-    assert!(!FrRepr::from(324834872).is_odd());
-    assert!(FrRepr::from(324834872).is_even());
-    assert!(FrRepr::from(324834873).is_odd());
-    assert!(!FrRepr::from(324834873).is_even());
-}
-
-#[test]
-fn test_fr_repr_is_zero() {
-    assert!(FrRepr::from(0).is_zero());
-    assert!(!FrRepr::from(1).is_zero());
-    assert!(!FrRepr([0, 0, 1, 0]).is_zero());
-}
-
-#[test]
-fn test_fr_repr_div2() {
-    let mut a = FrRepr([
-        0xbd2920b19c972321,
-        0x174ed0466a3be37e,
-        0xd468d5e3b551f0b5,
-        0xcb67c072733beefc,
-    ]);
-    a.div2();
-    assert_eq!(
-        a,
-        FrRepr([
-            0x5e949058ce4b9190,
-            0x8ba76823351df1bf,
-            0x6a346af1daa8f85a,
-            0x65b3e039399df77e
-        ])
-    );
-    for _ in 0..10 {
-        a.div2();
-    }
-    assert_eq!(
-        a,
-        FrRepr([
-            0x6fd7a524163392e4,
-            0x16a2e9da08cd477c,
-            0xdf9a8d1abc76aa3e,
-            0x196cf80e4e677d
-        ])
-    );
-    for _ in 0..200 {
-        a.div2();
-    }
-    assert_eq!(a, FrRepr([0x196cf80e4e67, 0x0, 0x0, 0x0]));
-    for _ in 0..40 {
-        a.div2();
-    }
-    assert_eq!(a, FrRepr([0x19, 0x0, 0x0, 0x0]));
-    for _ in 0..4 {
-        a.div2();
-    }
-    assert_eq!(a, FrRepr([0x1, 0x0, 0x0, 0x0]));
-    a.div2();
-    assert!(a.is_zero());
-}
-
-#[test]
-fn test_fr_repr_shr() {
-    let mut a = FrRepr([
-        0xb33fbaec482a283f,
-        0x997de0d3a88cb3df,
-        0x9af62d2a9a0e5525,
-        0x36003ab08de70da1,
-    ]);
-    a.shr(0);
-    assert_eq!(
-        a,
-        FrRepr([
-            0xb33fbaec482a283f,
-            0x997de0d3a88cb3df,
-            0x9af62d2a9a0e5525,
-            0x36003ab08de70da1
-        ])
-    );
-    a.shr(1);
-    assert_eq!(
-        a,
-        FrRepr([
-            0xd99fdd762415141f,
-            0xccbef069d44659ef,
-            0xcd7b16954d072a92,
-            0x1b001d5846f386d0
-        ])
-    );
-    a.shr(50);
-    assert_eq!(
-        a,
-        FrRepr([
-            0xbc1a7511967bf667,
-            0xc5a55341caa4b32f,
-            0x75611bce1b4335e,
-            0x6c0
-        ])
-    );
-    a.shr(130);
-    assert_eq!(a, FrRepr([0x1d5846f386d0cd7, 0x1b0, 0x0, 0x0]));
-    a.shr(64);
-    assert_eq!(a, FrRepr([0x1b0, 0x0, 0x0, 0x0]));
-}
-
-#[test]
-fn test_fr_repr_mul2() {
-    let mut a = FrRepr::from(23712937547);
-    a.mul2();
-    assert_eq!(a, FrRepr([0xb0acd6c96, 0x0, 0x0, 0x0]));
-    for _ in 0..60 {
-        a.mul2();
-    }
-    assert_eq!(a, FrRepr([0x6000000000000000, 0xb0acd6c9, 0x0, 0x0]));
-    for _ in 0..128 {
-        a.mul2();
-    }
-    assert_eq!(a, FrRepr([0x0, 0x0, 0x6000000000000000, 0xb0acd6c9]));
-    for _ in 0..60 {
-        a.mul2();
-    }
-    assert_eq!(a, FrRepr([0x0, 0x0, 0x0, 0x9600000000000000]));
-    for _ in 0..7 {
-        a.mul2();
-    }
-    assert!(a.is_zero());
-}
-
-#[test]
-fn test_fr_repr_num_bits() {
-    let mut a = FrRepr::from(0);
-    assert_eq!(0, a.num_bits());
-    a = FrRepr::from(1);
-    for i in 1..257 {
-        assert_eq!(i, a.num_bits());
-        a.mul2();
-    }
-    assert_eq!(0, a.num_bits());
-}
-
-#[test]
-fn test_fr_repr_sub_noborrow() {
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    let mut t = FrRepr([
-        0x8e62a7e85264e2c3,
-        0xb23d34c1941d3ca,
-        0x5976930b7502dd15,
-        0x600f3fb517bf5495,
-    ]);
-    t.sub_noborrow(&FrRepr([
-        0xd64f669809cbc6a4,
-        0xfa76cb9d90cf7637,
-        0xfefb0df9038d43b3,
-        0x298a30c744b31acf,
-    ]));
-    assert!(
-        t == FrRepr([
-            0xb813415048991c1f,
-            0x10ad07ae88725d92,
-            0x5a7b851271759961,
-            0x36850eedd30c39c5
-        ])
-    );
-
-    for _ in 0..1000 {
-        let mut a = Fr::random(&mut rng).into_repr();
-        a.0[3] >>= 30;
-        let mut b = a;
-        for _ in 0..10 {
-            b.mul2();
-        }
-        let mut c = b;
-        for _ in 0..10 {
-            c.mul2();
-        }
-
-        assert!(a < b);
-        assert!(b < c);
-
-        let mut csub_ba = c;
-        csub_ba.sub_noborrow(&b);
-        csub_ba.sub_noborrow(&a);
-
-        let mut csub_ab = c;
-        csub_ab.sub_noborrow(&a);
-        csub_ab.sub_noborrow(&b);
-
-        assert_eq!(csub_ab, csub_ba);
-    }
-
-    // Subtracting r+1 from r should produce -1 (mod 2**256)
-    let mut qplusone = FrRepr([
-        0xffffffff00000001,
-        0x53bda402fffe5bfe,
-        0x3339d80809a1d805,
-        0x73eda753299d7d48,
-    ]);
-    qplusone.sub_noborrow(&FrRepr([
-        0xffffffff00000002,
-        0x53bda402fffe5bfe,
-        0x3339d80809a1d805,
-        0x73eda753299d7d48,
-    ]));
-    assert_eq!(
-        qplusone,
-        FrRepr([
-            0xffffffffffffffff,
-            0xffffffffffffffff,
-            0xffffffffffffffff,
-            0xffffffffffffffff
-        ])
-    );
-}
-
-#[test]
-fn test_fr_repr_add_nocarry() {
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    let mut t = FrRepr([
-        0xd64f669809cbc6a4,
-        0xfa76cb9d90cf7637,
-        0xfefb0df9038d43b3,
-        0x298a30c744b31acf,
-    ]);
-    t.add_nocarry(&FrRepr([
-        0x8e62a7e85264e2c3,
-        0xb23d34c1941d3ca,
-        0x5976930b7502dd15,
-        0x600f3fb517bf5495,
-    ]));
-    assert_eq!(
-        t,
-        FrRepr([
-            0x64b20e805c30a967,
-            0x59a9ee9aa114a02,
-            0x5871a104789020c9,
-            0x8999707c5c726f65
-        ])
-    );
-
-    // Test for the associativity of addition.
-    for _ in 0..1000 {
-        let mut a = Fr::random(&mut rng).into_repr();
-        let mut b = Fr::random(&mut rng).into_repr();
-        let mut c = Fr::random(&mut rng).into_repr();
-
-        // Unset the first few bits, so that overflow won't occur.
-        a.0[3] >>= 3;
-        b.0[3] >>= 3;
-        c.0[3] >>= 3;
-
-        let mut abc = a;
-        abc.add_nocarry(&b);
-        abc.add_nocarry(&c);
-
-        let mut acb = a;
-        acb.add_nocarry(&c);
-        acb.add_nocarry(&b);
-
-        let mut bac = b;
-        bac.add_nocarry(&a);
-        bac.add_nocarry(&c);
-
-        let mut bca = b;
-        bca.add_nocarry(&c);
-        bca.add_nocarry(&a);
-
-        let mut cab = c;
-        cab.add_nocarry(&a);
-        cab.add_nocarry(&b);
-
-        let mut cba = c;
-        cba.add_nocarry(&b);
-        cba.add_nocarry(&a);
-
-        assert_eq!(abc, acb);
-        assert_eq!(abc, bac);
-        assert_eq!(abc, bca);
-        assert_eq!(abc, cab);
-        assert_eq!(abc, cba);
-    }
-
-    // Adding 1 to (2^256 - 1) should produce zero
-    let mut x = FrRepr([
-        0xffffffffffffffff,
-        0xffffffffffffffff,
-        0xffffffffffffffff,
-        0xffffffffffffffff,
-    ]);
-    x.add_nocarry(&FrRepr::from(1));
-    assert!(x.is_zero());
-}
-
 #[test]
 fn test_fr_is_valid() {
-    let mut a = Fr(MODULUS);
+    let mut a = MODULUS_LIMBS;
     assert!(!a.is_valid());
-    a.0.sub_noborrow(&FrRepr::from(1));
+    a.sub_noborrow(&Fr([1, 0, 0, 0]));
     assert!(a.is_valid());
     assert!(Fr::from(0).is_valid());
-    assert!(Fr(FrRepr([
+    assert!(Fr([
         0xffffffff00000000,
         0x53bda402fffe5bfe,
         0x3339d80809a1d805,
         0x73eda753299d7d48
-    ]))
+    ])
     .is_valid());
-    assert!(!Fr(FrRepr([
+    assert!(!Fr([
         0xffffffffffffffff,
         0xffffffffffffffff,
         0xffffffffffffffff,
         0xffffffffffffffff
-    ]))
+    ])
     .is_valid());
 
     let mut rng = XorShiftRng::from_seed([
@@ -399,85 +53,85 @@ fn test_fr_is_valid() {
 fn test_fr_add_assign() {
     {
         // Random number
-        let mut tmp = Fr(FrRepr([
+        let mut tmp = Fr([
             0x437ce7616d580765,
             0xd42d1ccb29d1235b,
             0xed8f753821bd1423,
             0x4eede1c9c89528ca,
-        ]));
+        ]);
         assert!(tmp.is_valid());
         // Test that adding zero has no effect.
-        tmp.add_assign(&Fr(FrRepr::from(0)));
+        tmp.add_assign(&Fr([0, 0, 0, 0]));
         assert_eq!(
             tmp,
-            Fr(FrRepr([
+            Fr([
                 0x437ce7616d580765,
                 0xd42d1ccb29d1235b,
                 0xed8f753821bd1423,
                 0x4eede1c9c89528ca
-            ]))
+            ])
         );
         // Add one and test for the result.
-        tmp.add_assign(&Fr(FrRepr::from(1)));
+        tmp.add_assign(&Fr([1, 0, 0, 0]));
         assert_eq!(
             tmp,
-            Fr(FrRepr([
+            Fr([
                 0x437ce7616d580766,
                 0xd42d1ccb29d1235b,
                 0xed8f753821bd1423,
                 0x4eede1c9c89528ca
-            ]))
+            ])
         );
         // Add another random number that exercises the reduction.
-        tmp.add_assign(&Fr(FrRepr([
+        tmp.add_assign(&Fr([
             0x946f435944f7dc79,
             0xb55e7ee6533a9b9b,
             0x1e43b84c2f6194ca,
             0x58717ab525463496,
-        ])));
+        ]));
         assert_eq!(
             tmp,
-            Fr(FrRepr([
+            Fr([
                 0xd7ec2abbb24fe3de,
                 0x35cdf7ae7d0d62f7,
                 0xd899557c477cd0e9,
                 0x3371b52bc43de018
-            ]))
+            ])
         );
         // Add one to (r - 1) and test for the result.
-        tmp = Fr(FrRepr([
+        tmp = Fr([
             0xffffffff00000000,
             0x53bda402fffe5bfe,
             0x3339d80809a1d805,
             0x73eda753299d7d48,
-        ]));
-        tmp.add_assign(&Fr(FrRepr::from(1)));
-        assert!(tmp.0.is_zero());
+        ]);
+        tmp.add_assign(&Fr([1, 0, 0, 0]));
+        assert!(tmp.is_zero());
         // Add a random number to another one such that the result is r - 1
-        tmp = Fr(FrRepr([
+        tmp = Fr([
             0xade5adacdccb6190,
             0xaa21ee0f27db3ccd,
             0x2550f4704ae39086,
             0x591d1902e7c5ba27,
-        ]));
-        tmp.add_assign(&Fr(FrRepr([
+        ]);
+        tmp.add_assign(&Fr([
             0x521a525223349e70,
             0xa99bb5f3d8231f31,
             0xde8e397bebe477e,
             0x1ad08e5041d7c321,
-        ])));
+        ]));
         assert_eq!(
             tmp,
-            Fr(FrRepr([
+            Fr([
                 0xffffffff00000000,
                 0x53bda402fffe5bfe,
                 0x3339d80809a1d805,
                 0x73eda753299d7d48
-            ]))
+            ])
         );
         // Add one to the result and test for it.
-        tmp.add_assign(&Fr(FrRepr::from(1)));
-        assert!(tmp.0.is_zero());
+        tmp.add_assign(&Fr([1, 0, 0, 0]));
+        assert!(tmp.is_zero());
     }
 
     // Test associativity
@@ -511,71 +165,71 @@ fn test_fr_add_assign() {
 fn test_fr_sub_assign() {
     {
         // Test arbitrary subtraction that tests reduction.
-        let mut tmp = Fr(FrRepr([
+        let mut tmp = Fr([
             0x6a68c64b6f735a2b,
             0xd5f4d143fe0a1972,
             0x37c17f3829267c62,
             0xa2f37391f30915c,
-        ]));
-        tmp.sub_assign(&Fr(FrRepr([
+        ]);
+        tmp.sub_assign(&Fr([
             0xade5adacdccb6190,
             0xaa21ee0f27db3ccd,
             0x2550f4704ae39086,
             0x591d1902e7c5ba27,
-        ])));
+        ]));
         assert_eq!(
             tmp,
-            Fr(FrRepr([
+            Fr([
                 0xbc83189d92a7f89c,
                 0x7f908737d62d38a3,
                 0x45aa62cfe7e4c3e1,
                 0x24ffc5896108547d
-            ]))
+            ])
         );
 
         // Test the opposite subtraction which doesn't test reduction.
-        tmp = Fr(FrRepr([
+        tmp = Fr([
             0xade5adacdccb6190,
             0xaa21ee0f27db3ccd,
             0x2550f4704ae39086,
             0x591d1902e7c5ba27,
-        ]));
-        tmp.sub_assign(&Fr(FrRepr([
+        ]);
+        tmp.sub_assign(&Fr([
             0x6a68c64b6f735a2b,
             0xd5f4d143fe0a1972,
             0x37c17f3829267c62,
             0xa2f37391f30915c,
-        ])));
+        ]));
         assert_eq!(
             tmp,
-            Fr(FrRepr([
+            Fr([
                 0x437ce7616d580765,
                 0xd42d1ccb29d1235b,
                 0xed8f753821bd1423,
                 0x4eede1c9c89528ca
-            ]))
+            ])
         );
 
         // Test for sensible results with zero
-        tmp = Fr(FrRepr::from(0));
-        tmp.sub_assign(&Fr(FrRepr::from(0)));
+        tmp = Fr::from(0);
+        tmp.sub_assign(&Fr::from(0));
         assert!(tmp.is_zero());
 
-        tmp = Fr(FrRepr([
+        tmp = Fr([
             0x437ce7616d580765,
             0xd42d1ccb29d1235b,
             0xed8f753821bd1423,
             0x4eede1c9c89528ca,
-        ]));
-        tmp.sub_assign(&Fr(FrRepr::from(0)));
+        ]);
+        tmp.sub_assign(&Fr::from(0));
         assert_eq!(
             tmp,
-            Fr(FrRepr([
+            Fr([
                 0x437ce7616d580765,
                 0xd42d1ccb29d1235b,
                 0xed8f753821bd1423,
                 0x4eede1c9c89528ca
-            ]))
+            ])
         );
     }
 
@@ -602,25 +256,25 @@ fn test_fr_sub_assign() {
 
 #[test]
 fn test_fr_mul_assign() {
-    let mut tmp = Fr(FrRepr([
+    let mut tmp = Fr([
         0x6b7e9b8faeefc81a,
         0xe30a8463f348ba42,
         0xeff3cb67a8279c9c,
         0x3d303651bd7c774d,
-    ]));
-    tmp.mul_assign(&Fr(FrRepr([
+    ]);
+    tmp.mul_assign(&Fr([
         0x13ae28e3bc35ebeb,
         0xa10f4488075cae2c,
         0x8160e95a853c3b5d,
         0x5ae3f03b561a841d,
-    ])));
+    ]));
     assert!(
-        tmp == Fr(FrRepr([
+        tmp == Fr([
             0x23717213ce710f71,
             0xdbee1fe53a16e1af,
             0xf565d3e1c2a48000,
             0x4426507ee75df9d7
-        ]))
+        ])
     );
 
     let mut rng = XorShiftRng::from_seed([
@@ -672,80 +326,73 @@ fn test_fr_mul_assign() {
 #[test]
 fn test_fr_shr() {
     let mut a = Fr::from_repr(FrRepr([
-        0xb33fbaec482a283f,
-        0x997de0d3a88cb3df,
-        0x9af62d2a9a0e5525,
-        0x36003ab08de70da1,
+        0x3f, 0x28, 0x2a, 0x48, 0xec, 0xba, 0x3f, 0xb3, 0xdf, 0xb3, 0x8c, 0xa8, 0xd3, 0xe0, 0x7d,
+        0x99, 0x25, 0x55, 0x0e, 0x9a, 0x2a, 0x2d, 0xf6, 0x9a, 0xa1, 0x0d, 0xe7, 0x8d, 0xb0, 0x3a,
+        0x00, 0x36,
     ]))
     .unwrap();
     a = a >> 0;
     assert_eq!(
         a.into_repr(),
         FrRepr([
-            0xb33fbaec482a283f,
-            0x997de0d3a88cb3df,
-            0x9af62d2a9a0e5525,
-            0x36003ab08de70da1,
+            0x3f, 0x28, 0x2a, 0x48, 0xec, 0xba, 0x3f, 0xb3, 0xdf, 0xb3, 0x8c, 0xa8, 0xd3, 0xe0,
+            0x7d, 0x99, 0x25, 0x55, 0x0e, 0x9a, 0x2a, 0x2d, 0xf6, 0x9a, 0xa1, 0x0d, 0xe7, 0x8d,
+            0xb0, 0x3a, 0x00, 0x36,
         ])
     );
     a = a >> 1;
     assert_eq!(
         a.into_repr(),
         FrRepr([
-            0xd99fdd762415141f,
-            0xccbef069d44659ef,
-            0xcd7b16954d072a92,
-            0x1b001d5846f386d0,
+            0x1f, 0x14, 0x15, 0x24, 0x76, 0xdd, 0x9f, 0xd9, 0xef, 0x59, 0x46, 0xd4, 0x69, 0xf0,
+            0xbe, 0xcc, 0x92, 0x2a, 0x07, 0x4d, 0x95, 0x16, 0x7b, 0xcd, 0xd0, 0x86, 0xf3, 0x46,
+            0x58, 0x1d, 0x00, 0x1b,
         ])
     );
     a = a >> 50;
     assert_eq!(
         a.into_repr(),
         FrRepr([
-            0xbc1a7511967bf667,
-            0xc5a55341caa4b32f,
-            0x075611bce1b4335e,
-            0x00000000000006c0,
+            0x67, 0xf6, 0x7b, 0x96, 0x11, 0x75, 0x1a, 0xbc, 0x2f, 0xb3, 0xa4, 0xca, 0x41, 0x53,
+            0xa5, 0xc5, 0x5e, 0x33, 0xb4, 0xe1, 0xbc, 0x11, 0x56, 0x07, 0xc0, 0x06, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00,
         ])
     );
     a = a >> 130;
     assert_eq!(
         a.into_repr(),
         FrRepr([
-            0x01d5846f386d0cd7,
-            0x00000000000001b0,
-            0x0000000000000000,
-            0x0000000000000000,
+            0xd7, 0x0c, 0x6d, 0x38, 0x6f, 0x84, 0xd5, 0x01, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00,
         ])
     );
     a = a >> 64;
     assert_eq!(
         a.into_repr(),
         FrRepr([
-            0x00000000000001b0,
-            0x0000000000000000,
-            0x0000000000000000,
-            0x0000000000000000,
+            0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00,
         ])
     );
 }
 
 #[test]
 fn test_fr_squaring() {
-    let a = Fr(FrRepr([
+    let a = Fr([
         0xffffffffffffffff,
         0xffffffffffffffff,
         0xffffffffffffffff,
         0x73eda753299d7d47,
-    ]));
+    ]);
     assert!(a.is_valid());
     assert_eq!(
         a.square(),
         Fr::from_repr(FrRepr([
-            0xc0d698e7bde077b8,
-            0xb79a310579e76ec2,
-            0xac1da8d0a9af4e5f,
-            0x13f629c49bf23e97
+            0xb8, 0x77, 0xe0, 0xbd, 0xe7, 0x98, 0xd6, 0xc0, 0xc2, 0x6e, 0xe7, 0x79, 0x05, 0x31,
+            0x9a, 0xb7, 0x5f, 0x4e, 0xaf, 0xa9, 0xd0, 0xa8, 0x1d, 0xac, 0x97, 0x3e, 0xf2, 0x9b,
+            0xc4, 0x29, 0xf6, 0x13,
         ]))
         .unwrap()
     );
@@ -883,42 +530,38 @@ fn test_fr_sqrt() {
 fn test_fr_from_into_repr() {
     // r + 1 should not be in the field
     assert!(Fr::from_repr(FrRepr([
-        0xffffffff00000002,
-        0x53bda402fffe5bfe,
-        0x3339d80809a1d805,
-        0x73eda753299d7d48
+        0x02, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x5b, 0xfe, 0xff, 0x02, 0xa4, 0xbd,
+        0x53, 0x05, 0xd8, 0xa1, 0x09, 0x08, 0xd8, 0x39, 0x33, 0x48, 0x7d, 0x9d, 0x29, 0x53, 0xa7,
+        0xed, 0x73,
     ]))
-    .is_err());
+    .is_none());
 
     // r should not be in the field
-    assert!(Fr::from_repr(Fr::char()).is_err());
+    assert!(Fr::from_repr(Fr::char()).is_none());
 
     // Multiply some arbitrary representations to see if the result is as expected.
     let a = FrRepr([
-        0x25ebe3a3ad3c0c6a,
-        0x6990e39d092e817c,
-        0x941f900d42f5658e,
-        0x44f8a103b38a71e0,
+        0x6a, 0x0c, 0x3c, 0xad, 0xa3, 0xe3, 0xeb, 0x25, 0x7c, 0x81, 0x2e, 0x09, 0x9d, 0xe3, 0x90,
+        0x69, 0x8e, 0x65, 0xf5, 0x42, 0x0d, 0x90, 0x1f, 0x94, 0xe0, 0x71, 0x8a, 0xb3, 0x03, 0xa1,
+        0xf8, 0x44,
     ]);
     let mut a_fr = Fr::from_repr(a).unwrap();
     let b = FrRepr([
-        0x264e9454885e2475,
-        0x46f7746bb0308370,
-        0x4683ef5347411f9,
-        0x58838d7f208d4492,
+        0x75, 0x24, 0x5e, 0x88, 0x54, 0x94, 0x4e, 0x26, 0x70, 0x83, 0x30, 0xb0, 0x6b, 0x74, 0xf7,
+        0x46, 0xf9, 0x11, 0x74, 0x34, 0xf5, 0x3e, 0x68, 0x04, 0x92, 0x44, 0x8d, 0x20, 0x7f, 0x8d,
+        0x83, 0x58,
     ]);
     let b_fr = Fr::from_repr(b).unwrap();
     let c = FrRepr([
-        0x48a09ab93cfc740d,
-        0x3a6600fbfc7a671,
-        0x838567017501d767,
-        0x7161d6da77745512,
+        0x0d, 0x74, 0xfc, 0x3c, 0xb9, 0x9a, 0xa0, 0x48, 0x71, 0xa6, 0xc7, 0xbf, 0x0f, 0x60, 0xa6,
+        0x03, 0x67, 0xd7, 0x01, 0x75, 0x01, 0x67, 0x85, 0x83, 0x12, 0x55, 0x74, 0x77, 0xda, 0xd6,
+        0x61, 0x71,
     ]);
     a_fr.mul_assign(&b_fr);
     assert_eq!(a_fr.into_repr(), c);
 
     // Zero should be in the field.
-    assert!(Fr::from_repr(FrRepr::from(0)).unwrap().is_zero());
+    assert!(Fr::from_repr(FrRepr([0; 32])).unwrap().is_zero());
 
     let mut rng = XorShiftRng::from_seed([
         0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
@@ -937,60 +580,15 @@ fn test_fr_from_into_repr() {
     }
 }
 
-#[test]
-fn test_fr_repr_display() {
-    assert_eq!(
-        format!(
-            "{}",
-            FrRepr([
-                0x2829c242fa826143,
-                0x1f32cf4dd4330917,
-                0x932e4e479d168cd9,
-                0x513c77587f563f64
-            ])
-        ),
-        "0x513c77587f563f64932e4e479d168cd91f32cf4dd43309172829c242fa826143".to_string()
-    );
-    assert_eq!(
-        format!(
-            "{}",
-            FrRepr([
-                0x25ebe3a3ad3c0c6a,
-                0x6990e39d092e817c,
-                0x941f900d42f5658e,
-                0x44f8a103b38a71e0
-            ])
-        ),
-        "0x44f8a103b38a71e0941f900d42f5658e6990e39d092e817c25ebe3a3ad3c0c6a".to_string()
-    );
-    assert_eq!(
-        format!(
-            "{}",
-            FrRepr([
-                0xffffffffffffffff,
-                0xffffffffffffffff,
-                0xffffffffffffffff,
-                0xffffffffffffffff
-            ])
-        ),
-        "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".to_string()
-    );
-    assert_eq!(
-        format!("{}", FrRepr([0, 0, 0, 0])),
-        "0x0000000000000000000000000000000000000000000000000000000000000000".to_string()
-    );
-}
-
 #[test]
 fn test_fr_display() {
     assert_eq!(
         format!(
             "{}",
             Fr::from_repr(FrRepr([
-                0xc3cae746a3b5ecc7,
-                0x185ec8eb3f5b5aee,
-                0x684499ffe4b9dd99,
-                0x7c9bba7afb68faa
+                0xc7, 0xec, 0xb5, 0xa3, 0x46, 0xe7, 0xca, 0xc3, 0xee, 0x5a, 0x5b, 0x3f, 0xeb, 0xc8,
+                0x5e, 0x18, 0x99, 0xdd, 0xb9, 0xe4, 0xff, 0x99, 0x44, 0x68, 0xaa, 0x8f, 0xb6, 0xaf,
+                0xa7, 0xbb, 0xc9, 0x07,
             ]))
             .unwrap()
         ),
@@ -1000,10 +598,9 @@ fn test_fr_display() {
         format!(
             "{}",
             Fr::from_repr(FrRepr([
-                0x44c71298ff198106,
-                0xb0ad10817df79b6a,
-                0xd034a80a2b74132b,
-                0x41cf9a1336f50719
+                0x06, 0x81, 0x19, 0xff, 0x98, 0x12, 0xc7, 0x44, 0x6a, 0x9b, 0xf7, 0x7d, 0x81, 0x10,
+                0xad, 0xb0, 0x2b, 0x13, 0x74, 0x2b, 0x0a, 0xa8, 0x34, 0xd0, 0x19, 0x07, 0xf5, 0x36,
+                0x13, 0x9a, 0xcf, 0x41,
             ]))
             .unwrap()
         ),
diff --git a/pairing/src/bls12_381/tests/mod.rs b/pairing/src/bls12_381/tests/mod.rs
index f79961c..6d9252e 100644
--- a/pairing/src/bls12_381/tests/mod.rs
+++ b/pairing/src/bls12_381/tests/mod.rs
@@ -1,4 +1,4 @@
-use ff::PrimeFieldRepr;
+use ff::PrimeField;
 use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError};
 
 use super::*;
@@ -147,13 +147,15 @@ fn test_g1_uncompressed_invalid_vectors() {
         }
     }
 
-    let m = Fq::char();
+    // PrimeField::char() returns the modulus in its little-endian byte representation,
+    // 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;
-        m.write_be(&mut o.as_mut()[0..]).unwrap();
+        o.as_mut()[..48].copy_from_slice(&m[..]);
 
-        if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() {
+        if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() {
             assert_eq!(coordinate, "x coordinate");
         } else {
             panic!("should have rejected the point")
@@ -162,9 +164,9 @@ fn test_g1_uncompressed_invalid_vectors() {
 
     {
         let mut o = o;
-        m.write_be(&mut o.as_mut()[48..]).unwrap();
+        o.as_mut()[48..].copy_from_slice(&m[..]);
 
-        if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() {
+        if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() {
             assert_eq!(coordinate, "y coordinate");
         } else {
             panic!("should have rejected the point")
@@ -175,7 +177,7 @@ fn test_g1_uncompressed_invalid_vectors() {
         let m = Fq::zero().into_repr();
 
         let mut o = o;
-        m.write_be(&mut o.as_mut()[0..]).unwrap();
+        o.as_mut()[..48].copy_from_slice(m.as_ref());
 
         if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() {
             // :)
@@ -198,8 +200,8 @@ fn test_g1_uncompressed_invalid_vectors() {
                 let y = y.unwrap();
 
                 // We know this is on the curve, but it's likely not going to be in the correct subgroup.
-                x.into_repr().write_be(&mut o.as_mut()[0..]).unwrap();
-                y.into_repr().write_be(&mut o.as_mut()[48..]).unwrap();
+                o.as_mut()[..48].copy_from_slice(x.into_repr().as_ref());
+                o.as_mut()[48..].copy_from_slice(y.into_repr().as_ref());
 
                 if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() {
                     break;
@@ -263,13 +265,15 @@ fn test_g2_uncompressed_invalid_vectors() {
         }
     }
 
-    let m = Fq::char();
+    // PrimeField::char() returns the modulus in its little-endian byte representation,
+    // 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;
-        m.write_be(&mut o.as_mut()[0..]).unwrap();
+        o.as_mut()[..48].copy_from_slice(&m[..]);
 
-        if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() {
+        if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() {
             assert_eq!(coordinate, "x coordinate (c1)");
         } else {
             panic!("should have rejected the point")
@@ -278,9 +282,9 @@ fn test_g2_uncompressed_invalid_vectors() {
 
     {
         let mut o = o;
-        m.write_be(&mut o.as_mut()[48..]).unwrap();
+        o.as_mut()[48..96].copy_from_slice(&m[..]);
 
-        if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() {
+        if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() {
             assert_eq!(coordinate, "x coordinate (c0)");
         } else {
             panic!("should have rejected the point")
@@ -289,9 +293,9 @@ fn test_g2_uncompressed_invalid_vectors() {
 
     {
         let mut o = o;
-        m.write_be(&mut o.as_mut()[96..]).unwrap();
+        o.as_mut()[96..144].copy_from_slice(&m[..]);
 
-        if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() {
+        if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() {
             assert_eq!(coordinate, "y coordinate (c1)");
         } else {
             panic!("should have rejected the point")
@@ -300,9 +304,9 @@ fn test_g2_uncompressed_invalid_vectors() {
 
     {
         let mut o = o;
-        m.write_be(&mut o.as_mut()[144..]).unwrap();
+        o.as_mut()[144..].copy_from_slice(&m[..]);
 
-        if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() {
+        if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() {
             assert_eq!(coordinate, "y coordinate (c0)");
         } else {
             panic!("should have rejected the point")
@@ -313,8 +317,8 @@ fn test_g2_uncompressed_invalid_vectors() {
         let m = Fq::zero().into_repr();
 
         let mut o = o;
-        m.write_be(&mut o.as_mut()[0..]).unwrap();
-        m.write_be(&mut o.as_mut()[48..]).unwrap();
+        o.as_mut()[..48].copy_from_slice(m.as_ref());
+        o.as_mut()[48..96].copy_from_slice(m.as_ref());
 
         if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() {
             // :)
@@ -340,10 +344,10 @@ fn test_g2_uncompressed_invalid_vectors() {
                 let y = y.unwrap();
 
                 // We know this is on the curve, but it's likely not going to be in the correct subgroup.
-                x.c1.into_repr().write_be(&mut o.as_mut()[0..]).unwrap();
-                x.c0.into_repr().write_be(&mut o.as_mut()[48..]).unwrap();
-                y.c1.into_repr().write_be(&mut o.as_mut()[96..]).unwrap();
-                y.c0.into_repr().write_be(&mut o.as_mut()[144..]).unwrap();
+                o.as_mut()[..48].copy_from_slice(x.c1.into_repr().as_ref());
+                o.as_mut()[48..96].copy_from_slice(x.c0.into_repr().as_ref());
+                o.as_mut()[96..144].copy_from_slice(y.c1.into_repr().as_ref());
+                o.as_mut()[144..].copy_from_slice(y.c0.into_repr().as_ref());
 
                 if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() {
                     break;
@@ -407,14 +411,16 @@ fn test_g1_compressed_invalid_vectors() {
         }
     }
 
-    let m = Fq::char();
+    // PrimeField::char() returns the modulus in its little-endian byte representation,
+    // 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;
-        m.write_be(&mut o.as_mut()[0..]).unwrap();
+        o.as_mut()[..48].copy_from_slice(&m[..]);
         o.as_mut()[0] |= 0b1000_0000;
 
-        if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() {
+        if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() {
             assert_eq!(coordinate, "x coordinate");
         } else {
             panic!("should have rejected the point")
@@ -433,7 +439,7 @@ fn test_g1_compressed_invalid_vectors() {
             if x3b.sqrt().is_some().into() {
                 x.add_assign(&Fq::one());
             } else {
-                x.into_repr().write_be(&mut o.as_mut()[0..]).unwrap();
+                o.as_mut().copy_from_slice(x.into_repr().as_ref());
                 o.as_mut()[0] |= 0b1000_0000;
 
                 if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() {
@@ -456,7 +462,7 @@ fn test_g1_compressed_invalid_vectors() {
 
             if x3b.sqrt().is_some().into() {
                 // We know this is on the curve, but it's likely not going to be in the correct subgroup.
-                x.into_repr().write_be(&mut o.as_mut()[0..]).unwrap();
+                o.as_mut().copy_from_slice(x.into_repr().as_ref());
                 o.as_mut()[0] |= 0b1000_0000;
 
                 if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() {
@@ -521,14 +527,16 @@ fn test_g2_compressed_invalid_vectors() {
         }
     }
 
-    let m = Fq::char();
+    // PrimeField::char() returns the modulus in its little-endian byte representation,
+    // 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;
-        m.write_be(&mut o.as_mut()[0..]).unwrap();
+        o.as_mut()[..48].copy_from_slice(&m[..]);
         o.as_mut()[0] |= 0b1000_0000;
 
-        if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() {
+        if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() {
             assert_eq!(coordinate, "x coordinate (c1)");
         } else {
             panic!("should have rejected the point")
@@ -537,10 +545,10 @@ fn test_g2_compressed_invalid_vectors() {
 
     {
         let mut o = o;
-        m.write_be(&mut o.as_mut()[48..]).unwrap();
+        o.as_mut()[48..96].copy_from_slice(&m[..]);
         o.as_mut()[0] |= 0b1000_0000;
 
-        if let Err(GroupDecodingError::CoordinateDecodingError(coordinate, _)) = o.into_affine() {
+        if let Err(GroupDecodingError::CoordinateDecodingError(coordinate)) = o.into_affine() {
             assert_eq!(coordinate, "x coordinate (c0)");
         } else {
             panic!("should have rejected the point")
@@ -565,8 +573,8 @@ fn test_g2_compressed_invalid_vectors() {
             if x3b.sqrt().is_some().into() {
                 x.add_assign(&Fq2::one());
             } else {
-                x.c1.into_repr().write_be(&mut o.as_mut()[0..]).unwrap();
-                x.c0.into_repr().write_be(&mut o.as_mut()[48..]).unwrap();
+                o.as_mut()[..48].copy_from_slice(x.c1.into_repr().as_ref());
+                o.as_mut()[48..].copy_from_slice(x.c0.into_repr().as_ref());
                 o.as_mut()[0] |= 0b1000_0000;
 
                 if let Err(GroupDecodingError::NotOnCurve) = o.into_affine() {
@@ -595,8 +603,8 @@ fn test_g2_compressed_invalid_vectors() {
 
             if x3b.sqrt().is_some().into() {
                 // We know this is on the curve, but it's likely not going to be in the correct subgroup.
-                x.c1.into_repr().write_be(&mut o.as_mut()[0..]).unwrap();
-                x.c0.into_repr().write_be(&mut o.as_mut()[48..]).unwrap();
+                o.as_mut()[..48].copy_from_slice(x.c1.into_repr().as_ref());
+                o.as_mut()[48..].copy_from_slice(x.c0.into_repr().as_ref());
                 o.as_mut()[0] |= 0b1000_0000;
 
                 if let Err(GroupDecodingError::NotInSubgroup) = o.into_affine() {
diff --git a/pairing/src/tests/field.rs b/pairing/src/tests/field.rs
index 6424232..0288987 100644
--- a/pairing/src/tests/field.rs
+++ b/pairing/src/tests/field.rs
@@ -2,7 +2,7 @@ use ff::{Field, PowVartime, PrimeField, SqrtField};
 use rand_core::{RngCore, SeedableRng};
 use rand_xorshift::XorShiftRng;
 
-pub fn random_frobenius_tests<F: Field, C: AsRef<[u64]>>(characteristic: C, maxpower: usize) {
+pub fn random_frobenius_tests<F: Field, C: AsRef<[u8]>>(characteristic: C, maxpower: usize) {
     let mut rng = XorShiftRng::from_seed([
         0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
         0xe5,
diff --git a/pairing/src/tests/repr.rs b/pairing/src/tests/repr.rs
index cde3ab3..7bc44e9 100644
--- a/pairing/src/tests/repr.rs
+++ b/pairing/src/tests/repr.rs
@@ -1,10 +1,9 @@
-use ff::{PrimeField, PrimeFieldRepr};
+use ff::PrimeField;
 use rand_core::SeedableRng;
 use rand_xorshift::XorShiftRng;
 
 pub fn random_repr_tests<P: PrimeField>() {
     random_encoding_tests::<P>();
-    random_shl_tests::<P>();
     random_shr_tests::<P>();
 }
 
@@ -15,71 +14,12 @@ fn random_encoding_tests<P: PrimeField>() {
     ]);
 
     for _ in 0..1000 {
-        let r = P::random(&mut rng).into_repr();
+        let r = P::random(&mut rng);
 
-        // Big endian
-        {
-            let mut rdecoded = <P as PrimeField>::Repr::default();
+        let v = r.into_repr();
+        let rdecoded = P::from_repr(v).unwrap();
 
-            let mut v: Vec<u8> = vec![];
-            r.write_be(&mut v).unwrap();
-            rdecoded.read_be(&v[0..]).unwrap();
-
-            assert_eq!(r, rdecoded);
-        }
-
-        // Little endian
-        {
-            let mut rdecoded = <P as PrimeField>::Repr::default();
-
-            let mut v: Vec<u8> = vec![];
-            r.write_le(&mut v).unwrap();
-            rdecoded.read_le(&v[0..]).unwrap();
-
-            assert_eq!(r, rdecoded);
-        }
-
-        {
-            let mut rdecoded_le = <P as PrimeField>::Repr::default();
-            let mut rdecoded_be_flip = <P as PrimeField>::Repr::default();
-
-            let mut v: Vec<u8> = vec![];
-            r.write_le(&mut v).unwrap();
-
-            // This reads in little-endian, so we are done.
-            rdecoded_le.read_le(&v[..]).unwrap();
-
-            // This reads in big-endian, so we perform a swap of the
-            // bytes beforehand.
-            let v: Vec<u8> = v.into_iter().rev().collect();
-            rdecoded_be_flip.read_be(&v[..]).unwrap();
-
-            assert_eq!(rdecoded_le, rdecoded_be_flip);
-        }
-    }
-}
-
-fn random_shl_tests<P: PrimeField>() {
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    for _ in 0..100 {
-        let r = P::random(&mut rng).into_repr();
-
-        for shift in 0..=r.num_bits() {
-            let mut r1 = r;
-            let mut r2 = r;
-
-            for _ in 0..shift {
-                r1.mul2();
-            }
-
-            r2.shl(shift);
-
-            assert_eq!(r1, r2);
-        }
+        assert_eq!(r, rdecoded);
     }
 }
 
@@ -90,19 +30,22 @@ fn random_shr_tests<P: PrimeField>() {
     ]);
 
     for _ in 0..100 {
-        let r = P::random(&mut rng).into_repr();
+        let r = P::random(&mut rng);
 
-        for shift in 0..=r.num_bits() {
-            let mut r1 = r;
-            let mut r2 = r;
+        for shift in 0..P::NUM_BITS {
+            let r1 = r >> shift;
 
+            // Doubling the shifted element inserts zeros on the right; re-shifting should
+            // undo the doubling.
+            let mut r2 = r1;
             for _ in 0..shift {
-                r1.div2();
+                r2 = r2.double();
             }
-
-            r2.shr(shift);
+            r2 = r2 >> shift;
 
             assert_eq!(r1, r2);
         }
+
+        assert_eq!(r >> P::NUM_BITS, P::zero());
     }
 }
diff --git a/zcash_client_backend/src/proto/mod.rs b/zcash_client_backend/src/proto/mod.rs
index 0ab1b6d..0872fbb 100644
--- a/zcash_client_backend/src/proto/mod.rs
+++ b/zcash_client_backend/src/proto/mod.rs
@@ -1,6 +1,6 @@
 //! Generated code for handling light client protobuf structs.
 
-use ff::{PrimeField, PrimeFieldRepr};
+use ff::PrimeField;
 use pairing::bls12_381::{Bls12, Fr, FrRepr};
 use zcash_primitives::{
     block::{BlockHash, BlockHeader},
@@ -67,8 +67,8 @@ impl compact_formats::CompactOutput {
     /// [`CompactOutput.cmu`]: #structfield.cmu
     pub fn cmu(&self) -> Result<Fr, ()> {
         let mut repr = FrRepr::default();
-        repr.read_le(&self.cmu[..]).map_err(|_| ())?;
-        Fr::from_repr(repr).map_err(|_| ())
+        repr.as_mut().copy_from_slice(&self.cmu[..]);
+        Fr::from_repr(repr).ok_or(())
     }
 
     /// Returns the ephemeral public key for this output.
diff --git a/zcash_client_backend/src/welding_rig.rs b/zcash_client_backend/src/welding_rig.rs
index 14939d7..d1f9bcd 100644
--- a/zcash_client_backend/src/welding_rig.rs
+++ b/zcash_client_backend/src/welding_rig.rs
@@ -183,7 +183,7 @@ pub fn scan_block(
 
 #[cfg(test)]
 mod tests {
-    use ff::{Field, PrimeField, PrimeFieldRepr};
+    use ff::{Field, PrimeField};
     use pairing::bls12_381::{Bls12, Fr};
     use rand_core::{OsRng, RngCore};
     use zcash_primitives::{
@@ -207,9 +207,7 @@ mod tests {
         };
         let fake_cmu = {
             let fake_cmu = Fr::random(rng);
-            let mut bytes = vec![];
-            fake_cmu.into_repr().write_le(&mut bytes).unwrap();
-            bytes
+            fake_cmu.into_repr().as_ref().to_owned()
         };
         let fake_epk = {
             let mut buffer = vec![0; 64];
@@ -264,8 +262,7 @@ mod tests {
             Memo::default(),
             &mut rng,
         );
-        let mut cmu = vec![];
-        note.cm(&JUBJUB).into_repr().write_le(&mut cmu).unwrap();
+        let cmu = note.cm(&JUBJUB).into_repr().as_ref().to_owned();
         let mut epk = vec![];
         encryptor.epk().write(&mut epk).unwrap();
         let enc_ciphertext = encryptor.encrypt_note_plaintext();
diff --git a/zcash_primitives/src/jubjub/edwards.rs b/zcash_primitives/src/jubjub/edwards.rs
index cbe4d0b..965b8d8 100644
--- a/zcash_primitives/src/jubjub/edwards.rs
+++ b/zcash_primitives/src/jubjub/edwards.rs
@@ -1,4 +1,4 @@
-use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField};
+use ff::{BitIterator, Field, PrimeField, SqrtField};
 use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
 use subtle::CtOption;
 
@@ -83,15 +83,15 @@ impl<E: JubjubEngine, Subgroup> PartialEq for Point<E, Subgroup> {
 }
 
 impl<E: JubjubEngine> Point<E, Unknown> {
-    pub fn read<R: Read>(reader: R, params: &E::Params) -> io::Result<Self> {
+    pub fn read<R: Read>(mut reader: R, params: &E::Params) -> io::Result<Self> {
         let mut y_repr = <E::Fr as PrimeField>::Repr::default();
-        y_repr.read_le(reader)?;
+        reader.read_exact(y_repr.as_mut())?;
 
-        let x_sign = (y_repr.as_ref()[3] >> 63) == 1;
-        y_repr.as_mut()[3] &= 0x7fffffffffffffff;
+        let x_sign = (y_repr.as_ref()[31] >> 7) == 1;
+        y_repr.as_mut()[31] &= 0x7f;
 
         match E::Fr::from_repr(y_repr) {
-            Ok(y) => {
+            Some(y) => {
                 let p = Self::get_for_y(y, x_sign, params);
                 if bool::from(p.is_some()) {
                     Ok(p.unwrap())
@@ -99,7 +99,7 @@ impl<E: JubjubEngine> Point<E, Unknown> {
                     Err(io::Error::new(io::ErrorKind::InvalidInput, "not on curve"))
                 }
             }
-            Err(_) => Err(io::Error::new(
+            None => Err(io::Error::new(
                 io::ErrorKind::InvalidInput,
                 "y is not in field",
             )),
@@ -167,17 +167,17 @@ impl<E: JubjubEngine> Point<E, Unknown> {
 }
 
 impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
-    pub fn write<W: Write>(&self, writer: W) -> io::Result<()> {
+    pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
         let (x, y) = self.to_xy();
 
         assert_eq!(E::Fr::NUM_BITS, 255);
 
         let mut y_repr = y.into_repr();
         if x.is_odd() {
-            y_repr.as_mut()[3] |= 0x8000000000000000u64;
+            y_repr.as_mut()[31] |= 0x80;
         }
 
-        y_repr.write_le(writer)
+        writer.write_all(y_repr.as_ref())
     }
 
     /// Convert from a Montgomery point
@@ -467,7 +467,7 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
 
         let mut res = Self::zero();
 
-        for b in BitIterator::<u64, _>::new(scalar.into()) {
+        for b in BitIterator::<u8, _>::new(scalar.into()) {
             res = res.double(params);
 
             if b {
diff --git a/zcash_primitives/src/jubjub/fs.rs b/zcash_primitives/src/jubjub/fs.rs
index 85c3df4..5e109d8 100644
--- a/zcash_primitives/src/jubjub/fs.rs
+++ b/zcash_primitives/src/jubjub/fs.rs
@@ -1,7 +1,5 @@
-use ff::{
-    adc, mac_with_carry, sbb, BitIterator, Field, PowVartime, PrimeField, PrimeFieldDecodingError,
-    PrimeFieldRepr, SqrtField,
-};
+use byteorder::{ByteOrder, LittleEndian};
+use ff::{adc, mac_with_carry, sbb, BitIterator, Field, PowVartime, PrimeField, SqrtField};
 use rand_core::RngCore;
 use std::mem;
 use std::ops::{Add, AddAssign, BitAnd, Mul, MulAssign, Neg, Shr, Sub, SubAssign};
@@ -11,6 +9,11 @@ use super::ToUniform;
 
 // s = 6554484396890773809930967563523245729705921265872317281365359162392183254199
 const MODULUS: FsRepr = FsRepr([
+    0xb7, 0x2c, 0xf7, 0xd6, 0x5e, 0x0e, 0x97, 0xd0, 0x82, 0x10, 0xc8, 0xcc, 0x93, 0x20, 0x68, 0xa6,
+    0x00, 0x3b, 0x34, 0x01, 0x01, 0x3b, 0x67, 0x06, 0xa9, 0xaf, 0x33, 0x65, 0xea, 0xb4, 0x7d, 0x0e,
+]);
+
+const MODULUS_LIMBS: Fs = Fs([
     0xd0970e5ed6f72cb7,
     0xa6682093ccc81082,
     0x6673b0101343b00,
@@ -25,7 +28,7 @@ const MODULUS_BITS: u32 = 252;
 const REPR_SHAVE_BITS: u32 = 4;
 
 // R = 2**256 % s
-const R: FsRepr = FsRepr([
+const R: Fs = Fs([
     0x25f80bb3b99607d9,
     0xf315d62f66b6e750,
     0x932514eeeb8814f4,
@@ -33,7 +36,7 @@ const R: FsRepr = FsRepr([
 ]);
 
 // R2 = R^2 % s
-const R2: FsRepr = FsRepr([
+const R2: Fs = Fs([
     0x67719aa495e57731,
     0x51b0cef09ce3fc26,
     0x69dab7fac026e9a5,
@@ -44,7 +47,7 @@ const R2: FsRepr = FsRepr([
 const INV: u64 = 0x1ba3a358ef788ef9;
 
 // GENERATOR = 6 (multiplicative generator of r-1 order, that is also quadratic nonresidue)
-const GENERATOR: FsRepr = FsRepr([
+const GENERATOR: Fs = Fs([
     0x720b1b19d49ea8f1,
     0xbf4aa36101f13a58,
     0x5fa8cc968193ccbb,
@@ -55,7 +58,7 @@ const GENERATOR: FsRepr = FsRepr([
 const S: u32 = 1;
 
 // 2^S root of unity computed by GENERATOR^t
-const ROOT_OF_UNITY: FsRepr = FsRepr([
+const ROOT_OF_UNITY: Fs = Fs([
     0xaa9f02ab1d6124de,
     0xb3524a6466112932,
     0x7342261215ac260b,
@@ -63,199 +66,45 @@ const ROOT_OF_UNITY: FsRepr = FsRepr([
 ]);
 
 // -((2**256) mod s) mod s
-const NEGATIVE_ONE: Fs = Fs(FsRepr([
+const NEGATIVE_ONE: Fs = Fs([
     0xaa9f02ab1d6124de,
     0xb3524a6466112932,
     0x7342261215ac260b,
     0x4d6b87b1da259e2,
-]));
+]);
 
 /// This is the underlying representation of an element of `Fs`.
 #[derive(Copy, Clone, PartialEq, Eq, Default, Debug)]
-pub struct FsRepr(pub [u64; 4]);
+pub struct FsRepr(pub [u8; 32]);
 
 impl ::std::fmt::Display for FsRepr {
     fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
         write!(f, "0x")?;
         for i in self.0.iter().rev() {
-            write!(f, "{:016x}", *i)?;
+            write!(f, "{:02x}", *i)?;
         }
 
         Ok(())
     }
 }
 
-impl AsRef<[u64]> for FsRepr {
+impl AsRef<[u8]> for FsRepr {
     #[inline(always)]
-    fn as_ref(&self) -> &[u64] {
+    fn as_ref(&self) -> &[u8] {
         &self.0
     }
 }
 
-impl AsMut<[u64]> for FsRepr {
+impl AsMut<[u8]> for FsRepr {
     #[inline(always)]
-    fn as_mut(&mut self) -> &mut [u64] {
+    fn as_mut(&mut self) -> &mut [u8] {
         &mut self.0
     }
 }
 
-impl From<u64> for FsRepr {
-    #[inline(always)]
-    fn from(val: u64) -> FsRepr {
-        let mut repr = Self::default();
-        repr.0[0] = val;
-        repr
-    }
-}
-
-impl Ord for FsRepr {
-    #[inline(always)]
-    fn cmp(&self, other: &FsRepr) -> ::std::cmp::Ordering {
-        for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) {
-            if a < b {
-                return ::std::cmp::Ordering::Less;
-            } else if a > b {
-                return ::std::cmp::Ordering::Greater;
-            }
-        }
-
-        ::std::cmp::Ordering::Equal
-    }
-}
-
-impl PartialOrd for FsRepr {
-    #[inline(always)]
-    fn partial_cmp(&self, other: &FsRepr) -> Option<::std::cmp::Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-impl PrimeFieldRepr for FsRepr {
-    #[inline(always)]
-    fn is_odd(&self) -> bool {
-        self.0[0] & 1 == 1
-    }
-
-    #[inline(always)]
-    fn is_even(&self) -> bool {
-        !self.is_odd()
-    }
-
-    #[inline(always)]
-    fn is_zero(&self) -> bool {
-        self.0.iter().all(|&e| e == 0)
-    }
-
-    #[inline(always)]
-    fn shr(&mut self, mut n: u32) {
-        if n >= 64 * 4 {
-            *self = Self::from(0);
-            return;
-        }
-
-        while n >= 64 {
-            let mut t = 0;
-            for i in self.0.iter_mut().rev() {
-                ::std::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;
-            }
-        }
-    }
-
-    #[inline(always)]
-    fn div2(&mut self) {
-        let mut t = 0;
-        for i in self.0.iter_mut().rev() {
-            let t2 = *i << 63;
-            *i >>= 1;
-            *i |= t;
-            t = t2;
-        }
-    }
-
-    #[inline(always)]
-    fn mul2(&mut self) {
-        let mut last = 0;
-        for i in &mut self.0 {
-            let tmp = *i >> 63;
-            *i <<= 1;
-            *i |= last;
-            last = tmp;
-        }
-    }
-
-    #[inline(always)]
-    fn shl(&mut self, mut n: u32) {
-        if n >= 64 * 4 {
-            *self = Self::from(0);
-            return;
-        }
-
-        while n >= 64 {
-            let mut t = 0;
-            for i in &mut self.0 {
-                ::std::mem::swap(&mut t, i);
-            }
-            n -= 64;
-        }
-
-        if n > 0 {
-            let mut t = 0;
-            for i in &mut self.0 {
-                let t2 = *i >> (64 - n);
-                *i <<= n;
-                *i |= t;
-                t = t2;
-            }
-        }
-    }
-
-    #[inline(always)]
-    fn num_bits(&self) -> u32 {
-        let mut ret = (4 as u32) * 64;
-        for i in self.0.iter().rev() {
-            let leading = i.leading_zeros();
-            ret -= leading;
-            if leading != 64 {
-                break;
-            }
-        }
-
-        ret
-    }
-
-    #[inline(always)]
-    fn add_nocarry(&mut self, other: &FsRepr) {
-        let mut carry = 0;
-
-        for (a, b) in self.0.iter_mut().zip(other.0.iter()) {
-            *a = adc(*a, *b, &mut carry);
-        }
-    }
-
-    #[inline(always)]
-    fn sub_noborrow(&mut self, other: &FsRepr) {
-        let mut borrow = 0;
-
-        for (a, b) in self.0.iter_mut().zip(other.0.iter()) {
-            *a = sbb(*a, *b, &mut borrow);
-        }
-    }
-}
-
 /// This is an element of the scalar field of the Jubjub curve.
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub struct Fs(FsRepr);
+pub struct Fs([u64; 4]);
 
 impl Default for Fs {
     fn default() -> Self {
@@ -265,17 +114,23 @@ impl Default for Fs {
 
 impl ConstantTimeEq for Fs {
     fn ct_eq(&self, other: &Fs) -> Choice {
-        (self.0).0[0].ct_eq(&(other.0).0[0])
-            & (self.0).0[1].ct_eq(&(other.0).0[1])
-            & (self.0).0[2].ct_eq(&(other.0).0[2])
-            & (self.0).0[3].ct_eq(&(other.0).0[3])
+        self.0[0].ct_eq(&other.0[0])
+            & self.0[1].ct_eq(&other.0[1])
+            & self.0[2].ct_eq(&other.0[2])
+            & self.0[3].ct_eq(&other.0[3])
     }
 }
 
 impl Ord for Fs {
     #[inline(always)]
     fn cmp(&self, other: &Fs) -> ::std::cmp::Ordering {
-        self.into_repr().cmp(&other.into_repr())
+        let mut a = *self;
+        a.mont_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0);
+
+        let mut b = *other;
+        b.mont_reduce(other.0[0], other.0[1], other.0[2], other.0[3], 0, 0, 0, 0);
+
+        a.cmp_native(&b)
     }
 }
 
@@ -297,7 +152,7 @@ impl From<u64> for Fs {
     fn from(val: u64) -> Fs {
         let mut raw = [0u64; 4];
         raw[0] = val;
-        Fs(FsRepr(raw)) * Fs(R2)
+        Fs(raw) * R2
     }
 }
 
@@ -307,14 +162,20 @@ impl From<Fs> for FsRepr {
     }
 }
 
+impl<'a> From<&'a Fs> for FsRepr {
+    fn from(e: &'a Fs) -> FsRepr {
+        e.into_repr()
+    }
+}
+
 impl ConditionallySelectable for Fs {
     fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
-        Fs(FsRepr([
-            u64::conditional_select(&(a.0).0[0], &(b.0).0[0], choice),
-            u64::conditional_select(&(a.0).0[1], &(b.0).0[1], choice),
-            u64::conditional_select(&(a.0).0[2], &(b.0).0[2], choice),
-            u64::conditional_select(&(a.0).0[3], &(b.0).0[3], choice),
-        ]))
+        Fs([
+            u64::conditional_select(&a.0[0], &b.0[0], choice),
+            u64::conditional_select(&a.0[1], &b.0[1], choice),
+            u64::conditional_select(&a.0[2], &b.0[2], choice),
+            u64::conditional_select(&a.0[3], &b.0[3], choice),
+        ])
     }
 }
 
@@ -324,9 +185,9 @@ impl Neg for Fs {
     #[inline]
     fn neg(mut self) -> Self {
         if !self.is_zero() {
-            let mut tmp = MODULUS;
-            tmp.sub_noborrow(&self.0);
-            self.0 = tmp;
+            let mut tmp = MODULUS_LIMBS;
+            tmp.sub_noborrow(&self);
+            self = tmp;
         }
         self
     }
@@ -356,7 +217,7 @@ impl<'r> AddAssign<&'r Fs> for Fs {
     #[inline]
     fn add_assign(&mut self, other: &Self) {
         // This cannot exceed the backing capacity.
-        self.0.add_nocarry(&other.0);
+        self.add_nocarry(&other);
 
         // However, it may need to be reduced.
         self.reduce();
@@ -394,11 +255,11 @@ impl<'r> SubAssign<&'r Fs> for Fs {
     #[inline]
     fn sub_assign(&mut self, other: &Self) {
         // If `other` is larger than `self`, we'll need to add the modulus to self first.
-        if other.0 > self.0 {
-            self.0.add_nocarry(&MODULUS);
+        if other.cmp_native(self) == ::core::cmp::Ordering::Greater {
+            self.add_nocarry(&MODULUS_LIMBS);
         }
 
-        self.0.sub_noborrow(&other.0);
+        self.sub_noborrow(&other);
     }
 }
 
@@ -433,28 +294,28 @@ impl<'r> MulAssign<&'r Fs> for Fs {
     #[inline]
     fn mul_assign(&mut self, other: &Self) {
         let mut carry = 0;
-        let r0 = mac_with_carry(0, (self.0).0[0], (other.0).0[0], &mut carry);
-        let r1 = mac_with_carry(0, (self.0).0[0], (other.0).0[1], &mut carry);
-        let r2 = mac_with_carry(0, (self.0).0[0], (other.0).0[2], &mut carry);
-        let r3 = mac_with_carry(0, (self.0).0[0], (other.0).0[3], &mut carry);
+        let r0 = mac_with_carry(0, self.0[0], other.0[0], &mut carry);
+        let r1 = mac_with_carry(0, self.0[0], other.0[1], &mut carry);
+        let r2 = mac_with_carry(0, self.0[0], other.0[2], &mut carry);
+        let r3 = mac_with_carry(0, self.0[0], other.0[3], &mut carry);
         let r4 = carry;
         let mut carry = 0;
-        let r1 = mac_with_carry(r1, (self.0).0[1], (other.0).0[0], &mut carry);
-        let r2 = mac_with_carry(r2, (self.0).0[1], (other.0).0[1], &mut carry);
-        let r3 = mac_with_carry(r3, (self.0).0[1], (other.0).0[2], &mut carry);
-        let r4 = mac_with_carry(r4, (self.0).0[1], (other.0).0[3], &mut carry);
+        let r1 = mac_with_carry(r1, self.0[1], other.0[0], &mut carry);
+        let r2 = mac_with_carry(r2, self.0[1], other.0[1], &mut carry);
+        let r3 = mac_with_carry(r3, self.0[1], other.0[2], &mut carry);
+        let r4 = mac_with_carry(r4, self.0[1], other.0[3], &mut carry);
         let r5 = carry;
         let mut carry = 0;
-        let r2 = mac_with_carry(r2, (self.0).0[2], (other.0).0[0], &mut carry);
-        let r3 = mac_with_carry(r3, (self.0).0[2], (other.0).0[1], &mut carry);
-        let r4 = mac_with_carry(r4, (self.0).0[2], (other.0).0[2], &mut carry);
-        let r5 = mac_with_carry(r5, (self.0).0[2], (other.0).0[3], &mut carry);
+        let r2 = mac_with_carry(r2, self.0[2], other.0[0], &mut carry);
+        let r3 = mac_with_carry(r3, self.0[2], other.0[1], &mut carry);
+        let r4 = mac_with_carry(r4, self.0[2], other.0[2], &mut carry);
+        let r5 = mac_with_carry(r5, self.0[2], other.0[3], &mut carry);
         let r6 = carry;
         let mut carry = 0;
-        let r3 = mac_with_carry(r3, (self.0).0[3], (other.0).0[0], &mut carry);
-        let r4 = mac_with_carry(r4, (self.0).0[3], (other.0).0[1], &mut carry);
-        let r5 = mac_with_carry(r5, (self.0).0[3], (other.0).0[2], &mut carry);
-        let r6 = mac_with_carry(r6, (self.0).0[3], (other.0).0[3], &mut carry);
+        let r3 = mac_with_carry(r3, self.0[3], other.0[0], &mut carry);
+        let r4 = mac_with_carry(r4, self.0[3], other.0[1], &mut carry);
+        let r5 = mac_with_carry(r5, self.0[3], other.0[2], &mut carry);
+        let r6 = mac_with_carry(r6, self.0[3], other.0[3], &mut carry);
         let r7 = carry;
         self.mont_reduce(r0, r1, r2, r3, r4, r5, r6, r7);
     }
@@ -472,17 +333,8 @@ impl BitAnd<u64> for Fs {
 
     #[inline(always)]
     fn bitand(mut self, rhs: u64) -> u64 {
-        self.mont_reduce(
-            (self.0).0[0],
-            (self.0).0[1],
-            (self.0).0[2],
-            (self.0).0[3],
-            0,
-            0,
-            0,
-            0,
-        );
-        (self.0).0[0] & rhs
+        self.mont_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0);
+        self.0[0] & rhs
     }
 }
 
@@ -496,20 +348,11 @@ impl Shr<u32> for Fs {
         }
 
         // Convert from Montgomery to native representation.
-        self.mont_reduce(
-            (self.0).0[0],
-            (self.0).0[1],
-            (self.0).0[2],
-            (self.0).0[3],
-            0,
-            0,
-            0,
-            0,
-        );
+        self.mont_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0);
 
         while n >= 64 {
             let mut t = 0;
-            for i in (self.0).0.iter_mut().rev() {
+            for i in self.0.iter_mut().rev() {
                 mem::swap(&mut t, i);
             }
             n -= 64;
@@ -517,7 +360,7 @@ impl Shr<u32> for Fs {
 
         if n > 0 {
             let mut t = 0;
-            for i in (self.0).0.iter_mut().rev() {
+            for i in self.0.iter_mut().rev() {
                 let t2 = *i << (64 - n);
                 *i >>= n;
                 *i |= t;
@@ -526,42 +369,42 @@ impl Shr<u32> for Fs {
         }
 
         // Convert back to Montgomery representation
-        self * Fs(R2)
+        self * R2
     }
 }
 
 impl PrimeField for Fs {
     type Repr = FsRepr;
 
-    fn from_repr(r: FsRepr) -> Result<Fs, PrimeFieldDecodingError> {
-        let mut r = Fs(r);
-        if r.is_valid() {
-            r.mul_assign(&Fs(R2));
+    fn from_repr(r: FsRepr) -> Option<Fs> {
+        let r = {
+            let mut inner = [0; 4];
+            LittleEndian::read_u64_into(r.as_ref(), &mut inner[..]);
+            Fs(inner)
+        };
 
-            Ok(r)
+        if r.is_valid() {
+            Some(r * &R2)
         } else {
-            Err(PrimeFieldDecodingError::NotInField)
+            None
         }
     }
 
     fn into_repr(&self) -> FsRepr {
         let mut r = *self;
-        r.mont_reduce(
-            (self.0).0[0],
-            (self.0).0[1],
-            (self.0).0[2],
-            (self.0).0[3],
-            0,
-            0,
-            0,
-            0,
-        );
-        r.0
+        r.mont_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0);
+
+        let mut repr = [0; 32];
+        LittleEndian::write_u64_into(&r.0, &mut repr[..]);
+        FsRepr(repr)
     }
 
     #[inline(always)]
     fn is_odd(&self) -> bool {
-        self.into_repr().is_odd()
+        let mut r = *self;
+        r.mont_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0);
+
+        r.0[0] & 1 == 1
     }
 
     fn char() -> FsRepr {
@@ -573,13 +416,13 @@ impl PrimeField for Fs {
     const CAPACITY: u32 = Self::NUM_BITS - 1;
 
     fn multiplicative_generator() -> Self {
-        Fs(GENERATOR)
+        GENERATOR
     }
 
     const S: u32 = S;
 
     fn root_of_unity() -> Self {
-        Fs(ROOT_OF_UNITY)
+        ROOT_OF_UNITY
     }
 }
 
@@ -591,7 +434,7 @@ impl Field for Fs {
                 for limb in &mut repr {
                     *limb = rng.next_u64();
                 }
-                Fs(FsRepr(repr))
+                Fs(repr)
             };
 
             // Mask away the unused most-significant bits.
@@ -610,12 +453,12 @@ impl Field for Fs {
 
     #[inline]
     fn one() -> Self {
-        Fs(R)
+        R
     }
 
     #[inline]
     fn is_zero(&self) -> bool {
-        self.0.is_zero()
+        self.0.iter().all(|&e| e == 0)
     }
 
     #[inline]
@@ -623,7 +466,13 @@ impl Field for Fs {
         let mut ret = *self;
 
         // This cannot exceed the backing capacity.
-        ret.0.mul2();
+        let mut last = 0;
+        for i in &mut ret.0 {
+            let tmp = *i >> 63;
+            *i <<= 1;
+            *i |= last;
+            last = tmp;
+        }
 
         // However, it may need to be reduced.
         ret.reduce();
@@ -658,16 +507,16 @@ impl Field for Fs {
     #[inline]
     fn square(&self) -> Self {
         let mut carry = 0;
-        let r1 = mac_with_carry(0, (self.0).0[0], (self.0).0[1], &mut carry);
-        let r2 = mac_with_carry(0, (self.0).0[0], (self.0).0[2], &mut carry);
-        let r3 = mac_with_carry(0, (self.0).0[0], (self.0).0[3], &mut carry);
+        let r1 = mac_with_carry(0, self.0[0], self.0[1], &mut carry);
+        let r2 = mac_with_carry(0, self.0[0], self.0[2], &mut carry);
+        let r3 = mac_with_carry(0, self.0[0], self.0[3], &mut carry);
         let r4 = carry;
         let mut carry = 0;
-        let r3 = mac_with_carry(r3, (self.0).0[1], (self.0).0[2], &mut carry);
-        let r4 = mac_with_carry(r4, (self.0).0[1], (self.0).0[3], &mut carry);
+        let r3 = mac_with_carry(r3, self.0[1], self.0[2], &mut carry);
+        let r4 = mac_with_carry(r4, self.0[1], self.0[3], &mut carry);
         let r5 = carry;
         let mut carry = 0;
-        let r5 = mac_with_carry(r5, (self.0).0[2], (self.0).0[3], &mut carry);
+        let r5 = mac_with_carry(r5, self.0[2], self.0[3], &mut carry);
         let r6 = carry;
 
         let r7 = r6 >> 63;
@@ -679,13 +528,13 @@ impl Field for Fs {
         let r1 = r1 << 1;
 
         let mut carry = 0;
-        let r0 = mac_with_carry(0, (self.0).0[0], (self.0).0[0], &mut carry);
+        let r0 = mac_with_carry(0, self.0[0], self.0[0], &mut carry);
         let r1 = adc(r1, 0, &mut carry);
-        let r2 = mac_with_carry(r2, (self.0).0[1], (self.0).0[1], &mut carry);
+        let r2 = mac_with_carry(r2, self.0[1], self.0[1], &mut carry);
         let r3 = adc(r3, 0, &mut carry);
-        let r4 = mac_with_carry(r4, (self.0).0[2], (self.0).0[2], &mut carry);
+        let r4 = mac_with_carry(r4, self.0[2], self.0[2], &mut carry);
         let r5 = adc(r5, 0, &mut carry);
-        let r6 = mac_with_carry(r6, (self.0).0[3], (self.0).0[3], &mut carry);
+        let r6 = mac_with_carry(r6, self.0[3], self.0[3], &mut carry);
         let r7 = adc(r7, 0, &mut carry);
 
         let mut ret = *self;
@@ -695,11 +544,46 @@ impl Field for Fs {
 }
 
 impl Fs {
+    /// Compares two elements in native representation. This is only used
+    /// internally.
+    #[inline(always)]
+    fn cmp_native(&self, other: &Fs) -> ::std::cmp::Ordering {
+        for (a, b) in self.0.iter().rev().zip(other.0.iter().rev()) {
+            if a < b {
+                return ::std::cmp::Ordering::Less;
+            } else if a > b {
+                return ::std::cmp::Ordering::Greater;
+            }
+        }
+
+        ::std::cmp::Ordering::Equal
+    }
+
     /// Determines if the element is really in the field. This is only used
     /// internally.
     #[inline(always)]
     fn is_valid(&self) -> bool {
-        self.0 < MODULUS
+        // The Ord impl calls `reduce`, which in turn calls `is_valid`, so we use
+        // this internal function to eliminate the cycle.
+        self.cmp_native(&MODULUS_LIMBS) == ::core::cmp::Ordering::Less
+    }
+
+    #[inline(always)]
+    fn add_nocarry(&mut self, other: &Fs) {
+        let mut carry = 0;
+
+        for (a, b) in self.0.iter_mut().zip(other.0.iter()) {
+            *a = adc(*a, *b, &mut carry);
+        }
+    }
+
+    #[inline(always)]
+    fn sub_noborrow(&mut self, other: &Fs) {
+        let mut borrow = 0;
+
+        for (a, b) in self.0.iter_mut().zip(other.0.iter()) {
+            *a = sbb(*a, *b, &mut borrow);
+        }
     }
 
     /// Subtracts the modulus from this element if this element is not in the
@@ -707,7 +591,7 @@ impl Fs {
     #[inline(always)]
     fn reduce(&mut self) {
         if !self.is_valid() {
-            self.0.sub_noborrow(&MODULUS);
+            self.sub_noborrow(&MODULUS_LIMBS);
         }
     }
 
@@ -729,39 +613,39 @@ impl Fs {
 
         let k = r0.wrapping_mul(INV);
         let mut carry = 0;
-        mac_with_carry(r0, k, MODULUS.0[0], &mut carry);
-        r1 = mac_with_carry(r1, k, MODULUS.0[1], &mut carry);
-        r2 = mac_with_carry(r2, k, MODULUS.0[2], &mut carry);
-        r3 = mac_with_carry(r3, k, MODULUS.0[3], &mut carry);
+        mac_with_carry(r0, k, MODULUS_LIMBS.0[0], &mut carry);
+        r1 = mac_with_carry(r1, k, MODULUS_LIMBS.0[1], &mut carry);
+        r2 = mac_with_carry(r2, k, MODULUS_LIMBS.0[2], &mut carry);
+        r3 = mac_with_carry(r3, k, MODULUS_LIMBS.0[3], &mut carry);
         r4 = adc(r4, 0, &mut carry);
         let carry2 = carry;
         let k = r1.wrapping_mul(INV);
         let mut carry = 0;
-        mac_with_carry(r1, k, MODULUS.0[0], &mut carry);
-        r2 = mac_with_carry(r2, k, MODULUS.0[1], &mut carry);
-        r3 = mac_with_carry(r3, k, MODULUS.0[2], &mut carry);
-        r4 = mac_with_carry(r4, k, MODULUS.0[3], &mut carry);
+        mac_with_carry(r1, k, MODULUS_LIMBS.0[0], &mut carry);
+        r2 = mac_with_carry(r2, k, MODULUS_LIMBS.0[1], &mut carry);
+        r3 = mac_with_carry(r3, k, MODULUS_LIMBS.0[2], &mut carry);
+        r4 = mac_with_carry(r4, k, MODULUS_LIMBS.0[3], &mut carry);
         r5 = adc(r5, carry2, &mut carry);
         let carry2 = carry;
         let k = r2.wrapping_mul(INV);
         let mut carry = 0;
-        mac_with_carry(r2, k, MODULUS.0[0], &mut carry);
-        r3 = mac_with_carry(r3, k, MODULUS.0[1], &mut carry);
-        r4 = mac_with_carry(r4, k, MODULUS.0[2], &mut carry);
-        r5 = mac_with_carry(r5, k, MODULUS.0[3], &mut carry);
+        mac_with_carry(r2, k, MODULUS_LIMBS.0[0], &mut carry);
+        r3 = mac_with_carry(r3, k, MODULUS_LIMBS.0[1], &mut carry);
+        r4 = mac_with_carry(r4, k, MODULUS_LIMBS.0[2], &mut carry);
+        r5 = mac_with_carry(r5, k, MODULUS_LIMBS.0[3], &mut carry);
         r6 = adc(r6, carry2, &mut carry);
         let carry2 = carry;
         let k = r3.wrapping_mul(INV);
         let mut carry = 0;
-        mac_with_carry(r3, k, MODULUS.0[0], &mut carry);
-        r4 = mac_with_carry(r4, k, MODULUS.0[1], &mut carry);
-        r5 = mac_with_carry(r5, k, MODULUS.0[2], &mut carry);
-        r6 = mac_with_carry(r6, k, MODULUS.0[3], &mut carry);
+        mac_with_carry(r3, k, MODULUS_LIMBS.0[0], &mut carry);
+        r4 = mac_with_carry(r4, k, MODULUS_LIMBS.0[1], &mut carry);
+        r5 = mac_with_carry(r5, k, MODULUS_LIMBS.0[2], &mut carry);
+        r6 = mac_with_carry(r6, k, MODULUS_LIMBS.0[3], &mut carry);
         r7 = adc(r7, carry2, &mut carry);
-        (self.0).0[0] = r4;
-        (self.0).0[1] = r5;
-        (self.0).0[2] = r6;
-        (self.0).0[3] = r7;
+        self.0[0] = r4;
+        self.0[1] = r5;
+        self.0[2] = r6;
+        self.0[3] = r7;
         self.reduce();
     }
 
@@ -821,340 +705,26 @@ use rand_core::SeedableRng;
 #[cfg(test)]
 use rand_xorshift::XorShiftRng;
 
-#[test]
-fn test_fs_repr_ordering() {
-    fn assert_equality(a: FsRepr, b: FsRepr) {
-        assert_eq!(a, b);
-        assert!(a.cmp(&b) == ::std::cmp::Ordering::Equal);
-    }
-
-    fn assert_lt(a: FsRepr, b: FsRepr) {
-        assert!(a < b);
-        assert!(b > a);
-    }
-
-    assert_equality(
-        FsRepr([9999, 9999, 9999, 9999]),
-        FsRepr([9999, 9999, 9999, 9999]),
-    );
-    assert_equality(
-        FsRepr([9999, 9998, 9999, 9999]),
-        FsRepr([9999, 9998, 9999, 9999]),
-    );
-    assert_equality(
-        FsRepr([9999, 9999, 9999, 9997]),
-        FsRepr([9999, 9999, 9999, 9997]),
-    );
-    assert_lt(
-        FsRepr([9999, 9997, 9999, 9998]),
-        FsRepr([9999, 9997, 9999, 9999]),
-    );
-    assert_lt(
-        FsRepr([9999, 9997, 9998, 9999]),
-        FsRepr([9999, 9997, 9999, 9999]),
-    );
-    assert_lt(
-        FsRepr([9, 9999, 9999, 9997]),
-        FsRepr([9999, 9999, 9999, 9997]),
-    );
-}
-
-#[test]
-fn test_fs_repr_from() {
-    assert_eq!(FsRepr::from(100), FsRepr([100, 0, 0, 0]));
-}
-
-#[test]
-fn test_fs_repr_is_odd() {
-    assert!(!FsRepr::from(0).is_odd());
-    assert!(FsRepr::from(0).is_even());
-    assert!(FsRepr::from(1).is_odd());
-    assert!(!FsRepr::from(1).is_even());
-    assert!(!FsRepr::from(324834872).is_odd());
-    assert!(FsRepr::from(324834872).is_even());
-    assert!(FsRepr::from(324834873).is_odd());
-    assert!(!FsRepr::from(324834873).is_even());
-}
-
-#[test]
-fn test_fs_repr_is_zero() {
-    assert!(FsRepr::from(0).is_zero());
-    assert!(!FsRepr::from(1).is_zero());
-    assert!(!FsRepr([0, 0, 1, 0]).is_zero());
-}
-
-#[test]
-fn test_fs_repr_div2() {
-    let mut a = FsRepr([
-        0xbd2920b19c972321,
-        0x174ed0466a3be37e,
-        0xd468d5e3b551f0b5,
-        0xcb67c072733beefc,
-    ]);
-    a.div2();
-    assert_eq!(
-        a,
-        FsRepr([
-            0x5e949058ce4b9190,
-            0x8ba76823351df1bf,
-            0x6a346af1daa8f85a,
-            0x65b3e039399df77e
-        ])
-    );
-    for _ in 0..10 {
-        a.div2();
-    }
-    assert_eq!(
-        a,
-        FsRepr([
-            0x6fd7a524163392e4,
-            0x16a2e9da08cd477c,
-            0xdf9a8d1abc76aa3e,
-            0x196cf80e4e677d
-        ])
-    );
-    for _ in 0..200 {
-        a.div2();
-    }
-    assert_eq!(a, FsRepr([0x196cf80e4e67, 0x0, 0x0, 0x0]));
-    for _ in 0..40 {
-        a.div2();
-    }
-    assert_eq!(a, FsRepr([0x19, 0x0, 0x0, 0x0]));
-    for _ in 0..4 {
-        a.div2();
-    }
-    assert_eq!(a, FsRepr([0x1, 0x0, 0x0, 0x0]));
-    a.div2();
-    assert!(a.is_zero());
-}
-
-#[test]
-fn test_fs_repr_shr() {
-    let mut a = FsRepr([
-        0xb33fbaec482a283f,
-        0x997de0d3a88cb3df,
-        0x9af62d2a9a0e5525,
-        0x36003ab08de70da1,
-    ]);
-    a.shr(0);
-    assert_eq!(
-        a,
-        FsRepr([
-            0xb33fbaec482a283f,
-            0x997de0d3a88cb3df,
-            0x9af62d2a9a0e5525,
-            0x36003ab08de70da1
-        ])
-    );
-    a.shr(1);
-    assert_eq!(
-        a,
-        FsRepr([
-            0xd99fdd762415141f,
-            0xccbef069d44659ef,
-            0xcd7b16954d072a92,
-            0x1b001d5846f386d0
-        ])
-    );
-    a.shr(50);
-    assert_eq!(
-        a,
-        FsRepr([
-            0xbc1a7511967bf667,
-            0xc5a55341caa4b32f,
-            0x75611bce1b4335e,
-            0x6c0
-        ])
-    );
-    a.shr(130);
-    assert_eq!(a, FsRepr([0x1d5846f386d0cd7, 0x1b0, 0x0, 0x0]));
-    a.shr(64);
-    assert_eq!(a, FsRepr([0x1b0, 0x0, 0x0, 0x0]));
-}
-
-#[test]
-fn test_fs_repr_mul2() {
-    let mut a = FsRepr::from(23712937547);
-    a.mul2();
-    assert_eq!(a, FsRepr([0xb0acd6c96, 0x0, 0x0, 0x0]));
-    for _ in 0..60 {
-        a.mul2();
-    }
-    assert_eq!(a, FsRepr([0x6000000000000000, 0xb0acd6c9, 0x0, 0x0]));
-    for _ in 0..128 {
-        a.mul2();
-    }
-    assert_eq!(a, FsRepr([0x0, 0x0, 0x6000000000000000, 0xb0acd6c9]));
-    for _ in 0..60 {
-        a.mul2();
-    }
-    assert_eq!(a, FsRepr([0x0, 0x0, 0x0, 0x9600000000000000]));
-    for _ in 0..7 {
-        a.mul2();
-    }
-    assert!(a.is_zero());
-}
-
-#[test]
-fn test_fs_repr_num_bits() {
-    let mut a = FsRepr::from(0);
-    assert_eq!(0, a.num_bits());
-    a = FsRepr::from(1);
-    for i in 1..257 {
-        assert_eq!(i, a.num_bits());
-        a.mul2();
-    }
-    assert_eq!(0, a.num_bits());
-}
-
-#[test]
-fn test_fs_repr_sub_noborrow() {
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    let mut t = FsRepr([
-        0x8e62a7e85264e2c3,
-        0xb23d34c1941d3ca,
-        0x5976930b7502dd15,
-        0x600f3fb517bf5495,
-    ]);
-    t.sub_noborrow(&FsRepr([
-        0xd64f669809cbc6a4,
-        0xfa76cb9d90cf7637,
-        0xfefb0df9038d43b3,
-        0x298a30c744b31acf,
-    ]));
-    assert!(
-        t == FsRepr([
-            0xb813415048991c1f,
-            0x10ad07ae88725d92,
-            0x5a7b851271759961,
-            0x36850eedd30c39c5
-        ])
-    );
-
-    for _ in 0..1000 {
-        let mut a = Fs::random(&mut rng).into_repr();
-        a.0[3] >>= 30;
-        let mut b = a;
-        for _ in 0..10 {
-            b.mul2();
-        }
-        let mut c = b;
-        for _ in 0..10 {
-            c.mul2();
-        }
-
-        assert!(a < b);
-        assert!(b < c);
-
-        let mut csub_ba = c;
-        csub_ba.sub_noborrow(&b);
-        csub_ba.sub_noborrow(&a);
-
-        let mut csub_ab = c;
-        csub_ab.sub_noborrow(&a);
-        csub_ab.sub_noborrow(&b);
-
-        assert_eq!(csub_ab, csub_ba);
-    }
-}
-
-#[test]
-fn test_fr_repr_add_nocarry() {
-    let mut rng = XorShiftRng::from_seed([
-        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
-        0xe5,
-    ]);
-
-    let mut t = FsRepr([
-        0xd64f669809cbc6a4,
-        0xfa76cb9d90cf7637,
-        0xfefb0df9038d43b3,
-        0x298a30c744b31acf,
-    ]);
-    t.add_nocarry(&FsRepr([
-        0x8e62a7e85264e2c3,
-        0xb23d34c1941d3ca,
-        0x5976930b7502dd15,
-        0x600f3fb517bf5495,
-    ]));
-    assert_eq!(
-        t,
-        FsRepr([
-            0x64b20e805c30a967,
-            0x59a9ee9aa114a02,
-            0x5871a104789020c9,
-            0x8999707c5c726f65
-        ])
-    );
-
-    // Test for the associativity of addition.
-    for _ in 0..1000 {
-        let mut a = Fs::random(&mut rng).into_repr();
-        let mut b = Fs::random(&mut rng).into_repr();
-        let mut c = Fs::random(&mut rng).into_repr();
-
-        // Unset the first few bits, so that overflow won't occur.
-        a.0[3] >>= 3;
-        b.0[3] >>= 3;
-        c.0[3] >>= 3;
-
-        let mut abc = a;
-        abc.add_nocarry(&b);
-        abc.add_nocarry(&c);
-
-        let mut acb = a;
-        acb.add_nocarry(&c);
-        acb.add_nocarry(&b);
-
-        let mut bac = b;
-        bac.add_nocarry(&a);
-        bac.add_nocarry(&c);
-
-        let mut bca = b;
-        bca.add_nocarry(&c);
-        bca.add_nocarry(&a);
-
-        let mut cab = c;
-        cab.add_nocarry(&a);
-        cab.add_nocarry(&b);
-
-        let mut cba = c;
-        cba.add_nocarry(&b);
-        cba.add_nocarry(&a);
-
-        assert_eq!(abc, acb);
-        assert_eq!(abc, bac);
-        assert_eq!(abc, bca);
-        assert_eq!(abc, cab);
-        assert_eq!(abc, cba);
-    }
-}
-
 #[test]
 fn test_fs_is_valid() {
-    let mut a = Fs(MODULUS);
+    let mut a = MODULUS_LIMBS;
     assert!(!a.is_valid());
-    a.0.sub_noborrow(&FsRepr::from(1));
+    a.sub_noborrow(&Fs([1, 0, 0, 0]));
     assert!(a.is_valid());
-    assert!(Fs(FsRepr::from(0)).is_valid());
-    assert!(Fs(FsRepr([
+    assert!(Fs::zero().is_valid());
+    assert!(Fs([
         0xd0970e5ed6f72cb6,
         0xa6682093ccc81082,
         0x6673b0101343b00,
         0xe7db4ea6533afa9
-    ]))
+    ])
     .is_valid());
-    assert!(!Fs(FsRepr([
+    assert!(!Fs([
         0xffffffffffffffff,
         0xffffffffffffffff,
         0xffffffffffffffff,
         0xffffffffffffffff
-    ]))
+    ])
     .is_valid());
 
     let mut rng = XorShiftRng::from_seed([
@@ -1178,77 +748,77 @@ fn test_fs_add_assign() {
         .unwrap();
         assert!(tmp.is_valid());
         // Test that adding zero has no effect.
-        tmp.add_assign(&Fs(FsRepr::from(0)));
+        tmp.add_assign(&Fs::zero());
         assert_eq!(
             tmp,
-            Fs(FsRepr([
+            Fs([
                 0x8e6bfff4722d6e67,
                 0x5643da5c892044f9,
                 0x9465f4b281921a69,
                 0x25f752d3edd7162
-            ]))
+            ])
         );
         // Add one and test for the result.
-        tmp.add_assign(&Fs(FsRepr::from(1)));
+        tmp.add_assign(&Fs([1, 0, 0, 0]));
         assert_eq!(
             tmp,
-            Fs(FsRepr([
+            Fs([
                 0x8e6bfff4722d6e68,
                 0x5643da5c892044f9,
                 0x9465f4b281921a69,
                 0x25f752d3edd7162
-            ]))
+            ])
         );
         // Add another random number that exercises the reduction.
-        tmp.add_assign(&Fs(FsRepr([
+        tmp.add_assign(&Fs([
             0xb634d07bc42d4a70,
             0xf724f0c008411f5f,
             0x456d4053d865af34,
             0x24ce814e8c63027,
-        ])));
+        ]));
         assert_eq!(
             tmp,
-            Fs(FsRepr([
+            Fs([
                 0x44a0d070365ab8d8,
                 0x4d68cb1c91616459,
                 0xd9d3350659f7c99e,
                 0x4ac5d4227a3a189
-            ]))
+            ])
         );
         // Add one to (s - 1) and test for the result.
-        tmp = Fs(FsRepr([
+        tmp = Fs([
             0xd0970e5ed6f72cb6,
             0xa6682093ccc81082,
             0x6673b0101343b00,
             0xe7db4ea6533afa9,
-        ]));
-        tmp.add_assign(&Fs(FsRepr::from(1)));
-        assert!(tmp.0.is_zero());
+        ]);
+        tmp.add_assign(&Fs([1, 0, 0, 0]));
+        assert!(tmp.is_zero());
         // Add a random number to another one such that the result is s - 1
-        tmp = Fs(FsRepr([
+        tmp = Fs([
             0xa11fda5950ce3636,
             0x922e0dbccfe0ca0e,
             0xacebb6e215b82d4a,
             0x97ffb8cdc3aee93,
-        ]));
-        tmp.add_assign(&Fs(FsRepr([
+        ]);
+        tmp.add_assign(&Fs([
             0x2f7734058628f680,
             0x143a12d6fce74674,
             0x597b841eeb7c0db6,
             0x4fdb95d88f8c115,
-        ])));
+        ]));
         assert_eq!(
             tmp,
-            Fs(FsRepr([
+            Fs([
                 0xd0970e5ed6f72cb6,
                 0xa6682093ccc81082,
                 0x6673b0101343b00,
                 0xe7db4ea6533afa9
-            ]))
+            ])
         );
         // Add one to the result and test for it.
-        tmp.add_assign(&Fs(FsRepr::from(1)));
-        assert!(tmp.0.is_zero());
+        tmp.add_assign(&Fs([1, 0, 0, 0]));
+        assert!(tmp.is_zero());
     }
 
     // Test associativity
@@ -1282,71 +852,71 @@ fn test_fs_add_assign() {
 fn test_fs_sub_assign() {
     {
         // Test arbitrary subtraction that tests reduction.
-        let mut tmp = Fs(FsRepr([
+        let mut tmp = Fs([
             0xb384d9f6877afd99,
             0x4442513958e1a1c1,
             0x352c4b8a95eccc3f,
             0x2db62dee4b0f2,
-        ]));
-        tmp.sub_assign(&Fs(FsRepr([
+        ]);
+        tmp.sub_assign(&Fs([
             0xec5bd2d13ed6b05a,
             0x2adc0ab3a39b5fa,
             0x82d3360a493e637e,
             0x53ccff4a64d6679,
-        ])));
+        ]));
         assert_eq!(
             tmp,
-            Fs(FsRepr([
+            Fs([
                 0x97c015841f9b79f6,
                 0xe7fcb121eb6ffc49,
                 0xb8c050814de2a3c1,
                 0x943c0589dcafa21
-            ]))
+            ])
         );
 
         // Test the opposite subtraction which doesn't test reduction.
-        tmp = Fs(FsRepr([
+        tmp = Fs([
             0xec5bd2d13ed6b05a,
             0x2adc0ab3a39b5fa,
             0x82d3360a493e637e,
             0x53ccff4a64d6679,
-        ]));
-        tmp.sub_assign(&Fs(FsRepr([
+        ]);
+        tmp.sub_assign(&Fs([
             0xb384d9f6877afd99,
             0x4442513958e1a1c1,
             0x352c4b8a95eccc3f,
             0x2db62dee4b0f2,
-        ])));
+        ]));
         assert_eq!(
             tmp,
-            Fs(FsRepr([
+            Fs([
                 0x38d6f8dab75bb2c1,
                 0xbe6b6f71e1581439,
                 0x4da6ea7fb351973e,
                 0x539f491c768b587
-            ]))
+            ])
         );
 
         // Test for sensible results with zero
-        tmp = Fs(FsRepr::from(0));
-        tmp.sub_assign(&Fs(FsRepr::from(0)));
+        tmp = Fs::zero();
+        tmp.sub_assign(&Fs::from(0));
         assert!(tmp.is_zero());
 
-        tmp = Fs(FsRepr([
+        tmp = Fs([
             0x361e16aef5cce835,
             0x55bbde2536e274c1,
             0x4dc77a63fd15ee75,
             0x1e14bb37c14f230,
-        ]));
-        tmp.sub_assign(&Fs(FsRepr::from(0)));
+        ]);
+        tmp.sub_assign(&Fs::from(0));
         assert_eq!(
             tmp,
-            Fs(FsRepr([
+            Fs([
                 0x361e16aef5cce835,
                 0x55bbde2536e274c1,
                 0x4dc77a63fd15ee75,
                 0x1e14bb37c14f230
-            ]))
+            ])
         );
     }
 
@@ -1373,25 +943,25 @@ fn test_fs_sub_assign() {
 
 #[test]
 fn test_fs_mul_assign() {
-    let mut tmp = Fs(FsRepr([
+    let mut tmp = Fs([
         0xb433b01287f71744,
         0x4eafb86728c4d108,
         0xfdd52c14b9dfbe65,
         0x2ff1f3434821118,
-    ]));
-    tmp.mul_assign(&Fs(FsRepr([
+    ]);
+    tmp.mul_assign(&Fs([
         0xdae00fc63c9fa90f,
         0x5a5ed89b96ce21ce,
         0x913cd26101bd6f58,
         0x3f0822831697fe9,
-    ])));
+    ]));
     assert!(
-        tmp == Fs(FsRepr([
+        tmp == Fs([
             0xb68ecb61d54d2992,
             0x5ff95874defce6a6,
             0x3590eb053894657d,
             0x53823a118515933
-        ]))
+        ])
     );
 
     let mut rng = XorShiftRng::from_seed([
@@ -1443,80 +1013,73 @@ fn test_fs_mul_assign() {
 #[test]
 fn test_fs_shr() {
     let mut a = Fs::from_repr(FsRepr([
-        0xb33fbaec482a283f,
-        0x997de0d3a88cb3df,
-        0x9af62d2a9a0e5525,
-        0x06003ab08de70da1,
+        0x3f, 0x28, 0x2a, 0x48, 0xec, 0xba, 0x3f, 0xb3, 0xdf, 0xb3, 0x8c, 0xa8, 0xd3, 0xe0, 0x7d,
+        0x99, 0x25, 0x55, 0x0e, 0x9a, 0x2a, 0x2d, 0xf6, 0x9a, 0xa1, 0x0d, 0xe7, 0x8d, 0xb0, 0x3a,
+        0x00, 0x06,
     ]))
     .unwrap();
     a = a >> 0;
     assert_eq!(
         a.into_repr(),
         FsRepr([
-            0xb33fbaec482a283f,
-            0x997de0d3a88cb3df,
-            0x9af62d2a9a0e5525,
-            0x06003ab08de70da1,
+            0x3f, 0x28, 0x2a, 0x48, 0xec, 0xba, 0x3f, 0xb3, 0xdf, 0xb3, 0x8c, 0xa8, 0xd3, 0xe0,
+            0x7d, 0x99, 0x25, 0x55, 0x0e, 0x9a, 0x2a, 0x2d, 0xf6, 0x9a, 0xa1, 0x0d, 0xe7, 0x8d,
+            0xb0, 0x3a, 0x00, 0x06,
         ])
     );
     a = a >> 1;
     assert_eq!(
         a.into_repr(),
         FsRepr([
-            0xd99fdd762415141f,
-            0xccbef069d44659ef,
-            0xcd7b16954d072a92,
-            0x03001d5846f386d0,
+            0x1f, 0x14, 0x15, 0x24, 0x76, 0xdd, 0x9f, 0xd9, 0xef, 0x59, 0x46, 0xd4, 0x69, 0xf0,
+            0xbe, 0xcc, 0x92, 0x2a, 0x07, 0x4d, 0x95, 0x16, 0x7b, 0xcd, 0xd0, 0x86, 0xf3, 0x46,
+            0x58, 0x1d, 0x00, 0x03,
         ])
     );
     a = a >> 50;
     assert_eq!(
         a.into_repr(),
         FsRepr([
-            0xbc1a7511967bf667,
-            0xc5a55341caa4b32f,
-            0x075611bce1b4335e,
-            0x00000000000000c0,
+            0x67, 0xf6, 0x7b, 0x96, 0x11, 0x75, 0x1a, 0xbc, 0x2f, 0xb3, 0xa4, 0xca, 0x41, 0x53,
+            0xa5, 0xc5, 0x5e, 0x33, 0xb4, 0xe1, 0xbc, 0x11, 0x56, 0x07, 0xc0, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00,
         ])
     );
     a = a >> 130;
     assert_eq!(
         a.into_repr(),
         FsRepr([
-            0x01d5846f386d0cd7,
-            0x0000000000000030,
-            0x0000000000000000,
-            0x0000000000000000,
+            0xd7, 0x0c, 0x6d, 0x38, 0x6f, 0x84, 0xd5, 0x01, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00,
         ])
     );
     a = a >> 64;
     assert_eq!(
         a.into_repr(),
         FsRepr([
-            0x0000000000000030,
-            0x0000000000000000,
-            0x0000000000000000,
-            0x0000000000000000,
+            0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00,
         ])
     );
 }
 
 #[test]
-fn test_fr_squaring() {
-    let a = Fs(FsRepr([
+fn test_fs_squaring() {
+    let a = Fs([
         0xffffffffffffffff,
         0xffffffffffffffff,
         0xffffffffffffffff,
         0xe7db4ea6533afa8,
-    ]));
+    ]);
     assert!(a.is_valid());
     assert_eq!(
         a.square(),
         Fs::from_repr(FsRepr([
-            0x12c7f55cbc52fbaa,
-            0xdedc98a0b5e6ce9e,
-            0xad2892726a5396a,
-            0x9fe82af8fee77b3
+            0xaa, 0xfb, 0x52, 0xbc, 0x5c, 0xf5, 0xc7, 0x12, 0x9e, 0xce, 0xe6, 0xb5, 0xa0, 0x98,
+            0xdc, 0xde, 0x6a, 0x39, 0xa5, 0x26, 0x27, 0x89, 0xd2, 0x0a, 0xb3, 0x77, 0xee, 0x8f,
+            0xaf, 0x82, 0xfe, 0x09,
         ]))
         .unwrap()
     );
@@ -1658,42 +1221,39 @@ fn test_fs_sqrt() {
 fn test_fs_from_into_repr() {
     // r + 1 should not be in the field
     assert!(Fs::from_repr(FsRepr([
-        0xd0970e5ed6f72cb8,
-        0xa6682093ccc81082,
-        0x6673b0101343b00,
-        0xe7db4ea6533afa9
+        0xb8, 0x2c, 0xf7, 0xd6, 0x5e, 0x0e, 0x97, 0xd0, 0x82, 0x10, 0xc8, 0xcc, 0x93, 0x20, 0x68,
+        0xa6, 0x00, 0x3b, 0x34, 0x01, 0x01, 0x3b, 0x67, 0x06, 0xa9, 0xaf, 0x33, 0x65, 0xea, 0xb4,
+        0x7d, 0x0e,
     ]))
-    .is_err());
+    .is_none());
 
     // r should not be in the field
-    assert!(Fs::from_repr(Fs::char()).is_err());
+    assert!(Fs::from_repr(Fs::char()).is_none());
 
     // Multiply some arbitrary representations to see if the result is as expected.
-    let a = FsRepr([
-        0x5f2d0c05d0337b71,
-        0xa1df2b0f8a20479,
-        0xad73785e71bb863,
-        0x504a00480c9acec,
-    ]);
-    let mut a_fs = Fs::from_repr(a).unwrap();
-    let b = FsRepr([
-        0x66356ff51e477562,
-        0x60a92ab55cf7603,
-        0x8e4273c7364dd192,
-        0x36df8844a344dc5,
-    ]);
-    let b_fs = Fs::from_repr(b).unwrap();
-    let c = FsRepr([
-        0x7eef61708f4f2868,
-        0x747a7e6cf52946fb,
-        0x83dd75d7c9120017,
-        0x762f5177f0f3df7,
-    ]);
+    let mut a_fs = Fs::from_repr(FsRepr([
+        0x71, 0x7b, 0x33, 0xd0, 0x05, 0x0c, 0x2d, 0x5f, 0x79, 0x04, 0xa2, 0xf8, 0xb0, 0xf2, 0x1d,
+        0x0a, 0x63, 0xb8, 0x1b, 0xe7, 0x85, 0x37, 0xd7, 0x0a, 0xec, 0xac, 0xc9, 0x80, 0x04, 0xa0,
+        0x04, 0x05,
+    ]))
+    .unwrap();
+    let b_fs = Fs::from_repr(FsRepr([
+        0x62, 0x75, 0x47, 0x1e, 0xf5, 0x6f, 0x35, 0x66, 0x03, 0x76, 0xcf, 0x55, 0xab, 0x92, 0x0a,
+        0x06, 0x92, 0xd1, 0x4d, 0x36, 0xc7, 0x73, 0x42, 0x8e, 0xc5, 0x4d, 0x34, 0x4a, 0x84, 0xf8,
+        0x6d, 0x03,
+    ]))
+    .unwrap();
+    let c_fs = Fs::from_repr(FsRepr([
+        0x68, 0x28, 0x4f, 0x8f, 0x70, 0x61, 0xef, 0x7e, 0xfb, 0x46, 0x29, 0xf5, 0x6c, 0x7e, 0x7a,
+        0x74, 0x17, 0x00, 0x12, 0xc9, 0xd7, 0x75, 0xdd, 0x83, 0xf7, 0x3d, 0x0f, 0x7f, 0x17, 0xf5,
+        0x62, 0x07,
+    ]))
+    .unwrap();
     a_fs.mul_assign(&b_fs);
-    assert_eq!(a_fs.into_repr(), c);
+    assert_eq!(a_fs, c_fs);
 
     // Zero should be in the field.
-    assert!(Fs::from_repr(FsRepr::from(0)).unwrap().is_zero());
+    assert!(Fs::from_repr(FsRepr::default()).unwrap().is_zero());
 
     let mut rng = XorShiftRng::from_seed([
         0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
@@ -1712,60 +1272,15 @@ fn test_fs_from_into_repr() {
     }
 }
 
-#[test]
-fn test_fs_repr_display() {
-    assert_eq!(
-        format!(
-            "{}",
-            FsRepr([
-                0xa296db59787359df,
-                0x8d3e33077430d318,
-                0xd1abf5c606102eb7,
-                0xcbc33ee28108f0
-            ])
-        ),
-        "0x00cbc33ee28108f0d1abf5c606102eb78d3e33077430d318a296db59787359df".to_string()
-    );
-    assert_eq!(
-        format!(
-            "{}",
-            FsRepr([
-                0x14cb03535054a620,
-                0x312aa2bf2d1dff52,
-                0x970fe98746ab9361,
-                0xc1e18acf82711e6
-            ])
-        ),
-        "0x0c1e18acf82711e6970fe98746ab9361312aa2bf2d1dff5214cb03535054a620".to_string()
-    );
-    assert_eq!(
-        format!(
-            "{}",
-            FsRepr([
-                0xffffffffffffffff,
-                0xffffffffffffffff,
-                0xffffffffffffffff,
-                0xffffffffffffffff
-            ])
-        ),
-        "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".to_string()
-    );
-    assert_eq!(
-        format!("{}", FsRepr([0, 0, 0, 0])),
-        "0x0000000000000000000000000000000000000000000000000000000000000000".to_string()
-    );
-}
-
 #[test]
 fn test_fs_display() {
     assert_eq!(
         format!(
             "{}",
             Fs::from_repr(FsRepr([
-                0x5528efb9998a01a3,
-                0x5bd2add5cb357089,
-                0xc061fa6adb491f98,
-                0x70db9d143db03d9
+                0xa3, 0x01, 0x8a, 0x99, 0xb9, 0xef, 0x28, 0x55, 0x89, 0x70, 0x35, 0xcb, 0xd5, 0xad,
+                0xd2, 0x5b, 0x98, 0x1f, 0x49, 0xdb, 0x6a, 0xfa, 0x61, 0xc0, 0xd9, 0x03, 0xdb, 0x43,
+                0xd1, 0xb9, 0x0d, 0x07,
             ]))
             .unwrap()
         ),
@@ -1775,10 +1290,9 @@ fn test_fs_display() {
         format!(
             "{}",
             Fs::from_repr(FsRepr([
-                0xd674745e2717999e,
-                0xbeb1f52d3e96f338,
-                0x9c7ae147549482b9,
-                0x999706024530d22
+                0x9e, 0x99, 0x17, 0x27, 0x5e, 0x74, 0x74, 0xd6, 0x38, 0xf3, 0x96, 0x3e, 0x2d, 0xf5,
+                0xb1, 0xbe, 0xb9, 0x82, 0x94, 0x54, 0x47, 0xe1, 0x7a, 0x9c, 0x22, 0x0d, 0x53, 0x24,
+                0x60, 0x70, 0x99, 0x09,
             ]))
             .unwrap()
         ),
diff --git a/zcash_primitives/src/jubjub/montgomery.rs b/zcash_primitives/src/jubjub/montgomery.rs
index 0992637..372f686 100644
--- a/zcash_primitives/src/jubjub/montgomery.rs
+++ b/zcash_primitives/src/jubjub/montgomery.rs
@@ -304,7 +304,7 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
 
         let mut res = Self::zero();
 
-        for b in BitIterator::<u64, _>::new(scalar.into()) {
+        for b in BitIterator::<u8, _>::new(scalar.into()) {
             res = res.double(params);
 
             if b {
diff --git a/zcash_primitives/src/keys.rs b/zcash_primitives/src/keys.rs
index 76914ba..2f067a2 100644
--- a/zcash_primitives/src/keys.rs
+++ b/zcash_primitives/src/keys.rs
@@ -9,7 +9,7 @@ use crate::{
     primitives::{ProofGenerationKey, ViewingKey},
 };
 use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
-use ff::{PrimeField, PrimeFieldRepr};
+use ff::PrimeField;
 use std::io::{self, Read, Write};
 
 pub const PRF_EXPAND_PERSONALIZATION: &[u8; 16] = b"Zcash_ExpandSeed";
@@ -71,14 +71,14 @@ impl<E: JubjubEngine> ExpandedSpendingKey<E> {
 
     pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
         let mut ask_repr = <E::Fs as PrimeField>::Repr::default();
-        ask_repr.read_le(&mut reader)?;
+        reader.read_exact(ask_repr.as_mut())?;
         let ask = E::Fs::from_repr(ask_repr)
-            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "ask not in field"))?;
 
         let mut nsk_repr = <E::Fs as PrimeField>::Repr::default();
-        nsk_repr.read_le(&mut reader)?;
+        reader.read_exact(nsk_repr.as_mut())?;
         let nsk = E::Fs::from_repr(nsk_repr)
-            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
+            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "nsk not in field"))?;
 
         let mut ovk = [0; 32];
         reader.read_exact(&mut ovk)?;
@@ -91,8 +91,8 @@ impl<E: JubjubEngine> ExpandedSpendingKey<E> {
     }
 
     pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
-        self.ask.into_repr().write_le(&mut writer)?;
-        self.nsk.into_repr().write_le(&mut writer)?;
+        writer.write_all(self.ask.into_repr().as_ref())?;
+        writer.write_all(self.nsk.into_repr().as_ref())?;
         writer.write_all(&self.ovk.0)?;
 
         Ok(())
diff --git a/zcash_primitives/src/merkle_tree.rs b/zcash_primitives/src/merkle_tree.rs
index 53600e5..a3fc1fc 100644
--- a/zcash_primitives/src/merkle_tree.rs
+++ b/zcash_primitives/src/merkle_tree.rs
@@ -511,9 +511,9 @@ mod tests {
     use super::{CommitmentTree, Hashable, IncrementalWitness, MerklePath, PathFiller};
     use crate::sapling::Node;
 
-    use ff::PrimeFieldRepr;
     use hex;
     use pairing::bls12_381::FrRepr;
+    use std::convert::TryInto;
     use std::io::{self, Read, Write};
 
     const HEX_EMPTY_ROOTS: [&str; 33] = [
@@ -1016,9 +1016,7 @@ mod tests {
         let mut paths_i = 0;
         let mut witness_ser_i = 0;
         for i in 0..16 {
-            let mut cm = FrRepr::default();
-            cm.read_le(&hex::decode(commitments[i]).unwrap()[..])
-                .expect("length is 32 bytes");
+            let cm = FrRepr(hex::decode(commitments[i]).unwrap()[..].try_into().unwrap());
 
             let cm = Node::new(cm);
 
diff --git a/zcash_primitives/src/note_encryption.rs b/zcash_primitives/src/note_encryption.rs
index 747bd8d..539ee64 100644
--- a/zcash_primitives/src/note_encryption.rs
+++ b/zcash_primitives/src/note_encryption.rs
@@ -11,9 +11,10 @@ use crate::{
 use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
 use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
 use crypto_api_chachapoly::{ChaCha20Ietf, ChachaPolyIetf};
-use ff::{PrimeField, PrimeFieldRepr};
+use ff::PrimeField;
 use pairing::bls12_381::{Bls12, Fr};
 use rand_core::{CryptoRng, RngCore};
+use std::convert::TryInto;
 use std::fmt;
 use std::str;
 
@@ -192,7 +193,7 @@ fn prf_ock(
     let mut ock_input = [0u8; 128];
     ock_input[0..32].copy_from_slice(&ovk.0);
     cv.write(&mut ock_input[32..64]).unwrap();
-    cmu.into_repr().write_le(&mut ock_input[64..96]).unwrap();
+    ock_input[64..96].copy_from_slice(cmu.into_repr().as_ref());
     epk.write(&mut ock_input[96..128]).unwrap();
 
     Blake2bParams::new()
@@ -302,11 +303,7 @@ impl SaplingNoteEncryption {
         (&mut input[12..20])
             .write_u64::<LittleEndian>(self.note.value)
             .unwrap();
-        self.note
-            .r
-            .into_repr()
-            .write_le(&mut input[20..COMPACT_NOTE_SIZE])
-            .unwrap();
+        input[20..COMPACT_NOTE_SIZE].copy_from_slice(self.note.r.into_repr().as_ref());
         input[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE].copy_from_slice(&self.memo.0);
 
         let mut output = [0u8; ENC_CIPHERTEXT_SIZE];
@@ -330,10 +327,7 @@ impl SaplingNoteEncryption {
 
         let mut input = [0u8; OUT_PLAINTEXT_SIZE];
         self.note.pk_d.write(&mut input[0..32]).unwrap();
-        self.esk
-            .into_repr()
-            .write_le(&mut input[32..OUT_PLAINTEXT_SIZE])
-            .unwrap();
+        input[32..OUT_PLAINTEXT_SIZE].copy_from_slice(self.esk.into_repr().as_ref());
 
         let mut output = [0u8; OUT_CIPHERTEXT_SIZE];
         assert_eq!(
@@ -363,9 +357,11 @@ fn parse_note_plaintext_without_memo(
 
     let v = (&plaintext[12..20]).read_u64::<LittleEndian>().ok()?;
 
-    let mut rcm = FsRepr::default();
-    rcm.read_le(&plaintext[20..COMPACT_NOTE_SIZE]).ok()?;
-    let rcm = Fs::from_repr(rcm).ok()?;
+    let rcm = Fs::from_repr(FsRepr(
+        plaintext[20..COMPACT_NOTE_SIZE]
+            .try_into()
+            .expect("slice is the correct length"),
+    ))?;
 
     let diversifier = Diversifier(d);
     let pk_d = diversifier
@@ -483,9 +479,11 @@ pub fn try_sapling_output_recovery(
         .ok()?
         .as_prime_order(&JUBJUB)?;
 
-    let mut esk = FsRepr::default();
-    esk.read_le(&op[32..OUT_PLAINTEXT_SIZE]).ok()?;
-    let esk = Fs::from_repr(esk).ok()?;
+    let esk = Fs::from_repr(FsRepr(
+        op[32..OUT_PLAINTEXT_SIZE]
+            .try_into()
+            .expect("slice is the correct length"),
+    ))?;
 
     let shared_secret = sapling_ka_agree(&esk, &pk_d);
     let key = kdf_sapling(shared_secret, &epk);
@@ -515,9 +513,11 @@ pub fn try_sapling_output_recovery(
 
     let v = (&plaintext[12..20]).read_u64::<LittleEndian>().ok()?;
 
-    let mut rcm = FsRepr::default();
-    rcm.read_le(&plaintext[20..COMPACT_NOTE_SIZE]).ok()?;
-    let rcm = Fs::from_repr(rcm).ok()?;
+    let rcm = Fs::from_repr(FsRepr(
+        plaintext[20..COMPACT_NOTE_SIZE]
+            .try_into()
+            .expect("slice is the correct length"),
+    ))?;
 
     let mut memo = [0u8; 512];
     memo.copy_from_slice(&plaintext[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE]);
@@ -554,10 +554,11 @@ mod tests {
         primitives::{Diversifier, PaymentAddress, ValueCommitment},
     };
     use crypto_api_chachapoly::ChachaPolyIetf;
-    use ff::{Field, PrimeField, PrimeFieldRepr};
+    use ff::{Field, PrimeField};
     use pairing::bls12_381::{Bls12, Fr, FrRepr};
     use rand_core::OsRng;
     use rand_core::{CryptoRng, RngCore};
+    use std::convert::TryInto;
     use std::str::FromStr;
 
     use super::{
@@ -791,9 +792,7 @@ mod tests {
             .as_prime_order(&JUBJUB)
             .unwrap();
 
-        let mut esk = FsRepr::default();
-        esk.read_le(&op[32..OUT_PLAINTEXT_SIZE]).unwrap();
-        let esk = Fs::from_repr(esk).unwrap();
+        let esk = Fs::from_repr(FsRepr(op[32..OUT_PLAINTEXT_SIZE].try_into().unwrap())).unwrap();
 
         let shared_secret = sapling_ka_agree(&esk, &pk_d);
         let key = kdf_sapling(shared_secret, &epk);
@@ -1292,17 +1291,13 @@ mod tests {
 
         macro_rules! read_fr {
             ($field:expr) => {{
-                let mut repr = FrRepr::default();
-                repr.read_le(&$field[..]).unwrap();
-                Fr::from_repr(repr).unwrap()
+                Fr::from_repr(FrRepr($field[..].try_into().unwrap())).unwrap()
             }};
         }
 
         macro_rules! read_fs {
             ($field:expr) => {{
-                let mut repr = FsRepr::default();
-                repr.read_le(&$field[..]).unwrap();
-                Fs::from_repr(repr).unwrap()
+                Fs::from_repr(FsRepr($field[..].try_into().unwrap())).unwrap()
             }};
         }
 
diff --git a/zcash_primitives/src/primitives.rs b/zcash_primitives/src/primitives.rs
index 6e01a10..cd06a60 100644
--- a/zcash_primitives/src/primitives.rs
+++ b/zcash_primitives/src/primitives.rs
@@ -1,6 +1,6 @@
 //! Structs for core Zcash primitives.
 
-use ff::{Field, PrimeField, PrimeFieldRepr};
+use ff::{Field, PrimeField};
 
 use crate::constants;
 
@@ -86,7 +86,7 @@ impl<E: JubjubEngine> ViewingKey<E> {
         h[31] &= 0b0000_0111;
 
         let mut e = <E::Fs as PrimeField>::Repr::default();
-        e.read_le(&h[..]).unwrap();
+        e.as_mut().copy_from_slice(&h[..]);
 
         E::Fs::from_repr(e).expect("should be a valid scalar")
     }
diff --git a/zcash_primitives/src/redjubjub.rs b/zcash_primitives/src/redjubjub.rs
index fcc3900..c816ddf 100644
--- a/zcash_primitives/src/redjubjub.rs
+++ b/zcash_primitives/src/redjubjub.rs
@@ -4,23 +4,23 @@
 //! [RedJubjub]: https://zips.z.cash/protocol/protocol.pdf#concretereddsa
 
 use crate::jubjub::{edwards::Point, FixedGenerators, JubjubEngine, JubjubParams, Unknown};
-use ff::{Field, PrimeField, PrimeFieldRepr};
+use ff::{Field, PrimeField};
 use rand_core::RngCore;
 use std::io::{self, Read, Write};
 use std::ops::{AddAssign, MulAssign, Neg};
 
 use crate::util::hash_to_scalar;
 
-fn read_scalar<E: JubjubEngine, R: Read>(reader: R) -> io::Result<E::Fs> {
+fn read_scalar<E: JubjubEngine, R: Read>(mut reader: R) -> io::Result<E::Fs> {
     let mut s_repr = <E::Fs as PrimeField>::Repr::default();
-    s_repr.read_le(reader)?;
+    reader.read_exact(s_repr.as_mut())?;
 
     E::Fs::from_repr(s_repr)
-        .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "scalar is not in field"))
+        .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "scalar is not in field"))
 }
 
-fn write_scalar<E: JubjubEngine, W: Write>(s: &E::Fs, writer: W) -> io::Result<()> {
-    s.into_repr().write_le(writer)
+fn write_scalar<E: JubjubEngine, W: Write>(s: &E::Fs, mut writer: W) -> io::Result<()> {
+    writer.write_all(s.into_repr().as_ref())
 }
 
 fn h_star<E: JubjubEngine>(a: &[u8], b: &[u8]) -> E::Fs {
diff --git a/zcash_primitives/src/sapling.rs b/zcash_primitives/src/sapling.rs
index ecf5cd4..4582fe6 100644
--- a/zcash_primitives/src/sapling.rs
+++ b/zcash_primitives/src/sapling.rs
@@ -5,7 +5,7 @@ use crate::{
     pedersen_hash::{pedersen_hash, Personalization},
     primitives::Note,
 };
-use ff::{BitIterator, PrimeField, PrimeFieldRepr};
+use ff::{BitIterator, PrimeField};
 use lazy_static::lazy_static;
 use pairing::bls12_381::{Bls12, Fr, FrRepr};
 use rand_core::{CryptoRng, RngCore};
@@ -21,7 +21,7 @@ pub const SAPLING_COMMITMENT_TREE_DEPTH: usize = 32;
 pub fn merkle_hash(depth: usize, lhs: &FrRepr, rhs: &FrRepr) -> FrRepr {
     let lhs = {
         let mut tmp = [false; 256];
-        for (a, b) in tmp.iter_mut().rev().zip(BitIterator::<u64, _>::new(lhs)) {
+        for (a, b) in tmp.iter_mut().rev().zip(BitIterator::<u8, _>::new(lhs)) {
             *a = b;
         }
         tmp
@@ -29,7 +29,7 @@ pub fn merkle_hash(depth: usize, lhs: &FrRepr, rhs: &FrRepr) -> FrRepr {
 
     let rhs = {
         let mut tmp = [false; 256];
-        for (a, b) in tmp.iter_mut().rev().zip(BitIterator::<u64, _>::new(rhs)) {
+        for (a, b) in tmp.iter_mut().rev().zip(BitIterator::<u8, _>::new(rhs)) {
             *a = b;
         }
         tmp
@@ -62,13 +62,13 @@ impl Node {
 
 impl Hashable for Node {
     fn read<R: Read>(mut reader: R) -> io::Result<Self> {
-        let mut repr = FrRepr::default();
-        repr.read_le(&mut reader)?;
+        let mut repr = FrRepr([0; 32]);
+        reader.read_exact(&mut repr.0)?;
         Ok(Node::new(repr))
     }
 
     fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
-        self.repr.write_le(&mut writer)
+        writer.write_all(self.repr.as_ref())
     }
 
     fn combine(depth: usize, lhs: &Self, rhs: &Self) -> Self {
diff --git a/zcash_primitives/src/transaction/components.rs b/zcash_primitives/src/transaction/components.rs
index dfc54fd..d53ee7f 100644
--- a/zcash_primitives/src/transaction/components.rs
+++ b/zcash_primitives/src/transaction/components.rs
@@ -2,7 +2,7 @@
 
 use crate::jubjub::{edwards, Unknown};
 use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
-use ff::{PrimeField, PrimeFieldRepr};
+use ff::PrimeField;
 use pairing::bls12_381::{Bls12, Fr, FrRepr};
 use std::io::{self, Read, Write};
 
@@ -138,9 +138,10 @@ impl SpendDescription {
 
         // Consensus rule (§7.3): Canonical encoding is enforced here
         let anchor = {
-            let mut f = FrRepr::default();
-            f.read_le(&mut reader)?;
-            Fr::from_repr(f).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?
+            let mut f = FrRepr([0; 32]);
+            reader.read_exact(&mut f.0)?;
+            Fr::from_repr(f)
+                .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "anchor not in field"))?
         };
 
         let mut nullifier = [0; 32];
@@ -175,7 +176,7 @@ impl SpendDescription {
 
     pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
         self.cv.write(&mut writer)?;
-        self.anchor.into_repr().write_le(&mut writer)?;
+        writer.write_all(self.anchor.into_repr().as_ref())?;
         writer.write_all(&self.nullifier)?;
         self.rk.write(&mut writer)?;
         writer.write_all(&self.zkproof)?;
@@ -218,9 +219,10 @@ impl OutputDescription {
 
         // Consensus rule (§7.4): Canonical encoding is enforced here
         let cmu = {
-            let mut f = FrRepr::default();
-            f.read_le(&mut reader)?;
-            Fr::from_repr(f).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?
+            let mut f = FrRepr([0; 32]);
+            reader.read_exact(&mut f.0)?;
+            Fr::from_repr(f)
+                .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "cmu not in field"))?
         };
 
         // Consensus rules (§4.5):
@@ -252,7 +254,7 @@ impl OutputDescription {
 
     pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
         self.cv.write(&mut writer)?;
-        self.cmu.into_repr().write_le(&mut writer)?;
+        writer.write_all(self.cmu.into_repr().as_ref())?;
         self.ephemeral_key.write(&mut writer)?;
         writer.write_all(&self.enc_ciphertext)?;
         writer.write_all(&self.out_ciphertext)?;
diff --git a/zcash_primitives/src/transaction/sighash.rs b/zcash_primitives/src/transaction/sighash.rs
index 4319f41..c77c2d0 100644
--- a/zcash_primitives/src/transaction/sighash.rs
+++ b/zcash_primitives/src/transaction/sighash.rs
@@ -1,6 +1,6 @@
 use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
 use byteorder::{LittleEndian, WriteBytesExt};
-use ff::{PrimeField, PrimeFieldRepr};
+use ff::PrimeField;
 
 use super::{
     components::{Amount, TxOut},
@@ -128,7 +128,7 @@ fn shielded_spends_hash(tx: &TransactionData) -> Blake2bHash {
     let mut data = Vec::with_capacity(tx.shielded_spends.len() * 384);
     for s_spend in &tx.shielded_spends {
         s_spend.cv.write(&mut data).unwrap();
-        s_spend.anchor.into_repr().write_le(&mut data).unwrap();
+        data.extend_from_slice(s_spend.anchor.into_repr().as_ref());
         data.extend_from_slice(&s_spend.nullifier);
         s_spend.rk.write(&mut data).unwrap();
         data.extend_from_slice(&s_spend.zkproof);
diff --git a/zcash_primitives/src/zip32.rs b/zcash_primitives/src/zip32.rs
index e34767b..a02457f 100644
--- a/zcash_primitives/src/zip32.rs
+++ b/zcash_primitives/src/zip32.rs
@@ -453,7 +453,7 @@ impl ExtendedFullViewingKey {
 mod tests {
     use super::*;
 
-    use ff::{PrimeField, PrimeFieldRepr};
+    use ff::PrimeField;
 
     #[test]
     fn derive_nonhardened_child() {
@@ -1014,11 +1014,8 @@ mod tests {
             let xsk = &xsks[j];
             let tv = &test_vectors[j];
 
-            let mut buf = [0; 32];
-            xsk.expsk.ask.into_repr().write_le(&mut buf[..]).unwrap();
-            assert_eq!(buf, tv.ask.unwrap());
-            xsk.expsk.nsk.into_repr().write_le(&mut buf[..]).unwrap();
-            assert_eq!(buf, tv.nsk.unwrap());
+            assert_eq!(xsk.expsk.ask.into_repr().as_ref(), tv.ask.unwrap());
+            assert_eq!(xsk.expsk.nsk.into_repr().as_ref(), tv.nsk.unwrap());
 
             assert_eq!(xsk.expsk.ovk.0, tv.ovk);
             assert_eq!(xsk.dk.0, tv.dk);
@@ -1043,13 +1040,7 @@ mod tests {
             assert_eq!(xfvk.dk.0, tv.dk);
             assert_eq!(xfvk.chain_code.0, tv.c);
 
-            xfvk.fvk
-                .vk
-                .ivk()
-                .into_repr()
-                .write_le(&mut buf[..])
-                .unwrap();
-            assert_eq!(buf, tv.ivk);
+            assert_eq!(xfvk.fvk.vk.ivk().into_repr().as_ref(), tv.ivk);
 
             let mut ser = vec![];
             xfvk.write(&mut ser).unwrap();
diff --git a/zcash_proofs/src/circuit/ecc.rs b/zcash_proofs/src/circuit/ecc.rs
index 01ed2d4..59eb761 100644
--- a/zcash_proofs/src/circuit/ecc.rs
+++ b/zcash_proofs/src/circuit/ecc.rs
@@ -769,7 +769,7 @@ mod test {
             let q = p.mul(s, params);
             let (x1, y1) = q.to_xy();
 
-            let mut s_bits = BitIterator::<u64, _>::new(s.into_repr()).collect::<Vec<_>>();
+            let mut s_bits = BitIterator::<u8, _>::new(s.into_repr()).collect::<Vec<_>>();
             s_bits.reverse();
             s_bits.truncate(Fs::NUM_BITS as usize);
 
@@ -822,7 +822,7 @@ mod test {
                 y: num_y0,
             };
 
-            let mut s_bits = BitIterator::<u64, _>::new(s.into_repr()).collect::<Vec<_>>();
+            let mut s_bits = BitIterator::<u8, _>::new(s.into_repr()).collect::<Vec<_>>();
             s_bits.reverse();
             s_bits.truncate(Fs::NUM_BITS as usize);
 
diff --git a/zcash_proofs/src/circuit/sapling.rs b/zcash_proofs/src/circuit/sapling.rs
index 7d1fbba..5e6c05f 100644
--- a/zcash_proofs/src/circuit/sapling.rs
+++ b/zcash_proofs/src/circuit/sapling.rs
@@ -615,8 +615,8 @@ fn test_input_circuit_with_bls12_381() {
                     ::std::mem::swap(&mut lhs, &mut rhs);
                 }
 
-                let mut lhs: Vec<bool> = BitIterator::<u64, _>::new(lhs.into_repr()).collect();
-                let mut rhs: Vec<bool> = BitIterator::<u64, _>::new(rhs.into_repr()).collect();
+                let mut lhs: Vec<bool> = BitIterator::<u8, _>::new(lhs.into_repr()).collect();
+                let mut rhs: Vec<bool> = BitIterator::<u8, _>::new(rhs.into_repr()).collect();
 
                 lhs.reverse();
                 rhs.reverse();
@@ -799,8 +799,8 @@ fn test_input_circuit_with_bls12_381_external_test_vectors() {
                     ::std::mem::swap(&mut lhs, &mut rhs);
                 }
 
-                let mut lhs: Vec<bool> = BitIterator::<u64, _>::new(lhs.into_repr()).collect();
-                let mut rhs: Vec<bool> = BitIterator::<u64, _>::new(rhs.into_repr()).collect();
+                let mut lhs: Vec<bool> = BitIterator::<u8, _>::new(lhs.into_repr()).collect();
+                let mut rhs: Vec<bool> = BitIterator::<u8, _>::new(rhs.into_repr()).collect();
 
                 lhs.reverse();
                 rhs.reverse();