Skip to content

Commit

Permalink
Base spcot protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
kisakishy committed Jun 18, 2024
1 parent 05a62bd commit 365ef7b
Show file tree
Hide file tree
Showing 8 changed files with 570 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ serde = { version = "1.0.195", features = ["derive"] }
tokio = { version = "1.35.1", features = ["full"] }
trait-variant = "0.1.1"
async-trait = "0.1.77"
aes = "0.8.4"
block-modes = "0.9.1"
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ pub mod fpre;
pub mod protocol;

mod garble;

mod otext;
91 changes: 91 additions & 0 deletions src/otext/block.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
//! Block
//Later look into replacing this to __m128i, e.g., using https://docs.rs/safe_arch/latest/src/safe_arch/x86_x64/m128i_.rs.html#19

/// Block type
pub type Block = u128;

/// Generate a 128-bit value from two 64-bit values
pub fn make_block(high: u64, low: u64) -> u128 {
let high = (high as u128) << 64;
let low = low as u128;
high | low
}

/// All zero block
pub const ZERO_BLOCK: Block = 0;

/// All one block
pub const ALL_ONE_BLOCK: Block = u128::MAX;

/// XOR blocks
pub fn xor_blocks_arr(res: &mut [Block], x: &[Block], y: &[Block], nblocks: usize) {
for i in 0..nblocks {
res[i] = x[i] ^ y[i];
}
}

/// XOR single block
pub fn xor_blocks_arr_single(res: &mut [Block], x: &[Block], y: Block, nblocks: usize) {
for i in 0..nblocks {
res[i] = x[i] ^ y;
}
}

/// Compare blocks
pub fn cmp_block(x: &[Block], y: &[Block], nblocks: usize) -> bool {
for i in 0..nblocks {
if x[i] != y[i] {
return false;
}
}
true
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_make_block() {
let high = 0x0123456789ABCDEF;
let low = 0xFEDCBA9876543210;
let block = make_block(high, low);
assert_eq!(block, 0x0123456789ABCDEF_FEDCBA9876543210);
}

#[test]
fn test_xor_blocks_arr() {
let x = vec![make_block(1, 2); 3];
let y = vec![make_block(3, 4); 3];
let mut res = vec![ZERO_BLOCK; 3];

xor_blocks_arr(&mut res, &x, &y, 3);

for block in &res {
assert_eq!(*block, make_block(1 ^ 3, 2 ^ 4));
}
}

#[test]
fn test_xor_blocks_arr_single() {
let x = vec![make_block(1, 2); 3];
let y = make_block(5, 6);
let mut res = vec![ZERO_BLOCK; 3];

xor_blocks_arr_single(&mut res, &x, y, 3);

for block in &res {
assert_eq!(*block, make_block(1 ^ 5, 2 ^ 6));
}
}

#[test]
fn test_cmp_block() {
let x = vec![make_block(1, 2); 3];
let y = vec![make_block(1, 2); 3];
let z = vec![make_block(3, 4); 3];

assert!(cmp_block(&x, &y, 3)); // Should be true
assert!(!cmp_block(&x, &z, 3)); // Should be false
}
}
90 changes: 90 additions & 0 deletions src/otext/crypto_utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
//! Smaller crypto utilities
use blake3::Hasher;
use super::block::ZERO_BLOCK;

use super::block::Block;

/// Function to hash data using BLAKE3 and store the result in a Block[2] array
pub fn hash_once(dgst: &mut [Block; 2], data: &Block) {
let mut hasher = Hasher::new();
let data_bytes = data.to_le_bytes();
hasher.update(&data_bytes);
let hash = hasher.finalize();
let hash_bytes = hash.as_bytes();
dgst[0] = Block::from_le_bytes(hash_bytes[0..16].try_into().unwrap());
dgst[1] = Block::from_le_bytes(hash_bytes[16..32].try_into().unwrap());
}

/// Galois Field multiplication function for Block
fn gfmul(a: Block, b: Block) -> Block {
let mut p: Block = 0;
let mut counter = 0;
let mut hi = a;
while hi != 0 {
if (hi & 1) != 0 {
p ^= b << counter;
}
hi >>= 1;
counter += 1;
}
p
}

/// Function to generate coefficients for almost universal hash function
pub fn uni_hash_coeff_gen(coeff: &mut [Block], seed: Block, sz: usize) {
// Handle the case with small `sz`
coeff[0] = seed;
if sz == 1 {
return;
}

coeff[1] = gfmul(seed, seed);
if sz == 2 {
return;
}

coeff[2] = gfmul(coeff[1], seed);
if sz == 3 {
return;
}

let multiplier = gfmul(coeff[2], seed);
coeff[3] = multiplier;
if sz == 4 {
return;
}

// Computing the rest with a batch of 4
let mut i = 4;
while i < sz - 3 {
coeff[i] = gfmul(coeff[i - 4], multiplier);
coeff[i + 1] = gfmul(coeff[i - 3], multiplier);
coeff[i + 2] = gfmul(coeff[i - 2], multiplier);
coeff[i + 3] = gfmul(coeff[i - 1], multiplier);
i += 4;
}

// Cleaning up with the rest
let remainder = sz % 4;
if remainder != 0 {
let start = sz - remainder;
for j in start..sz {
coeff[j] = gfmul(coeff[j - 1], seed);
}
}
}

/// Function to compute inner product of two Galois field vectors with reduction
pub fn vector_inn_prdt_sum_red(a: &[Block], b: &[Block], sz: usize) -> Block {
let mut r = ZERO_BLOCK;

// Ensure both vectors have the same size
assert_eq!(a.len(), b.len());
assert_eq!(a.len(), sz);

for i in 0..sz {
let r1 = gfmul(a[i], b[i]);
r ^= r1;
}
r
}
5 changes: 5 additions & 0 deletions src/otext/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub mod block;
pub mod crypto_utils;
pub mod twokeyprp;
pub mod spcot_recver;
pub mod spcot_sender;
135 changes: 135 additions & 0 deletions src/otext/spcot_recver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
//! SPCOT receiver implementation
use super::block::ZERO_BLOCK;

use super::block::{make_block, Block};
use crate::channel::SimpleChannel;
use super::crypto_utils::{hash_once, uni_hash_coeff_gen, vector_inn_prdt_sum_red};
use super::twokeyprp::TwoKeyPRP;

/// SPCOT Receiver
struct SpcotRecver {
ggm_tree: Vec<Block>,
m: Vec<Block>,
b: Vec<bool>,
choice_pos: usize,
depth: usize,
leave_n: usize,
secret_sum_f2: Block,
channel: SimpleChannel,
}

///SPCOT Receiver
impl SpcotRecver {
fn new(channel: SimpleChannel, depth: usize) -> Self {
let leave_n = 1 << (depth - 1);
let m = vec![Block::default(); depth - 1];
let b = vec![false; depth - 1];

SpcotRecver {
ggm_tree: vec![],
m,
b,
choice_pos: 0,
depth,
leave_n,
secret_sum_f2: Block::default(),
channel,
}
}

///Get index
fn get_index(&mut self) -> usize {
self.choice_pos = 0;
for &bi in self.b.iter() {
self.choice_pos <<= 1;
if !bi {
self.choice_pos += 1;
}
}
self.choice_pos
}

// TODO OTs through channel

// Receive the message and reconstruct the tree
fn compute(&mut self, ggm_tree_mem: Vec<Block>) {
self.ggm_tree = ggm_tree_mem;
self.ggm_tree_reconstruction();
self.ggm_tree[self.choice_pos] = Block::default();

let mut nodes_sum = Block::default();
let one = make_block(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFE);
for i in 0..self.leave_n {
self.ggm_tree[i] &= one;
nodes_sum ^= self.ggm_tree[i];
}
self.ggm_tree[self.choice_pos] = nodes_sum ^ self.secret_sum_f2;
}

/// Tree reconstruct
fn ggm_tree_reconstruction(&mut self) {
let mut to_fill_idx = 0;
let prp = TwoKeyPRP::new(ZERO_BLOCK, make_block(0, 1));
for i in 1..self.depth {
to_fill_idx *= 2;
self.ggm_tree[to_fill_idx] = ZERO_BLOCK;
self.ggm_tree[to_fill_idx + 1] = ZERO_BLOCK;
if !self.b[i - 1] {
self.layer_recover(i, 0, to_fill_idx, self.m[i - 1], &prp);
to_fill_idx += 1;
} else {
self.layer_recover(i, 1, to_fill_idx + 1, self.m[i - 1], &prp);
}
}
}

///Recover layer
fn layer_recover(
&mut self,
depth: usize,
lr: usize,
to_fill_idx: usize,
sum: Block,
prp: &TwoKeyPRP,
) {
let layer_start = 0;
let item_n = 1 << depth;
let mut nodes_sum = ZERO_BLOCK;
let lr_start = if lr == 0 {
layer_start
} else {
layer_start + 1
};
for i in (lr_start..item_n).step_by(2) {
nodes_sum ^= self.ggm_tree[i];
}
self.ggm_tree[to_fill_idx] = nodes_sum ^ sum;
if depth == self.depth - 1 {
return;
}
if item_n == 2 {
let parent: &mut [Block; 2] = &mut [self.ggm_tree[0], self.ggm_tree[1]];
self.ggm_tree = prp.node_expand_2to4(parent);
} else {
for _ in (0..item_n - 4).rev().step_by(4) {
let parent: &mut [Block; 4] = &mut [
self.ggm_tree[0],
self.ggm_tree[2],
self.ggm_tree[4],
self.ggm_tree[6],
];
self.ggm_tree = prp.node_expand_4to8(parent);
}
}
}

//Check
fn consistency_check_msg_gen(&mut self, chi_alpha: &mut Block) -> Block {
let mut chi = vec![Block::default(); self.leave_n];
let mut digest: [u128; 2] = [Block::default(); 2];
hash_once(&mut digest, &self.secret_sum_f2);
uni_hash_coeff_gen(&mut chi, digest[0], self.leave_n);
*chi_alpha = chi[self.choice_pos];
vector_inn_prdt_sum_red(&chi, &self.ggm_tree, self.leave_n)
}
}
Loading

0 comments on commit 365ef7b

Please sign in to comment.