Skip to content

Commit

Permalink
pass secrte_tree_test
Browse files Browse the repository at this point in the history
  • Loading branch information
yngrtc committed Aug 22, 2023
1 parent 4ddf919 commit 8a33a3c
Show file tree
Hide file tree
Showing 4 changed files with 255 additions and 14 deletions.
4 changes: 2 additions & 2 deletions src/cipher_suite/cipher_suite_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use super::*;
use crate::codec::codec_test::*;
use crate::crypto::provider::{ring::RingCryptoProvider, rust::RustCryptoProvider, CryptoProvider};
use crate::error::*;

use crate::tree::secret_tree::derive_tree_secret;

use serde::{Deserialize, Serialize};

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
Expand Down Expand Up @@ -267,7 +267,7 @@ fn test_crypto_basics_with_crypto_provider(
) -> Result<()> {
for tc in tests {
let cipher_suite: CipherSuite = tc.cipher_suite.try_into()?;
println!("testing {}:\n\t {:?}", cipher_suite, tc);
println!("test_crypto_basics {}:\n\t {:?}", cipher_suite, tc);

test_ref_hash(crypto_provider, cipher_suite, &tc.ref_hash)?;

Expand Down
49 changes: 49 additions & 0 deletions src/framing/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::cipher_suite::CipherSuite;
use bytes::{Buf, BufMut, Bytes};

use crate::codec::*;
use crate::crypto::provider::CryptoProvider;
use crate::error::*;

pub(crate) type ProtocolVersion = u16;
Expand Down Expand Up @@ -53,3 +55,50 @@ impl Writer for ContentType {
Ok(())
}
}

pub(crate) fn expand_sender_data_key(
crypto_provider: &impl CryptoProvider,
cipher_suite: CipherSuite,
sender_data_secret: &[u8],
ciphertext: &[u8],
) -> Result<Bytes> {
let nk = crypto_provider.hpke(cipher_suite).aead_key_size() as u16;
let ciphertext_sample = sample_ciphertext(crypto_provider, cipher_suite, ciphertext);
crypto_provider.expand_with_label(
cipher_suite,
sender_data_secret,
b"key",
ciphertext_sample,
nk,
)
}

pub(crate) fn expand_sender_data_nonce(
crypto_provider: &impl CryptoProvider,
cipher_suite: CipherSuite,
sender_data_secret: &[u8],
ciphertext: &[u8],
) -> Result<Bytes> {
let nn = crypto_provider.hpke(cipher_suite).aead_nonce_size() as u16;
let ciphertext_sample = sample_ciphertext(crypto_provider, cipher_suite, ciphertext);
crypto_provider.expand_with_label(
cipher_suite,
sender_data_secret,
b"nonce",
ciphertext_sample,
nn,
)
}

pub(crate) fn sample_ciphertext<'a>(
crypto_provider: &impl CryptoProvider,
cipher_suite: CipherSuite,
ciphertext: &'a [u8],
) -> &'a [u8] {
let n = crypto_provider.hpke(cipher_suite).kdf_extract_size();
if ciphertext.len() < n {
ciphertext
} else {
&ciphertext[..n]
}
}
47 changes: 35 additions & 12 deletions src/tree/secret_tree.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,38 @@
#[cfg(test)]
mod secret_tree_test;

use bytes::{BufMut, Bytes, BytesMut};
use std::fmt::{Display, Formatter};

use crate::cipher_suite::*;
use crate::crypto::provider::CryptoProvider;
use crate::error::*;
use crate::framing::*;
use crate::tree::tree_math::*;

pub(crate) type RatchetLabel = Bytes;
const RATCHET_LABEL_HANDSHAKE_STR: &str = "handshake";
const RATCHET_LABEL_APPLICATION_STR: &str = "application";

#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
pub(crate) enum RatchetLabel {
#[default]
Handshake,
Application,
}

pub(crate) static RATCHET_LABEL_HANDSHAKE: Bytes = Bytes::from_static(b"handshake");
pub(crate) static RATCHET_LABEL_APPLICATION: Bytes = Bytes::from_static(b"application");
impl Display for RatchetLabel {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match *self {
RatchetLabel::Handshake => write!(f, "{}", RATCHET_LABEL_HANDSHAKE_STR),
RatchetLabel::Application => write!(f, "{}", RATCHET_LABEL_APPLICATION_STR),
}
}
}

fn ratchet_label_from_content_type(ct: ContentType) -> Result<RatchetLabel> {
match ct {
ContentType::Application => Ok(RATCHET_LABEL_APPLICATION.clone()),
ContentType::Proposal | ContentType::Commit => Ok(RATCHET_LABEL_HANDSHAKE.clone()),
ContentType::Application => Ok(RatchetLabel::Handshake),
ContentType::Proposal | ContentType::Commit => Ok(RatchetLabel::Application),
}
}

Expand All @@ -27,10 +45,10 @@ fn derive_secret_tree(
crypto_provider: &impl CryptoProvider,
cipher_suite: CipherSuite,
n: NumLeaves,
encryption_secret: Bytes,
encryption_secret: &[u8],
) -> Result<SecretTree> {
let mut tree = SecretTree(vec![None; n.width() as usize]);
tree.set(n.root(), encryption_secret);
tree.set(n.root(), encryption_secret.to_vec().into());
tree.derive_children(crypto_provider, cipher_suite, n.root())?;
Ok(tree)
}
Expand Down Expand Up @@ -89,16 +107,21 @@ impl SecretTree {
crypto_provider: &impl CryptoProvider,
cipher_suite: CipherSuite,
ni: NodeIndex,
label: &RatchetLabel,
label: RatchetLabel,
) -> Result<RatchetSecret> {
let parent_secret = self
.get(ni)
.ok_or(Error::InvalidParentNode)?
.as_ref()
.ok_or(Error::InvalidParentNode)?;
let nh = crypto_provider.hpke(cipher_suite).kdf_extract_size() as u16;
let secret =
crypto_provider.expand_with_label(cipher_suite, parent_secret, label, &[], nh)?;
let secret = crypto_provider.expand_with_label(
cipher_suite,
parent_secret,
label.to_string().as_bytes(),
&[],
nh,
)?;
Ok(RatchetSecret {
secret,
generation: 0,
Expand All @@ -107,8 +130,8 @@ impl SecretTree {
}

pub(crate) struct RatchetSecret {
secret: Bytes,
generation: u32,
pub(crate) secret: Bytes,
pub(crate) generation: u32,
}

impl RatchetSecret {
Expand Down
169 changes: 169 additions & 0 deletions src/tree/secret_tree/secret_tree_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
use super::*;
use crate::crypto::provider::{ring::RingCryptoProvider, rust::RustCryptoProvider, CryptoProvider};
use crate::error::*;

use crate::codec::codec_test::{hex_to_bytes, load_test_vector};
use serde::{Deserialize, Serialize};

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
struct SenderData {
sender_data_secret: String,
ciphertext: String,
key: String,
nonce: String,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
struct Leaf {
generation: u32,
handshake_key: String,
handshake_nonce: String,
application_key: String,
application_nonce: String,
}

#[derive(Default, Debug, Clone, Serialize, Deserialize)]
struct SecretTreeTest {
cipher_suite: u16,
sender_data: SenderData,
encryption_secret: String,
leaves: Vec<Vec<Leaf>>,
}

fn secret_tree_test(
crypto_provider: &impl CryptoProvider,
cipher_suite: CipherSuite,
tc: &SecretTreeTest,
) -> Result<()> {
let sender_data_secret = hex_to_bytes(&tc.sender_data.sender_data_secret);
let ciphertext = hex_to_bytes(&tc.sender_data.ciphertext);
let encryption_secret = hex_to_bytes(&tc.encryption_secret);
let expect_key = hex_to_bytes(&tc.sender_data.key);
let expect_nonce = hex_to_bytes(&tc.sender_data.nonce);

let key = expand_sender_data_key(
crypto_provider,
cipher_suite,
&sender_data_secret,
&ciphertext,
)?;
assert_eq!(
&key, &expect_key,
"expand_sender_data_key() = {:?}, want {:?}",
key, expect_key
);

let nonce = expand_sender_data_nonce(
crypto_provider,
cipher_suite,
&sender_data_secret,
&ciphertext,
)?;
assert_eq!(
&nonce, &expect_nonce,
"expand_sender_data_nonce() = {:?}, want {:?}",
nonce, expect_nonce
);

let tree = derive_secret_tree(
crypto_provider,
cipher_suite,
NumLeaves(tc.leaves.len() as u32),
&encryption_secret,
)?;

for (i, gens) in tc.leaves.iter().enumerate() {
let li = LeafIndex(i as u32);
test_ratchet_secret(
crypto_provider,
cipher_suite,
&tree,
li,
RatchetLabel::Handshake,
gens,
)?;

test_ratchet_secret(
crypto_provider,
cipher_suite,
&tree,
li,
RatchetLabel::Application,
gens,
)?;
}

Ok(())
}

fn test_ratchet_secret(
crypto_provider: &impl CryptoProvider,
cipher_suite: CipherSuite,
tree: &SecretTree,
li: LeafIndex,
label: RatchetLabel,
gens: &[Leaf],
) -> Result<()> {
let mut secret =
tree.derive_ratchet_root(crypto_provider, cipher_suite, li.node_index(), label)?;

for gen in gens {
assert!(!(gen.generation < secret.generation));

while secret.generation != gen.generation {
secret = secret.derive_next(crypto_provider, cipher_suite)?;
}

let (want_key, want_nonce) = match label {
RatchetLabel::Handshake => (
hex_to_bytes(&gen.handshake_key),
hex_to_bytes(&gen.handshake_nonce),
),
RatchetLabel::Application => (
hex_to_bytes(&gen.application_key),
hex_to_bytes(&gen.application_nonce),
),
};

let key = secret.derive_key(crypto_provider, cipher_suite)?;
assert_eq!(
&key, &want_key,
"deriveKey() = {:?}, want {:?}",
key, want_key
);

let nonce = secret.derive_nonce(crypto_provider, cipher_suite)?;
assert_eq!(
&nonce, &want_nonce,
"deriveNonce() = {:?}, want {:?}",
nonce, want_nonce
);
}

Ok(())
}

fn test_secret_tree_with_crypto_provider(
tests: &[SecretTreeTest],
crypto_provider: &impl CryptoProvider,
) -> Result<()> {
for tc in tests {
let cipher_suite: CipherSuite = tc.cipher_suite.try_into()?;
println!("test_secret_tree {}:\n\t {:?}", cipher_suite, tc);

secret_tree_test(crypto_provider, cipher_suite, tc)?;
}

Ok(())
}

#[test]
fn test_secret_tree() -> Result<()> {
let tests: Vec<SecretTreeTest> = load_test_vector("test-vectors/secret-tree.json")?;

test_secret_tree_with_crypto_provider(&tests, &RingCryptoProvider {})?;

test_secret_tree_with_crypto_provider(&tests, &RustCryptoProvider {})?;

Ok(())
}

0 comments on commit 8a33a3c

Please sign in to comment.