mirror of
https://github.com/tlsnotary/tlsn.git
synced 2026-01-09 14:48:13 -05:00
ot extension semi-honest, test failing
This commit is contained in:
@@ -9,3 +9,4 @@ pub mod errors;
|
||||
pub mod garble;
|
||||
mod gate;
|
||||
pub mod ot;
|
||||
pub mod utils;
|
||||
|
||||
271
pop-mpc/src/ot/extension.rs
Normal file
271
pop-mpc/src/ot/extension.rs
Normal file
@@ -0,0 +1,271 @@
|
||||
//! Implementation of the oblivious transfer extension by Keller, Orsini, Scholl
|
||||
//! https://eprint.iacr.org/2015/546
|
||||
|
||||
use super::base::{
|
||||
BaseOTReceiver, BaseOTReceiverSetup, BaseOTSender, BaseOTSenderSend, BaseOTSenderSetup,
|
||||
};
|
||||
use crate::block::Block;
|
||||
use crate::utils;
|
||||
use aes::{BlockCipher, BlockEncrypt};
|
||||
use cipher::consts::U16;
|
||||
use curve25519_dalek::ristretto::RistrettoPoint;
|
||||
use rand::{CryptoRng, Rng, RngCore, SeedableRng};
|
||||
use rand_chacha::ChaCha12Rng;
|
||||
use std::convert::TryInto;
|
||||
|
||||
const K: usize = 40;
|
||||
const NBASE: usize = 128;
|
||||
|
||||
pub struct OTSender<R, C> {
|
||||
rng: R,
|
||||
cipher: C,
|
||||
base_choice: Vec<bool>,
|
||||
base: BaseOTReceiver,
|
||||
seeds: Option<Vec<Block>>,
|
||||
rngs: Option<Vec<ChaCha12Rng>>,
|
||||
table: Option<Vec<Vec<u8>>>,
|
||||
}
|
||||
|
||||
pub struct OTSenderSend {
|
||||
encrypted_values: Vec<[Block; 2]>,
|
||||
}
|
||||
|
||||
pub struct OTReceiver<R, C> {
|
||||
cipher: C,
|
||||
rng: R,
|
||||
base: BaseOTSender,
|
||||
seeds: Option<Vec<[Block; 2]>>,
|
||||
rngs: Option<Vec<[ChaCha12Rng; 2]>>,
|
||||
table: Option<Vec<Vec<u8>>>,
|
||||
}
|
||||
|
||||
pub struct OTReceiverSetup {
|
||||
table: Vec<Vec<u8>>,
|
||||
}
|
||||
|
||||
pub struct OTReceiverReceive {
|
||||
values: Vec<Block>,
|
||||
}
|
||||
|
||||
impl<R: Rng + CryptoRng + SeedableRng, C: BlockCipher<BlockSize = U16> + BlockEncrypt>
|
||||
OTSender<R, C>
|
||||
{
|
||||
pub fn new(mut rng: R, cipher: C, base_sender_setup: BaseOTSenderSetup) -> Self {
|
||||
let mut base_choice = vec![0u8; NBASE / 8];
|
||||
rng.fill_bytes(&mut base_choice);
|
||||
Self {
|
||||
rng,
|
||||
cipher,
|
||||
base_choice: utils::u8vec_to_boolvec(&base_choice),
|
||||
base: BaseOTReceiver::new(base_sender_setup),
|
||||
seeds: None,
|
||||
rngs: None,
|
||||
table: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn base_setup(&mut self) -> BaseOTReceiverSetup {
|
||||
self.base.setup(&mut self.rng, &self.base_choice)
|
||||
}
|
||||
|
||||
pub fn base_receive_seeds(&mut self, send: BaseOTSenderSend) {
|
||||
let receive = self.base.receive(&self.base_choice, send);
|
||||
self.set_seeds(receive.values);
|
||||
}
|
||||
|
||||
pub fn set_seeds(&mut self, seeds: Vec<Block>) {
|
||||
let rngs: Vec<ChaCha12Rng> = seeds
|
||||
.iter()
|
||||
.map(|k| {
|
||||
let k: [u8; 16] = k.to_be_bytes();
|
||||
let k: [u8; 32] = [k, k]
|
||||
.concat()
|
||||
.try_into()
|
||||
.expect("Could not convert block into [u8; 32]");
|
||||
ChaCha12Rng::from_seed(k)
|
||||
})
|
||||
.collect();
|
||||
self.seeds = Some(seeds);
|
||||
self.rngs = Some(rngs);
|
||||
}
|
||||
|
||||
pub fn extension_setup(&mut self, receiver_setup: OTReceiverSetup) {
|
||||
let ncols = receiver_setup.table[0].len() * 8;
|
||||
let mut qs: Vec<Vec<u8>> = vec![vec![0u8; ncols / 8]; NBASE];
|
||||
|
||||
let rngs = self.rngs.as_mut().unwrap();
|
||||
for j in 0..NBASE {
|
||||
let b = &self.base_choice[j];
|
||||
let mut q = &mut qs[j];
|
||||
rngs[j].fill_bytes(&mut q);
|
||||
let q_: Vec<u8> = q
|
||||
.iter()
|
||||
.zip(&receiver_setup.table[j])
|
||||
.map(|(q, u)| *q ^ if *b { *u } else { 0 })
|
||||
.collect();
|
||||
qs[j] = q_;
|
||||
}
|
||||
self.table = Some(utils::transpose(&qs));
|
||||
}
|
||||
|
||||
pub fn send(&mut self, inputs: &[[Block; 2]]) -> OTSenderSend {
|
||||
let table = self.table.as_ref().unwrap();
|
||||
let mut encrypted_values: Vec<[Block; 2]> = Vec::with_capacity(table.len());
|
||||
|
||||
let base_choice: [u8; 16] = utils::boolvec_to_u8vec(&self.base_choice)
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let base_choice = Block::from(base_choice);
|
||||
for (j, input) in inputs.iter().enumerate() {
|
||||
let q: [u8; 16] = table[j].clone().try_into().unwrap();
|
||||
let q = Block::from(q);
|
||||
let y0 = q.hash_tweak(&mut self.cipher, j) ^ input[0];
|
||||
let q = q ^ base_choice;
|
||||
let y1 = q.hash_tweak(&mut self.cipher, j) ^ input[1];
|
||||
encrypted_values.push([y0, y1]);
|
||||
}
|
||||
|
||||
OTSenderSend { encrypted_values }
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Rng + CryptoRng + SeedableRng, C: BlockCipher<BlockSize = U16> + BlockEncrypt>
|
||||
OTReceiver<R, C>
|
||||
{
|
||||
pub fn new(mut rng: R, cipher: C) -> Self {
|
||||
let base = BaseOTSender::new(&mut rng);
|
||||
Self {
|
||||
rng,
|
||||
cipher,
|
||||
base,
|
||||
seeds: None,
|
||||
rngs: None,
|
||||
table: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn base_setup(&mut self) -> BaseOTSenderSetup {
|
||||
self.base.setup()
|
||||
}
|
||||
|
||||
pub fn base_send_seeds(
|
||||
&mut self,
|
||||
base_receiver_setup: BaseOTReceiverSetup,
|
||||
) -> BaseOTSenderSend {
|
||||
let mut seeds: Vec<[Block; 2]> = Vec::with_capacity(NBASE);
|
||||
for i in 0..NBASE {
|
||||
seeds.push([Block::random(&mut self.rng), Block::random(&mut self.rng)]);
|
||||
}
|
||||
|
||||
let base_send = self.base.send(&seeds.as_slice(), base_receiver_setup);
|
||||
|
||||
self.set_seeds(seeds);
|
||||
base_send
|
||||
}
|
||||
|
||||
fn set_seeds(&mut self, seeds: Vec<[Block; 2]>) {
|
||||
let rngs: Vec<[ChaCha12Rng; 2]> = seeds
|
||||
.iter()
|
||||
.map(|k| {
|
||||
let k0: [u8; 16] = k[0].to_be_bytes();
|
||||
let k1: [u8; 16] = k[1].to_be_bytes();
|
||||
let k0: [u8; 32] = [k0, k0]
|
||||
.concat()
|
||||
.try_into()
|
||||
.expect("Could not convert block into [u8; 32]");
|
||||
let k1: [u8; 32] = [k1, k1]
|
||||
.concat()
|
||||
.try_into()
|
||||
.expect("Could not convert block into [u8; 32]");
|
||||
[ChaCha12Rng::from_seed(k0), ChaCha12Rng::from_seed(k1)]
|
||||
})
|
||||
.collect();
|
||||
self.seeds = Some(seeds);
|
||||
self.rngs = Some(rngs);
|
||||
}
|
||||
|
||||
pub fn extension_setup(&mut self, choice: &[bool]) -> OTReceiverSetup {
|
||||
let r = utils::boolvec_to_u8vec(choice);
|
||||
let m = choice.len();
|
||||
let ncols = if m % 8 != 0 { m + (8 - m % 8) } else { m };
|
||||
let mut ts: Vec<Vec<u8>> = vec![vec![0u8; ncols / 8]; NBASE];
|
||||
let mut gs: Vec<Vec<u8>> = Vec::with_capacity(NBASE);
|
||||
|
||||
let rngs = self.rngs.as_mut().unwrap();
|
||||
let mut g = vec![0u8; ncols / 8];
|
||||
for j in 0..NBASE {
|
||||
let mut t = &mut ts[j];
|
||||
rngs[j][0].fill_bytes(&mut t);
|
||||
rngs[j][1].fill_bytes(&mut g);
|
||||
g = g
|
||||
.iter()
|
||||
.zip(t)
|
||||
.zip(&r)
|
||||
.map(|((g, t), r)| *g ^ *t ^ *r)
|
||||
.collect();
|
||||
gs.push(g.clone());
|
||||
}
|
||||
self.table = Some(utils::transpose(&ts));
|
||||
|
||||
OTReceiverSetup { table: gs }
|
||||
}
|
||||
|
||||
pub fn receive(&mut self, choice: &[bool], send: OTSenderSend) -> OTReceiverReceive {
|
||||
let mut values: Vec<Block> = Vec::with_capacity(choice.len());
|
||||
let r = utils::boolvec_to_u8vec(choice);
|
||||
let ts = self.table.as_ref().unwrap();
|
||||
|
||||
for (j, b) in choice.iter().enumerate() {
|
||||
let t: [u8; 16] = ts[j].clone().try_into().unwrap();
|
||||
let t = Block::from(t);
|
||||
let y = send.encrypted_values[j];
|
||||
let y = if *b { y[1] } else { y[0] };
|
||||
let y = y ^ t.hash_tweak(&mut self.cipher, j);
|
||||
values.push(y);
|
||||
}
|
||||
|
||||
OTReceiverReceive { values }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use aes::cipher::{generic_array::GenericArray, NewBlockCipher};
|
||||
use aes::Aes128;
|
||||
use rand::{CryptoRng, Rng, SeedableRng};
|
||||
use rand_chacha::ChaCha12Rng;
|
||||
|
||||
#[test]
|
||||
fn test_ot() {
|
||||
let s_rng = ChaCha12Rng::from_entropy();
|
||||
let s_cipher = Aes128::new(GenericArray::from_slice(&[0u8; 16]));
|
||||
let r_rng = ChaCha12Rng::from_entropy();
|
||||
let r_cipher = Aes128::new(GenericArray::from_slice(&[0u8; 16]));
|
||||
|
||||
let mut receiver = OTReceiver::new(r_rng, r_cipher);
|
||||
let base_sender_setup = receiver.base_setup();
|
||||
|
||||
let mut sender = OTSender::new(s_rng, s_cipher, base_sender_setup);
|
||||
let base_receiver_setup = sender.base_setup();
|
||||
|
||||
let send_seeds = receiver.base_send_seeds(base_receiver_setup);
|
||||
sender.base_receive_seeds(send_seeds);
|
||||
|
||||
let choice = [false, true, false, true];
|
||||
let receiver_setup = receiver.extension_setup(&choice);
|
||||
sender.extension_setup(receiver_setup);
|
||||
|
||||
let inputs = [[Block::new(123), Block::new(456)]; 4];
|
||||
let send = sender.send(&inputs);
|
||||
let receive = receiver.receive(&choice, send);
|
||||
|
||||
let expected: Vec<Block> = inputs
|
||||
.iter()
|
||||
.zip(choice)
|
||||
.map(|(input, choice)| input[choice as usize])
|
||||
.collect();
|
||||
|
||||
assert_eq!(expected, receive.values);
|
||||
}
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
pub mod base;
|
||||
pub mod extension;
|
||||
|
||||
78
pop-mpc/src/utils.rs
Normal file
78
pop-mpc/src/utils.rs
Normal file
@@ -0,0 +1,78 @@
|
||||
#[inline]
|
||||
pub fn boolvec_to_u8vec(bv: &[bool]) -> Vec<u8> {
|
||||
let offset = if bv.len() % 8 == 0 { 0 } else { 1 };
|
||||
let mut v = vec![0u8; bv.len() / 8 + offset];
|
||||
for (i, b) in bv.iter().enumerate() {
|
||||
v[i / 8] |= (*b as u8) << (i % 8);
|
||||
}
|
||||
v
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn u8vec_to_boolvec(v: &[u8]) -> Vec<bool> {
|
||||
let mut bv = Vec::with_capacity(v.len() * 8);
|
||||
for byte in v.iter() {
|
||||
for i in 0..8 {
|
||||
bv.push((1 << i) & byte != 0);
|
||||
}
|
||||
}
|
||||
bv
|
||||
}
|
||||
|
||||
pub fn transpose(m: &Vec<Vec<u8>>) -> Vec<Vec<u8>> {
|
||||
let col_count = m[0].len() * 8;
|
||||
let row_count = m.len();
|
||||
|
||||
let mut m_: Vec<Vec<u8>> = Vec::with_capacity(col_count);
|
||||
|
||||
for j in 0..col_count {
|
||||
let byte_n = j >> 3;
|
||||
let bit_idx = j % 8;
|
||||
|
||||
let mut row_bits: Vec<bool> = (0..row_count)
|
||||
.map(|i| ((m[i][byte_n] >> (7 - bit_idx)) & 1) == 1)
|
||||
.collect();
|
||||
row_bits.reverse();
|
||||
let mut row = boolvec_to_u8vec(&row_bits);
|
||||
row.reverse();
|
||||
m_.push(row);
|
||||
}
|
||||
|
||||
m_
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::block::Block;
|
||||
use rand::{CryptoRng, Rng, SeedableRng};
|
||||
use rand_chacha::ChaCha12Rng;
|
||||
|
||||
#[test]
|
||||
fn test_transpose() {
|
||||
let mut rng = ChaCha12Rng::from_entropy();
|
||||
let a: Vec<Vec<u8>> = (0..256)
|
||||
.map(|i| Vec::from(Block::random(&mut rng).to_be_bytes()))
|
||||
.collect();
|
||||
let b = transpose(&a);
|
||||
assert_eq!(a, transpose(&b));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_boolvec_to_u8vec() {
|
||||
let v = (0..128)
|
||||
.map(|_| rand::random::<bool>())
|
||||
.collect::<Vec<bool>>();
|
||||
let v_ = boolvec_to_u8vec(&v);
|
||||
let v__ = u8vec_to_boolvec(&v_);
|
||||
assert_eq!(v, v__);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_u8vec_to_boolvec() {
|
||||
let v = (0..128).map(|_| rand::random::<u8>()).collect::<Vec<u8>>();
|
||||
let v_ = u8vec_to_boolvec(&v);
|
||||
let v__ = boolvec_to_u8vec(&v_);
|
||||
assert_eq!(v, v__);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user