Don't provide keys when we could version-negotiate to v0.

This commit is contained in:
gram-signal 2025-05-30 10:46:26 -07:00 committed by GitHub
parent ea2d65a896
commit cff58d922a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 531 additions and 44 deletions

View file

@ -12,7 +12,7 @@ mod tests {
#[bench]
fn add_epoch(b: &mut Bencher) {
let mut c = chain::Chain::new(b"1", Direction::A2B, ChainParams::default())
let mut c = chain::Chain::new(b"1", Direction::A2B, ChainParams::default().into_pb())
.expect("should be valid");
let mut e: u64 = 0;
b.iter(|| {
@ -28,7 +28,7 @@ mod tests {
#[bench]
fn send_key(b: &mut Bencher) {
let mut c = chain::Chain::new(b"1", Direction::A2B, ChainParams::default())
let mut c = chain::Chain::new(b"1", Direction::A2B, ChainParams::default().into_pb())
.expect("should be valid");
b.iter(|| {
// Inner closure, the actual test
@ -38,7 +38,7 @@ mod tests {
#[bench]
fn recv_key(b: &mut Bencher) {
let mut c = chain::Chain::new(b"1", Direction::A2B, ChainParams::default())
let mut c = chain::Chain::new(b"1", Direction::A2B, ChainParams::default().into_pb())
.expect("should be valid");
let mut k: u32 = 0;
b.iter(|| {
@ -50,7 +50,7 @@ mod tests {
#[bench]
fn recv_skip_key(b: &mut Bencher) {
let mut c = chain::Chain::new(b"1", Direction::A2B, ChainParams::default())
let mut c = chain::Chain::new(b"1", Direction::A2B, ChainParams::default().into_pb())
.expect("should be valid");
let mut k: u32 = 0;
b.iter(|| {
@ -63,7 +63,7 @@ mod tests {
#[bench]
fn recv_with_truncate(b: &mut Bencher) {
let mut c = chain::Chain::new(b"1", Direction::A2B, ChainParams::default())
let mut c = chain::Chain::new(b"1", Direction::A2B, ChainParams::default().into_pb())
.expect("should be valid");
let mut k: u32 = 0;
b.iter(|| {

View file

@ -58,7 +58,7 @@ mod tests {
} = send(x, &mut rng).unwrap();
*x = state;
let Recv { state, key: key_b } = recv(y, &msg).unwrap();
assert_eq!(key_a.unwrap(), key_b.unwrap());
assert_eq!(key_a, key_b);
if drop_ctr == 0 {
drop_ctr += 30;
// We 'drop' a message by not replacing y's state.

View file

@ -302,7 +302,7 @@ impl Chain {
})
}
pub fn new(initial_key: &[u8], dir: Direction, params: ChainParams) -> Result<Self, Error> {
pub fn new(initial_key: &[u8], dir: Direction, params: ChainParamsPB) -> Result<Self, Error> {
hax_lib::fstar!("admit ()");
let mut gen = [0u8; 96];
kdf::hkdf_to_slice(
@ -320,7 +320,7 @@ impl Chain {
recv: Self::ced_for_direction(&gen, &dir.switch()),
}]),
next_root: gen[0..32].to_vec(),
params: params.into_pb(),
params,
})
}
@ -429,8 +429,8 @@ mod test {
#[test]
fn directions_match() {
let mut a2b = Chain::new(b"1", Direction::A2B, ChainParams::default()).unwrap();
let mut b2a = Chain::new(b"1", Direction::B2A, ChainParams::default()).unwrap();
let mut a2b = Chain::new(b"1", Direction::A2B, ChainParams::default().into_pb()).unwrap();
let mut b2a = Chain::new(b"1", Direction::B2A, ChainParams::default().into_pb()).unwrap();
let sk1 = a2b.send_key(0).unwrap();
assert_eq!(sk1.0, 1);
assert_eq!(sk1.1, b2a.recv_key(0, 1).unwrap());
@ -455,7 +455,7 @@ mod test {
#[test]
fn previously_returned_key() {
let mut a2b = Chain::new(b"1", Direction::A2B, ChainParams::default()).unwrap();
let mut a2b = Chain::new(b"1", Direction::A2B, ChainParams::default().into_pb()).unwrap();
a2b.recv_key(0, 2).expect("should get key first time");
assert!(matches!(
a2b.recv_key(0, 2),
@ -468,7 +468,8 @@ mod test {
let params = ChainParams {
max_jump: 10,
max_ooo_keys: 10,
};
}
.into_pb();
let mut a2b = Chain::new(b"1", Direction::A2B, params).unwrap();
a2b.recv_key(0, 10).expect("should allow this jump");
a2b.recv_key(0, 12).expect("should allow progression");
@ -478,8 +479,8 @@ mod test {
#[test]
fn out_of_order_keys() {
let max_ooo = DEFAULT_CHAIN_PARAMS.max_ooo_keys;
let mut a2b = Chain::new(b"1", Direction::A2B, ChainParams::default()).unwrap();
let mut b2a = Chain::new(b"1", Direction::B2A, ChainParams::default()).unwrap();
let mut a2b = Chain::new(b"1", Direction::A2B, ChainParams::default().into_pb()).unwrap();
let mut b2a = Chain::new(b"1", Direction::B2A, ChainParams::default().into_pb()).unwrap();
let mut keys = Vec::with_capacity(max_ooo as usize);
for _i in 0..(max_ooo as usize) {
keys.push(a2b.send_key(0).unwrap());
@ -493,7 +494,7 @@ mod test {
#[test]
fn clear_old_send_keys() {
let mut a2b = Chain::new(b"1", Direction::A2B, ChainParams::default()).unwrap();
let mut a2b = Chain::new(b"1", Direction::A2B, ChainParams::default().into_pb()).unwrap();
a2b.send_key(0).unwrap();
a2b.send_key(0).unwrap();
a2b.add_epoch(EpochSecret {

View file

@ -68,6 +68,15 @@ pub enum SecretOutput {
Recv(Secret),
}
#[derive(Debug)]
pub enum CurrentVersion {
StillNegotiating {
version: Version,
min_version: Version,
},
NegotiationComplete(Version),
}
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("state decode failed")]
@ -100,6 +109,8 @@ pub enum Error {
SendKeyEpochDecreased(u64, u64),
#[error("Invalid params: {0}")]
InvalidParams(&'static str),
#[error("Chain not available")]
ChainNotAvailable,
}
impl From<encoding::EncodingError> for Error {
@ -191,12 +202,11 @@ pub fn initial_state(params: Params) -> Result<SerializedState, Error> {
auth_key: params.auth_key.to_vec(),
direction: params.direction.into(),
min_version: params.min_version.into(),
chain_params: Some(params.chain_params.into_pb()),
});
let chain =
Some(Chain::new(params.auth_key, params.direction, params.chain_params)?.into_pb());
Ok(pqrpb::PqRatchetState {
inner: init_inner(params.version, params.direction, params.auth_key),
chain,
chain: None,
version_negotiation,
}
.encode_to_vec())
@ -215,6 +225,21 @@ pub struct Send {
pub key: MessageKey,
}
pub fn current_version(state: &SerializedState) -> Result<CurrentVersion, Error> {
let state_pb = decode_state(state)?;
let version = match state_pb.inner {
None => Version::V0,
Some(pqrpb::pq_ratchet_state::Inner::V1(_)) => Version::V1,
};
Ok(match state_pb.version_negotiation {
None => CurrentVersion::NegotiationComplete(version),
Some(vn) => CurrentVersion::StillNegotiating {
version,
min_version: vn.min_version.try_into().map_err(|_| Error::StateDecode)?,
},
})
}
#[hax_lib::fstar::verification_status(lax)]
pub fn send<R: Rng + CryptoRng>(state: &SerializedState, rng: &mut R) -> Result<Send, Error> {
let state_pb = decode_state(state)?;
@ -225,14 +250,35 @@ pub fn send<R: Rng + CryptoRng>(state: &SerializedState, rng: &mut R) -> Result<
key: None,
}),
Some(pqrpb::pq_ratchet_state::Inner::V1(pb)) => {
let mut chain = Chain::from_pb(state_pb.chain.ok_or(Error::StateDecode)?)?;
let v1states::Send { msg, key, state } = v1states::States::from_pb(pb)?.send(rng)?;
if let Some(epoch_secret) = key {
chain.add_epoch(epoch_secret);
}
let (index, msg_key) = chain.send_key(msg.epoch - 1)?;
let chain = match state_pb.chain {
None => match state_pb.version_negotiation.as_ref() {
Some(vn) => {
if vn.min_version > Version::V0 as i32 {
Some(chain_from_version_negotiation(vn)?)
} else {
None
}
}
None => {
return Err(Error::ChainNotAvailable);
}
},
Some(pb) => Some(Chain::from_pb(pb)?),
};
let (index, msg_key, chain_pb) = match chain {
None => {
assert!(key.is_none());
(0, vec![], None)
}
Some(mut chain) => {
if let Some(epoch_secret) = key {
chain.add_epoch(epoch_secret);
}
let (index, msg_key) = chain.send_key(msg.epoch - 1)?;
(index, msg_key, Some(chain.into_pb()))
}
};
let msg = msg.serialize(index);
assert!(!msg.is_empty());
@ -242,11 +288,16 @@ pub fn send<R: Rng + CryptoRng>(state: &SerializedState, rng: &mut R) -> Result<
inner: Some(pqrpb::pq_ratchet_state::Inner::V1(state.into_pb())),
// Sending never changes our version negotiation.
version_negotiation: state_pb.version_negotiation,
chain: Some(chain.into_pb()),
chain: chain_pb,
}
.encode_to_vec(),
msg,
key: Some(msg_key),
// hax does not like `filter`
key: if msg_key.is_empty() {
None
} else {
Some(msg_key)
},
})
}
}
@ -257,6 +308,29 @@ pub struct Recv {
pub key: MessageKey,
}
fn chain_from_version_negotiation(
vn: &pqrpb::pq_ratchet_state::VersionNegotiation,
) -> Result<Chain, Error> {
Chain::new(
&vn.auth_key,
vn.direction.try_into().map_err(|_| Error::StateDecode)?,
vn.chain_params.ok_or(Error::ChainNotAvailable)?,
)
}
fn chain_from(
pb: Option<pqrpb::Chain>,
vn: Option<&pqrpb::pq_ratchet_state::VersionNegotiation>,
) -> Result<Chain, Error> {
match pb {
Some(pb) => Ok(Chain::from_pb(pb)?),
None => match vn {
None => Err(Error::ChainNotAvailable),
Some(vn) => chain_from_version_negotiation(vn),
},
}
}
#[hax_lib::fstar::verification_status(lax)]
pub fn recv(state: &SerializedState, msg: &SerializedMessage) -> Result<Recv, Error> {
// Perform version negotiation. At the beginning of our interaction
@ -275,16 +349,10 @@ pub fn recv(state: &SerializedState, msg: &SerializedMessage) -> Result<Recv, Er
});
}
Some(v) => match (v as u8).cmp(&(state_version(&prenegotiated_state_pb) as u8)) {
Ordering::Equal => {
Ordering::Equal | Ordering::Greater => {
// Our versions are equal; proceed with existing state
prenegotiated_state_pb
}
Ordering::Greater => {
// Their version is greater than ours, but still one we support.
// This should not happen, since we should use our highest supported
// version.
return Err(Error::VersionMismatch);
}
Ordering::Less => {
// Their version is less than ours. If we are allowed to negotiate, we
// should. Otherwise, we should error out.
@ -306,7 +374,13 @@ pub fn recv(state: &SerializedState, msg: &SerializedMessage) -> Result<Recv, Er
),
// This is our negotiation; we disallow any further.
version_negotiation: None,
chain: prenegotiated_state_pb.chain,
chain: Some(
chain_from(
prenegotiated_state_pb.chain,
prenegotiated_state_pb.version_negotiation.as_ref(),
)?
.into_pb(),
),
}
}
}
@ -323,16 +397,20 @@ pub fn recv(state: &SerializedState, msg: &SerializedMessage) -> Result<Recv, Er
key: None,
}),
Some(pqrpb::pq_ratchet_state::Inner::V1(pb)) => {
let mut chain = Chain::from_pb(state_pb.chain.ok_or(Error::StateDecode)?)?;
let (scka_msg, index, _) = v1states::Message::deserialize(msg)?;
let v1states::Recv { key, state } = v1states::States::from_pb(pb)?.recv(&scka_msg)?;
let msg_key_epoch = scka_msg.epoch - 1;
let mut chain = chain_from(state_pb.chain, state_pb.version_negotiation.as_ref())?;
if let Some(epoch_secret) = key {
chain.add_epoch(epoch_secret);
}
let msg_key = if msg_key_epoch == 0 && index == 0 {
vec![]
} else {
chain.recv_key(msg_key_epoch, index)?
};
let msg_key = chain.recv_key(scka_msg.epoch - 1, index)?;
Ok(Recv {
state: pqrpb::PqRatchetState {
inner: Some(pqrpb::pq_ratchet_state::Inner::V1(state.into_pb())),
@ -341,7 +419,12 @@ pub fn recv(state: &SerializedState, msg: &SerializedMessage) -> Result<Recv, Er
chain: Some(chain.into_pb()),
}
.encode_to_vec(),
key: Some(msg_key),
// hax does not like `filter`
key: if msg_key.is_empty() {
None
} else {
Some(msg_key)
},
})
}
}
@ -567,4 +650,399 @@ mod lib_test {
let v = empty_state();
assert!(v.is_empty());
}
#[test]
fn empty_key_until_version_negotiation() -> Result<(), Error> {
let mut rng = OsRng.unwrap_err();
let version = Version::V1;
let alex_pq_state = initial_state(Params {
version,
min_version: Version::V0,
direction: Direction::A2B,
auth_key: &[41u8; 32],
chain_params: ChainParams::default(),
})?;
let blake_pq_state = initial_state(Params {
version,
min_version: Version::V0,
direction: Direction::B2A,
auth_key: &[41u8; 32],
chain_params: ChainParams::default(),
})?;
// Now let's send some messages
let Send {
state: alex_pq_state,
msg: msg_a1,
key: key_a1,
} = send(&alex_pq_state, &mut rng)?;
let Send {
state: alex_pq_state,
msg: msg_a2,
key: key_a2,
} = send(&alex_pq_state, &mut rng)?;
let Send {
state: alex_pq_state,
msg: msg_a3,
key: key_a3,
} = send(&alex_pq_state, &mut rng)?;
let Send {
state: blake_pq_state,
msg: msg_b1,
key: key_b1,
} = send(&blake_pq_state, &mut rng)?;
let Send {
state: blake_pq_state,
msg: msg_b2,
key: key_b2,
} = send(&blake_pq_state, &mut rng)?;
let Send {
state: blake_pq_state,
msg: msg_b3,
key: key_b3,
} = send(&blake_pq_state, &mut rng)?;
assert_eq!(key_a1, None);
assert_eq!(key_a2, None);
assert_eq!(key_a3, None);
assert_eq!(key_b1, None);
assert_eq!(key_b2, None);
assert_eq!(key_b3, None);
let Recv {
state: alex_pq_state,
key: key_b2,
} = recv(&alex_pq_state, &msg_b2)?;
assert_eq!(key_b2, None);
// After our first Recv, keys are now non-empty.
let Send {
state: alex_pq_state,
msg: msg_a4,
key: key_a4,
} = send(&alex_pq_state, &mut rng)?;
assert!(key_a4.is_some());
let Send {
state: mut alex_pq_state,
msg: msg_a5,
key: key_a5,
} = send(&alex_pq_state, &mut rng)?;
assert!(key_a5.is_some());
let Recv {
state: blake_pq_state,
key: key_a1,
} = recv(&blake_pq_state, &msg_a1)?;
assert_eq!(key_a1, None);
// After our first Recv, keys are now non-empty.
let Send {
state: blake_pq_state,
msg: msg_b4,
key: key_b4,
} = send(&blake_pq_state, &mut rng)?;
assert!(key_b4.is_some());
let Send {
state: mut blake_pq_state,
msg: msg_b5,
key: key_b5,
} = send(&blake_pq_state, &mut rng)?;
assert!(key_b5.is_some());
for (msg, want_key) in [
(msg_a3, key_a3),
(msg_a4, key_a4),
(msg_a2, key_a2),
(msg_a5, key_a5),
] {
let Recv { state, key } = recv(&blake_pq_state, &msg)?;
assert_eq!(want_key, key);
blake_pq_state = state;
}
for (msg, want_key) in [
(msg_b1, key_b1),
(msg_b3, key_b3),
(msg_b4, key_b4),
(msg_b5, key_b5),
] {
let Recv { state, key } = recv(&alex_pq_state, &msg)?;
assert_eq!(want_key, key);
alex_pq_state = state;
}
Ok(())
}
#[test]
fn min_version_v1_always_creates_keys_a2b() -> Result<(), Error> {
let mut rng = OsRng.unwrap_err();
let alex_pq_state = initial_state(Params {
version: Version::MAX,
min_version: Version::V1,
direction: Direction::A2B,
auth_key: &[41u8; 32],
chain_params: ChainParams::default(),
})?;
let blake_pq_state = initial_state(Params {
version: Version::MAX,
min_version: Version::V0,
direction: Direction::B2A,
auth_key: &[41u8; 32],
chain_params: ChainParams::default(),
})?;
let Send {
msg: msg_a1,
key: key_a1,
..
} = send(&alex_pq_state, &mut rng)?;
assert!(key_a1.is_some());
let Send {
state: blake_pq_state,
key: key_b1,
..
} = send(&blake_pq_state, &mut rng)?;
assert!(key_b1.is_none());
let Recv {
state: blake_pq_state,
..
} = recv(&blake_pq_state, &msg_a1)?;
// After our first Recv, keys are now non-empty.
let Send { key: key_b2, .. } = send(&blake_pq_state, &mut rng)?;
assert!(key_b2.is_some());
Ok(())
}
#[test]
fn min_version_v1_always_creates_keys_b2a() -> Result<(), Error> {
let mut rng = OsRng.unwrap_err();
let alex_pq_state = initial_state(Params {
version: Version::MAX,
min_version: Version::V0,
direction: Direction::A2B,
auth_key: &[41u8; 32],
chain_params: ChainParams::default(),
})?;
let blake_pq_state = initial_state(Params {
version: Version::MAX,
min_version: Version::V1,
direction: Direction::B2A,
auth_key: &[41u8; 32],
chain_params: ChainParams::default(),
})?;
let Send {
msg: msg_b1,
key: key_b1,
..
} = send(&blake_pq_state, &mut rng)?;
assert!(key_b1.is_some());
let Send {
state: alex_pq_state,
key: key_a1,
..
} = send(&alex_pq_state, &mut rng)?;
assert!(key_a1.is_none());
let Recv {
state: alex_pq_state,
..
} = recv(&alex_pq_state, &msg_b1)?;
// After our first Recv, keys are now non-empty.
let Send { key: key_a2, .. } = send(&alex_pq_state, &mut rng)?;
assert!(key_a2.is_some());
Ok(())
}
#[test]
fn negotiate_to_v0_a2b() -> Result<(), Error> {
let mut rng = OsRng.unwrap_err();
let alex_pq_state = initial_state(Params {
version: Version::MAX,
min_version: Version::V0,
direction: Direction::A2B,
auth_key: &[41u8; 32],
chain_params: ChainParams::default(),
})?;
let blake_pq_state = initial_state(Params {
version: Version::V0,
min_version: Version::V0,
direction: Direction::B2A,
auth_key: &[41u8; 32],
chain_params: ChainParams::default(),
})?;
assert!(matches!(
current_version(&alex_pq_state)?,
CurrentVersion::StillNegotiating {
version: Version::MAX,
min_version: Version::V0
},
));
assert!(matches!(
current_version(&blake_pq_state)?,
CurrentVersion::NegotiationComplete(Version::V0),
));
let Send {
msg: msg_a1,
state: alex_pq_state,
..
} = send(&alex_pq_state, &mut rng)?;
let Recv {
state: blake_pq_state,
..
} = recv(&blake_pq_state, &msg_a1)?;
let Send { msg: msg_b1, .. } = send(&blake_pq_state, &mut rng)?;
let Recv {
state: alex_pq_state,
..
} = recv(&alex_pq_state, &msg_b1)?;
assert!(matches!(
current_version(&alex_pq_state)?,
CurrentVersion::NegotiationComplete(Version::V0),
));
assert!(matches!(
current_version(&alex_pq_state)?,
CurrentVersion::NegotiationComplete(Version::V0),
));
Ok(())
}
#[test]
fn negotiate_to_v0_b2a() -> Result<(), Error> {
let mut rng = OsRng.unwrap_err();
let alex_pq_state = initial_state(Params {
version: Version::V0,
min_version: Version::V0,
direction: Direction::A2B,
auth_key: &[41u8; 32],
chain_params: ChainParams::default(),
})?;
let blake_pq_state = initial_state(Params {
version: Version::MAX,
min_version: Version::V0,
direction: Direction::B2A,
auth_key: &[41u8; 32],
chain_params: ChainParams::default(),
})?;
assert!(matches!(
current_version(&alex_pq_state)?,
CurrentVersion::NegotiationComplete(Version::V0),
));
assert!(matches!(
current_version(&blake_pq_state)?,
CurrentVersion::StillNegotiating {
version: Version::MAX,
min_version: Version::V0
},
));
let Send {
msg: msg_a1,
state: alex_pq_state,
..
} = send(&alex_pq_state, &mut rng)?;
let Recv {
state: blake_pq_state,
..
} = recv(&blake_pq_state, &msg_a1)?;
let Send { msg: msg_b1, .. } = send(&blake_pq_state, &mut rng)?;
let Recv {
state: alex_pq_state,
..
} = recv(&alex_pq_state, &msg_b1)?;
assert!(matches!(
current_version(&alex_pq_state)?,
CurrentVersion::NegotiationComplete(Version::V0),
));
assert!(matches!(
current_version(&alex_pq_state)?,
CurrentVersion::NegotiationComplete(Version::V0),
));
Ok(())
}
#[test]
fn negotiation_refused_a2b() -> Result<(), Error> {
let mut rng = OsRng.unwrap_err();
let alex_pq_state = initial_state(Params {
version: Version::MAX,
min_version: Version::V1,
direction: Direction::A2B,
auth_key: &[41u8; 32],
chain_params: ChainParams::default(),
})?;
let blake_pq_state = initial_state(Params {
version: Version::V0,
min_version: Version::V0,
direction: Direction::B2A,
auth_key: &[41u8; 32],
chain_params: ChainParams::default(),
})?;
assert!(matches!(
current_version(&alex_pq_state)?,
CurrentVersion::StillNegotiating {
version: Version::MAX,
min_version: Version::V1
},
));
assert!(matches!(
current_version(&blake_pq_state)?,
CurrentVersion::NegotiationComplete(Version::V0),
));
let Send {
msg: msg_a1,
state: alex_pq_state,
..
} = send(&alex_pq_state, &mut rng)?;
let Recv {
state: blake_pq_state,
..
} = recv(&blake_pq_state, &msg_a1)?;
let Send { msg: msg_b1, .. } = send(&blake_pq_state, &mut rng)?;
assert!(matches!(
recv(&alex_pq_state, &msg_b1),
Err(Error::MinimumVersion),
));
Ok(())
}
#[test]
fn negotiation_refused_b2a() -> Result<(), Error> {
let mut rng = OsRng.unwrap_err();
let alex_pq_state = initial_state(Params {
version: Version::V0,
min_version: Version::V0,
direction: Direction::A2B,
auth_key: &[41u8; 32],
chain_params: ChainParams::default(),
})?;
let blake_pq_state = initial_state(Params {
version: Version::MAX,
min_version: Version::V1,
direction: Direction::B2A,
auth_key: &[41u8; 32],
chain_params: ChainParams::default(),
})?;
assert!(matches!(
current_version(&alex_pq_state)?,
CurrentVersion::NegotiationComplete(Version::V0),
));
assert!(matches!(
current_version(&blake_pq_state)?,
CurrentVersion::StillNegotiating {
version: Version::MAX,
min_version: Version::V1
},
));
let Send { msg: msg_a1, .. } = send(&alex_pq_state, &mut rng)?;
assert!(matches!(
recv(&blake_pq_state, &msg_a1),
Err(Error::MinimumVersion)
));
Ok(())
}
}

View file

@ -27,6 +27,7 @@ message PqRatchetState {
bytes auth_key = 1;
Direction direction = 2;
Version min_version = 3;
ChainParams chain_params = 4;
}
VersionNegotiation version_negotiation = 1;
Chain chain = 2;

View file

@ -116,7 +116,7 @@ mod test {
let key = kdf::hkdf_to_vec(
&[0u8; 32],
&[pq_send.key.unwrap(), ec_send.key.unwrap().to_vec()].concat(),
&[pq_send.key.unwrap_or(vec![]), ec_send.key.unwrap().to_vec()].concat(),
b"hybrid ratchet merge",
32,
);
@ -141,7 +141,7 @@ mod test {
let key = kdf::hkdf_to_vec(
&[0u8; 32],
&[pq_recv.key.unwrap(), ec_recv.key.unwrap().to_vec()].concat(),
&[pq_recv.key.unwrap_or(vec![]), ec_recv.key.unwrap().to_vec()].concat(),
b"hybrid ratchet merge",
32,
);
@ -151,7 +151,11 @@ mod test {
#[test]
fn hybrid_ratchet() -> Result<(), Error> {
let alex_ec_ratchet = x25519_scka::states::States::init_a();
let alex_ec_chain = chain::Chain::new(&[43u8; 32], Direction::A2B, ChainParams::default())?;
let alex_ec_chain = chain::Chain::new(
&[43u8; 32],
Direction::A2B,
ChainParams::default().into_pb(),
)?;
let alex_ec_state = DoubleRatchet {
asymratchet: alex_ec_ratchet,
@ -159,8 +163,11 @@ mod test {
};
let blake_ec_ratchet = x25519_scka::states::States::init_b();
let blake_ec_chain =
chain::Chain::new(&[43u8; 32], Direction::B2A, ChainParams::default())?;
let blake_ec_chain = chain::Chain::new(
&[43u8; 32],
Direction::B2A,
ChainParams::default().into_pb(),
)?;
let blake_ec_state = DoubleRatchet {
asymratchet: blake_ec_ratchet,