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.
This commit is contained in:
Jack Grigg
2020-04-23 17:32:04 +12:00
parent 1fe3e3784c
commit 49f119fb03
35 changed files with 1705 additions and 3634 deletions

View File

@@ -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 {

File diff suppressed because it is too large Load Diff

View File

@@ -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 {

View File

@@ -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(())

View File

@@ -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);

View File

@@ -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()
}};
}

View File

@@ -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")
}

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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)?;

View File

@@ -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);

View File

@@ -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();