Skip to content

Commit c81fc91

Browse files
committed
optimizations
1 parent 8a95c15 commit c81fc91

8 files changed

Lines changed: 73 additions & 62 deletions

File tree

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ license = "Apache-2.0"
1111

1212
[profile.release]
1313
opt-level = 3
14-
lto = "thin"
14+
lto = "fat"
1515
incremental = true
1616
panic = 'abort'
17+
codegen-units = 1
1718

1819
[profile.bench]
1920
opt-level = 3

timelock-ffi/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ pub unsafe extern "C" fn timelock_encrypt(
348348
};
349349

350350
// Create identity
351-
let timelock_identity = Identity::new(b"", identity_slice.to_vec());
351+
let timelock_identity = Identity::new(b"", identity_slice.try_into().unwrap());
352352

353353
// Perform encryption
354354
let ciphertext = match tle::<TinyBLS381, AESGCMBlockCipherProvider, OsRng>(

timelock/benches/tlock.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ fn tlock_split(c: &mut Criterion) {
4444
static KB: usize = 1024;
4545
let s = <TinyBLS381 as EngineBLS>::Scalar::rand(&mut OsRng);
4646
let p_pub = <TinyBLS381 as EngineBLS>::PublicKeyGroup::generator() * s;
47-
let id = Identity::new(b"", b"test".to_vec());
47+
let id = Identity::new(b"", &[1,2,3]);
4848

4949
// Benchmark encryption
5050
let mut encrypt_group = c.benchmark_group("tlock_encrypt");

timelock/src/ibe/fullident.rs

Lines changed: 30 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,31 @@
1414
* limitations under the License.
1515
*/
1616

17-
use super::utils::{cross_product_32, h2, h3, h4};
17+
use super::utils::{cross_product_const, h2, h3, h4};
1818
use alloc::vec;
1919
use ark_ec::PrimeGroup;
2020
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
2121
use ark_std::{ops::Mul, rand::Rng, vec::Vec};
2222
use serde::{Deserialize, Serialize};
2323

24-
use crate::Message;
25-
2624
use crate::engines::EngineBLS;
25+
use crate::{Hash, HASH_LENGTH, Message};
26+
27+
/// Represents a serialized field element of a scalar field
28+
pub type SerializedFieldElement = [u8; 32];
2729

2830
/// Represents a ciphertext in the BF-IBE FullIdent scheme
2931
#[derive(
3032
Debug, Clone, PartialEq, CanonicalDeserialize, CanonicalSerialize, Serialize, Deserialize,
3133
)]
34+
#[repr(C)] // since we know the exact size at compile time
3235
pub struct Ciphertext<E: EngineBLS> {
3336
/// U = rP
3437
pub u: E::PublicKeyGroup,
3538
/// V = sigma (+) H_2(g_id^r)
36-
pub v: Vec<u8>,
39+
pub v: Hash,
3740
/// W = message (+) H_4(sigma)
38-
pub w: Vec<u8>,
41+
pub w: Hash,
3942
}
4043

4144
#[derive(Debug, Clone, PartialEq)]
@@ -55,17 +58,10 @@ pub struct Input<E: EngineBLS> {
5558
}
5659

5760
impl<E: EngineBLS> Input<E> {
58-
pub fn new(data: Vec<u8>) -> Result<Self, InputError> {
59-
if data.len() != E::SECRET_KEY_SIZE {
60-
return Err(InputError::InvalidLength);
61-
}
61+
pub fn new(data: SerializedFieldElement) -> Result<Self, InputError> {
6262
Ok(Self { data, _phantom: ark_std::marker::PhantomData })
6363
}
6464

65-
pub fn from_array(data: [u8; 32]) -> Result<Self, InputError> {
66-
Self::new(data.to_vec())
67-
}
68-
6965
pub fn as_bytes(&self) -> &[u8] {
7066
&self.data
7167
}
@@ -77,10 +73,8 @@ pub struct Identity(pub Message);
7773

7874
impl Identity {
7975
/// construct a new identity from a string
80-
pub fn new(ctx: &[u8], bytes: Vec<u8>) -> Self {
81-
Self(
82-
Message::new(ctx, &bytes)
83-
)
76+
pub fn new(ctx: &[u8], identity: &[u8]) -> Self {
77+
Self(Message::new(ctx, &identity))
8478
}
8579

8680
/// The IBE extract function on a given secret key
@@ -113,7 +107,7 @@ impl Identity {
113107
{
114108
let bytes = message.as_bytes();
115109
// sigma <- {0, 1}^d
116-
let mut sigma = vec![0u8;E::SECRET_KEY_SIZE];
110+
let mut sigma = vec![0u8; E::SECRET_KEY_SIZE];
117111
rng.fill_bytes(&mut sigma);
118112
// r= H3(sigma, message)
119113
let r: E::Scalar = h3::<E>(&sigma, bytes);
@@ -124,12 +118,12 @@ impl Identity {
124118
let g_id = E::pairing(p_pub.mul(r), self.public::<E>());
125119
// sigma (+) H2(e(P_pub, Q_id))
126120
let v_rhs = h2(g_id);
127-
let v_out = cross_product_32(&sigma, &v_rhs);
121+
let v = cross_product_const::<HASH_LENGTH>(&sigma, &v_rhs);
128122
// message (+) H4(sigma)
129123
let w_rhs = h4(&sigma);
130-
let w_out = cross_product_32(bytes, &w_rhs);
124+
let w = cross_product_const::<HASH_LENGTH>(bytes, &w_rhs);
131125
// (rP, sigma (+) H2(e(Q_id, P_pub)), message (+) H4(sigma))
132-
Ciphertext::<E> { u, v: v_out.to_vec(), w: w_out.to_vec() }
126+
Ciphertext::<E> { u, v, w }
133127
}
134128
}
135129

@@ -138,23 +132,21 @@ impl Identity {
138132
pub struct IBESecret<E: EngineBLS>(pub E::SignatureGroup);
139133

140134
impl<E: EngineBLS> IBESecret<E> {
141-
/// BF-IBE decryption of a
142-
/// * `ciphertext`: C = <U, V, W>
135+
/// BF-IBE decryption of a
136+
/// * `ciphertext`: C = <U, V, W>
143137
///
144138
/// Attempts to decrypt under the given IBESecret (in G1)
145-
pub fn decrypt(&self, ciphertext: &Ciphertext<E>) -> Result<Vec<u8>, IbeError> {
139+
pub fn decrypt(&self, ciphertext: &Ciphertext<E>) -> Result<Hash, IbeError> {
146140
// sigma = V (+) H2(e(d_id, U))
147141
let sigma_rhs = h2(E::pairing(ciphertext.u, self.0));
148-
let sigma = cross_product_32(&ciphertext.v, &sigma_rhs);
142+
let sigma = cross_product_const::<HASH_LENGTH>(&ciphertext.v, &sigma_rhs);
149143
// m = W (+) H4(sigma)
150144
let m_rhs = h4(&sigma);
151-
let m = cross_product_32(&ciphertext.w, &m_rhs);
145+
let m = cross_product_const::<HASH_LENGTH>(&ciphertext.w, &m_rhs);
152146
// check: U == rP
153147
let p = E::PublicKeyGroup::generator();
154148
let r = h3::<E>(&sigma, &m);
155149
let u_check = p * r;
156-
157-
// TODO: timing attack? should do a constant-time check
158150
if !u_check.eq(&ciphertext.u) {
159151
return Err(IbeError::DecryptionFailed);
160152
}
@@ -172,7 +164,7 @@ mod test {
172164

173165
// this enum represents the conditions or branches that I want to test
174166
enum TestStatusReport {
175-
DecryptionResult { data: Vec<u8>, verify: Vec<u8> },
167+
DecryptionResult { data: [u8; 32], verify: Vec<u8> },
176168
DecryptionFailure { error: IbeError },
177169
}
178170

@@ -198,10 +190,10 @@ mod test {
198190

199191
let p_pub = <<EB as EngineBLS>::PublicKeyGroup as PrimeGroup>::generator() * msk;
200192

201-
let mut ct = Ciphertext { u: EB::PublicKeyGroup::generator(), v: vec![], w: vec![] };
193+
let mut ct = Ciphertext { u: EB::PublicKeyGroup::generator(), v: [0u8; 32], w: [0u8; 32] };
202194

203195
if !insert_bad_ciphertext {
204-
ct = identity.encrypt(&Input::from_array(message).unwrap(), p_pub, &mut test_rng());
196+
ct = identity.encrypt(&Input::new(message).unwrap(), p_pub, &mut test_rng());
205197
}
206198

207199
match sk.decrypt(&ct) {
@@ -226,22 +218,21 @@ mod test {
226218

227219
#[test]
228220
pub fn fullident_identity_construction_works() {
229-
let id_string = b"example@test.com";
230-
let identity = Identity::new(b"", id_string.to_vec());
231-
let expected_message = Message::new(b"", id_string);
221+
222+
let identity = Identity::new(b"", &[1,2,3]);
223+
let expected_message = Message::new(b"", &[1,2,3]);
232224
assert_eq!(identity.0, expected_message);
233225
}
234226

235227
#[test]
236228
pub fn fullident_encrypt_and_decrypt() {
237-
let id_string = b"example@test.com";
238-
let identity = Identity::new(b"", id_string.to_vec());
229+
let identity = Identity::new(b"", &[1,2,3]);
239230
let message: [u8; 32] = [2; 32];
240231

241232
run_test::<TinyBLS381>(identity, message, false, false, &|status: TestStatusReport| {
242233
match status {
243234
TestStatusReport::DecryptionResult { data, verify } => {
244-
assert_eq!(data, verify);
235+
assert_eq!(data.to_vec(), verify);
245236
},
246237
_ => panic!("Decryption should work"),
247238
}
@@ -250,8 +241,7 @@ mod test {
250241

251242
#[test]
252243
pub fn fullident_decryption_fails_with_bad_ciphertext() {
253-
let id_string = b"example@test.com";
254-
let identity = Identity::new(b"", id_string.to_vec());
244+
let identity = Identity::new(b"", &[1,2,3]);
255245
let message: [u8; 32] = [2; 32];
256246

257247
run_test::<TinyBLS381>(identity, message, false, true, &|status: TestStatusReport| {
@@ -266,8 +256,7 @@ mod test {
266256

267257
#[test]
268258
pub fn fullident_decryption_fails_with_bad_key() {
269-
let id_string = b"example@test.com";
270-
let identity = Identity::new(b"", id_string.to_vec());
259+
let identity = Identity::new(b"", &[1,2,3]);
271260
let message: [u8; 32] = [2; 32];
272261

273262
run_test::<TinyBLS381>(identity, message, true, false, &|status: TestStatusReport| {

timelock/src/ibe/utils.rs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616

1717
use crate::engines::EngineBLS;
18-
use alloc::borrow::ToOwned;
1918
use ark_ff::PrimeField;
2019
use ark_serialize::CanonicalSerialize;
2120
use ark_std::vec::Vec;
@@ -28,13 +27,32 @@ pub fn sha256(b: &[u8]) -> Vec<u8> {
2827
hasher.finalize().to_vec()
2928
}
3029

31-
// TODO: can do this in place instead
32-
pub fn cross_product_32(a: &[u8], b: &[u8]) -> Vec<u8> {
33-
let mut o = a.to_owned();
34-
for (i, ri) in o.iter_mut().enumerate().take(32) {
35-
*ri ^= b[i];
30+
#[inline(always)]
31+
pub fn cross_product_const<const N: usize>(a: &[u8], b: &[u8]) -> [u8; N] {
32+
let mut result = [0u8; N];
33+
34+
// Process 8 bytes at a time using u64 for better performance
35+
let chunks = N / 8;
36+
let remainder = N % 8;
37+
38+
// Process full 8-byte chunks
39+
for i in 0..chunks {
40+
let start_idx = i * 8;
41+
let end_idx = start_idx + 8;
42+
43+
let a_chunk = u64::from_ne_bytes(a[start_idx..end_idx].try_into().unwrap());
44+
let b_chunk = u64::from_ne_bytes(b[start_idx..end_idx].try_into().unwrap());
45+
let result_chunk = (a_chunk ^ b_chunk).to_ne_bytes();
46+
result[start_idx..end_idx].copy_from_slice(&result_chunk);
3647
}
37-
o.to_vec()
48+
49+
// Handle remaining bytes
50+
let remainder_start = chunks * 8;
51+
for j in 0..remainder {
52+
result[remainder_start + j] = a[remainder_start + j] ^ b[remainder_start + j];
53+
}
54+
55+
result
3856
}
3957

4058
/// a map from G -> {0, 1}^{32}

timelock/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,17 @@ pub mod ibe;
2626
pub mod tlock;
2727
use crate::engines::EngineBLS;
2828

29+
/// The length of hashes output from sha256
30+
const HASH_LENGTH: usize = 32;
31+
type Hash = [u8; HASH_LENGTH];
2932
// Adapted from: https://github.com/w3f/bls
3033
/// Internal message hash size.
3134
///
3235
/// We choose 256 bits here so that birthday bound attacks cannot
3336
/// find messages with the same hash.
3437
const MESSAGE_SIZE: usize = 32;
3538

36-
type MessageDigest = [u8; MESSAGE_SIZE];
39+
pub type MessageDigest = [u8; MESSAGE_SIZE];
3740
/// Internal message hash type. Short for frequent rehashing
3841
/// by `HashMap`, etc.
3942
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]

timelock/src/tlock.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ use crate::{
1919
ibe::fullident::{Ciphertext as IBECiphertext, IBESecret, Identity, Input},
2020
};
2121
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
22-
2322
use ark_std::{
2423
rand::{CryptoRng, Rng},
2524
vec::Vec,
@@ -79,11 +78,12 @@ where
7978
R: Rng + CryptoRng,
8079
{
8180
// IBE encryption 'to the future'
82-
let input = Input::from_array(secret_key).expect("The secret key has 32");
81+
let input = Input::new(secret_key).expect("The secret key has 32 bytes.");
8382
let header: IBECiphertext<E> = id.encrypt(&input, p_pub, &mut rng);
8483
// encrypt arbitrary-length messages with a block cipher
8584
let body =
8685
S::encrypt(message, secret_key, &mut rng).map_err(|_| Error::MessageEncryptionError)?;
86+
8787
let mut message_bytes = Vec::new();
8888
body.serialize_compressed(&mut message_bytes)
8989
.expect("Encryption output must be serializable.");
@@ -145,7 +145,7 @@ mod test {
145145
handler: &dyn Fn(TestStatusReport) -> (),
146146
) {
147147
let message = b"this is a test message".to_vec();
148-
let id = Identity::new(b"", b"id".to_vec());
148+
let id = Identity::new(b"", &message);
149149
let sk = E::Scalar::rand(&mut OsRng);
150150
let p_pub = E::PublicKeyGroup::generator() * sk;
151151

@@ -286,7 +286,7 @@ mod test {
286286
hasher.finalize().to_vec()
287287
};
288288

289-
let identity = Identity::new(b"", message);
289+
let identity = Identity::new(b"", &message);
290290

291291
let ct = tle::<TinyBLS381, AESGCMBlockCipherProvider, OsRng>(
292292
pub_key, esk, plaintext, identity, OsRng,

wasm/src/js.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ pub fn do_tle<E: EngineBLS>(
7474

7575
let id_bytes: Vec<u8> = serde_wasm_bindgen::from_value(id_js.clone())
7676
.map_err(|_| JsError::new("could not decode id"))?;
77-
let identity = Identity::new(b"", id_bytes);
77+
let identity = Identity::new(b"", &id_bytes);
7878
let message_bytes: Vec<u8> = serde_wasm_bindgen::from_value(message_js.clone())
7979
.map_err(|_| JsError::new("could not decode message"))?;
8080

@@ -204,7 +204,7 @@ mod test {
204204

205205
let msk: <E as EngineBLS>::Scalar =
206206
convert_from_bytes::<<E as EngineBLS>::Scalar, 32>(&sk.clone()).unwrap();
207-
let identity = Identity::new(b"", identity_vec);
207+
let identity = Identity::new(b"", &identity_vec);
208208

209209
let sig: E::SignatureGroup = identity.extract::<E>(msk).0;
210210
let mut sig_bytes: Vec<_> = Vec::new();
@@ -213,7 +213,7 @@ mod test {
213213
sig.serialize_compressed(&mut sig_bytes).unwrap();
214214
} else {
215215
let bad_ident_vec = b"bad_ident".to_vec();
216-
let bad_ident = Identity::new(b"", bad_ident_vec);
216+
let bad_ident = Identity::new(b"", &bad_ident_vec);
217217
let bad_sig: E::SignatureGroup = bad_ident.extract::<E>(msk).0;
218218
let bad_sig_vec = vec![bad_sig];
219219
bad_sig_vec.serialize_compressed(&mut sig_bytes).unwrap();
@@ -258,7 +258,7 @@ mod test {
258258

259259
pub fn can_encrypt_decrypt<E: EngineBLS>() {
260260
let message: Vec<u8> = b"this is a test message".to_vec();
261-
let id: Vec<u8> = b"testing purposes".to_vec();
261+
let id: Vec<u8> = b"testing purposes!!!!!!!!!!!!!!!!!".to_vec();
262262
setup_test::<E>(id, message.clone(), true, true, &|status: TestStatusReport| match status {
263263
TestStatusReport::EncryptSuccess { ciphertext } => {
264264
let ciphertext_convert: Vec<u8> =
@@ -281,8 +281,8 @@ mod test {
281281
}
282282

283283
pub fn can_encrypt_decrypt_early<E: EngineBLS>() {
284-
let message: Vec<u8> = b"this is a test message".to_vec();
285-
let id: Vec<u8> = b"testing purposes".to_vec();
284+
let message: Vec<u8> = b"this is a test message0".to_vec();
285+
let id: Vec<u8> = b"testing purposes!!!!!!!!!!!!!!!!!".to_vec();
286286
setup_test::<E>(
287287
id,
288288
message.clone(),

0 commit comments

Comments
 (0)