Skip to content

Commit 9c5002d

Browse files
committed
Verifiable encryption tz_21: Make XOF generic and refactor encryption scheme in a trait to remove code duplication
Signed-off-by: lovesh <lovesh.bond@gmail.com>
1 parent 5f125d0 commit 9c5002d

File tree

11 files changed

+611
-1266
lines changed

11 files changed

+611
-1266
lines changed

oblivious_transfer/src/base_ot/naor_pinkas_ot.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,19 @@
11
//! OT based on the paper [Efficient oblivious transfer protocols](https://dl.acm.org/doi/10.5555/365411.365502).
22
//! Protocol is described in section 3.1. Allows to run `m` instances of 1-of-n chosen message OTs.
33
4+
use crate::{configs::OTConfig, error::OTError, util::xor, Message};
45
use ark_ec::{AffineRepr, CurveGroup, Group};
56
use ark_ff::PrimeField;
67
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
78
use ark_std::{cfg_into_iter, cfg_iter, log2, rand::RngCore, vec, vec::Vec, UniformRand};
89
use digest::{ExtendableOutput, Update};
9-
use itertools::Itertools;
10-
11-
use crate::{util::xor, Message};
1210
use dock_crypto_utils::msm::WindowTable;
11+
use itertools::Itertools;
12+
use sha3::Shake256;
1313

1414
#[cfg(feature = "parallel")]
1515
use rayon::prelude::*;
1616

17-
use crate::{configs::OTConfig, error::OTError};
18-
use sha3::Shake256;
19-
2017
/// Setup for running multiple 1-of-n OTs
2118
#[derive(Clone, Debug, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)]
2219
pub struct OTSenderSetup<G: AffineRepr> {

verifiable_encryption/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ serde.workspace = true
1717
serde_with.workspace = true
1818
zeroize.workspace = true
1919
dock_crypto_utils = { version = "0.20.0", default-features = false, path = "../utils" }
20-
sha3 = { version = "0.10.6", default-features = false }
2120
itertools.workspace = true
2221
secret_sharing_and_dkg = { version = "0.13.0", default-features = false, path = "../secret_sharing_and_dkg" }
2322

2423
[dev-dependencies]
2524
blake2.workspace = true
25+
sha3 = { version = "0.10.6", default-features = false }
2626
ark-bls12-381.workspace = true
2727
ark-secp256r1 = { version = "^0.4.0", default-features = false }
2828

verifiable_encryption/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#![cfg_attr(not(feature = "std"), no_std)]
2+
13
//! # Verifiable encryption schemes
24
//!
35
//! Verifiable encryption of discrete log(s) from the paper [Verifiable Encryption from MPC-in-the-Head](https://eprint.iacr.org/2021/1704.pdf).

verifiable_encryption/src/tz_21/dkgith.rs

+196-119
Large diffs are not rendered by default.

verifiable_encryption/src/tz_21/dkgith_batched_elgamal.rs

-494
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
use crate::tz_21::seed_tree::SeedTree;
2+
use ark_ec::{AffineRepr, CurveGroup};
3+
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
4+
use ark_std::{
5+
cfg_into_iter, cfg_iter, cfg_iter_mut, fmt::Debug, rand::RngCore, vec::Vec, UniformRand,
6+
};
7+
use dock_crypto_utils::{
8+
aliases::FullDigest,
9+
elgamal::{BatchedHashedElgamalCiphertext, HashedElgamalCiphertext},
10+
msm::WindowTable,
11+
};
12+
13+
#[cfg(feature = "parallel")]
14+
use rayon::prelude::*;
15+
16+
/// A list of Elgamal ciphertexts, one for each message. For each message, encryptor creates fresh
17+
/// randomness and a thus a new shared secret using Diffie-Hellman key exchange
18+
#[derive(Clone, Debug, Default, CanonicalSerialize, CanonicalDeserialize)]
19+
pub struct SimpleBatchElgamalCiphertext<G: AffineRepr>(Vec<HashedElgamalCiphertext<G>>);
20+
21+
/// A trait implemented by schemes encrypting a batch of messages
22+
pub trait BatchCiphertext<G: AffineRepr>:
23+
Sized + Clone + Default + Debug + Send + Sync + CanonicalSerialize + CanonicalDeserialize
24+
{
25+
/// Randomness used in the encryption
26+
type Randomness: Clone + Default + CanonicalSerialize + CanonicalDeserialize;
27+
28+
/// Create a new ciphertext for the batch of messages
29+
fn new<D: FullDigest>(
30+
msgs: &[G::ScalarField],
31+
randomness: &Self::Randomness,
32+
public_key: &WindowTable<G::Group>,
33+
gen: &WindowTable<G::Group>,
34+
) -> Self;
35+
36+
fn batch_size(&self) -> usize;
37+
38+
/// Decrypt the ciphertext to get the message batch back
39+
fn decrypt<D: FullDigest>(&self, secret_key: &G::ScalarField) -> Vec<G::ScalarField>;
40+
41+
/// Add 1 item each from the given `deltas` to a ciphertext
42+
fn add_to_ciphertexts(&mut self, deltas: &[G::ScalarField]);
43+
44+
/// Multiply each ciphertext by the given multiplier `m`
45+
fn multiply_with_ciphertexts(&mut self, m: &G::ScalarField);
46+
47+
/// Multiply the OTP (one time pad) with given `m` before applying the OTP
48+
fn decrypt_after_multiplying_otp<D: FullDigest>(
49+
&self,
50+
m: &G::ScalarField,
51+
secret_key: &G::ScalarField,
52+
) -> Vec<G::ScalarField>;
53+
54+
/// Get randomness for encryption deterministically. Used in DKGitH
55+
fn get_randomness_from_seed_tree<
56+
const NUM_PARTIES: usize,
57+
const DEPTH: usize,
58+
const NUM_TOTAL_NODES: usize,
59+
const SEED_SIZE: usize,
60+
D: FullDigest,
61+
>(
62+
seed_tree: &SeedTree<NUM_PARTIES, DEPTH, NUM_TOTAL_NODES, SEED_SIZE>,
63+
party_index: u16,
64+
witness_count: usize,
65+
) -> Self::Randomness;
66+
67+
/// Get randomness for encryption using the given random number generator. Used in RDKGitH
68+
fn get_randomness_from_rng<R: RngCore>(rng: &mut R, witness_count: usize) -> Self::Randomness;
69+
70+
fn is_randomness_size_correct(randomness: &Self::Randomness, witness_count: usize) -> bool;
71+
}
72+
73+
impl<G: AffineRepr> BatchCiphertext<G> for SimpleBatchElgamalCiphertext<G> {
74+
/// A different random value is created for each message to be encrypted
75+
type Randomness = Vec<G::ScalarField>;
76+
77+
fn new<D: FullDigest>(
78+
msgs: &[G::ScalarField],
79+
randomness: &Vec<G::ScalarField>,
80+
public_key: &WindowTable<G::Group>,
81+
gen: &WindowTable<G::Group>,
82+
) -> Self {
83+
assert_eq!(msgs.len(), randomness.len());
84+
Self(
85+
cfg_into_iter!(msgs)
86+
.zip(cfg_into_iter!(randomness))
87+
.map(|(m, r)| {
88+
HashedElgamalCiphertext::<G>::new_given_randomness_and_window_tables::<D>(
89+
m, r, public_key, gen,
90+
)
91+
})
92+
.collect(),
93+
)
94+
}
95+
96+
fn batch_size(&self) -> usize {
97+
self.0.len()
98+
}
99+
100+
fn decrypt<D: FullDigest>(&self, secret_key: &G::ScalarField) -> Vec<G::ScalarField> {
101+
cfg_into_iter!(0..self.batch_size())
102+
.map(|i| self.0[i].decrypt::<D>(secret_key))
103+
.collect()
104+
}
105+
106+
fn add_to_ciphertexts(&mut self, deltas: &[G::ScalarField]) {
107+
assert_eq!(deltas.len(), self.batch_size());
108+
cfg_iter_mut!(self.0)
109+
.zip(cfg_iter!(deltas))
110+
.for_each(|(m, d)| {
111+
m.encrypted += d;
112+
})
113+
}
114+
115+
fn multiply_with_ciphertexts(&mut self, m: &G::ScalarField) {
116+
cfg_iter_mut!(self.0).for_each(|c| {
117+
c.encrypted *= m;
118+
})
119+
}
120+
121+
fn decrypt_after_multiplying_otp<D: FullDigest>(
122+
&self,
123+
m: &G::ScalarField,
124+
secret_key: &G::ScalarField,
125+
) -> Vec<G::ScalarField> {
126+
cfg_into_iter!(0..self.batch_size())
127+
.map(|i| {
128+
let otp = HashedElgamalCiphertext::otp::<D>(
129+
(self.0[i].eph_pk * secret_key).into_affine(),
130+
) * m;
131+
self.0[i].encrypted - otp
132+
})
133+
.collect()
134+
}
135+
136+
fn get_randomness_from_seed_tree<
137+
const NUM_PARTIES: usize,
138+
const DEPTH: usize,
139+
const NUM_TOTAL_NODES: usize,
140+
const SEED_SIZE: usize,
141+
D: FullDigest,
142+
>(
143+
seed_tree: &SeedTree<NUM_PARTIES, DEPTH, NUM_TOTAL_NODES, SEED_SIZE>,
144+
party_index: u16,
145+
witness_count: usize,
146+
) -> Self::Randomness {
147+
cfg_into_iter!(0..witness_count)
148+
.map(|k| {
149+
seed_tree.get_leaf_as_finite_field_element::<G::ScalarField, D>(
150+
party_index,
151+
&(witness_count + k).to_le_bytes(),
152+
)
153+
})
154+
.collect()
155+
}
156+
157+
fn get_randomness_from_rng<R: RngCore>(rng: &mut R, witness_count: usize) -> Self::Randomness {
158+
(0..witness_count)
159+
.map(|_| G::ScalarField::rand(rng))
160+
.collect()
161+
}
162+
163+
fn is_randomness_size_correct(randomness: &Self::Randomness, witness_count: usize) -> bool {
164+
randomness.len() == witness_count
165+
}
166+
}
167+
168+
impl<G: AffineRepr> BatchCiphertext<G> for BatchedHashedElgamalCiphertext<G> {
169+
/// Only a single value is created and then OTPs are generated by "appending" counters for each message to be encrypted
170+
type Randomness = G::ScalarField;
171+
172+
fn new<D: FullDigest>(
173+
msgs: &[G::ScalarField],
174+
randomness: &G::ScalarField,
175+
public_key: &WindowTable<G::Group>,
176+
gen: &WindowTable<G::Group>,
177+
) -> Self {
178+
BatchedHashedElgamalCiphertext::new_given_randomness_and_window_tables::<D>(
179+
msgs, randomness, public_key, gen,
180+
)
181+
}
182+
183+
fn batch_size(&self) -> usize {
184+
self.batch_size()
185+
}
186+
187+
fn decrypt<D: FullDigest>(&self, secret_key: &G::ScalarField) -> Vec<G::ScalarField> {
188+
self.decrypt::<D>(secret_key)
189+
}
190+
191+
fn add_to_ciphertexts(&mut self, deltas: &[G::ScalarField]) {
192+
cfg_iter_mut!(self.encrypted)
193+
.zip(cfg_into_iter!(deltas))
194+
.for_each(|(e_j, s_j)| {
195+
*e_j += s_j;
196+
})
197+
}
198+
199+
fn multiply_with_ciphertexts(&mut self, m: &G::ScalarField) {
200+
cfg_iter_mut!(self.encrypted).for_each(|c| {
201+
*c *= m;
202+
})
203+
}
204+
205+
fn decrypt_after_multiplying_otp<D: FullDigest>(
206+
&self,
207+
m: &G::ScalarField,
208+
secret_key: &G::ScalarField,
209+
) -> Vec<G::ScalarField> {
210+
let shared_secret = (self.eph_pk * secret_key).into_affine();
211+
cfg_into_iter!(0..self.batch_size())
212+
.map(|i| {
213+
let otp = BatchedHashedElgamalCiphertext::otp::<D>(&shared_secret, i as u32) * m;
214+
self.encrypted[i] - otp
215+
})
216+
.collect()
217+
}
218+
219+
fn get_randomness_from_seed_tree<
220+
const NUM_PARTIES: usize,
221+
const DEPTH: usize,
222+
const NUM_TOTAL_NODES: usize,
223+
const SEED_SIZE: usize,
224+
D: FullDigest,
225+
>(
226+
seed_tree: &SeedTree<NUM_PARTIES, DEPTH, NUM_TOTAL_NODES, SEED_SIZE>,
227+
party_index: u16,
228+
witness_count: usize,
229+
) -> Self::Randomness {
230+
seed_tree.get_leaf_as_finite_field_element::<G::ScalarField, D>(
231+
party_index,
232+
&(witness_count + party_index as usize).to_le_bytes(),
233+
)
234+
}
235+
236+
fn get_randomness_from_rng<R: RngCore>(rng: &mut R, _witness_count: usize) -> Self::Randomness {
237+
G::ScalarField::rand(rng)
238+
}
239+
240+
fn is_randomness_size_correct(_randomness: &Self::Randomness, _witness_count: usize) -> bool {
241+
true
242+
}
243+
}

verifiable_encryption/src/tz_21/mod.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@
1818
//!
1919
//! More docs in the corresponding modules.
2020
21+
// TODO: Replace asserts with error handling in non-test code.
22+
2123
#[macro_use]
2224
pub mod util;
2325

26+
pub mod seed_tree;
27+
2428
pub mod dkgith;
25-
pub mod dkgith_batched_elgamal;
29+
pub mod encryption;
2630
pub mod rdkgith;
27-
pub mod rdkgith_batched_elgamal;
28-
pub mod seed_tree;

0 commit comments

Comments
 (0)