impl ole with rot

This commit is contained in:
sinu
2023-12-21 21:38:08 -08:00
parent c3d958c0c8
commit 6071433659
11 changed files with 51 additions and 1163 deletions

View File

@@ -1,227 +0,0 @@
//! This module is a testing ground for the E2F protocol (page 33) from <https://eprint.iacr.org/2023/964>
mod prover;
mod verifier;
use crate::func::ole::Ole;
use mpz_share_conversion_core::fields::p256::P256;
pub use prover::Prover;
pub use verifier::Verifier;
/// Returns the x-coordinate shares of the sum of the two EC points
pub fn e2f(
prover_point: (P256, P256),
prover: &mut Prover,
verifier_point: (P256, P256),
verifier: &mut Verifier,
) -> (P256, P256) {
let mut ole = Ole::default();
// Preprocessing
prover.preprocess1();
verifier.preprocess1();
prover.preprocess2_ole_input(&mut ole);
verifier.preprocess2_ole_input(&mut ole);
prover.preprocess2_ole_output(&mut ole);
verifier.preprocess2_ole_output(&mut ole);
prover.preprocess3();
verifier.preprocess3();
prover.preprocess4();
verifier.preprocess4();
// Handshake
prover.handshake5_input_ec(prover_point);
verifier.handshake5_input_ec(verifier_point);
let varespilon1_share_prover = prover.handshake5_varepsilon1_share_open();
let varespilon1_share_verifier = verifier.handshake5_varepsilon1_share_open();
let varepsilon1 = varespilon1_share_prover + varespilon1_share_verifier;
prover.handshake5_set_omega(varepsilon1);
verifier.handshake5_set_omega(varepsilon1);
let omega_share_prover = prover.handshake6_omega_share_open();
let omega_share_verifier = verifier.handshake6_omega_share_open();
let omega = omega_share_prover + omega_share_verifier;
let varespilon2_share_prover = prover.handshake6_varepsilon2_share_open();
let varespilon2_share_verifier = verifier.handshake6_varepsilon2_share_open();
let varepsilon2 = varespilon2_share_prover + varespilon2_share_verifier;
prover.handshake6_set_eta(omega, varepsilon2);
verifier.handshake6_set_eta(omega, varepsilon2);
let varepsilon3_share_prover = prover.handshake7_varepsilon3_share_open();
let varepsilon3_share_verifier = verifier.handshake7_varepsilon3_share_open();
let varepsilon3 = varepsilon3_share_prover + varepsilon3_share_verifier;
prover.handshake7_set_z1(varepsilon3);
verifier.handshake7_set_z2(varepsilon3);
// Output
let z1 = prover.handshake8_z1_open();
let z2 = verifier.handshake8_z2_open();
(z1, z2)
}
#[cfg(test)]
mod tests {
use super::*;
use mpz_share_conversion_core::Field;
use p256::{elliptic_curve::sec1::ToEncodedPoint, EncodedPoint, NonZeroScalar, PublicKey};
use rand::thread_rng;
#[test]
fn test_e2f() {
let mut rng = thread_rng();
let prover_scalar = NonZeroScalar::random(&mut rng);
let verifier_scalar = NonZeroScalar::random(&mut rng);
let prover_ec = point_to_p256(scalar_to_encoded_point(prover_scalar));
let mut prover = Prover::default();
let verifier_ec = point_to_p256(scalar_to_encoded_point(verifier_scalar));
let mut verifier = Verifier::default();
let (z1, z2) = e2f(prover_ec, &mut prover, verifier_ec, &mut verifier);
let x_ec_expected = add_ec_points(prover_ec, verifier_ec);
assert_eq!(z1 + z2, x_ec_expected.0);
}
#[test]
fn test_sharing_sums() {
let mut rng = thread_rng();
let prover_scalar = NonZeroScalar::random(&mut rng);
let verifier_scalar = NonZeroScalar::random(&mut rng);
let prover_ec = point_to_p256(scalar_to_encoded_point(prover_scalar));
let mut prover = Prover::default();
let verifier_ec = point_to_p256(scalar_to_encoded_point(verifier_scalar));
let mut verifier = Verifier::default();
let _ = e2f(prover_ec, &mut prover, verifier_ec, &mut verifier);
// Assertions
// c
let c = prover.a1.unwrap() * prover.b1.unwrap()
+ prover.a1_b2_share.unwrap()
+ prover.a2_b1_share.unwrap()
+ verifier.a2_b1_share.unwrap()
+ verifier.a1_b2_share.unwrap()
+ verifier.a2.unwrap() * verifier.b2.unwrap();
assert_eq!(prover.c1.unwrap() + verifier.c2.unwrap(), c);
// c_prime
let c_prime = prover.a1.unwrap() * prover.b1_prime.unwrap()
+ prover.a1_b2_prime_share.unwrap()
+ prover.a2_b1_prime_share.unwrap()
+ verifier.a2_b1_prime_share.unwrap()
+ verifier.a1_b2_prime_share.unwrap()
+ verifier.a2.unwrap() * verifier.b2_prime.unwrap();
assert_eq!(
prover.c1_prime.unwrap() + verifier.c2_prime.unwrap(),
c_prime
);
// r_squared
let r_squared = prover.r1.unwrap() * prover.r1.unwrap()
+ P256::new(2).unwrap() * (prover.r1_r2_share.unwrap() + verifier.r1_r2_share.unwrap())
+ verifier.r2.unwrap() * verifier.r2.unwrap();
assert_eq!(
prover.r_squared_share.unwrap() + verifier.r_squared_share.unwrap(),
r_squared
);
// omega
let b = prover.b1.unwrap() + verifier.b2.unwrap();
let varepsilon1 = -prover.ec_point.unwrap().0 + verifier.ec_point.unwrap().0 + -b;
let omega = varepsilon1 * (prover.a1.unwrap() + verifier.a2.unwrap())
+ prover.c1.unwrap()
+ verifier.c2.unwrap();
assert_eq!(
prover.omega_share.unwrap() + verifier.omega_share.unwrap(),
omega
);
// eta
let b_prime = prover.b1_prime.unwrap() + verifier.b2_prime.unwrap();
let varepsilon2 = -prover.ec_point.unwrap().1 + verifier.ec_point.unwrap().1 + -b_prime;
let eta = (prover.omega_share.unwrap() + verifier.omega_share.unwrap()).inverse()
* (varepsilon2 * (prover.a1.unwrap() + verifier.a2.unwrap())
+ prover.c1_prime.unwrap()
+ verifier.c2_prime.unwrap());
assert_eq!(prover.eta_share.unwrap() + verifier.eta_share.unwrap(), eta);
// z
let varepsilon3 = prover.eta_share.unwrap()
+ verifier.eta_share.unwrap()
+ -prover.r1.unwrap()
+ -verifier.r2.unwrap();
let z = varepsilon3 * varepsilon3
+ P256::new(2).unwrap() * varepsilon3 * (prover.r1.unwrap() + verifier.r2.unwrap())
+ prover.r_squared_share.unwrap()
+ verifier.r_squared_share.unwrap()
+ -prover.ec_point.unwrap().0
+ -verifier.ec_point.unwrap().0;
assert_eq!(prover.z1.unwrap() + verifier.z2.unwrap(), z);
}
#[test]
fn test_add_ec_points() {
let mut rng = thread_rng();
let scalar1 = p256::NonZeroScalar::random(&mut rng);
let scalar2 = p256::NonZeroScalar::random(&mut rng);
let pk1 = PublicKey::from_secret_scalar(&scalar1);
let pk2 = PublicKey::from_secret_scalar(&scalar2);
let pr1 = pk1.to_projective();
let pr2 = pk2.to_projective();
let ec_added_expected = point_to_p256((pr1 + pr2).to_affine().to_encoded_point(false));
let ec1 = pr1.to_affine().to_encoded_point(false);
let ec2 = pr2.to_affine().to_encoded_point(false);
let ec_added = add_ec_points(point_to_p256(ec1), point_to_p256(ec2));
assert_eq!(ec_added, ec_added_expected);
}
fn add_ec_points((x1, y1): (P256, P256), (x2, y2): (P256, P256)) -> (P256, P256) {
let nominator = y2 + -y1;
let denominator = x2 + -x1;
let fraction = nominator * denominator.inverse();
let squared = fraction * fraction;
let x_r = squared + -x1 + -x2;
let y_r = fraction * (x1 + -x_r) + -y1;
(x_r, y_r)
}
fn scalar_to_encoded_point(scalar: NonZeroScalar) -> EncodedPoint {
PublicKey::from_secret_scalar(&scalar).to_encoded_point(false)
}
fn point_to_p256(point: EncodedPoint) -> (P256, P256) {
let mut x: [u8; 32] = (*point.x().unwrap()).into();
let mut y: [u8; 32] = (*point.y().unwrap()).into();
// reverse to little endian
x.reverse();
y.reverse();
let x = P256::try_from(x).unwrap();
let y = P256::try_from(y).unwrap();
(x, y)
}
}

View File

@@ -1,141 +0,0 @@
//! The prover implementation
use crate::func::ole::Ole;
use crate::func::Role;
use mpz_share_conversion_core::fields::{p256::P256, Field, UniformRand};
use rand::thread_rng;
#[derive(Debug, Default)]
pub struct Prover {
// Preprocess 1
pub(crate) a1: Option<P256>,
pub(crate) b1: Option<P256>,
pub(crate) b1_prime: Option<P256>,
pub(crate) r1: Option<P256>,
// Preprocess 2
pub(crate) a1_b2_share: Option<P256>,
pub(crate) a2_b1_share: Option<P256>,
pub(crate) a1_b2_prime_share: Option<P256>,
pub(crate) a2_b1_prime_share: Option<P256>,
pub(crate) r1_r2_share: Option<P256>,
// Preprocess 3
pub(crate) c1: Option<P256>,
pub(crate) c1_prime: Option<P256>,
// Preprocess 4
pub(crate) r_squared_share: Option<P256>,
// Handshake 5
pub(crate) ec_point: Option<(P256, P256)>,
pub(crate) omega_share: Option<P256>,
// Handshake 6
pub(crate) eta_share: Option<P256>,
// Handshake 7
pub(crate) z1: Option<P256>,
}
impl Prover {
pub fn preprocess1(&mut self) {
let mut rng = thread_rng();
self.a1 = Some(P256::rand(&mut rng));
self.b1 = Some(P256::rand(&mut rng));
self.b1_prime = Some(P256::rand(&mut rng));
self.r1 = Some(P256::rand(&mut rng));
}
pub fn preprocess2_ole_input(&mut self, ole: &mut Ole<P256>) {
let a1 = self.a1.unwrap();
let b1 = self.b1.unwrap();
let b1_prime = self.b1_prime.unwrap();
let r1 = self.r1.unwrap();
ole.input(Role::Sender, vec![a1, b1, a1, b1_prime, r1]);
}
pub fn preprocess2_ole_output(&mut self, ole: &mut Ole<P256>) {
let output = ole.output(Role::Sender);
self.a1_b2_share = Some(output[0]);
self.a2_b1_share = Some(output[1]);
self.a1_b2_prime_share = Some(output[2]);
self.a2_b1_prime_share = Some(output[3]);
self.r1_r2_share = Some(output[4]);
}
pub fn preprocess3(&mut self) {
let a1_b1_share = self.a1.unwrap() * self.b1.unwrap();
let a1_b2_share = self.a1_b2_share.unwrap();
let a2_b1_share = self.a2_b1_share.unwrap();
self.c1 = Some(a1_b1_share + a1_b2_share + a2_b1_share);
let a1_b1_prime_share = self.a1.unwrap() * self.b1_prime.unwrap();
let a1_b2_prime_share = self.a1_b2_prime_share.unwrap();
let a2_b1_prime_share = self.a2_b1_prime_share.unwrap();
self.c1_prime = Some(a1_b1_prime_share + a1_b2_prime_share + a2_b1_prime_share);
}
pub fn preprocess4(&mut self) {
let r1_squared = self.r1.unwrap() * self.r1.unwrap();
let two = P256::new(2).unwrap();
let r1_r2_share = self.r1_r2_share.unwrap();
self.r_squared_share = Some(r1_squared + two * r1_r2_share);
}
pub fn handshake5_input_ec(&mut self, ec_point: (P256, P256)) {
self.ec_point = Some(ec_point);
}
pub fn handshake5_varepsilon1_share_open(&self) -> P256 {
-self.ec_point.unwrap().0 + -self.b1.unwrap()
}
pub fn handshake5_set_omega(&mut self, varepsilon1: P256) {
self.omega_share = Some(varepsilon1 * self.a1.unwrap() + self.c1.unwrap());
}
pub fn handshake6_omega_share_open(&self) -> P256 {
self.omega_share.unwrap()
}
pub fn handshake6_varepsilon2_share_open(&self) -> P256 {
-self.ec_point.unwrap().1 + -self.b1_prime.unwrap()
}
pub fn handshake6_set_eta(&mut self, omega: P256, varepsilon2: P256) {
if omega == P256::new(0).unwrap() {
panic!("omega is 0");
}
let omega_inv = omega.inverse();
let a1 = self.a1.unwrap();
let c1_prime = self.c1_prime.unwrap();
self.eta_share = Some(omega_inv * (varepsilon2 * a1 + c1_prime));
}
pub fn handshake7_varepsilon3_share_open(&self) -> P256 {
self.eta_share.unwrap() + -self.r1.unwrap()
}
pub fn handshake7_set_z1(&mut self, varepsilon3: P256) {
let two = P256::new(2).unwrap();
let r1 = self.r1.unwrap();
let r_squared_share = self.r_squared_share.unwrap();
let x1 = self.ec_point.unwrap().0;
self.z1 = Some(varepsilon3 * varepsilon3 + two * varepsilon3 * r1 + r_squared_share + -x1);
}
pub fn handshake8_z1_open(&self) -> P256 {
self.z1.unwrap()
}
}

View File

@@ -1,141 +0,0 @@
//! The verifier implementation
use crate::func::ole::Ole;
use crate::func::Role;
use mpz_share_conversion_core::fields::{p256::P256, Field, UniformRand};
use rand::thread_rng;
#[derive(Debug, Default)]
pub struct Verifier {
// Preprocess 1
pub(crate) a2: Option<P256>,
pub(crate) b2: Option<P256>,
pub(crate) b2_prime: Option<P256>,
pub(crate) r2: Option<P256>,
// Preprocess 2
pub(crate) a1_b2_share: Option<P256>,
pub(crate) a2_b1_share: Option<P256>,
pub(crate) a1_b2_prime_share: Option<P256>,
pub(crate) a2_b1_prime_share: Option<P256>,
pub(crate) r1_r2_share: Option<P256>,
// Preprocess 3
pub(crate) c2: Option<P256>,
pub(crate) c2_prime: Option<P256>,
// Preprocess 4
pub(crate) r_squared_share: Option<P256>,
// Handshake 5
pub(crate) ec_point: Option<(P256, P256)>,
pub(crate) omega_share: Option<P256>,
// Handshake 6
pub(crate) eta_share: Option<P256>,
// Handshake 7
pub(crate) z2: Option<P256>,
}
impl Verifier {
pub fn preprocess1(&mut self) {
let mut rng = thread_rng();
self.a2 = Some(P256::rand(&mut rng));
self.b2 = Some(P256::rand(&mut rng));
self.b2_prime = Some(P256::rand(&mut rng));
self.r2 = Some(P256::rand(&mut rng));
}
pub fn preprocess2_ole_input(&mut self, ole: &mut Ole<P256>) {
let a2 = self.a2.unwrap();
let b2 = self.b2.unwrap();
let b2_prime = self.b2_prime.unwrap();
let r2 = self.r2.unwrap();
ole.input(Role::Receiver, vec![b2, a2, b2_prime, a2, r2]);
}
pub fn preprocess2_ole_output(&mut self, ole: &mut Ole<P256>) {
let output = ole.output(Role::Receiver);
self.a1_b2_share = Some(output[0]);
self.a2_b1_share = Some(output[1]);
self.a1_b2_prime_share = Some(output[2]);
self.a2_b1_prime_share = Some(output[3]);
self.r1_r2_share = Some(output[4]);
}
pub fn preprocess3(&mut self) {
let a2_b2_share = self.a2.unwrap() * self.b2.unwrap();
let a1_b2_share = self.a1_b2_share.unwrap();
let a2_b1_share = self.a2_b1_share.unwrap();
self.c2 = Some(a2_b2_share + a1_b2_share + a2_b1_share);
let a2_b2_prime_share = self.a2.unwrap() * self.b2_prime.unwrap();
let a1_b2_prime_share = self.a1_b2_prime_share.unwrap();
let a2_b1_prime_share = self.a2_b1_prime_share.unwrap();
self.c2_prime = Some(a2_b2_prime_share + a1_b2_prime_share + a2_b1_prime_share);
}
pub fn preprocess4(&mut self) {
let r2_squared = self.r2.unwrap() * self.r2.unwrap();
let two = P256::new(2).unwrap();
let r1_r2_share = self.r1_r2_share.unwrap();
self.r_squared_share = Some(r2_squared + two * r1_r2_share);
}
pub fn handshake5_input_ec(&mut self, ec_point: (P256, P256)) {
self.ec_point = Some(ec_point);
}
pub fn handshake5_varepsilon1_share_open(&self) -> P256 {
self.ec_point.unwrap().0 + -self.b2.unwrap()
}
pub fn handshake5_set_omega(&mut self, varepsilon1: P256) {
self.omega_share = Some(varepsilon1 * self.a2.unwrap() + self.c2.unwrap());
}
pub fn handshake6_omega_share_open(&self) -> P256 {
self.omega_share.unwrap()
}
pub fn handshake6_varepsilon2_share_open(&self) -> P256 {
self.ec_point.unwrap().1 + -self.b2_prime.unwrap()
}
pub fn handshake6_set_eta(&mut self, omega: P256, varepsilon2: P256) {
if omega == P256::new(0).unwrap() {
panic!("omega is 0");
}
let omega_inv = omega.inverse();
let a2 = self.a2.unwrap();
let c2_prime = self.c2_prime.unwrap();
self.eta_share = Some(omega_inv * (varepsilon2 * a2 + c2_prime));
}
pub fn handshake7_varepsilon3_share_open(&self) -> P256 {
self.eta_share.unwrap() + -self.r2.unwrap()
}
pub fn handshake7_set_z2(&mut self, varepsilon3: P256) {
let two = P256::new(2).unwrap();
let r2 = self.r2.unwrap();
let r_squared_share = self.r_squared_share.unwrap();
let x2 = self.ec_point.unwrap().0;
self.z2 = Some(two * varepsilon3 * r2 + r_squared_share + -x2);
}
pub fn handshake8_z2_open(&self) -> P256 {
self.z2.unwrap()
}
}

106
src/f2.rs
View File

@@ -1,106 +0,0 @@
use itybity::{BitLength, FromBitIterator, GetBit, Lsb0, Msb0};
use mpz_share_conversion_core::fields::Field;
use rand::distributions::{Distribution, Standard};
use std::ops::{Add, Mul, Neg};
/// A simple boolean field type
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct F2 {
inner: u8,
}
impl F2 {
/// Create a new `F2` from a `bool`.
///
/// `False` encodes 0 and `true` encodes 1.
pub fn new(value: bool) -> Self {
Self { inner: value as u8 }
}
}
impl Field for F2 {
const BIT_SIZE: u32 = 1;
fn zero() -> Self {
Self::new(false)
}
fn one() -> Self {
Self::new(true)
}
fn two_pow(_rhs: u32) -> Self {
unimplemented!()
}
fn inverse(self) -> Self {
if self.inner == 0 {
panic!("No inverse for 0")
}
Self::one()
}
fn to_le_bytes(&self) -> Vec<u8> {
unimplemented!()
}
fn to_be_bytes(&self) -> Vec<u8> {
unimplemented!()
}
}
impl Distribution<F2> for Standard {
fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> F2 {
F2::new(rng.gen())
}
}
impl Add for F2 {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self::new((self.inner ^ rhs.inner) != 0)
}
}
impl Mul for F2 {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self::new(self.inner & rhs.inner != 0)
}
}
impl Neg for F2 {
type Output = Self;
fn neg(self) -> Self::Output {
self
}
}
impl BitLength for F2 {
const BITS: usize = 1;
}
impl GetBit<Lsb0> for F2 {
fn get_bit(&self, _index: usize) -> bool {
unimplemented!()
}
}
impl GetBit<Msb0> for F2 {
fn get_bit(&self, _index: usize) -> bool {
unimplemented!()
}
}
impl FromBitIterator for F2 {
fn from_lsb0_iter(_iter: impl IntoIterator<Item = bool>) -> Self {
unimplemented!()
}
fn from_msb0_iter(_iter: impl IntoIterator<Item = bool>) -> Self {
unimplemented!()
}
}

View File

@@ -1,140 +0,0 @@
//! This module implements the COT functionality (page 5) from <https://eprint.iacr.org/2015/546> without errors.
use mpz_share_conversion_core::fields::UniformRand;
use super::Role;
use crate::f2::F2;
#[derive(Debug, Default)]
pub struct Cot {
kappa: usize,
l: usize,
delta: Vec<F2>,
t: Vec<Vec<F2>>,
q: Vec<Vec<F2>>,
}
impl Cot {
pub fn new(kappa: usize, l: usize) -> Self {
Self {
kappa,
l,
..Default::default()
}
}
pub fn initialize_input_delta(&mut self, delta: Vec<F2>) {
assert_eq!(delta.len(), self.kappa);
self.delta = delta;
}
pub fn extend_input_x(&mut self, x: Vec<Vec<F2>>) {
assert!(self.t.is_empty());
assert!(self.q.is_empty());
assert_eq!(x.len(), self.l);
for vec in x.iter() {
assert_eq!(vec.len(), self.kappa);
}
let mut rng = rand::thread_rng();
for _ in 0..self.l {
let inner = (0..self.kappa)
.map(|_| F2::rand(&mut rng))
.collect::<Vec<F2>>();
self.t.push(inner);
}
for (ti, xi) in self.t.iter().zip(x.iter()) {
let xi_times_delta = self
.delta
.iter()
.zip(xi.iter())
.map(|(&deltai, &xi)| deltai * xi)
.collect::<Vec<F2>>();
self.q.push(
ti.iter()
.zip(xi_times_delta.iter())
.map(|(&tk, &xtdk)| tk + xtdk)
.collect::<Vec<F2>>(),
);
}
}
pub fn output(&mut self, role: Role) -> Vec<Vec<F2>> {
let out = if role == Role::Sender {
std::mem::take(&mut self.q)
} else {
std::mem::take(&mut self.t)
};
std::mem::take(self);
out
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cot() {
let mut cot = Cot::new(5, 3);
let delta = vec![
F2::new(true),
F2::new(false),
F2::new(true),
F2::new(false),
F2::new(true),
];
let x = vec![
vec![
F2::new(true),
F2::new(false),
F2::new(true),
F2::new(false),
F2::new(true),
],
vec![
F2::new(false),
F2::new(true),
F2::new(false),
F2::new(true),
F2::new(true),
],
vec![
F2::new(false),
F2::new(true),
F2::new(true),
F2::new(false),
F2::new(false),
],
];
cot.initialize_input_delta(delta.clone());
cot.extend_input_x(x.clone());
let q = cot.output(Role::Sender);
let t = cot.output(Role::Receiver);
for ((qi, ti), xi) in q.iter().zip(t.iter()).zip(x.iter()) {
let qi_minus_ti = qi
.iter()
.zip(ti.iter())
.map(|(&qij, &tij)| qij + -tij)
.collect::<Vec<F2>>();
let xi_times_delta = xi
.iter()
.zip(delta.iter())
.map(|(&xij, &deltai)| xij * deltai)
.collect::<Vec<F2>>();
assert_eq!(qi_minus_ti, xi_times_delta);
}
}
}

View File

@@ -1,10 +0,0 @@
//! This module implements some functionalities.
pub mod cot;
pub mod ole;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Role {
Sender,
Receiver,
}

View File

@@ -1,100 +0,0 @@
//! This module implements an OLE functionality.
use super::Role;
use mpz_share_conversion_core::Field;
use rand::thread_rng;
#[derive(Debug)]
pub struct Ole<T: Field> {
input_sender: Vec<T>,
input_receiver: Vec<T>,
output: Vec<T>,
}
impl<T: Field> Default for Ole<T> {
fn default() -> Self {
Self {
input_sender: vec![],
input_receiver: vec![],
output: vec![],
}
}
}
impl<T: Field> Ole<T> {
pub fn input(&mut self, role: Role, input: Vec<T>) {
if role == Role::Sender {
self.input_sender = input;
} else {
self.input_receiver = input;
}
}
pub fn output(&mut self, role: Role) -> Vec<T> {
assert!(self.input_sender.len() == self.input_receiver.len());
if !self.output.is_empty() {
return std::mem::take(&mut self.output);
}
let mut rng = thread_rng();
let mut output = vec![];
let mut output_cached = vec![];
for (s, r) in self.input_sender.iter().zip(self.input_receiver.iter()) {
let s_out = T::rand(&mut rng);
let r_out = *s * *r + -s_out;
if role == Role::Sender {
output.push(s_out);
output_cached.push(r_out);
} else {
output.push(r_out);
output_cached.push(s_out);
}
}
self.input_sender.clear();
self.input_receiver.clear();
self.output = output_cached;
output
}
}
#[cfg(test)]
mod tests {
use mpz_share_conversion_core::fields::{p256::P256, UniformRand};
use super::*;
#[test]
fn test_ole() {
let mut ole = Ole::default();
let mut rng = thread_rng();
let input_sender = vec![
P256::rand(&mut rng),
P256::rand(&mut rng),
P256::rand(&mut rng),
];
let input_receiver = vec![
P256::rand(&mut rng),
P256::rand(&mut rng),
P256::rand(&mut rng),
];
ole.input(Role::Sender, input_sender.clone());
ole.input(Role::Receiver, input_receiver.clone());
let output_sender = ole.output(Role::Sender);
let output_receiver = ole.output(Role::Receiver);
for (((is, ir), os), or) in input_sender
.into_iter()
.zip(input_receiver)
.zip(output_sender)
.zip(output_receiver)
{
assert_eq!(is * ir, os + or);
}
}
}

View File

@@ -1,138 +0,0 @@
//! This module is a testing ground for the GHASH protocol (page 36) from <https://eprint.iacr.org/2023/964>
mod prover;
mod verifier;
use crate::func::ole::Ole;
use mpz_share_conversion_core::{fields::gf2_128::Gf2_128, Field};
pub use prover::Prover;
pub use verifier::Verifier;
pub fn ghash(blocks: &[Gf2_128], prover: &mut Prover, verifier: &mut Verifier) -> Gf2_128 {
let mut ole = Ole::default();
prover.preprocess_ole_input(&mut ole);
verifier.preprocess_ole_input(&mut ole);
prover.preprocess_ole_output(&mut ole);
verifier.preprocess_ole_output(&mut ole);
let d1 = prover.handshake_a_open_d();
let d2 = verifier.handshake_a_open_d();
let d = d1 + d2;
prover.handshake_a_set_di(d);
verifier.handshake_a_set_di(d);
prover.handshake_a_set_hi();
verifier.handshake_a_set_hi();
let ghash1 = prover.handshake_output_ghash(blocks);
let ghash2 = verifier.handshake_output_ghash(blocks);
ghash1 + ghash2
}
fn pascal_tri<T: Field>(n: usize) -> Vec<Vec<T>> {
let mut pascal = vec![vec![T::one()]];
for _ in 0..n {
let last_row = pascal.last().unwrap();
let mut new_row = vec![T::one()];
last_row
.iter()
.map_windows(|[&a, &b]| a + b)
.for_each(|el| {
new_row.push(el);
});
new_row.push(T::one());
pascal.push(new_row);
}
pascal
}
#[cfg(test)]
mod tests {
use super::*;
use mpz_share_conversion_core::fields::{compute_product_repeated, UniformRand};
use rand::thread_rng;
#[test]
fn test_ghash() {
let mut rng = thread_rng();
let blocks: Vec<Gf2_128> = (0..10).map(|_| Gf2_128::rand(&mut rng)).collect();
let h1: Gf2_128 = Gf2_128::rand(&mut rng);
let h2: Gf2_128 = Gf2_128::rand(&mut rng);
let h = h1 + h2;
let mut prover = Prover::new(blocks.len(), h1);
let mut verifier = Verifier::new(blocks.len(), h2);
let ghash = ghash(&blocks, &mut prover, &mut verifier);
let ghash_expected = {
let mut hi = vec![h];
compute_product_repeated(&mut hi, h, blocks.len());
blocks
.iter()
.zip(hi.iter())
.fold(Gf2_128::zero(), |acc, (&b, &h)| acc + (b * h))
};
assert_eq!(ghash, ghash_expected);
}
#[test]
fn test_ghash_invariants() {
let mut rng = thread_rng();
let blocks: Vec<Gf2_128> = (0..1).map(|_| Gf2_128::rand(&mut rng)).collect();
let h1: Gf2_128 = Gf2_128::rand(&mut rng);
let h2: Gf2_128 = Gf2_128::rand(&mut rng);
let mut prover = Prover::new(blocks.len(), h1);
let mut verifier = Verifier::new(blocks.len(), h2);
let _ = ghash(&blocks, &mut prover, &mut verifier);
assert_eq!(prover.d_powers[0], Gf2_128::one());
assert_eq!(verifier.d_powers[0], Gf2_128::one());
assert_eq!(prover.d_powers[1], verifier.d_powers[1]);
assert_eq!(prover.ai[1] + verifier.bi[1], prover.r1 * verifier.r2);
assert_eq!(prover.h1 + verifier.h2, prover.hi[0] + verifier.hi[0]);
assert_eq!(prover.d_powers[1] + prover.ai[1] + verifier.bi[1], h1 + h2);
}
#[test]
fn test_pascal_tri() {
// This is an extension field so no naive arithmetic!
let pascal = pascal_tri::<Gf2_128>(4);
let expected0 = vec![Gf2_128::one()];
let expected1 = vec![Gf2_128::one(), Gf2_128::one()];
let expected2 = vec![Gf2_128::one(), Gf2_128::zero(), Gf2_128::one()];
let expected3 = vec![
Gf2_128::one(),
Gf2_128::one(),
Gf2_128::one(),
Gf2_128::one(),
];
let expected4 = vec![
Gf2_128::one(),
Gf2_128::zero(),
Gf2_128::zero(),
Gf2_128::zero(),
Gf2_128::one(),
];
assert_eq!(pascal[0], expected0);
assert_eq!(pascal[1], expected1);
assert_eq!(pascal[2], expected2);
assert_eq!(pascal[3], expected3);
assert_eq!(pascal[4], expected4);
}
}

View File

@@ -1,77 +0,0 @@
use super::pascal_tri;
use crate::func::ole::Ole;
use crate::func::Role;
use mpz_share_conversion_core::{
fields::{compute_product_repeated, gf2_128::Gf2_128, UniformRand},
Field,
};
use rand::thread_rng;
#[derive(Debug)]
pub struct Prover {
pub(crate) block_num: usize,
pub(crate) h1: Gf2_128,
pub(crate) r1: Gf2_128,
pub(crate) ai: Vec<Gf2_128>,
pub(crate) d_powers: Vec<Gf2_128>,
pub(crate) hi: Vec<Gf2_128>,
}
impl Prover {
pub fn new(block_num: usize, h1: Gf2_128) -> Self {
let mut rng = thread_rng();
let r1 = Gf2_128::rand(&mut rng);
Self {
block_num,
h1,
r1,
ai: vec![],
d_powers: vec![],
hi: vec![],
}
}
pub fn preprocess_ole_input(&self, ole: &mut Ole<Gf2_128>) {
let mut r1_powers = vec![Gf2_128::one()];
compute_product_repeated(&mut r1_powers, self.r1, self.block_num);
ole.input(Role::Sender, r1_powers)
}
pub fn preprocess_ole_output(&mut self, ole: &mut Ole<Gf2_128>) {
self.ai = ole.output(Role::Sender);
}
pub fn handshake_a_open_d(&self) -> Gf2_128 {
self.h1 + -self.ai[1]
}
pub fn handshake_a_set_di(&mut self, d: Gf2_128) {
self.d_powers = vec![Gf2_128::one(), d];
compute_product_repeated(&mut self.d_powers, d, self.block_num);
}
pub fn handshake_a_set_hi(&mut self) {
let pascal_tri = pascal_tri::<Gf2_128>(self.block_num);
for pascal_row in pascal_tri.iter().skip(1) {
let h_pow_share = pascal_row
.iter()
.enumerate()
.fold(Gf2_128::new(0), |acc, (i, &el)| {
acc + el * self.d_powers[pascal_row.len() - 1 - i] * self.ai[i]
});
self.hi.push(h_pow_share);
}
}
pub fn handshake_output_ghash(&self, blocks: &[Gf2_128]) -> Gf2_128 {
let mut res = Gf2_128::zero();
for (i, block) in blocks.iter().enumerate() {
res = res + *block * self.hi[i];
}
res
}
}

View File

@@ -1,77 +0,0 @@
use super::pascal_tri;
use crate::func::ole::Ole;
use crate::func::Role;
use mpz_share_conversion_core::{
fields::{compute_product_repeated, gf2_128::Gf2_128, UniformRand},
Field,
};
use rand::thread_rng;
#[derive(Debug)]
pub struct Verifier {
pub(crate) block_num: usize,
pub(crate) h2: Gf2_128,
pub(crate) r2: Gf2_128,
pub(crate) bi: Vec<Gf2_128>,
pub(crate) d_powers: Vec<Gf2_128>,
pub(crate) hi: Vec<Gf2_128>,
}
impl Verifier {
pub fn new(block_num: usize, h2: Gf2_128) -> Self {
let mut rng = thread_rng();
let r2 = Gf2_128::rand(&mut rng);
Self {
block_num,
h2,
r2,
bi: vec![],
d_powers: vec![],
hi: vec![],
}
}
pub fn preprocess_ole_input(&self, ole: &mut Ole<Gf2_128>) {
let mut r2_powers = vec![Gf2_128::one()];
compute_product_repeated(&mut r2_powers, self.r2, self.block_num);
ole.input(Role::Receiver, r2_powers)
}
pub fn preprocess_ole_output(&mut self, ole: &mut Ole<Gf2_128>) {
self.bi = ole.output(Role::Receiver);
}
pub fn handshake_a_open_d(&self) -> Gf2_128 {
self.h2 + -self.bi[1]
}
pub fn handshake_a_set_di(&mut self, d: Gf2_128) {
self.d_powers = vec![Gf2_128::one(), d];
compute_product_repeated(&mut self.d_powers, d, self.block_num);
}
pub fn handshake_a_set_hi(&mut self) {
let pascal_tri = pascal_tri::<Gf2_128>(self.block_num);
for pascal_row in pascal_tri.iter().skip(1) {
let h_pow_share = pascal_row
.iter()
.enumerate()
.fold(Gf2_128::new(0), |acc, (i, &el)| {
acc + el * self.d_powers[pascal_row.len() - 1 - i] * self.bi[i]
});
self.hi.push(h_pow_share);
}
}
pub fn handshake_output_ghash(&self, blocks: &[Gf2_128]) -> Gf2_128 {
let mut res = Gf2_128::zero();
for (i, block) in blocks.iter().enumerate() {
res = res + *block * self.hi[i];
}
res
}
}

View File

@@ -1,7 +1,52 @@
//! This crate is for testing TLSNotary sub protocols based on OLE, and check their security properties.
#![feature(iter_map_windows)]
use itybity::ToBits;
use mpz_share_conversion_core::fields::gf2_128::Gf2_128;
use mpz_share_conversion_core::Field;
use rand::Rng;
pub mod e2f;
mod f2;
pub mod func;
pub mod ghash;
#[test]
fn test() {
let a: Gf2_128 = rand::thread_rng().gen();
let b: Gf2_128 = rand::thread_rng().gen();
let mut ts = Vec::new();
let mut ys = Vec::new();
for b_i in b.iter_lsb0() {
let ((t_0, t_1), t_b) = rot(b_i);
let u_i = t_0 + -t_1 + a;
let y_i = if b_i { t_b + u_i } else { t_b };
assert_eq!(y_i, if b_i { t_0 + a } else { t_0 });
ts.push(t_0);
ys.push(y_i);
}
let x = ts
.into_iter()
.enumerate()
.fold(Gf2_128::zero(), |acc, (i, t_i)| {
acc + (t_i * Gf2_128::two_pow(i as u32))
});
let y = -ys
.into_iter()
.enumerate()
.fold(Gf2_128::zero(), |acc, (i, y_i)| {
acc + (y_i * Gf2_128::two_pow(i as u32))
});
assert_eq!(x + y, a * b);
}
pub fn rot(x: bool) -> ((Gf2_128, Gf2_128), Gf2_128) {
let t_0: Gf2_128 = rand::thread_rng().gen();
let t_1: Gf2_128 = rand::thread_rng().gen();
let t_x = if x { t_1 } else { t_0 };
((t_0, t_1), t_x)
}
pub fn get_bit(a: u64, idx: usize) -> bool {
(a >> idx) & 1 == 1
}