crypto: Proptest the emoji/decimal calculation.
parent
9f0fbcccf6
commit
26ec0c6368
|
@ -63,7 +63,7 @@ impl Sas {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the decimal version of the short auth string.
|
/// Get the decimal version of the short auth string.
|
||||||
pub fn decimals(&self) -> Option<(u32, u32, u32)> {
|
pub fn decimals(&self) -> Option<(u16, u16, u16)> {
|
||||||
self.inner.decimals()
|
self.inner.decimals()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,8 +45,9 @@ default-features = false
|
||||||
features = ["runtime-tokio", "sqlite"]
|
features = ["runtime-tokio", "sqlite"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tokio = { version = "0.2.21", features = ["rt-threaded", "macros"] }
|
tokio = { version = "0.2.22", features = ["rt-threaded", "macros"] }
|
||||||
serde_json = "1.0.56"
|
proptest = "0.10.0"
|
||||||
|
serde_json = "1.0.57"
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
http = "0.2.1"
|
http = "0.2.1"
|
||||||
matrix-sdk-test = { version = "0.1.0", path = "../matrix_sdk_test" }
|
matrix-sdk-test = { version = "0.1.0", path = "../matrix_sdk_test" }
|
||||||
|
|
|
@ -318,13 +318,15 @@ pub fn get_emoji(
|
||||||
flow_id: &str,
|
flow_id: &str,
|
||||||
we_started: bool,
|
we_started: bool,
|
||||||
) -> Vec<(&'static str, &'static str)> {
|
) -> Vec<(&'static str, &'static str)> {
|
||||||
let bytes: Vec<u64> = sas
|
let bytes = sas
|
||||||
.generate_bytes(&extra_info_sas(&ids, &flow_id, we_started), 6)
|
.generate_bytes(&extra_info_sas(&ids, &flow_id, we_started), 6)
|
||||||
.expect("Can't generate bytes")
|
.expect("Can't generate bytes");
|
||||||
.into_iter()
|
|
||||||
.map(|b| b as u64)
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
|
bytes_to_emoji(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bytes_to_emoji_index(bytes: Vec<u8>) -> Vec<u8> {
|
||||||
|
let bytes: Vec<u64> = bytes.iter().map(|b| *b as u64).collect();
|
||||||
// Join the 6 bytes into one 64 bit unsigned int. This u64 will contain 48
|
// Join the 6 bytes into one 64 bit unsigned int. This u64 will contain 48
|
||||||
// bits from our 6 bytes.
|
// bits from our 6 bytes.
|
||||||
let mut num: u64 = bytes[0] << 40;
|
let mut num: u64 = bytes[0] << 40;
|
||||||
|
@ -336,7 +338,7 @@ pub fn get_emoji(
|
||||||
|
|
||||||
// Take the top 42 bits of our 48 bits from the u64 and convert each 6 bits
|
// Take the top 42 bits of our 48 bits from the u64 and convert each 6 bits
|
||||||
// into a 6 bit number.
|
// into a 6 bit number.
|
||||||
let numbers = vec![
|
vec![
|
||||||
((num >> 42) & 63) as u8,
|
((num >> 42) & 63) as u8,
|
||||||
((num >> 36) & 63) as u8,
|
((num >> 36) & 63) as u8,
|
||||||
((num >> 30) & 63) as u8,
|
((num >> 30) & 63) as u8,
|
||||||
|
@ -344,7 +346,11 @@ pub fn get_emoji(
|
||||||
((num >> 18) & 63) as u8,
|
((num >> 18) & 63) as u8,
|
||||||
((num >> 12) & 63) as u8,
|
((num >> 12) & 63) as u8,
|
||||||
((num >> 6) & 63) as u8,
|
((num >> 6) & 63) as u8,
|
||||||
];
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bytes_to_emoji(bytes: Vec<u8>) -> Vec<(&'static str, &'static str)> {
|
||||||
|
let numbers = bytes_to_emoji_index(bytes);
|
||||||
|
|
||||||
// Convert the 6 bit number into a emoji/description tuple.
|
// Convert the 6 bit number into a emoji/description tuple.
|
||||||
numbers.into_iter().map(emoji_from_index).collect()
|
numbers.into_iter().map(emoji_from_index).collect()
|
||||||
|
@ -369,13 +375,16 @@ pub fn get_emoji(
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// This will panic if the public key of the other side wasn't set.
|
/// This will panic if the public key of the other side wasn't set.
|
||||||
pub fn get_decimal(sas: &OlmSas, ids: &SasIds, flow_id: &str, we_started: bool) -> (u32, u32, u32) {
|
pub fn get_decimal(sas: &OlmSas, ids: &SasIds, flow_id: &str, we_started: bool) -> (u16, u16, u16) {
|
||||||
let bytes: Vec<u32> = sas
|
let bytes = sas
|
||||||
.generate_bytes(&extra_info_sas(&ids, &flow_id, we_started), 5)
|
.generate_bytes(&extra_info_sas(&ids, &flow_id, we_started), 5)
|
||||||
.expect("Can't generate bytes")
|
.expect("Can't generate bytes");
|
||||||
.into_iter()
|
|
||||||
.map(|b| b as u32)
|
bytes_to_decimal(bytes)
|
||||||
.collect();
|
}
|
||||||
|
|
||||||
|
fn bytes_to_decimal(bytes: Vec<u8>) -> (u16, u16, u16) {
|
||||||
|
let bytes: Vec<u16> = bytes.into_iter().map(|b| b as u16).collect();
|
||||||
|
|
||||||
// This bitwise operation is taken from the [spec]
|
// This bitwise operation is taken from the [spec]
|
||||||
// [spec]: https://matrix.org/docs/spec/client_server/latest#sas-method-decimal
|
// [spec]: https://matrix.org/docs/spec/client_server/latest#sas-method-decimal
|
||||||
|
@ -415,3 +424,62 @@ pub fn content_to_request(
|
||||||
messages,
|
messages,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use proptest::prelude::*;
|
||||||
|
|
||||||
|
use super::{bytes_to_decimal, bytes_to_emoji, bytes_to_emoji_index, emoji_from_index};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_emoji_generation() {
|
||||||
|
let bytes = vec![0, 0, 0, 0, 0, 0];
|
||||||
|
let index: Vec<(&'static str, &'static str)> = vec![0, 0, 0, 0, 0, 0, 0]
|
||||||
|
.into_iter()
|
||||||
|
.map(emoji_from_index)
|
||||||
|
.collect();
|
||||||
|
assert_eq!(bytes_to_emoji(bytes), index);
|
||||||
|
|
||||||
|
let bytes = vec![0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
|
||||||
|
|
||||||
|
let index: Vec<(&'static str, &'static str)> = vec![63, 63, 63, 63, 63, 63, 63]
|
||||||
|
.into_iter()
|
||||||
|
.map(emoji_from_index)
|
||||||
|
.collect();
|
||||||
|
assert_eq!(bytes_to_emoji(bytes), index);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_decimal_generation() {
|
||||||
|
let bytes = vec![0, 0, 0, 0, 0];
|
||||||
|
let result = bytes_to_decimal(bytes);
|
||||||
|
|
||||||
|
assert_eq!(result, (1000, 1000, 1000));
|
||||||
|
|
||||||
|
let bytes = vec![0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
|
||||||
|
let result = bytes_to_decimal(bytes);
|
||||||
|
assert_eq!(result, (9191, 9191, 9191));
|
||||||
|
}
|
||||||
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn proptest_emoji(bytes in prop::array::uniform6(0u8..)) {
|
||||||
|
let numbers = bytes_to_emoji_index(bytes.to_vec());
|
||||||
|
|
||||||
|
for number in numbers {
|
||||||
|
prop_assert!(number < 64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
proptest! {
|
||||||
|
#[test]
|
||||||
|
fn proptest_decimals(bytes in prop::array::uniform5(0u8..)) {
|
||||||
|
let (first, second, third) = bytes_to_decimal(bytes.to_vec());
|
||||||
|
|
||||||
|
prop_assert!(first <= 9191 && first >= 1000);
|
||||||
|
prop_assert!(second <= 9191 && second >= 1000);
|
||||||
|
prop_assert!(third <= 9191 && third >= 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -257,7 +257,7 @@ impl Sas {
|
||||||
/// Returns None if we can't yet present the short auth string, otherwise a
|
/// Returns None if we can't yet present the short auth string, otherwise a
|
||||||
/// tuple containing three 4-digit integers that represent the short auth
|
/// tuple containing three 4-digit integers that represent the short auth
|
||||||
/// string.
|
/// string.
|
||||||
pub fn decimals(&self) -> Option<(u32, u32, u32)> {
|
pub fn decimals(&self) -> Option<(u16, u16, u16)> {
|
||||||
self.inner.lock().unwrap().decimals()
|
self.inner.lock().unwrap().decimals()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,7 +464,7 @@ impl InnerSas {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decimals(&self) -> Option<(u32, u32, u32)> {
|
fn decimals(&self) -> Option<(u16, u16, u16)> {
|
||||||
match self {
|
match self {
|
||||||
InnerSas::KeyRecieved(s) => Some(s.get_decimal()),
|
InnerSas::KeyRecieved(s) => Some(s.get_decimal()),
|
||||||
InnerSas::MacReceived(s) => Some(s.get_decimal()),
|
InnerSas::MacReceived(s) => Some(s.get_decimal()),
|
||||||
|
|
|
@ -530,7 +530,7 @@ impl SasState<KeyReceived> {
|
||||||
///
|
///
|
||||||
/// Returns a tuple containing three 4 digit integer numbers that represent
|
/// Returns a tuple containing three 4 digit integer numbers that represent
|
||||||
/// the short auth string.
|
/// the short auth string.
|
||||||
pub fn get_decimal(&self) -> (u32, u32, u32) {
|
pub fn get_decimal(&self) -> (u16, u16, u16) {
|
||||||
get_decimal(
|
get_decimal(
|
||||||
&self.inner.lock().unwrap(),
|
&self.inner.lock().unwrap(),
|
||||||
&self.ids,
|
&self.ids,
|
||||||
|
@ -667,7 +667,7 @@ impl SasState<MacReceived> {
|
||||||
///
|
///
|
||||||
/// Returns a tuple containing three 4 digit integer numbers that represent
|
/// Returns a tuple containing three 4 digit integer numbers that represent
|
||||||
/// the short auth string.
|
/// the short auth string.
|
||||||
pub fn get_decimal(&self) -> (u32, u32, u32) {
|
pub fn get_decimal(&self) -> (u16, u16, u16) {
|
||||||
get_decimal(
|
get_decimal(
|
||||||
&self.inner.lock().unwrap(),
|
&self.inner.lock().unwrap(),
|
||||||
&self.ids,
|
&self.ids,
|
||||||
|
|
Loading…
Reference in New Issue