Files
voprf-vx/src/serialization.rs
T

229 lines
7.0 KiB
Rust
Raw Normal View History

2021-09-09 01:56:54 -07:00
// Copyright (c) Facebook, Inc. and its affiliates.
//
2021-09-27 18:53:06 -07:00
// This source code is licensed under both the MIT license found in the
// LICENSE-MIT file in the root directory of this source tree and the Apache
// License, Version 2.0 found in the LICENSE-APACHE file in the root directory
// of this source tree.
2021-09-09 01:56:54 -07:00
2021-09-15 17:49:31 -07:00
//! Handles the serialization of each of the components used
//! in the VOPRF protocol
use crate::{
ciphersuite::CipherSuite,
errors::InternalError,
group::Group,
voprf::{
BlindedElement, EvaluationElement, NonVerifiableClient, NonVerifiableServer, Proof,
VerifiableClient, VerifiableServer,
},
};
2021-09-09 01:56:54 -07:00
use alloc::vec::Vec;
2021-09-15 17:49:31 -07:00
use generic_array::{typenum::Unsigned, GenericArray};
//////////////////////////////////////////////////////////
// Serialization and Deserialization for High-Level API //
// ==================================================== //
//////////////////////////////////////////////////////////
impl<CS: CipherSuite> NonVerifiableClient<CS> {
/// Serialization into bytes
pub fn serialize(&self) -> Vec<u8> {
[
CS::Group::scalar_as_bytes(self.blind).to_vec(),
self.data.clone(),
]
.concat()
}
/// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, InternalError> {
let scalar_len = <CS::Group as Group>::ScalarLen::USIZE;
if input.len() < scalar_len {
return Err(InternalError::SizeError);
}
let blind = CS::Group::from_scalar_slice(GenericArray::from_slice(&input[..scalar_len]))?;
let data = input[scalar_len..].to_vec();
Ok(Self { blind, data })
}
}
impl<CS: CipherSuite> VerifiableClient<CS> {
/// Serialization into bytes
pub fn serialize(&self) -> Vec<u8> {
[
CS::Group::scalar_as_bytes(self.blind).to_vec(),
self.blinded_element.to_arr().to_vec(),
self.data.clone(),
]
.concat()
}
/// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, InternalError> {
let scalar_len = <CS::Group as Group>::ScalarLen::USIZE;
let elem_len = <CS::Group as Group>::ElemLen::USIZE;
if input.len() < scalar_len + elem_len {
return Err(InternalError::SizeError);
}
let blind = CS::Group::from_scalar_slice(GenericArray::from_slice(&input[..scalar_len]))?;
let blinded_element = CS::Group::from_element_slice(GenericArray::from_slice(
&input[scalar_len..scalar_len + elem_len],
))?;
let data = input[scalar_len + elem_len..].to_vec();
Ok(Self {
blind,
blinded_element,
data,
})
}
}
impl<CS: CipherSuite> NonVerifiableServer<CS> {
/// Serialization into bytes
pub fn serialize(&self) -> Vec<u8> {
CS::Group::scalar_as_bytes(self.sk).to_vec()
}
/// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, InternalError> {
let scalar_len = <CS::Group as Group>::ScalarLen::USIZE;
if input.len() != scalar_len {
return Err(InternalError::SizeError);
}
let sk = CS::Group::from_scalar_slice(GenericArray::from_slice(input))?;
Ok(Self { sk })
}
}
impl<CS: CipherSuite> VerifiableServer<CS> {
/// Serialization into bytes
pub fn serialize(&self) -> Vec<u8> {
[
CS::Group::scalar_as_bytes(self.sk).to_vec(),
self.pk.to_arr().to_vec(),
]
.concat()
}
/// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, InternalError> {
let scalar_len = <CS::Group as Group>::ScalarLen::USIZE;
let elem_len = <CS::Group as Group>::ElemLen::USIZE;
if input.len() != scalar_len + elem_len {
return Err(InternalError::SizeError);
}
let sk = CS::Group::from_scalar_slice(GenericArray::from_slice(&input[..scalar_len]))?;
let pk = CS::Group::from_element_slice(GenericArray::from_slice(&input[scalar_len..]))?;
Ok(Self { sk, pk })
}
}
impl<CS: CipherSuite> Proof<CS> {
/// Serialization into bytes
pub fn serialize(&self) -> Vec<u8> {
[
CS::Group::scalar_as_bytes(self.c_scalar),
CS::Group::scalar_as_bytes(self.s_scalar),
]
.concat()
}
/// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, InternalError> {
let scalar_len = <CS::Group as Group>::ScalarLen::USIZE;
if input.len() < scalar_len + scalar_len {
return Err(InternalError::SizeError);
}
Ok(Proof {
c_scalar: CS::Group::from_scalar_slice(GenericArray::from_slice(&input[..scalar_len]))?,
s_scalar: CS::Group::from_scalar_slice(GenericArray::from_slice(&input[scalar_len..]))?,
})
}
}
impl<CS: CipherSuite> BlindedElement<CS> {
/// Serialization into bytes
pub fn serialize(&self) -> Vec<u8> {
2021-09-28 19:44:57 -07:00
self.value.to_arr().to_vec()
2021-09-15 17:49:31 -07:00
}
/// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, InternalError> {
2021-09-28 19:44:57 -07:00
Ok(Self {
value: CS::Group::from_element_slice(GenericArray::from_slice(input))?,
})
2021-09-15 17:49:31 -07:00
}
}
impl<CS: CipherSuite> EvaluationElement<CS> {
/// Serialization into bytes
pub fn serialize(&self) -> Vec<u8> {
2021-09-28 19:44:57 -07:00
self.value.to_arr().to_vec()
2021-09-15 17:49:31 -07:00
}
/// Deserialization from bytes
pub fn deserialize(input: &[u8]) -> Result<Self, InternalError> {
2021-09-28 19:44:57 -07:00
Ok(Self {
value: CS::Group::from_element_slice(GenericArray::from_slice(input))?,
})
2021-09-15 17:49:31 -07:00
}
}
//////////////////////
// Helper Functions //
// ================ //
//////////////////////
2021-09-09 01:56:54 -07:00
// Corresponds to the I2OSP() function from RFC8017
pub(crate) fn i2osp(input: usize, length: usize) -> Result<alloc::vec::Vec<u8>, InternalError> {
let sizeof_usize = core::mem::size_of::<usize>();
// Check if input >= 256^length
if (sizeof_usize as u32 - input.leading_zeros() / 8) > length as u32 {
return Err(InternalError::SerializationError);
}
if length <= sizeof_usize {
return Ok((&input.to_be_bytes()[sizeof_usize - length..]).to_vec());
}
let mut output = alloc::vec![0u8; length];
output.splice(
length - sizeof_usize..length,
input.to_be_bytes().iter().cloned(),
);
Ok(output)
}
// Computes I2OSP(len(input), max_bytes) || input
pub(crate) fn serialize(input: &[u8], max_bytes: usize) -> Result<Vec<u8>, InternalError> {
Ok([&i2osp(input.len(), max_bytes)?, input].concat())
}
#[cfg(test)]
mod unit_tests {
use super::*;
// Test the error condition for I2OSP
#[test]
fn test_i2osp_err_check() {
assert!(i2osp(0, 1).is_ok());
assert!(i2osp(255, 1).is_ok());
assert!(i2osp(256, 1).is_err());
assert!(i2osp(257, 1).is_err());
assert!(i2osp(256 * 256 - 1, 2).is_ok());
assert!(i2osp(256 * 256, 2).is_err());
assert!(i2osp(256 * 256 + 1, 2).is_err());
}
}