Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/ibe/waters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,5 +367,31 @@ impl Compress for CipherText {

#[cfg(test)]
mod tests {
use super::*;

test_ibe!(Waters);

// Two distinct strings whose SHA3-256 digests happen to agree on the 8 bits
// that the buggy `bits()` read (one bit each from the last 8 bytes of the
// digest). Under the old code, both produce the same curve point — i.e. a
// user secret key extracted for one would decrypt ciphertexts for the other.
#[test]
fn realistic_identities_do_not_collide_in_entangle() {
use crate::Derive;

let mut rng = rand::thread_rng();
let (pk, _sk) = Waters::setup(&mut rng);

let id_a = Identity::derive_str("user17@example.com");
let id_b = Identity::derive_str("user20@example.com");
assert_ne!(id_a.0, id_b.0, "sanity: digests must differ");

let u_a = G1Affine::from(entangle(&pk, &id_a));
let u_b = G1Affine::from(entangle(&pk, &id_b));

assert_ne!(
u_a, u_b,
"distinct identities must entangle to distinct curve points"
);
}
}
22 changes: 22 additions & 0 deletions src/kem/kiltz_vahlis_one.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,4 +351,26 @@ mod tests {

#[cfg(feature = "mkem")]
test_multi_kem!(KV1);

// Two distinct strings whose SHA3-512 digests happen to agree on the 8 bits
// that the buggy `bits()` read (one bit each from the last 8 bytes of the
// digest). Under the old code, both produce the same curve point — i.e. a
// user secret key extracted for one would decrypt ciphertexts for the other.
#[test]
fn realistic_identities_do_not_collide_in_hash_to_curve() {
let mut rng = rand::thread_rng();
let (pk, _sk) = KV1::setup(&mut rng);

let id_a = Identity::derive_str("user12@example.com");
let id_b = Identity::derive_str("user26@example.com");
assert_ne!(id_a.0, id_b.0, "sanity: digests must differ");

let h_a = G1Affine::from(hash_to_curve(&pk, &id_a));
let h_b = G1Affine::from(hash_to_curve(&pk, &id_b));

assert_ne!(
h_a, h_b,
"distinct identities must hash to distinct curve points"
);
}
}
39 changes: 34 additions & 5 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,40 @@ pub fn rand_gt<R: RngCore + CryptoRng>(rng: &mut R) -> Gt {
}

pub fn bits<'a>(slice: &'a [u8]) -> impl Iterator<Item = subtle::Choice> + 'a {
slice
.iter()
.rev()
.zip((0..8).rev())
.map(|(x, i)| subtle::Choice::from((*x >> i) & 1))
slice.iter().rev().flat_map(|byte| {
(0..8u8)
.rev()
.map(move |i| subtle::Choice::from((byte >> i) & 1))
})
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn bits_produces_eight_bits_per_byte() {
let data = [0xABu8; 64];
assert_eq!(bits(&data).count(), 64 * 8);

let data = [0xCDu8; 32];
assert_eq!(bits(&data).count(), 32 * 8);

let data = [0u8; 0];
assert_eq!(bits(&data).count(), 0);

let data = [0xFFu8; 1];
let bits_vec: std::vec::Vec<u8> = bits(&data).map(|c| c.unwrap_u8()).collect();
assert_eq!(bits_vec, [1, 1, 1, 1, 1, 1, 1, 1]);
}

#[test]
fn bits_reflects_exact_bit_pattern() {
// 0b1010_0101 = 0xA5, high bit (bit 7) first.
let data = [0xA5u8];
let bits_vec: std::vec::Vec<u8> = bits(&data).map(|c| c.unwrap_u8()).collect();
assert_eq!(bits_vec, [1, 0, 1, 0, 0, 1, 0, 1]);
}
}

pub fn sha3_256(slice: &[u8]) -> [u8; 32] {
Expand Down
Loading