Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shuffle verification #1255

Merged
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions ipa-core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ pub enum Error {
ShardInfraError(#[from] crate::helpers::Error<ShardIndex>),
#[error("Value truncation error: {0}")]
FieldValueTruncation(String),
#[error("The field element size is too small: {0}")]
FieldConversion(String),
#[error("Invalid query parameter: {0}")]
InvalidQueryParameter(BoxError),
#[error("invalid report: {0}")]
Expand Down Expand Up @@ -94,6 +96,8 @@ pub enum Error {
EpsilonOutOfBounds,
#[error("Missing total records in {0}")]
MissingTotalRecords(String),
#[error("The verification of the shuffle failed: {0}")]
ShuffleValidationFailed(String),
}

impl Default for Error {
Expand Down
50 changes: 47 additions & 3 deletions ipa-core/src/ff/boolean_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use typenum::{U14, U2, U32, U8};

use crate::{
error::LengthError,
ff::{boolean::Boolean, ArrayAccess, Expand, Field, Serializable, U128Conversions},
ff::{boolean::Boolean, ArrayAccess, Expand, Field, Gf32Bit, Serializable, U128Conversions},
protocol::prss::{FromRandom, FromRandomU128},
secret_sharing::{Block, SharedValue, StdArray, Vectorizable},
};
Expand All @@ -32,7 +32,11 @@ macro_rules! store_impl {
}

pub trait BooleanArray:
SharedValue + ArrayAccess<Output = Boolean> + Expand<Input = Boolean> + FromIterator<Boolean>
SharedValue
+ ArrayAccess<Output = Boolean>
+ Expand<Input = Boolean>
+ FromIterator<Boolean>
+ TryInto<Vec<Gf32Bit>, Error = crate::error::Error>
{
}

Expand All @@ -41,6 +45,7 @@ impl<A> BooleanArray for A where
+ ArrayAccess<Output = Boolean>
+ Expand<Input = Boolean>
+ FromIterator<Boolean>
+ TryInto<Vec<Gf32Bit>, Error = crate::error::Error>
{
}

Expand Down Expand Up @@ -266,7 +271,7 @@ macro_rules! boolean_array_impl {
mod $modname {
use super::*;
use crate::{
ff::{boolean::Boolean, ArrayAccess, Expand, Serializable},
ff::{boolean::Boolean, ArrayAccess, Expand, Serializable, Gf32Bit},
impl_shared_value_common,
secret_sharing::{
replicated::semi_honest::{BAASIterator, AdditiveShare},
Expand Down Expand Up @@ -497,6 +502,28 @@ macro_rules! boolean_array_impl {
}
}

/// This function converts an `BA` type into a vector of `32 bit` Galois field elements.
///
/// ##Errors
/// Outputs an error when conversion from raw slice to Galois field element fails.
impl TryFrom<$name> for Vec<Gf32Bit> {
type Error = crate::error::Error;

fn try_from(value: $name) -> Result<Self, Self::Error> {
// len() returns bits, so divide by 8
// further divide by 4 since Gf32Bit has 4 byte
// add 31 to round up
let length = (value.0.len() + 31) / 32;
let mut chunks = Vec::<Gf32Bit>::with_capacity(length);
let last_chunk_start = length-1;
for i in 0..last_chunk_start {
chunks.push(Gf32Bit::try_from(&value.0.as_raw_slice()[4 * i..4 * (i + 1)])?);
}
chunks.push(Gf32Bit::try_from(&value.0.as_raw_slice()[4 * last_chunk_start..])?);
Ok(chunks)
}
}

impl SharedValueArray<Boolean> for $name {
const ZERO_ARRAY: Self = <$name as SharedValue>::ZERO;

Expand Down Expand Up @@ -657,6 +684,23 @@ macro_rules! boolean_array_impl {
assert_eq!(ba.get(i), Some(a));
}

#[test]
fn convert_to_galois_field(){
let mut rng = thread_rng();
let ba = rng.gen::<$name>();
let mut vec = ba.as_raw_slice().to_vec();
// append with zeros when necessary
for _ in 0..(4-vec.len()%4)%4 {
vec.push(0u8);
}
let converted = <Vec<Gf32Bit>>::try_from(ba).unwrap();
for (i,element) in converted.iter().enumerate() {
let temp = element.as_raw_slice().to_vec();
assert_eq!(vec[4*i..4*(i+1)],temp);
}

}

proptest! {
#[test]
fn iterate_boolean_array(a: $name) {
Expand Down
67 changes: 65 additions & 2 deletions ipa-core/src/ff/galois_field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
ops::Index,
};

use bitvec::prelude::{bitarr, BitArr, Lsb0};
use bitvec::{
array::BitArray,
prelude::{bitarr, BitArr, Lsb0},
};
use generic_array::GenericArray;
use typenum::{Unsigned, U1, U2, U3, U4, U5};

Expand Down Expand Up @@ -133,7 +136,7 @@
}

macro_rules! bit_array_impl {
( $modname:ident, $name:ident, $store:ty, $bits:expr, $one:expr, $polynomial:expr, $deser_type: tt, $({$($extra:item)*})? ) => {
( $modname:ident, $name:ident, $store:ty, $bits:expr, $bytes:expr, $one:expr, $polynomial:expr, $deser_type: tt, $({$($extra:item)*})? ) => {
#[allow(clippy::suspicious_arithmetic_impl)]
#[allow(clippy::suspicious_op_assign_impl)]
mod $modname {
Expand All @@ -153,6 +156,15 @@
}
}

impl $name {

#[inline]
#[must_use]
pub fn as_raw_slice(&self) -> &[u8] {
self.0.as_raw_slice()
}
}

impl SharedValue for $name {
type Storage = $store;
const BITS: u32 = $bits;
Expand Down Expand Up @@ -187,6 +199,34 @@
}
}

/// This function generates a Galois field element from a raw slice.
/// When the length of the slice is smaller than the byte length
/// of an element, the remaining bytes are filled with Zeros.
///
/// ## Errors
/// Returns an error when the slice is too long.
///
/// ## Panics
/// Panics when `u32` to `usize` conversion fails
impl TryFrom<&[u8]> for $name {

type Error = crate::error::Error;

fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
if value.len()<=usize::try_from(Self::BITS/8).unwrap() {
let mut bitarray = [0u8;$bytes];
bitarray[0..value.len()].copy_from_slice(value);
Ok($name(BitArray::<[u8;$bytes],Lsb0>::new(bitarray)))
} else {
Err(crate::error::Error::FieldConversion(format!(
"Element bit size {} is too small to hold {} bytes.",
Self::BITS,
value.len()
)))

Check warning on line 225 in ipa-core/src/ff/galois_field.rs

View check run for this annotation

Codecov / codecov/patch

ipa-core/src/ff/galois_field.rs#L221-L225

Added lines #L221 - L225 were not covered by tests
}
}
}

impl FromRandomU128 for $name {
fn from_random_u128(src: u128) -> Self {
U128Conversions::truncate_from(src)
Expand Down Expand Up @@ -583,6 +623,22 @@

assert_eq!(a, $name::deserialize(&buf).unwrap(), "failed to serialize/deserialize {a:?}");
}

#[test]
fn element_from_raw_slice(){
// initialize array with 1s
let mut a = [255;$bytes];
for i in (0usize..$bytes).rev() {
// check when inserting elements 0..i
// try_from implementation sets elements i..$bytes to 0
// check whether there are enough bits to insert a byte
if usize::try_from(<$name>::BITS).unwrap() >= (i+1)*8 {
assert_eq!($name(BitArray::<[u8;$bytes],Lsb0>::new(a)),$name::try_from(vec![255u8;i+1].as_slice()).unwrap());
}
// set last element to 0 to be consistent with try_from for next iteration
a[i] = 0;
}
}
}

$( $( $extra )* )?
Expand All @@ -597,6 +653,7 @@
Gf40Bit,
U8_5,
40,
5,
bitarr!(const u8, Lsb0; 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
// x^40 + x^5 + x^3 + x^2 + 1
0b1_0000_0000_0000_0000_0000_0000_0000_0000_0010_1101_u128,
Expand All @@ -608,6 +665,7 @@
Gf32Bit,
U8_4,
32,
4,
bitarr!(const u8, Lsb0; 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
// x^32 + x^7 + x^3 + x^2 + 1
0b1_0000_0000_0000_0000_0000_0000_1000_1101_u128,
Expand All @@ -619,6 +677,7 @@
Gf20Bit,
U8_3,
20,
3,
bitarr!(const u8, Lsb0; 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
// x^20 + x^7 + x^3 + x^2 + 1
0b1_0000_0000_0000_1000_1101_u128,
Expand All @@ -630,6 +689,7 @@
Gf8Bit,
U8_1,
8,
1,
bitarr!(const u8, Lsb0; 1, 0, 0, 0, 0, 0, 0, 0),
// x^8 + x^4 + x^3 + x + 1
0b1_0001_1011_u128,
Expand All @@ -641,6 +701,7 @@
Gf9Bit,
U8_2,
9,
2,
bitarr!(const u8, Lsb0; 1, 0, 0, 0, 0, 0, 0, 0, 0),
// x^9 + x^4 + x^3 + x + 1
0b10_0001_1011_u128,
Expand All @@ -652,6 +713,7 @@
Gf3Bit,
U8_1,
3,
1,
bitarr!(const u8, Lsb0; 1, 0, 0),
// x^3 + x + 1
0b1_011_u128,
Expand All @@ -663,6 +725,7 @@
Gf2,
U8_1,
1,
1,
bitarr!(const u8, Lsb0; 1),
// x
0b10_u128,
Expand Down
Loading