mirror of
https://github.com/tlsnotary/tlsn.git
synced 2026-04-28 03:00:14 -04:00
comments
This commit is contained in:
@@ -32,6 +32,16 @@ impl Block {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
// OT extension Sender must break correlation between his 2 masks before
|
||||
// using them in 1-out-of-2 Oblivious Transfer. Every pair of masks has
|
||||
// a constant correlation: their XOR equals a delta (delta is choice bits
|
||||
// in base OT).
|
||||
// If masks were used as-is in OT, Receiver could infer bits of delta and break
|
||||
// the OT security.
|
||||
// For performance reasons, we don't use a hash but a construction which has
|
||||
// tweakable correlation robustness (tcr). The GKWY20 paper shows (in
|
||||
// Section 7.4) how to achieve tcr using a fixed-key cipher C instead of a
|
||||
// hash, i.e. instead of Hash(x, i) we must do C(C(x) xor i) xor C(x).
|
||||
pub fn hash_tweak<C: BlockCipher<BlockSize = U16> + BlockEncrypt>(
|
||||
&self,
|
||||
c: &mut C,
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
//! this crate implements the CO15 Oblivious Transfer protocol from
|
||||
//! [ref1] https://eprint.iacr.org/2015/267.pdf (see Figure 1)
|
||||
|
||||
pub mod errors;
|
||||
pub mod receiver;
|
||||
pub mod sender;
|
||||
|
||||
@@ -66,6 +66,7 @@ impl<R: Rng + CryptoRng> ReceiveCore for ReceiverCore<R> {
|
||||
if choice.len() != self.count {
|
||||
return Err(ReceiverCoreError::InvalidChoiceLength);
|
||||
}
|
||||
// point_table is A in [ref1]
|
||||
let point_table = RistrettoBasepointTable::create(&sender_setup.public_key);
|
||||
let zero = &Scalar::zero() * &point_table;
|
||||
let one = &Scalar::one() * &point_table;
|
||||
@@ -73,10 +74,14 @@ impl<R: Rng + CryptoRng> ReceiveCore for ReceiverCore<R> {
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, b)| {
|
||||
// x is b in [ref1]
|
||||
let x = Scalar::random(&mut self.rng);
|
||||
let c = if *b { one } else { zero };
|
||||
// k is B in [ref1]
|
||||
let k = c + &x * &RISTRETTO_BASEPOINT_TABLE;
|
||||
// h is k_r in [ref1] == hash(A^b)
|
||||
let h = Block::hash_point(&(&x * &point_table), i as u32);
|
||||
// we send the k values to the Sender and keep the h values
|
||||
(k, h)
|
||||
})
|
||||
.unzip();
|
||||
@@ -101,7 +106,9 @@ impl<R: Rng + CryptoRng> ReceiveCore for ReceiverCore<R> {
|
||||
.zip(hashes)
|
||||
.zip(payload.encrypted_values.iter())
|
||||
.map(|((c, h), v)| {
|
||||
// select an encrypted value based on the choice bit
|
||||
let b = if *c { v[1] } else { v[0] };
|
||||
// decrypt it with the corresponding key (the key is a hash)
|
||||
*h ^ b
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -18,7 +18,9 @@ pub enum State {
|
||||
pub struct SenderCore<R = ChaCha12Rng> {
|
||||
rng: R,
|
||||
count: usize,
|
||||
// private_key is random "a" in [ref1]
|
||||
private_key: Option<Scalar>,
|
||||
// public_key is A == g^a in [ref1]
|
||||
public_key: Option<RistrettoPoint>,
|
||||
state: State,
|
||||
}
|
||||
@@ -84,12 +86,15 @@ impl<R: Rng + CryptoRng> SendCore for SenderCore<R> {
|
||||
}
|
||||
let private_key = self.private_key.unwrap();
|
||||
let ninputs = inputs.len();
|
||||
// ys is A^a in [ref1]
|
||||
let ys = private_key * self.public_key.unwrap();
|
||||
let mut encrypted_values: Vec<[Block; 2]> = Vec::with_capacity(ninputs);
|
||||
|
||||
for (i, (input, receiver_key)) in inputs.iter().zip(receiver_setup.keys).enumerate() {
|
||||
// yr is B^a in [ref1]
|
||||
let yr = private_key * receiver_key;
|
||||
let k0 = Block::hash_point(&yr, i as u32);
|
||||
// yr - ys == (B/A)^a in [ref1]
|
||||
let k1 = Block::hash_point(&(yr - ys), i as u32);
|
||||
encrypted_values.push([k0 ^ input[0], k1 ^ input[1]]);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//! This crate implements the KOS15 Oblivious Transfer extension protocol.
|
||||
|
||||
pub mod errors;
|
||||
pub mod receiver;
|
||||
pub mod sender;
|
||||
@@ -20,6 +22,7 @@ const K: usize = 40;
|
||||
pub trait ExtSendCore {
|
||||
fn state(&self) -> sender::State;
|
||||
|
||||
//
|
||||
fn base_setup(
|
||||
&mut self,
|
||||
base_sender_setup: BaseSenderSetup,
|
||||
@@ -42,6 +45,8 @@ pub trait ExtRandomSendCore: ExtSendCore {
|
||||
ExtSendCore::state(self)
|
||||
}
|
||||
|
||||
// Sender in OT extension acts as Receiver in base OT and receives a setup
|
||||
// message from base OT Sender and responds with its own setup message.
|
||||
fn base_setup(
|
||||
&mut self,
|
||||
base_sender_setup: BaseSenderSetup,
|
||||
@@ -74,6 +79,8 @@ pub trait ExtRandomSendCore: ExtSendCore {
|
||||
pub trait ExtReceiveCore {
|
||||
fn state(&self) -> &receiver::State;
|
||||
|
||||
// Receiver in OT extension acts as Sender in base OT and sends the first
|
||||
// base OT setup message.
|
||||
fn base_setup(&mut self) -> Result<BaseSenderSetup, ExtReceiverCoreError>;
|
||||
|
||||
fn base_send(
|
||||
@@ -96,6 +103,8 @@ pub trait ExtRandomReceiveCore: ExtReceiveCore {
|
||||
ExtReceiveCore::state(self)
|
||||
}
|
||||
|
||||
// Receiver in OT extension acts as Sender in base OT and sends the first
|
||||
// base OT setup message.
|
||||
fn base_setup(&mut self) -> Result<BaseSenderSetup, ExtReceiverCoreError> {
|
||||
ExtReceiveCore::base_setup(self)
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ pub struct ExtReceiverCore<R = ChaCha12Rng, C = Aes128, OT = SenderCore<ChaCha12
|
||||
base: OT,
|
||||
state: State,
|
||||
count: usize,
|
||||
// seeds are the result of running base OT setup. They are used to seed the
|
||||
// RNGs.
|
||||
seeds: Option<Vec<[Block; 2]>>,
|
||||
rngs: Option<Vec<[ChaCha12Rng; 2]>>,
|
||||
table: Option<Vec<Vec<u8>>>,
|
||||
@@ -174,12 +176,19 @@ where
|
||||
.as_mut()
|
||||
.ok_or(ExtReceiverCoreError::BaseOTNotSetup)?;
|
||||
|
||||
// The amount of choice bits must be equal to the amount of OT instances
|
||||
// needed plus extra 256 instances which will be sacrificed as part of the
|
||||
// KOS protocol.
|
||||
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]; BASE_COUNT];
|
||||
let mut gs: Vec<Vec<u8>> = vec![vec![0u8; ncols / 8]; BASE_COUNT];
|
||||
|
||||
// Note that for each row j of the matrix gs which will be sent to Sender,
|
||||
// Sender knows either rng[0] or rng[1] depending on his choice bit during
|
||||
// base OT. If he knows rng[1] then he will XOR it with gs[j] and get a
|
||||
// row ( ts[j] ^ r ). But if he knows rng[0] then his row will be ts[j].
|
||||
for j in 0..BASE_COUNT {
|
||||
rngs[j][0].fill_bytes(&mut ts[j]);
|
||||
rngs[j][1].fill_bytes(&mut gs[j]);
|
||||
@@ -190,6 +199,12 @@ where
|
||||
.map(|((g, t), r)| *g ^ *t ^ *r)
|
||||
.collect();
|
||||
}
|
||||
|
||||
// After Sender transposes his matrix, he will have a table S such that
|
||||
// for each row j:
|
||||
// self.table[j] = S[j], if our choice bit was 0 or
|
||||
// self.table[j] = S[j] ^ delta, if our choice bit was 1
|
||||
// (note that delta is known only to Sender)
|
||||
self.table = Some(utils::transpose(&ts));
|
||||
self.state = State::Setup(ChoiceState {
|
||||
choice: Vec::from(choice),
|
||||
|
||||
@@ -30,9 +30,17 @@ pub struct ExtSenderCore<C = Aes128, OT = ReceiverCore<ChaCha12Rng>> {
|
||||
state: State,
|
||||
count: usize,
|
||||
sent: usize,
|
||||
// choice bits for the base OT protocol
|
||||
base_choice: Vec<bool>,
|
||||
// seeds are the result of running base OT setup. They are used to seed the
|
||||
// RNGs.
|
||||
seeds: Option<Vec<Block>>,
|
||||
rngs: Option<Vec<ChaCha12Rng>>,
|
||||
// table's rows are such that for each row j:
|
||||
// table[j] = R[j], if Receiver's choice bit was 0 or
|
||||
// table[j] = R[j] ^ base_choice, if Receiver's choice bit was 1
|
||||
// (where R is the table which Receiver has. Note that base_choice is known
|
||||
// only to us).
|
||||
table: Option<Vec<Vec<u8>>>,
|
||||
}
|
||||
|
||||
@@ -41,6 +49,9 @@ pub struct ExtSenderPayload {
|
||||
pub encrypted_values: Vec<[Block; 2]>,
|
||||
}
|
||||
|
||||
// Having 2 messages that Receiver chooses from, we encrypt each message with
|
||||
// a unique mask (i.e. XOR the message them with the mask). Receiver who knows
|
||||
// only 1 mask will be able to decrypt only 1 message out of 2.
|
||||
fn encrypt_values<C: BlockCipher<BlockSize = U16> + BlockEncrypt>(
|
||||
cipher: &mut C,
|
||||
inputs: &[[Block; 2]],
|
||||
@@ -51,6 +62,9 @@ fn encrypt_values<C: BlockCipher<BlockSize = U16> + BlockEncrypt>(
|
||||
let mut encrypted_values: Vec<[Block; 2]> = Vec::with_capacity(table.len());
|
||||
let base_choice: [u8; 16] = utils::boolvec_to_u8vec(base_choice).try_into().unwrap();
|
||||
let delta = Block::from(base_choice);
|
||||
// If Receiver used *random* choice bits during OT extension setup, he will now
|
||||
// instruct us to de-randomize, so that the value corresponding to his *actual*
|
||||
// choice bit would be masked by that mask which Receiver knows.
|
||||
let flip = flip.unwrap_or(vec![false; inputs.len()]);
|
||||
for (j, (input, flip)) in inputs.iter().zip(flip).enumerate() {
|
||||
let q: [u8; 16] = table[j].clone().try_into().unwrap();
|
||||
|
||||
Reference in New Issue
Block a user