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

Add Ferret-core #90

Merged
merged 24 commits into from
Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions mpz-core/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ impl Block {
pub const LEN: usize = 16;
/// A zero block
pub const ZERO: Self = Self([0; 16]);
/// A one block
pub const ONE: Self = Self([1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
/// A block with all bits set to 1
pub const ONES: Self = Self([0xff; 16]);
/// A length 2 array of zero and one blocks
Expand Down
43 changes: 43 additions & 0 deletions mpz-core/src/lpn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//! More especifically, a local linear code is a random boolean matrix with at most D non-zero values in each row.

use crate::{prp::Prp, Block};
use rand::{seq::SliceRandom, thread_rng};
use rayon::prelude::*;
/// An LPN encoder.
///
Expand Down Expand Up @@ -111,6 +112,48 @@ impl<const D: usize> LpnEncoder<D> {
}
}

/// Lpn paramters
#[derive(Copy, Clone, Debug)]
pub struct LpnParameters {
/// The length of output vecotrs.
pub n: usize,
/// The length of the secret vector
pub k: usize,
/// The Hamming Weight of error vectors
pub t: usize,
}

impl LpnParameters {
/// Create a new LpnParameters instance.
pub fn new(n: usize, k: usize, t: usize) -> Self {
assert!(t <= n);
LpnParameters { n, k, t }
}

/// Sample a uniform error vector with HW t.
pub fn sample_uniform_error_vector(&self) -> Vec<Block> {
let one: Block = bytemuck::cast(1_u128);
let mut res = vec![Block::ZERO; self.n];
res[0..self.t].iter_mut().for_each(|x| *x = one);
let mut rng = thread_rng();
res.shuffle(&mut rng);
res
}

/// Sample a regular error vector with HW t
pub fn sample_regular_error_vector(&self) -> Vec<Block> {
assert_eq!(self.n % self.t, 0);
let one: Block = bytemuck::cast(1_u128);
let mut res = vec![Block::ZERO; self.n];
res.chunks_exact_mut(self.n / self.t).for_each(|x| {
x[0] = one;
let mut rng = thread_rng();
x.shuffle(&mut rng);
});
res
}
}

#[cfg(test)]
mod tests {
use crate::lpn::LpnEncoder;
Expand Down
11 changes: 11 additions & 0 deletions ot/mpz-ot-core/src/ferret/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//! Errors that can occur when using the Ferret protocol.

/// Errors that can occur when using the Ferret sender.
#[derive(Debug, thiserror::Error)]
#[error("invalid input: expected {0}")]
pub struct SenderError(pub String);

/// Errors that can occur when using the Ferret receiver.
#[derive(Debug, thiserror::Error)]
#[error("invalid input: expected {0}")]
pub struct ReceiverError(pub String);
134 changes: 134 additions & 0 deletions ot/mpz-ot-core/src/ferret/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
//! An implementation of the [`Ferret`](https://eprint.iacr.org/2020/924.pdf) protocol.

use mpz_core::lpn::LpnParameters;

pub mod cuckoo;
pub mod error;
pub mod mpcot;
pub mod msgs;
pub mod receiver;
pub mod sender;
pub mod spcot;

/// Computational security parameter
Expand All @@ -12,3 +18,131 @@ pub const CUCKOO_HASH_NUM: usize = 3;

/// Trial numbers in Cuckoo hash insertion.
pub const CUCKOO_TRIAL_NUM: usize = 100;

/// LPN parameters with regular noise.
/// Derived from https://github.com/emp-toolkit/emp-ot/blob/master/emp-ot/ferret/constants.h
pub const LPN_PARAMETERS_REGULAR: LpnParameters = LpnParameters {
n: 10180608,
k: 124000,
t: 4971,
};

/// LPN parameters with uniform noise.
/// Derived from Table 2.
pub const LPN_PARAMETERS_UNIFORM: LpnParameters = LpnParameters {
n: 10616092,
k: 588160,
t: 1324,
};

/// The type of Lpn parameters.
pub enum LpnType {
/// Uniform error distribution.
Uniform,
/// Regular error distribution.
Regular,
}

#[cfg(test)]
mod tests {
use super::{
msgs::LpnMatrixSeed, receiver::Receiver as FerretReceiver, sender::Sender as FerretSender,
LpnType,
};
use crate::ideal::{
ideal_cot::{CotMsgForReceiver, CotMsgForSender, IdealCOT},
ideal_mpcot::{IdealMpcot, MpcotMsgForReceiver, MpcotMsgForSender},
};
use mpz_core::{lpn::LpnParameters, prg::Prg};

const LPN_PARAMETERS_TEST: LpnParameters = LpnParameters {
n: 9600,
k: 1220,
t: 600,
};

#[test]
fn ferret_test() {
let mut prg = Prg::new();
let delta = prg.random_block();
let mut ideal_cot = IdealCOT::new_with_delta(delta);
let mut ideal_mpcot = IdealMpcot::init_with_delta(delta);

let sender = FerretSender::new();
let receiver = FerretReceiver::new();

// Invoke Ideal COT to init the Ferret setup phase.
let (sender_cot, receiver_cot) = ideal_cot.extend(LPN_PARAMETERS_TEST.k);

let CotMsgForSender { qs: v } = sender_cot;
let CotMsgForReceiver { rs: u, ts: w } = receiver_cot;

// receiver generates the random seed of lpn matrix.
let lpn_matrix_seed = prg.random_block();

// init the setup of sender and receiver.
let (mut receiver, seed) = receiver
.setup(
LPN_PARAMETERS_TEST,
LpnType::Regular,
lpn_matrix_seed,
&u,
&w,
)
.unwrap();

let LpnMatrixSeed {
seed: lpn_matrix_seed,
} = seed;

let mut sender = sender
.setup(
delta,
LPN_PARAMETERS_TEST,
LpnType::Regular,
lpn_matrix_seed,
&v,
)
.unwrap();

// extend once
let _ = sender.get_mpcot_query();
let query = receiver.get_mpcot_query();

let (sender_mpcot, receiver_mpcot) = ideal_mpcot.extend(&query.0, query.1, query.2);

let MpcotMsgForSender { s } = sender_mpcot;
let MpcotMsgForReceiver { r } = receiver_mpcot;

let sender_out = sender.extend(&s).unwrap();
let receiver_out = receiver.extend(&r).unwrap();

assert!(ideal_cot.check(
CotMsgForSender { qs: sender_out },
CotMsgForReceiver {
rs: receiver_out.0,
ts: receiver_out.1,
},
));

// extend twice
let _ = sender.get_mpcot_query();
let query = receiver.get_mpcot_query();

let (sender_mpcot, receiver_mpcot) = ideal_mpcot.extend(&query.0, query.1, query.2);

let MpcotMsgForSender { s } = sender_mpcot;
let MpcotMsgForReceiver { r } = receiver_mpcot;

let sender_out = sender.extend(&s).unwrap();
let receiver_out = receiver.extend(&r).unwrap();

assert!(ideal_cot.check(
CotMsgForSender { qs: sender_out },
CotMsgForReceiver {
rs: receiver_out.0,
ts: receiver_out.1,
},
));
}
}
10 changes: 10 additions & 0 deletions ot/mpz-ot-core/src/ferret/msgs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//! Messages for the Ferret protocol.
use mpz_core::Block;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
/// The seed to generate Lpn matrix.
pub struct LpnMatrixSeed {
/// The seed.
pub seed: Block,
}
Loading
Loading