diff --git a/src/client.rs b/src/client.rs index 173091475..ca3a9676d 100644 --- a/src/client.rs +++ b/src/client.rs @@ -28,7 +28,7 @@ impl Client { pub fn new(dimension: usize, public_key1: PublicKey, public_key2: PublicKey) -> Option { let n = (dimension + 1).next_power_of_two(); - if 2 * n > N_ROOTS as usize { + if 2 * n > Field::num_roots() as usize { // too many elements for this field, not enough roots of unity return None; } diff --git a/src/finite_field.rs b/src/finite_field.rs index 3dc36fffa..0134a179a 100644 --- a/src/finite_field.rs +++ b/src/finite_field.rs @@ -3,7 +3,12 @@ //! Finite field arithmetic over a prime field using a 32bit prime. -use crate::fp::FieldParameters; +use crate::fp::{FP126, FP32, FP64, FP80}; +use std::{ + convert::TryFrom, + fmt::{Display, Formatter}, + ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}, +}; /// Possible errors from finite field operations. #[derive(Debug, thiserror::Error)] @@ -13,153 +18,253 @@ pub enum FiniteFieldError { InputSizeMismatch, } -/// Newtype wrapper over u128 -/// -/// Implements the arithmetic over the finite prime field -#[derive(Clone, Copy, Debug, PartialOrd, Ord, Hash, Default)] -pub struct Field(u128); - -/// Parameters for GF(2^32 - 2^20 + 1). -pub(crate) const SMALL_FP: FieldParameters = FieldParameters { - p: 4293918721, - p2: 8587837442, - mu: 17302828673139736575, - r2: 1676699750, -}; - -/// Modulus for the field, a FFT friendly prime: 2^32 - 2^20 + 1 -pub const MODULUS: u32 = SMALL_FP.p as u32; -/// Generator for the multiplicative subgroup -pub(crate) const GENERATOR: u32 = 3925978153; -/// Number of primitive roots -pub(crate) const N_ROOTS: u32 = 1 << 20; // number of primitive roots - -impl std::ops::Add for Field { - type Output = Field; - - fn add(self, rhs: Self) -> Self { - Self(SMALL_FP.add(self.0, rhs.0)) - } -} - -impl std::ops::AddAssign for Field { - fn add_assign(&mut self, rhs: Self) { - *self = *self + rhs; - } +/// Objects with this trait represent an element of `GF(p)` for some prime `p`. +pub trait FieldElement: + Sized + + PartialEq + + Eq + + Add + + AddAssign + + Sub + + SubAssign + + Mul + + MulAssign + + Div + + DivAssign + + Neg + + Display +{ + /// The integer representation of the field element. + type Integer; + + /// Modular exponentation, i.e., `self^exp (mod p)`. + fn pow(&self, exp: Self) -> Self; + + /// Modular inversion, i.e., `self^-1 (mod p)`. If `self` is 0, then the output is undefined. + fn inv(&self) -> Self; + + /// Returns the prime modulus `p`. + fn modulus() -> Self::Integer; + + /// Returns a generator of the multiplicative subgroup of size `FieldElement::num_roots()`. + fn generator() -> Self; + + /// Returns the size of the multiplicative subgroup generated by `FieldElement::generator()`. + fn num_roots() -> Self::Integer; } -impl std::ops::Sub for Field { - type Output = Field; - - fn sub(self, rhs: Self) -> Self { - Self(SMALL_FP.sub(self.0, rhs.0)) - } +macro_rules! make_field { + ( + $(#[$meta:meta])* + $elem:ident, $int:ident, $fp:ident + ) => { + $(#[$meta])* + #[derive(Clone, Copy, Debug, PartialOrd, Ord, Hash, Default)] + pub struct $elem(u128); + + impl PartialEq for $elem { + fn eq(&self, rhs: &Self) -> bool { + $fp.from_elem(self.0) == $fp.from_elem(rhs.0) + } + } + + impl Eq for $elem {} + + impl Add for $elem { + type Output = $elem; + fn add(self, rhs: Self) -> Self { + Self($fp.add(self.0, rhs.0)) + } + } + + impl Add for &$elem { + type Output = $elem; + fn add(self, rhs: Self) -> $elem { + *self + *rhs + } + } + + impl AddAssign for $elem { + fn add_assign(&mut self, rhs: Self) { + *self = *self + rhs; + } + } + + impl Sub for $elem { + type Output = $elem; + fn sub(self, rhs: Self) -> Self { + Self($fp.sub(self.0, rhs.0)) + } + } + + impl Sub for &$elem { + type Output = $elem; + fn sub(self, rhs: Self) -> $elem { + *self - *rhs + } + } + + impl SubAssign for $elem { + fn sub_assign(&mut self, rhs: Self) { + *self = *self - rhs; + } + } + + impl Mul for $elem { + type Output = $elem; + fn mul(self, rhs: Self) -> Self { + Self($fp.mul(self.0, rhs.0)) + } + } + + impl Mul for &$elem { + type Output = $elem; + fn mul(self, rhs: Self) -> $elem { + *self * *rhs + } + } + + impl MulAssign for $elem { + fn mul_assign(&mut self, rhs: Self) { + *self = *self * rhs; + } + } + + impl Div for $elem { + type Output = $elem; + fn div(self, rhs: Self) -> Self { + self * rhs.inv() + } + } + + impl Div for &$elem { + type Output = $elem; + fn div(self, rhs: Self) -> $elem { + *self / *rhs + } + } + + impl DivAssign for $elem { + fn div_assign(&mut self, rhs: Self) { + *self = *self / rhs; + } + } + + impl Neg for $elem { + type Output = $elem; + fn neg(self) -> Self { + Self($fp.neg(self.0)) + } + } + + impl Neg for &$elem { + type Output = $elem; + fn neg(self) -> $elem { + -(*self) + } + } + + impl From<$int> for $elem { + fn from(x: $int) -> Self { + Self($fp.elem(u128::try_from(x).unwrap())) + } + } + + impl From<$elem> for $int { + fn from(x: $elem) -> Self { + $int::try_from($fp.from_elem(x.0)).unwrap() + } + } + + impl PartialEq<$int> for $elem { + fn eq(&self, rhs: &$int) -> bool { + $fp.from_elem(self.0) == u128::try_from(*rhs).unwrap() + } + } + + impl Display for $elem { + fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { + write!(f, "{}", $fp.from_elem(self.0)) + } + } + + impl FieldElement for $elem { + type Integer = $int; + + fn pow(&self, exp: Self) -> Self { + Self($fp.pow(self.0, $fp.from_elem(exp.0))) + } + + fn inv(&self) -> Self { + Self($fp.inv(self.0)) + } + + fn modulus() -> Self::Integer { + $fp.p as $int + } + + fn generator() -> Self { + Self($fp.g) + } + + fn num_roots() -> Self::Integer { + $fp.num_roots as Self::Integer + } + } + }; } -impl std::ops::SubAssign for Field { - fn sub_assign(&mut self, rhs: Self) { - *self = *self - rhs; - } -} - -impl std::ops::Mul for Field { - type Output = Field; - - fn mul(self, rhs: Self) -> Self { - Self(SMALL_FP.mul(self.0, rhs.0)) - } -} - -impl std::ops::MulAssign for Field { - fn mul_assign(&mut self, rhs: Self) { - *self = *self * rhs; - } -} - -impl std::ops::Div for Field { - type Output = Field; - - fn div(self, rhs: Self) -> Self { - self * rhs.inv() - } -} - -impl std::ops::DivAssign for Field { - fn div_assign(&mut self, rhs: Self) { - *self = *self / rhs; - } -} - -impl PartialEq for Field { - fn eq(&self, rhs: &Self) -> bool { - SMALL_FP.from_elem(self.0) == SMALL_FP.from_elem(rhs.0) - } -} - -impl Eq for Field {} - -impl Field { - /// Modular exponentation - pub fn pow(self, exp: Self) -> Self { - Self(SMALL_FP.pow(self.0, SMALL_FP.from_elem(exp.0))) - } - - /// Modular inverse - /// - /// Note: inverse of 0 is defined as 0. - pub fn inv(self) -> Self { - Self(SMALL_FP.inv(self.0)) - } -} - -impl From for Field { - fn from(x: u32) -> Self { - Field(SMALL_FP.elem(x as u128)) - } -} - -impl From for u32 { - fn from(x: Field) -> Self { - SMALL_FP.from_elem(x.0) as u32 - } -} - -impl PartialEq for Field { - fn eq(&self, rhs: &u32) -> bool { - SMALL_FP.from_elem(self.0) == *rhs as u128 - } -} - -impl std::fmt::Display for Field { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", SMALL_FP.from_elem(self.0)) - } -} - -#[test] -fn test_small_fp() { - assert_eq!(SMALL_FP.check(), Ok(())); -} +// TODO(cjpatton) Rename this to Field32. +make_field!( + /// `GF(4293918721)`, a 32-bit field. The generator has order `2^20`. + Field, + u32, + FP32 +); + +make_field!( + /// `GF(15564440312192434177)`, a 64-bit field. The generator has order `2^59`. + Field64, + u64, + FP64 +); + +make_field!( + /// `GF(779190469673491460259841)`, an 80-bit field. The generator has order `2^72`. + Field80, + u128, + FP80 +); + +make_field!( + /// `GF(74769074762901517850839147140769382401)`, a 126-bit field. The generator has order `2^118`. + Field126, + u128, + FP126 +); #[test] fn test_arithmetic() { + // TODO(cjpatton) Add tests for Field64, Field80, and Field126. use rand::prelude::*; + let modulus = Field::modulus(); + // add - assert_eq!(Field::from(MODULUS - 1) + Field::from(1), 0); - assert_eq!(Field::from(MODULUS - 2) + Field::from(2), 0); - assert_eq!(Field::from(MODULUS - 2) + Field::from(3), 1); + assert_eq!(Field::from(modulus - 1) + Field::from(1), 0); + assert_eq!(Field::from(modulus - 2) + Field::from(2), 0); + assert_eq!(Field::from(modulus - 2) + Field::from(3), 1); assert_eq!(Field::from(1) + Field::from(1), 2); - assert_eq!(Field::from(2) + Field::from(MODULUS), 2); - assert_eq!(Field::from(3) + Field::from(MODULUS - 1), 2); + assert_eq!(Field::from(2) + Field::from(modulus), 2); + assert_eq!(Field::from(3) + Field::from(modulus - 1), 2); // sub - assert_eq!(Field::from(0) - Field::from(1), MODULUS - 1); - assert_eq!(Field::from(1) - Field::from(2), MODULUS - 1); + assert_eq!(Field::from(0) - Field::from(1), modulus - 1); + assert_eq!(Field::from(1) - Field::from(2), modulus - 1); assert_eq!(Field::from(15) - Field::from(3), 12); assert_eq!(Field::from(1) - Field::from(1), 0); - assert_eq!(Field::from(2) - Field::from(MODULUS), 2); - assert_eq!(Field::from(3) - Field::from(MODULUS - 1), 4); + assert_eq!(Field::from(2) - Field::from(modulus), 2); + assert_eq!(Field::from(3) - Field::from(modulus - 1), 4); // add + sub for _ in 0..100 { @@ -172,7 +277,7 @@ fn test_arithmetic() { // mul assert_eq!(Field::from(35) * Field::from(123), 4305); - assert_eq!(Field::from(1) * Field::from(MODULUS), 0); + assert_eq!(Field::from(1) * Field::from(modulus), 0); assert_eq!(Field::from(0) * Field::from(123), 0); assert_eq!(Field::from(123) * Field::from(0), 0); assert_eq!(Field::from(123123123) * Field::from(123123123), 1237630077); @@ -186,7 +291,7 @@ fn test_arithmetic() { assert_eq!(Field::from(0).inv(), 0); // mul and div - let uniform = rand::distributions::Uniform::from(1..MODULUS); + let uniform = rand::distributions::Uniform::from(1..modulus); let mut rng = thread_rng(); for _ in 0..100 { // non-zero element diff --git a/src/fp.rs b/src/fp.rs index 1ec49c8ef..027fe7674 100644 --- a/src/fp.rs +++ b/src/fp.rs @@ -3,11 +3,11 @@ //! Finite field arithmetic for any field GF(p) for which p < 2^126. -use rand::prelude::*; -use rand::Rng; +#[cfg(test)] +use rand::{prelude::*, Rng}; /// This structure represents the parameters of a finite field GF(p) for which p < 2^126. -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] pub(crate) struct FieldParameters { /// The prime modulus `p`. pub p: u128, @@ -17,8 +17,49 @@ pub(crate) struct FieldParameters { pub mu: u64, /// `r2 = (2^128)^2 mod p`. pub r2: u128, + /// The generator of a multiplicative subgroup of order `num_roots`. The value is mapped to the + /// Montgomeryh domain. + pub g: u128, + /// The order of the multiplicaitve subgroup of generated by `g`. + pub num_roots: u128, } +pub(crate) const FP32: FieldParameters = FieldParameters { + p: 4293918721, // 32-bit prime + p2: 8587837442, + mu: 17302828673139736575, + r2: 1676699750, + g: 1074114499, + num_roots: 1 << 20, +}; + +pub(crate) const FP64: FieldParameters = FieldParameters { + p: 15564440312192434177, // 64-bit prime + p2: 31128880624384868354, + mu: 15564440312192434175, + r2: 13031533328350459868, + g: 8693478717884812021, + num_roots: 1 << 59, +}; + +pub(crate) const FP80: FieldParameters = FieldParameters { + p: 779190469673491460259841, // 80-bit prime + p2: 1558380939346982920519682, + mu: 18446744073709551615, + r2: 699883506621195336351723, + g: 470015708362303528848629, + num_roots: 1 << 72, +}; + +pub(crate) const FP126: FieldParameters = FieldParameters { + p: 74769074762901517850839147140769382401, // 126-bit prime + p2: 149538149525803035701678294281538764802, + mu: 18446744073709551615, + r2: 27801541991839173768379182336352451464, + g: 63245316532470582112420298384754157617, + num_roots: 1 << 118, +}; + impl FieldParameters { /// Addition. pub fn add(&self, x: u128, y: u128) -> u128 { @@ -178,6 +219,7 @@ impl FieldParameters { } /// Returns a random field element mapped. + #[cfg(test)] pub fn rand_elem(&self, rng: &mut R) -> u128 { let uniform = rand::distributions::Uniform::from(0..self.p); self.elem(uniform.sample(rng)) @@ -194,17 +236,18 @@ impl FieldParameters { } /// Returns the number of bytes required to encode field elements. + #[cfg(test)] // This code is only used by tests for now. pub fn size(&self) -> usize { (16 - (self.p.leading_zeros() / 8)) as usize } #[cfg(test)] - pub fn check(&self) -> Result<(), &'static str> { + pub fn new(p: u128, g: u128, num_roots: u128) -> Result { use modinverse::modinverse; use num_bigint::{BigInt, ToBigInt}; let err_modulus_too_large = "p > 2^126"; - if let Some(x) = self.p.checked_next_power_of_two() { + if let Some(x) = p.checked_next_power_of_two() { if x > 1 << 126 { return Err(err_modulus_too_large); } @@ -212,19 +255,12 @@ impl FieldParameters { return Err(err_modulus_too_large); } - if self.p2 != self.p << 1 { - return Err("value of p2 is incorrect"); - } - - let mu = match modinverse((-(self.p as i128)).rem_euclid(1 << 64), 1 << 64) { + let mu = match modinverse((-(p as i128)).rem_euclid(1 << 64), 1 << 64) { Some(mu) => mu as u64, None => return Err("inverse of -p (mod 2^64) is undefined"), }; - if self.mu != mu { - return Err("value of mu is incorrect"); - } - let big_p = &self.p.to_bigint().unwrap(); + let big_p = &p.to_bigint().unwrap(); let big_r: &BigInt = &(&(BigInt::from(1) << 128) % big_p); let big_r2: &BigInt = &(&(big_r * big_r) % big_p); let mut it = big_r2.iter_u64_digits(); @@ -233,11 +269,18 @@ impl FieldParameters { if let Some(x) = it.next() { r2 |= (x as u128) << 64; } - if self.r2 != r2 { - return Err("value of r2 is not correct"); - } - Ok(()) + let mut fp = FieldParameters { + p: p, + p2: p << 1, + mu: mu, + r2: r2, + g: 0, + num_roots: num_roots, + }; + + fp.g = fp.elem(g); + Ok(fp) } } @@ -262,96 +305,110 @@ mod tests { use num_bigint::ToBigInt; struct TestFieldParametersData { - fp: FieldParameters, - expected_size: usize, + fp: FieldParameters, // The paramters being tested + expected_p: u128, // Expected fp.p + expected_g: u128, // Expected fp.from_elem(fp.g) + expected_order: u128, // Expect fp.from_elem(fp.pow(fp.g, expected_order)) == 1 + expected_size: usize, // expected fp.size() } #[test] fn test_fp() { - let mut rng = rand::thread_rng(); let test_fps = vec![ TestFieldParametersData { - fp: FieldParameters { - p: 4293918721, // 32-bit prime - p2: 8587837442, - mu: 17302828673139736575, - r2: 1676699750, - }, + fp: FP32, + expected_p: 4293918721, + expected_g: 3925978153, + expected_order: 1 << 20, expected_size: 4, }, TestFieldParametersData { - fp: FieldParameters { - p: 15564440312192434177, // 64-bit prime - p2: 31128880624384868354, - mu: 15564440312192434175, - r2: 13031533328350459868, - }, + fp: FP64, + expected_p: 15564440312192434177, + expected_g: 7450580596923828125, + expected_order: 1 << 59, expected_size: 8, }, TestFieldParametersData { - fp: FieldParameters { - p: 779190469673491460259841, // 80-bit prime - p2: 1558380939346982920519682, - mu: 18446744073709551615, - r2: 699883506621195336351723, - }, + fp: FP80, + expected_p: 779190469673491460259841, + expected_g: 41782115852031095118226, + expected_order: 1 << 72, expected_size: 10, }, TestFieldParametersData { - fp: FieldParameters { - p: 74769074762901517850839147140769382401, // 126-bit prime - p2: 149538149525803035701678294281538764802, - mu: 18446744073709551615, - r2: 27801541991839173768379182336352451464, - }, + fp: FP126, + expected_p: 74769074762901517850839147140769382401, + expected_g: 43421413544015439978138831414974882540, + expected_order: 1 << 118, expected_size: 16, }, ]; for t in test_fps.into_iter() { - let fp = t.fp; - assert_eq!(fp.size(), t.expected_size); - assert_eq!(fp.check(), Ok(())); - - // Test arithmetic. - let big_p = &fp.p.to_bigint().unwrap(); - for _ in 0..100 { - let x = fp.rand_elem(&mut rng); - let y = fp.rand_elem(&mut rng); - let big_x = &fp.from_elem(x).to_bigint().unwrap(); - let big_y = &fp.from_elem(y).to_bigint().unwrap(); - - // Test addition. - let got = fp.add(x, y); - let want = (big_x + big_y) % big_p; - assert_eq!(fp.from_elem(got).to_bigint().unwrap(), want); - - // Test subtraction. - let got = fp.sub(x, y); - let want = if big_x >= big_y { - big_x - big_y - } else { - big_p - big_y + big_x - }; - assert_eq!(fp.from_elem(got).to_bigint().unwrap(), want); - - // Test multiplication. - let got = fp.mul(x, y); - let want = (big_x * big_y) % big_p; - assert_eq!(fp.from_elem(got).to_bigint().unwrap(), want); - - // Test inversion. - let got = fp.inv(x); - let want = modinverse(fp.from_elem(x) as i128, fp.p as i128).unwrap(); - assert_eq!(fp.from_elem(got) as i128, want); - assert_eq!(fp.from_elem(fp.mul(got, x)), 1); - - // Test negation. - let got = fp.neg(x); - let want = (-(fp.from_elem(x) as i128)).rem_euclid(fp.p as i128); - assert_eq!(fp.from_elem(got) as i128, want); - assert_eq!(fp.from_elem(fp.add(got, x)), 0); - } + // Check that the field parameters have been constructed properly. + assert_eq!( + t.fp, + FieldParameters::new(t.expected_p, t.expected_g, t.expected_order).unwrap(), + "error for GF({})", + t.expected_p, + ); + + // Check that the field element size is computed correctly. + assert_eq!( + t.fp.size(), + t.expected_size, + "error for GF({})", + t.expected_p + ); + + // Check that the generator has the correct order. + assert_eq!(t.fp.from_elem(t.fp.pow(t.fp.g, t.expected_order)), 1); + + // Test arithmetic using the field parameters. + test_arithmetic(t.fp); + } + } + + fn test_arithmetic(fp: FieldParameters) { + let mut rng = rand::thread_rng(); + let big_p = &fp.p.to_bigint().unwrap(); + for _ in 0..100 { + let x = fp.rand_elem(&mut rng); + let y = fp.rand_elem(&mut rng); + let big_x = &fp.from_elem(x).to_bigint().unwrap(); + let big_y = &fp.from_elem(y).to_bigint().unwrap(); + + // Test addition. + let got = fp.add(x, y); + let want = (big_x + big_y) % big_p; + assert_eq!(fp.from_elem(got).to_bigint().unwrap(), want); + + // Test subtraction. + let got = fp.sub(x, y); + let want = if big_x >= big_y { + big_x - big_y + } else { + big_p - big_y + big_x + }; + assert_eq!(fp.from_elem(got).to_bigint().unwrap(), want); + + // Test multiplication. + let got = fp.mul(x, y); + let want = (big_x * big_y) % big_p; + assert_eq!(fp.from_elem(got).to_bigint().unwrap(), want); + + // Test inversion. + let got = fp.inv(x); + let want = modinverse(fp.from_elem(x) as i128, fp.p as i128).unwrap(); + assert_eq!(fp.from_elem(got) as i128, want); + assert_eq!(fp.from_elem(fp.mul(got, x)), 1); + + // Test negation. + let got = fp.neg(x); + let want = (-(fp.from_elem(x) as i128)).rem_euclid(fp.p as i128); + assert_eq!(fp.from_elem(got) as i128, want); + assert_eq!(fp.from_elem(fp.add(got, x)), 0); } } } diff --git a/src/polynomial.rs b/src/polynomial.rs index dcff40412..b546997e6 100644 --- a/src/polynomial.rs +++ b/src/polynomial.rs @@ -108,13 +108,13 @@ fn fft_recurse( /// Calculate `count` number of roots of unity of order `count` fn fft_get_roots(count: usize, invert: bool) -> Vec { let mut roots = vec![Field::from(0); count]; - let mut gen: Field = GENERATOR.into(); + let mut gen = Field::generator(); if invert { gen = gen.inv(); } roots[0] = 1.into(); - let step_size: u32 = N_ROOTS / (count as u32); + let step_size: u32 = (Field::num_roots() as u32) / (count as u32); // generator for subgroup of order count gen = gen.pow(step_size.into()); diff --git a/src/prng.rs b/src/prng.rs index b98df0352..de78b0e26 100644 --- a/src/prng.rs +++ b/src/prng.rs @@ -1,7 +1,7 @@ // Copyright (c) 2020 Apple Inc. // SPDX-License-Identifier: MPL-2.0 -use super::finite_field::{Field, MODULUS, SMALL_FP}; +use super::finite_field::{Field, FieldElement}; use aes_ctr::stream_cipher::generic_array::GenericArray; use aes_ctr::stream_cipher::NewStreamCipher; use aes_ctr::stream_cipher::SyncStreamCipher; @@ -61,9 +61,14 @@ fn random_field_from_seed(seed: &[u8], length: usize) -> Vec { cipher.apply_keystream(&mut buffer); // rejection sampling - for chunk in buffer.chunks_exact(SMALL_FP.size()) { - let integer = u32::from_le_bytes(chunk.try_into().unwrap()); - if integer < MODULUS { + // + // TODO(cjpatton): Once implemented, use FieldParameters::size() and + // FieldElement::form_bytes() to implement this loop. + let field_size = std::mem::size_of::<::Integer>(); + for chunk in buffer.chunks_exact(field_size) { + let integer = + ::Integer::from_le_bytes(chunk.try_into().unwrap()); + if integer < Field::modulus() { output[output_written] = Field::from(integer); output_written += 1; if output_written == length { diff --git a/src/util.rs b/src/util.rs index de717dd39..84382aa4e 100644 --- a/src/util.rs +++ b/src/util.rs @@ -3,7 +3,7 @@ //! Utility functions for handling Prio stuff. -use crate::finite_field::{Field, SMALL_FP}; +use crate::finite_field::{Field, FieldElement}; /// Convenience function for initializing fixed sized vectors of Field elements. pub fn vector_with_length(len: usize) -> Vec { @@ -97,11 +97,13 @@ pub fn unpack_proof_mut(proof: &mut [Field], dimension: usize) -> Option Vec { - let field_size = std::mem::size_of::(); + let field_size = std::mem::size_of::<::Integer>(); let mut vec = Vec::with_capacity(data.len() * field_size); for elem in data.iter() { - let int = u32::from(*elem); + // TODO(cjpatton) Implement FieldElement::bytes() that encodes each field element using + // FieldParameters::size() bytes. + let int = ::Integer::from(*elem); vec.extend(int.to_le_bytes().iter()); } @@ -110,13 +112,15 @@ pub fn serialize(data: &[Field]) -> Vec { /// Get a vector of field elements from a byte slice pub fn deserialize(data: &[u8]) -> Vec { - let field_size = SMALL_FP.size(); + let field_size = std::mem::size_of::<::Integer>(); let mut vec = Vec::with_capacity(data.len() / field_size); use std::convert::TryInto; for chunk in data.chunks_exact(field_size) { - let integer = u32::from_le_bytes(chunk.try_into().unwrap()); + // TODO(cjpatton) Implement FieldElement::from_bytes() that decodes field elements from a + // string with FieldParameters::size() bytes. + let integer = ::Integer::from_le_bytes(chunk.try_into().unwrap()); vec.push(Field::from(integer)); }