Skip to content

Commit

Permalink
Deprecate old field vector conversion methods (#863)
Browse files Browse the repository at this point in the history
  • Loading branch information
divergentdave authored Dec 4, 2023
1 parent 711aec2 commit 995a0e5
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 38 deletions.
32 changes: 21 additions & 11 deletions src/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ pub enum FieldError {
Io(#[from] std::io::Error),
/// Error encoding or decoding a field.
#[error("Codec error")]
Codec(#[from] CodecError),
#[deprecated]
Codec(CodecError),
/// Error converting to [`FieldElementWithInteger::Integer`].
#[error("Integer TryFrom error")]
IntegerTryFrom,
Expand Down Expand Up @@ -134,6 +135,7 @@ pub trait FieldElement:
/// Ideally we would implement `From<&[F: FieldElement]> for Vec<u8>` or the corresponding
/// `Into`, but the orphan rule and the stdlib's blanket implementations of `Into` make this
/// impossible.
#[deprecated]
fn slice_into_byte_vec(values: &[Self]) -> Vec<u8> {
let mut vec = Vec::with_capacity(values.len() * Self::ENCODED_SIZE);
encode_fieldvec(values, &mut vec);
Expand All @@ -154,13 +156,15 @@ pub trait FieldElement:
/// Ideally we would implement `From<&[u8]> for Vec<F: FieldElement>` or the corresponding
/// `Into`, but the orphan rule and the stdlib's blanket implementations of `Into` make this
/// impossible.
#[deprecated]
fn byte_slice_into_vec(bytes: &[u8]) -> Result<Vec<Self>, FieldError> {
if bytes.len() % Self::ENCODED_SIZE != 0 {
return Err(FieldError::ShortRead);
}
let mut vec = Vec::with_capacity(bytes.len() / Self::ENCODED_SIZE);
for chunk in bytes.chunks_exact(Self::ENCODED_SIZE) {
vec.push(Self::get_decoded(chunk)?);
#[allow(deprecated)]
vec.push(Self::get_decoded(chunk).map_err(FieldError::Codec)?);
}
Ok(vec)
}
Expand Down Expand Up @@ -1026,9 +1030,12 @@ pub(crate) mod test_utils {
assert_eq!(got, *want);
}

let serialized_vec = F::slice_into_byte_vec(&test_inputs);
let deserialized = F::byte_slice_into_vec(&serialized_vec).unwrap();
assert_eq!(deserialized, test_inputs);
#[allow(deprecated)]
{
let serialized_vec = F::slice_into_byte_vec(&test_inputs);
let deserialized = F::byte_slice_into_vec(&serialized_vec).unwrap();
assert_eq!(deserialized, test_inputs);
}

let test_input = prng.get();
let json = serde_json::to_string(&test_input).unwrap();
Expand All @@ -1041,13 +1048,16 @@ pub(crate) mod test_utils {
element.as_u64().unwrap();
}

let err = F::byte_slice_into_vec(&[0]).unwrap_err();
assert_matches!(err, FieldError::ShortRead);
#[allow(deprecated)]
{
let err = F::byte_slice_into_vec(&[0]).unwrap_err();
assert_matches!(err, FieldError::ShortRead);

let err = F::byte_slice_into_vec(&vec![0xffu8; F::ENCODED_SIZE]).unwrap_err();
assert_matches!(err, FieldError::Codec(CodecError::Other(err)) => {
assert_matches!(err.downcast_ref::<FieldError>(), Some(FieldError::ModulusOverflow));
});
let err = F::byte_slice_into_vec(&vec![0xffu8; F::ENCODED_SIZE]).unwrap_err();
assert_matches!(err, FieldError::Codec(CodecError::Other(err)) => {
assert_matches!(err.downcast_ref::<FieldError>(), Some(FieldError::ModulusOverflow));
});
}

let insufficient = vec![0u8; F::ENCODED_SIZE - 1];
let err = F::try_from(insufficient.as_ref()).unwrap_err();
Expand Down
5 changes: 4 additions & 1 deletion src/prng.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ where
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "prio2")]
use crate::field::encode_fieldvec;
use crate::{
codec::Decode,
field::{Field64, FieldPrio2},
Expand Down Expand Up @@ -164,7 +166,8 @@ mod tests {
let seed = BASE64_STANDARD.decode(seed_base64).unwrap();
let random_data = extract_share_from_seed::<FieldPrio2>(len, &seed);

let random_bytes = FieldPrio2::slice_into_byte_vec(&random_data);
let mut random_bytes = Vec::new();
encode_fieldvec(&random_data, &mut random_bytes);

let mut hasher = Sha256::new();
hasher.update(&random_bytes);
Expand Down
9 changes: 5 additions & 4 deletions src/vdaf/prio2/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
//! Primitives for the Prio2 client.
use crate::{
field::{FftFriendlyFieldElement, FieldError},
codec::CodecError,
field::FftFriendlyFieldElement,
polynomial::{poly_fft, PolyAuxMemory},
prng::{Prng, PrngError},
vdaf::{xof::SeedStreamAes128, VdafError},
Expand Down Expand Up @@ -32,9 +33,9 @@ pub enum SerializeError {
/// Emitted by `unpack_proof[_mut]` if the serialized share+proof has the wrong length
#[error("serialized input has wrong length")]
UnpackInputSizeMismatch,
/// Finite field operation error.
#[error("finite field operation error")]
Field(#[from] FieldError),
/// Codec error.
#[error(transparent)]
Codec(#[from] CodecError),
}

#[derive(Debug)]
Expand Down
44 changes: 28 additions & 16 deletions src/vdaf/prio2/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,13 @@ pub(crate) fn is_valid_share<F: FftFriendlyFieldElement>(
#[cfg(test)]
mod test_util {
use crate::{
codec::ParameterizedDecode,
field::{merge_vector, FftFriendlyFieldElement},
prng::Prng,
vdaf::prio2::client::proof_length,
vdaf::{
prio2::client::{proof_length, SerializeError},
Share, ShareDecodingParameter,
},
};

use super::{generate_verification_message, is_valid_share, ServerError, VerificationMessage};
Expand Down Expand Up @@ -133,17 +137,17 @@ mod test_util {
/// Deserialize
fn deserialize_share(&self, share: &[u8]) -> Result<Vec<F>, ServerError> {
let len = proof_length(self.dimension);
Ok(if self.is_first_server {
F::byte_slice_into_vec(share)?
let decoding_parameter = if self.is_first_server {
ShareDecodingParameter::Leader(len)
} else {
if share.len() != 32 {
return Err(ServerError::ShareLength);
}

Prng::from_prio2_seed(&share.try_into().unwrap())
.take(len)
.collect()
})
ShareDecodingParameter::Helper
};
let decoded_share = Share::get_decoded_with_param(&decoding_parameter, share)
.map_err(SerializeError::from)?;
match decoded_share {
Share::Leader(vec) => Ok(vec),
Share::Helper(seed) => Ok(Prng::from_prio2_seed(&seed.0).take(len).collect()),
}
}

/// Generate verification message from an encrypted share
Expand Down Expand Up @@ -194,14 +198,19 @@ mod test_util {
mod tests {
use super::*;
use crate::{
codec::Encode,
codec::{Encode, ParameterizedDecode},
field::{FieldElement, FieldPrio2},
prng::Prng,
vdaf::{
prio2::{client::unpack_proof_mut, server::test_util::Server, Prio2},
Client,
prio2::{
client::{proof_length, unpack_proof_mut},
server::test_util::Server,
Prio2,
},
Client, Share, ShareDecodingParameter,
},
};
use assert_matches::assert_matches;
use rand::{random, Rng};

fn secret_share(share: &mut [FieldPrio2]) -> Vec<FieldPrio2> {
Expand Down Expand Up @@ -289,7 +298,10 @@ mod tests {
let share1_original = shares[0].get_encoded();
let share2 = shares[1].get_encoded();

let mut share1_field = FieldPrio2::byte_slice_into_vec(&share1_original).unwrap();
let mut share1_field: Vec<FieldPrio2> = assert_matches!(
Share::get_decoded_with_param(&ShareDecodingParameter::<32>::Leader(proof_length(dim)), &share1_original),
Ok(Share::Leader(vec)) => vec
);
let unpacked_share1 = unpack_proof_mut(&mut share1_field, dim).unwrap();

let one = FieldPrio2::from(1);
Expand All @@ -304,7 +316,7 @@ mod tests {
};

// reserialize altered share1
let share1_modified = FieldPrio2::slice_into_byte_vec(&share1_field);
let share1_modified = Share::<FieldPrio2, 32>::Leader(share1_field).get_encoded();

let mut prng = Prng::from_prio2_seed(&random());
let eval_at = vdaf.choose_eval_at(&mut prng);
Expand Down
20 changes: 14 additions & 6 deletions src/vdaf/prio2/test_vector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,12 @@ mod base64 {
//! instead of an array of an array of integers when serializing to JSON.
//
// Thank you, Alice! https://users.rust-lang.org/t/serialize-a-vec-u8-to-json-as-base64/57781/2
use crate::field::{FieldElement, FieldPrio2};
use crate::{
codec::ParameterizedDecode,
field::{encode_fieldvec, FieldElement, FieldPrio2},
vdaf::{Share, ShareDecodingParameter},
};
use assert_matches::assert_matches;
use base64::{engine::Engine, prelude::BASE64_STANDARD};
use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};

Expand All @@ -68,16 +73,19 @@ mod base64 {
}

pub fn serialize_field<S: Serializer>(v: &[FieldPrio2], s: S) -> Result<S::Ok, S::Error> {
String::serialize(
&BASE64_STANDARD.encode(FieldPrio2::slice_into_byte_vec(v)),
s,
)
let mut bytes = Vec::new();
encode_fieldvec(v, &mut bytes);
String::serialize(&BASE64_STANDARD.encode(&bytes), s)
}

pub fn deserialize_field<'de, D: Deserializer<'de>>(d: D) -> Result<Vec<FieldPrio2>, D::Error> {
let bytes = BASE64_STANDARD
.decode(String::deserialize(d)?.as_bytes())
.map_err(Error::custom)?;
FieldPrio2::byte_slice_into_vec(&bytes).map_err(Error::custom)
let decoding_parameter =
ShareDecodingParameter::<32>::Leader(bytes.len() / FieldPrio2::ENCODED_SIZE);
let share = Share::<FieldPrio2, 32>::get_decoded_with_param(&decoding_parameter, &bytes)
.map_err(Error::custom)?;
assert_matches!(share, Share::Leader(vec) => Ok(vec))
}
}

0 comments on commit 995a0e5

Please sign in to comment.