Skip to content

Commit

Permalink
Add Ferret-core (#90)
Browse files Browse the repository at this point in the history
* add spcot ideal func

* add cuckoo hash

* add MPCOT sender

* add mpcot receiver

* change to next power of two

* test mpcot for general indices, and fix bugs

* rename extend_hash to extend_pre

* comment and doc

* minor change

* doc and comments

* add MPCOT for regular distribution

* cargo clippy

* finish ferret building blocks

* add ideal mpcot and tests

* add ideal mpcot and tests

* update ideal functionalities

* fmt

* rename util to cuckoo

* simplify errors

* update

* update
  • Loading branch information
xiangxiecrypto authored Mar 14, 2024
1 parent 9f7403b commit a6127ce
Show file tree
Hide file tree
Showing 9 changed files with 656 additions and 1 deletion.
2 changes: 2 additions & 0 deletions mpz-core/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,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 specifically, 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

0 comments on commit a6127ce

Please sign in to comment.