#![allow(clippy::items_after_statements)]
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use std::rc::Rc;
use std::time::{Duration, Instant};
use super::*;
use crate::config::{Config, WallClock};
use crate::constants::{
HANDSHAKE_GIVEUP, INIT_HEADER_LEN, INIT_PACKET_LEN, INTRO_MAX_PER_SOURCE, INTRO_QUEUE_CAP,
INTRO_TTL, MAC1_LEN, PKT_DATA, PKT_HANDSHAKE_INIT, PKT_HANDSHAKE_RESP, RESP_PACKET_LEN,
RETRANSMIT_BASE, RETRANSMIT_JITTER_MAX, STATIC_PUBLIC_LEN, TS_GUARD_ORPHAN_TTL, VERSION,
};
use crate::error::{AcceptError, AuthError, ConnectError, IntroError};
use crate::identity::{Identity, PublicKeyOf};
use crate::packet::mac::Mac1Key;
use crate::testutil::{CountingIdentity, DhCounter};
type Suite = crate::packet::ReferenceSuite;
type Id = CountingIdentity<Suite>;
type Pk = PublicKeyOf<Id>;
trait AmbiguousIfSend<A> {
fn assertion() {}
}
impl<T: ?Sized> AmbiguousIfSend<()> for T {}
impl<T: ?Sized + Send> AmbiguousIfSend<u8> for T {}
const _: fn() = || {
<Endpoint<Id> as AmbiguousIfSend<_>>::assertion();
};
#[derive(Debug, Default)]
struct Drained {
outs: Vec<EndpointOutput<Suite>>,
deadline: Option<Instant>,
}
impl Drained {
fn transmits(&self) -> Vec<(SocketAddr, Vec<u8>)> {
self.outs
.iter()
.filter_map(|o| match o {
EndpointOutput::Transmit(t) => Some((t.to, t.data.clone())),
_ => None,
})
.collect()
}
fn intros(&self) -> Vec<(IntroId, SocketAddr)> {
self.outs
.iter()
.filter_map(|o| match o {
EndpointOutput::IntroReady(id, src) => Some((*id, *src)),
_ => None,
})
.collect()
}
fn installs(&self) -> Vec<ConnectionId> {
self.outs
.iter()
.filter_map(|o| match o {
EndpointOutput::ToConnection(id, _) => Some(*id),
_ => None,
})
.collect()
}
fn failures(&self) -> Vec<(ConnectionId, ConnectError)> {
self.outs
.iter()
.filter_map(|o| match o {
EndpointOutput::HandshakeFailed(id, e) => Some((*id, e.clone())),
_ => None,
})
.collect()
}
fn replaced(&self) -> Vec<ConnectionId> {
self.outs
.iter()
.filter_map(|o| match o {
EndpointOutput::Replaced(id) => Some(*id),
_ => None,
})
.collect()
}
fn one_intro(&self) -> (IntroId, SocketAddr) {
let v = self.intros();
assert_eq!(v.len(), 1, "expected exactly one IntroReady, got {v:?}");
v[0]
}
fn one_transmit(&self) -> (SocketAddr, Vec<u8>) {
let v = self.transmits();
assert_eq!(v.len(), 1, "expected exactly one Transmit, got {}", v.len());
v[0].clone()
}
fn is_silent(&self) -> bool {
self.outs.is_empty()
}
}
struct Ep {
ep: Endpoint<Id>,
dhs: DhCounter,
public_static: Pk,
addr: SocketAddr,
}
impl Ep {
fn new(now: Instant, key_seed: u8, rng_seed: u8, addr: SocketAddr, config: Config) -> Self {
let identity: Id = CountingIdentity::seeded([key_seed; 32]);
let dhs = identity.counter();
let public_static = *identity.public_static();
let ep = Endpoint::new(now, config, identity, [rng_seed; 32]);
Ep {
ep,
dhs,
public_static,
addr,
}
}
fn canonical(&self) -> &[u8] {
self.public_static.as_ref()
}
fn mac1_key(&self) -> Mac1Key {
Mac1Key::derive(self.canonical())
}
fn drain(&mut self) -> Drained {
let mut d = Drained::default();
for _ in 0..100_000 {
match self.ep.poll_output() {
EndpointOutput::Timeout(t) => {
d.deadline = t;
return d;
}
other => d.outs.push(other),
}
}
panic!("poll_output() did not reach the terminal Timeout in 100_000 outputs (§16.4)");
}
fn datagram(&mut self, now: Instant, src: SocketAddr, dgram: &[u8]) -> (Disposition, Drained) {
let disp = self.ep.handle_datagram(now, src, dgram);
(disp, self.drain())
}
fn feed(&mut self, now: Instant, src: SocketAddr, dgram: &[u8]) -> Drained {
self.datagram(now, src, dgram).1
}
fn timeout(&mut self, now: Instant) -> Drained {
self.ep.handle_timeout(now);
self.drain()
}
fn connect(&mut self, now: Instant, remote: SocketAddr, peer: &Pk) -> (ConnectionId, Drained) {
let (id, _conn) = self
.ep
.mint_pending(now, remote, *peer, ())
.expect("connect should succeed");
self.ep.start_attempt(now, id);
(id, self.drain())
}
fn present(&self, id: IntroId) -> bool {
self.ep.intro_source(id).is_some()
}
}
const T_BASE_SECS: u64 = 1_700_000_000;
fn t0() -> Instant {
Instant::now()
}
fn v4(a: u8, port: u16) -> SocketAddr {
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(10, 0, 0, a)), port)
}
fn v4_nth(n: usize, port: u16) -> SocketAddr {
let n = u32::try_from(n).expect("test index fits");
let ip = Ipv4Addr::from(0x0a01_0000u32 + n);
SocketAddr::new(IpAddr::V4(ip), port)
}
fn v6_in_64(prefix: u8, host: u16, port: u16) -> SocketAddr {
let mut o = [0u8; 16];
o[0] = 0x20;
o[1] = 0x01;
o[7] = prefix; o[14..16].copy_from_slice(&host.to_be_bytes());
SocketAddr::new(IpAddr::V6(Ipv6Addr::from(o)), port)
}
fn forged_init(responder: &Ep, sender_index: u32, filler: u8) -> Vec<u8> {
let mut d = vec![filler; INIT_PACKET_LEN];
d[0] = PKT_HANDSHAKE_INIT;
d[1] = VERSION;
d[2..6].copy_from_slice(&sender_index.to_le_bytes());
let (preimage, tag) = d.split_at_mut(INIT_PACKET_LEN - MAC1_LEN);
let t = responder.mac1_key().tag(preimage);
tag.copy_from_slice(&t);
d
}
fn init_sender_index(dgram: &[u8]) -> u32 {
u32::from_le_bytes(dgram[2..6].try_into().expect("init header"))
}
fn msg1_ephemeral(dgram: &[u8]) -> &[u8] {
&dgram[INIT_HEADER_LEN..INIT_HEADER_LEN + STATIC_PUBLIC_LEN]
}
fn resp_indices(dgram: &[u8]) -> (u32, u32) {
(
u32::from_le_bytes(dgram[2..6].try_into().expect("resp header")),
u32::from_le_bytes(dgram[6..10].try_into().expect("resp header")),
)
}
fn data_packet(receiver_index: u32, counter: u64, body: usize) -> Vec<u8> {
let mut d = vec![0x5Au8; crate::constants::DATA_HEADER_LEN + body];
d[0] = PKT_DATA;
d[1] = VERSION;
d[2..6].copy_from_slice(&receiver_index.to_le_bytes());
d[6..14].copy_from_slice(&counter.to_le_bytes());
d
}
struct FrozenClock(Timestamp);
impl WallClock for FrozenClock {
fn now(&self) -> Timestamp {
self.0
}
}
fn default_config() -> Config {
Config::default()
}
fn capped_config(cap: usize, per_source: usize) -> Config {
Config::default()
.with_intro_queue_cap(cap)
.with_intro_max_per_source(per_source)
}
fn frozen_clock_config(secs: u64, nanos: u32) -> Config {
Config::default().with_clock(Rc::new(FrozenClock(Timestamp::new(secs, nanos))))
}
fn real_msg1(initiator: &mut Ep, now: Instant, responder: &Ep) -> Vec<u8> {
let peer = responder.public_static;
let (_id, drained) = initiator.connect(now, responder.addr, &peer);
let (to, data) = drained.one_transmit();
assert_eq!(
to, responder.addr,
"§5.5 step 1 sends to the dialled address"
);
assert_eq!(data.len(), INIT_PACKET_LEN, "§3.2, exact (ruling 65)");
data
}
fn pair(now: Instant) -> (Ep, Ep) {
let a = Ep::new(now, 7, 0x11, v4(1, 1), default_config());
let b = Ep::new(now, 9, 0x22, v4(2, 2), default_config());
(a, b)
}
#[test]
fn the_drain_always_terminates_in_timeout() {
let t = t0();
let (mut a, mut b) = pair(t);
let _ = b.drain();
let peer = b.public_static;
let (conn, d) = a.connect(t, b.addr, &peer);
assert!(d.deadline.is_some(), "a pending arms a retransmit");
let msg1 = d.one_transmit().1;
let intro = b.feed(t, a.addr, &msg1).one_intro().0;
let _ = b.feed(t, v4(3, 3), &forged_init(&b, 1, 0x11));
let _ = b.feed(t, v4(4, 4), b"not a slither packet");
let _ = b.ep.read_identity(t, intro);
let _ = b.drain();
let _ = b.ep.authenticate(t, intro, &());
let _ = b.drain();
let _ = b.ep.accept(t, intro);
let _ = b.drain();
b.ep.reject(t, intro);
let _ = b.drain();
let _ = a.timeout(t + Duration::from_secs(1));
let _ = b.timeout(t + INTRO_TTL * 4);
a.ep.handle_connection_event(t, conn, ToEndpoint::Retired { our_index: 1 });
let _ = a.drain();
}
#[test]
fn a_second_drain_with_no_mutating_call_yields_only_timeout() {
let t = t0();
let (mut a, b) = pair(t);
let peer = b.public_static;
let (_id, first) = a.connect(t, b.addr, &peer);
assert_eq!(first.transmits().len(), 1);
let second = a.drain();
assert!(second.is_silent(), "outputs re-emitted: {:?}", second.outs);
assert_eq!(
second.deadline, first.deadline,
"the announced deadline is a property of state, not of the drain"
);
}
#[test]
fn the_announced_deadline_is_the_minimum_of_the_live_timers() {
let t = t0();
let (mut a, mut b) = pair(t);
let d = b.feed(t, v4(5, 5), &forged_init(&b, 1, 0x11));
assert_eq!(
d.deadline,
Some(t + INTRO_TTL),
"a parked intro's expiry is the endpoint's only deadline"
);
let later = t + Duration::from_secs(2);
let d = b.feed(later, v4(5, 6), &forged_init(&b, 2, 0x22));
assert_eq!(
d.deadline,
Some(t + INTRO_TTL),
"a later timer displaced the minimum"
);
let d = b.timeout(t + INTRO_TTL);
assert_eq!(
d.deadline,
Some(later + INTRO_TTL),
"the surviving intro's expiry was not announced"
);
let d = a.feed(t, v4(6, 6), &forged_init(&a, 1, 0x33));
assert_eq!(d.deadline, Some(t + INTRO_TTL));
let peer = b.public_static;
let (_conn, d) = a.connect(t, b.addr, &peer);
let retransmit = d.deadline.expect("a pending arms a deadline");
assert!(
retransmit >= t + RETRANSMIT_BASE,
"§5.5 step 2: never earlier than RETRANSMIT_BASE"
);
assert!(
retransmit <= t + RETRANSMIT_BASE + RETRANSMIT_JITTER_MAX,
"§5.5 step 2: never later than RETRANSMIT_BASE + RETRANSMIT_JITTER_MAX"
);
assert!(
retransmit < t + INTRO_TTL,
"fixture: 5 s must be inside 15 s for this to test a minimum"
);
}
#[test]
fn handle_timeout_twice_at_the_same_instant_is_a_no_op() {
let t = t0();
let (mut a, b) = pair(t);
let peer = b.public_static;
let (_conn, d) = a.connect(t, b.addr, &peer);
let due = d.deadline.expect("retransmit armed");
let first = a.timeout(due);
assert_eq!(first.transmits().len(), 1, "the retransmit fires once");
let second = a.timeout(due);
assert!(
second.is_silent(),
"a repeated handle_timeout at the same instant emitted {:?}",
second.outs
);
assert_eq!(
second.deadline, first.deadline,
"and did not re-arm anything"
);
}
#[test]
fn handle_timeout_before_any_deadline_is_a_no_op() {
let t = t0();
let (_a, mut b) = pair(t);
let d = b.feed(t, v4(5, 5), &forged_init(&b, 1, 0x11));
let deadline = d.deadline.expect("intro expiry armed");
let early = b.timeout(t + INTRO_TTL - Duration::from_nanos(1));
assert!(early.is_silent(), "{:?}", early.outs);
assert_eq!(early.deadline, Some(deadline));
}
#[test]
fn an_idle_endpoint_announces_no_deadline() {
let t = t0();
let (mut a, _b) = pair(t);
let d = a.drain();
assert_eq!(d.deadline, None, "an idle endpoint arms nothing");
}
#[test]
fn park_costs_no_dh() {
let t = t0();
let (_a, mut b) = pair(t);
for n in 0..INTRO_QUEUE_CAP {
let src = v4_nth(
n / INTRO_MAX_PER_SOURCE,
1000 + (n % INTRO_MAX_PER_SOURCE) as u16,
);
let d = b.feed(t, src, &forged_init(&b, n as u32 + 1, 0x33));
assert_eq!(d.intros().len(), 1, "arrival {n} did not surface");
}
assert_eq!(
b.dhs.get(),
0,
"parking {INTRO_QUEUE_CAP} initiations spent DH"
);
}
#[test]
fn reject_at_intro_costs_no_dh() {
let t = t0();
let (_a, mut b) = pair(t);
let id = b.feed(t, v4(5, 5), &forged_init(&b, 1, 0x11)).one_intro().0;
assert_eq!(b.dhs.get(), 0);
b.ep.reject(t, id);
let d = b.drain();
assert_eq!(b.dhs.get(), 0, "reject at Intro spent DH");
assert!(
d.transmits().is_empty(),
"a rejection transmitted something"
);
assert!(d.is_silent(), "a rejection is silent: {:?}", d.outs);
assert!(!b.present(id), "the slot was not freed");
}
#[test]
fn read_identity_costs_one_dh() {
let t = t0();
let (mut a, mut b) = pair(t);
let msg1 = real_msg1(&mut a, t, &b);
let id = b.feed(t, a.addr, &msg1).one_intro().0;
assert_eq!(b.dhs.get(), 0, "the arrival itself is free");
let claimed = b.ep.read_identity(t, id).expect("a real msg1 is readable");
let _ = b.drain();
assert_eq!(b.dhs.get(), 1, "read_identity is exactly one DH");
assert_eq!(
claimed.as_ref(),
a.canonical(),
"the claimed static is the initiator's"
);
}
#[test]
fn reject_at_claimed_costs_one_dh() {
let t = t0();
let (mut a, mut b) = pair(t);
let msg1 = real_msg1(&mut a, t, &b);
let id = b.feed(t, a.addr, &msg1).one_intro().0;
b.ep.read_identity(t, id).expect("readable");
let _ = b.drain();
b.ep.reject(t, id);
let d = b.drain();
assert_eq!(b.dhs.get(), 1, "reject at Claimed ran a second DH");
assert!(d.transmits().is_empty());
assert!(!b.present(id));
}
#[test]
fn authenticate_costs_two_dh_cumulative() {
let t = t0();
let (mut a, mut b) = pair(t);
let msg1 = real_msg1(&mut a, t, &b);
let id = b.feed(t, a.addr, &msg1).one_intro().0;
b.ep.read_identity(t, id).expect("readable");
let _ = b.drain();
let (peer, _ts) =
b.ep.authenticate(t, id, &())
.expect("a real msg1 authenticates");
let _ = b.drain();
assert_eq!(b.dhs.get(), 2, "cumulative cost at Proven is 2");
assert_eq!(peer.as_ref(), a.canonical(), "the proven static");
}
#[test]
fn reject_at_proven_costs_two_dh_and_installs_nothing() {
let t = t0();
let (mut a, mut b) = pair(t);
let msg1 = real_msg1(&mut a, t, &b);
let id = b.feed(t, a.addr, &msg1).one_intro().0;
b.ep.read_identity(t, id).expect("readable");
let _ = b.drain();
b.ep.authenticate(t, id, &()).expect("authenticates");
let _ = b.drain();
b.ep.reject(t, id);
let d = b.drain();
assert_eq!(b.dhs.get(), 2, "reject at Proven ran ee/se");
assert!(d.transmits().is_empty(), "a declined accept sent msg2");
assert!(
d.installs().is_empty(),
"a declined accept installed a session"
);
assert!(!b.present(id));
}
#[test]
fn accept_fast_path_costs_four_dh() {
let t = t0();
let (mut a, mut b) = pair(t);
let msg1 = real_msg1(&mut a, t, &b);
let id = b.feed(t, a.addr, &msg1).one_intro().0;
b.ep.read_identity(t, id).expect("readable");
let _ = b.drain();
b.ep.authenticate(t, id, &()).expect("authenticates");
let _ = b.drain();
let (_conn, _core) = b.ep.accept(t, id).expect("a fresh static accepts");
let d = b.drain();
assert_eq!(b.dhs.get(), 4, "the accept fast path is exactly 4 DH");
let (to, data) = d.one_transmit();
assert_eq!(to, a.addr, "§5.6 anchors at the msg1 source address");
assert_eq!(data.len(), RESP_PACKET_LEN, "§3.3, exact (ruling 65)");
assert_eq!(data[0], PKT_HANDSHAKE_RESP);
assert_eq!(data[1], VERSION);
assert!(
d.installs().is_empty(),
"accept() must not be followed by an Install (double-install)"
);
}
#[test]
fn expiry_costs_no_further_dh() {
let t = t0();
let (_a, mut b) = pair(t);
let id = b.feed(t, v4(5, 5), &forged_init(&b, 1, 0x11)).one_intro().0;
let d = b.timeout(t + INTRO_TTL);
assert_eq!(b.dhs.get(), 0, "expiry spent DH");
assert!(d.is_silent(), "expiry is silent: {:?}", d.outs);
assert!(!b.present(id), "the entry outlived INTRO_TTL");
}
#[test]
fn a_dial_costs_two_dh_and_each_retransmit_two_more() {
let t = t0();
let (mut a, b) = pair(t);
let peer = b.public_static;
let (_conn, d) = a.connect(t, b.addr, &peer);
assert_eq!(a.dhs.get(), 2, "write_message_1 is es + ss");
let mut due = d.deadline.expect("retransmit armed");
for n in 1..=3u32 {
let d = a.timeout(due);
assert_eq!(d.transmits().len(), 1, "retransmit {n} did not fire");
assert_eq!(
a.dhs.get(),
2 * (n + 1),
"retransmit {n} is a completely fresh initiation: 2 more DH"
);
due = d.deadline.expect("the next retransmit is armed");
}
}
#[test]
fn a_completed_dial_costs_four_dh_end_to_end() {
let t = t0();
let (mut a, mut b) = pair(t);
let msg1 = real_msg1(&mut a, t, &b);
assert_eq!(a.dhs.get(), 2);
let id = b.feed(t, a.addr, &msg1).one_intro().0;
b.ep.read_identity(t, id).expect("readable");
let _ = b.drain();
b.ep.authenticate(t, id, &()).expect("authenticates");
let _ = b.drain();
b.ep.accept(t, id).expect("accepts");
let msg2 = b.drain().one_transmit().1;
let d = a.feed(t, b.addr, &msg2);
assert_eq!(a.dhs.get(), 4, "read_message_2 is ee + se");
assert_eq!(d.installs().len(), 1, "completion installs exactly once");
}
#[test]
fn only_an_exactly_sized_init_reaches_the_queue() {
let t = t0();
let (_a, mut b) = pair(t);
let exact = forged_init(&b, 1, 0x11);
assert_eq!(exact.len(), INIT_PACKET_LEN);
let short = &exact[..INIT_PACKET_LEN - 1];
assert!(
b.feed(t, v4(5, 5), short).is_silent(),
"INIT_PACKET_LEN - 1 reached the queue"
);
let mut long = exact.clone();
long.push(0x00);
assert!(
b.feed(t, v4(5, 6), &long).is_silent(),
"INIT_PACKET_LEN + 1 reached the queue — an exact check was relaxed to a minimum"
);
assert_eq!(
b.feed(t, v4(5, 7), &exact).intros().len(),
1,
"the exactly-sized packet must park"
);
assert_eq!(b.dhs.get(), 0, "none of the three cost a DH");
}
#[test]
fn a_wrong_version_never_reaches_the_queue() {
let t = t0();
let (_a, mut b) = pair(t);
for bad in [VERSION.wrapping_sub(1), VERSION.wrapping_add(1)] {
let mut d = forged_init(&b, 1, 0x11);
d[1] = bad;
let (preimage, tag) = d.split_at_mut(INIT_PACKET_LEN - MAC1_LEN);
let recomputed = b.mac1_key().tag(preimage);
tag.copy_from_slice(&recomputed);
assert!(
b.feed(t, v4(5, 5), &d).is_silent(),
"version {bad:#04x} reached the queue"
);
}
assert_eq!(b.dhs.get(), 0);
}
#[test]
fn a_mac1_invalid_init_never_reaches_the_queue() {
let t = t0();
let (_a, mut b) = pair(t);
let mut d = forged_init(&b, 1, 0x11);
let last = d.len() - 1;
d[last] ^= 0x01;
assert!(
b.feed(t, v4(5, 5), &d).is_silent(),
"a mac1-invalid initiation surfaced"
);
assert_eq!(b.dhs.get(), 0);
}
#[test]
fn an_init_mac1ed_for_another_static_never_reaches_the_queue() {
let t = t0();
let (a, mut b) = pair(t);
let for_a = forged_init(&a, 1, 0x11);
assert!(
b.feed(t, v4(5, 5), &for_a).is_silent(),
"an initiation keyed to another static surfaced"
);
assert_eq!(b.dhs.get(), 0);
}
#[test]
fn dedup_replaces_and_keeps_the_intro_id_without_a_second_surfacing() {
let t = t0();
let (_a, mut b) = pair(t);
let src = v4(5, 5);
let first = b.feed(t, src, &forged_init(&b, 0xAAAA_AAAA, 0x11));
let (id, surfaced) = first.one_intro();
assert_eq!(surfaced, src);
let second = b.feed(
t + Duration::from_secs(1),
src,
&forged_init(&b, 0xBBBB_BBBB, 0x22),
);
assert!(
second.intros().is_empty(),
"a same-source replacement surfaced a second IntroReady"
);
assert!(b.present(id), "the original IntroId was dropped");
assert_eq!(b.dhs.get(), 0);
}
#[test]
fn intro_sender_index_reflects_the_newest_bytes_after_a_refresh() {
let t = t0();
let (_a, mut b) = pair(t);
let src = v4(5, 5);
let id = b
.feed(t, src, &forged_init(&b, 0xAAAA_AAAA, 0x11))
.one_intro()
.0;
assert_eq!(b.ep.intro_sender_index(id), Some(0xAAAA_AAAA));
assert_eq!(b.ep.intro_source(id), Some(src));
let _ = b.feed(
t + Duration::from_secs(1),
src,
&forged_init(&b, 0xBBBB_BBBB, 0x22),
);
assert_eq!(
b.ep.intro_sender_index(id),
Some(0xBBBB_BBBB),
"the accessor answered from a cache taken at surfacing"
);
assert_eq!(
b.ep.intro_source(id),
Some(src),
"the source is the dedup key and cannot change under a replacement"
);
}
#[test]
fn the_intro_accessors_answer_none_for_an_absent_entry() {
let t = t0();
let (_a, mut b) = pair(t);
let id = b.feed(t, v4(5, 5), &forged_init(&b, 7, 0x11)).one_intro().0;
assert_eq!(b.ep.intro_source(id), Some(v4(5, 5)));
assert_eq!(b.ep.intro_sender_index(id), Some(7));
b.ep.reject(t, id);
let _ = b.drain();
assert_eq!(b.ep.intro_source(id), None, "a rejected id still answers");
assert_eq!(b.ep.intro_sender_index(id), None);
let gone = b.feed(t, v4(6, 6), &forged_init(&b, 8, 0x11)).one_intro().0;
let _ = b.timeout(t + INTRO_TTL);
assert_eq!(b.ep.intro_source(gone), None, "an expired id still answers");
assert_eq!(b.ep.intro_sender_index(gone), None);
}
#[test]
fn the_dedup_key_is_the_full_socket_addr_not_the_source_ip() {
let t = t0();
let (_a, mut b) = pair(t);
let ip = Ipv4Addr::new(10, 9, 9, 9);
let a1 = b
.feed(
t,
SocketAddr::new(IpAddr::V4(ip), 1000),
&forged_init(&b, 1, 0x11),
)
.one_intro()
.0;
let a2 = b
.feed(
t,
SocketAddr::new(IpAddr::V4(ip), 1001),
&forged_init(&b, 2, 0x22),
)
.one_intro()
.0;
assert_ne!(a1, a2, "two ports on one IP must be two entries");
assert!(b.present(a1) && b.present(a2));
}
#[test]
fn a_stage_zero_slot_costs_ruling_272s_figure_not_the_superseded_220_bytes() {
const MSG1_HEAP: usize = 196;
assert_eq!(
MSG1_HEAP, INIT_PACKET_LEN,
"§3.1's exact msg1 is the heap half of ruling 272's figure"
);
let inline = size_of::<endpoint::intro_queue::IntroEntry<Id>>();
assert!(
(256..=320).contains(&inline),
"ruling 272 measured `IntroEntry` at 288 B inline; this tree says \
{inline} B, which is outside the band the ruling's ≈ 484 B per \
entry and ≈ 0.47 MiB at INTRO_QUEUE_CAP are stated over. Below \
256 B the superseded ≈ 220 B whole-entry figure is back; above \
320 B a slot has passed 512 B and §17.5's flood budget needs \
re-ruling, not re-expecting (CLAUDE.md: a red here is \"this needs \
a ruling\")"
);
let per_entry = inline + MSG1_HEAP;
assert!(
per_entry > 2 * 220,
"ruling 272's whole point is that ≈ 220 B was 2.2x under: {per_entry} B"
);
assert!(
per_entry * INTRO_QUEUE_CAP < 1 << 20,
"§17.5's worst case must stay inside a MiB: {} B at the default cap",
per_entry * INTRO_QUEUE_CAP
);
}
#[test]
fn the_queue_caps_at_1024_endpoint_wide() {
let t = t0();
let (_a, mut b) = pair(t);
let mut ids = Vec::with_capacity(INTRO_QUEUE_CAP + 1);
for n in 0..INTRO_QUEUE_CAP {
let src = v4_nth(
n / INTRO_MAX_PER_SOURCE,
2000 + (n % INTRO_MAX_PER_SOURCE) as u16,
);
let now = t + Duration::from_millis(n as u64);
ids.push(
b.feed(now, src, &forged_init(&b, n as u32 + 1, 0x33))
.one_intro()
.0,
);
}
assert_eq!(
ids.iter().filter(|id| b.present(**id)).count(),
INTRO_QUEUE_CAP,
"an entry was evicted at or below the cap"
);
let overflow_src = v4_nth(9_000, 3000);
let now = t + Duration::from_millis(INTRO_QUEUE_CAP as u64);
let extra = b
.feed(now, overflow_src, &forged_init(&b, 0xFFFF, 0x44))
.one_intro()
.0;
let survivors = ids.iter().filter(|id| b.present(**id)).count();
assert_eq!(
survivors,
INTRO_QUEUE_CAP - 1,
"overflow evicted {survivors} entries, expected 1"
);
assert!(
b.present(extra),
"§6.3: a genuine initiation always obtains a slot"
);
assert!(!b.present(ids[0]), "overflow did not evict the oldest");
assert_eq!(b.dhs.get(), 0, "1025 arrivals cost DH");
}
#[test]
fn the_per_source_cap_is_four_chains_per_ip() {
let t = t0();
let (_a, mut b) = pair(t);
let mut ids = Vec::new();
for n in 0..INTRO_MAX_PER_SOURCE {
let now = t + Duration::from_secs(n as u64 + 1);
ids.push(
b.feed(
now,
v4(5, 100 + n as u16),
&forged_init(&b, n as u32 + 1, 0x11),
)
.one_intro()
.0,
);
}
assert_eq!(
ids.iter().filter(|id| b.present(**id)).count(),
INTRO_MAX_PER_SOURCE,
"an entry was evicted at or below the per-source cap"
);
let other = b
.feed(t, v4(6, 100), &forged_init(&b, 99, 0x22))
.one_intro()
.0;
let now = t + Duration::from_secs(INTRO_MAX_PER_SOURCE as u64 + 1);
let fifth = b
.feed(now, v4(5, 200), &forged_init(&b, 0xAAAA, 0x33))
.one_intro()
.0;
assert_eq!(
ids.iter().filter(|id| b.present(**id)).count(),
INTRO_MAX_PER_SOURCE - 1,
"the per-source cap evicted the wrong number of entries"
);
assert!(
b.present(fifth),
"the arrival replaced within its own source"
);
assert!(b.present(other), "the cap reached across source IPs");
assert!(
!b.present(ids[0]),
"the per-source cap evicted out of order"
);
}
#[test]
fn ipv6_shares_one_cap_across_a_64() {
let t = t0();
let (_a, mut b) = pair(t);
let mut ids = Vec::new();
for n in 0..INTRO_MAX_PER_SOURCE {
let now = t + Duration::from_secs(n as u64);
let src = v6_in_64(0x11, n as u16 + 1, 500 + n as u16);
ids.push(
b.feed(now, src, &forged_init(&b, n as u32 + 1, 0x11))
.one_intro()
.0,
);
}
let neighbour = b
.feed(t, v6_in_64(0x12, 1, 500), &forged_init(&b, 77, 0x22))
.one_intro()
.0;
let now = t + Duration::from_secs(INTRO_MAX_PER_SOURCE as u64);
let fifth = b
.feed(now, v6_in_64(0x11, 99, 999), &forged_init(&b, 0xBBBB, 0x33))
.one_intro()
.0;
assert_eq!(
ids.iter().filter(|id| b.present(**id)).count(),
INTRO_MAX_PER_SOURCE - 1,
"the /64 allowance was not shared"
);
assert!(b.present(fifth));
assert!(
b.present(neighbour),
"the cap reached across a /64 boundary — the prefix is 64 bits, not fewer"
);
}
#[test]
fn a_dedup_replacement_is_net_zero_for_the_per_source_count() {
let t = t0();
let (_a, mut b) = pair(t);
let mut ids = Vec::new();
for n in 0..INTRO_MAX_PER_SOURCE {
let now = t + Duration::from_secs(n as u64);
ids.push(
b.feed(
now,
v4(5, 100 + n as u16),
&forged_init(&b, n as u32 + 1, 0x11),
)
.one_intro()
.0,
);
}
let now = t + Duration::from_secs(10);
let d = b.feed(now, v4(5, 100), &forged_init(&b, 0xCCCC, 0x44));
assert!(d.intros().is_empty(), "a replacement surfaced again");
assert_eq!(
ids.iter().filter(|id| b.present(**id)).count(),
INTRO_MAX_PER_SOURCE,
"a replacement evicted an entry — the cap ran before the dedup"
);
}
#[test]
fn overflow_evicts_the_oldest_by_last_refresh_not_by_park_time() {
let t = t0();
let cap = 4usize;
let mut b = Ep::new(t, 9, 0x22, v4(2, 2), capped_config(cap, 4));
let a_src = v4(11, 11);
let b_src = v4(12, 12);
let c_src = v4(13, 13);
let d_src = v4(14, 14);
let e_src = v4(15, 15);
let id_a = b.feed(t, a_src, &forged_init(&b, 1, 0x11)).one_intro().0;
let id_b = b
.feed(t + Duration::from_secs(1), b_src, &forged_init(&b, 2, 0x22))
.one_intro()
.0;
let id_c = b
.feed(t + Duration::from_secs(2), c_src, &forged_init(&b, 3, 0x33))
.one_intro()
.0;
let id_d = b
.feed(t + Duration::from_secs(3), d_src, &forged_init(&b, 4, 0x44))
.one_intro()
.0;
let refresh = b.feed(t + Duration::from_secs(4), a_src, &forged_init(&b, 5, 0x55));
assert!(refresh.intros().is_empty(), "a refresh must not re-surface");
assert_eq!(
b.ep.intro_sender_index(id_a),
Some(5),
"the refresh did not land"
);
let id_e = b
.feed(t + Duration::from_secs(5), e_src, &forged_init(&b, 6, 0x66))
.one_intro()
.0;
assert!(
b.present(id_a),
"the refreshed entry was evicted — eviction is still ordered by park time (ruling 69)"
);
assert!(
!b.present(id_b),
"the oldest-by-last-refresh entry survived"
);
assert!(b.present(id_c) && b.present(id_d) && b.present(id_e));
}
#[test]
fn the_per_source_cap_evicts_the_oldest_by_last_refresh() {
let t = t0();
let (_a, mut b) = pair(t);
let ip = 5u8;
let mut ids = Vec::new();
for n in 0..INTRO_MAX_PER_SOURCE {
let now = t + Duration::from_secs(n as u64);
ids.push(
b.feed(
now,
v4(ip, 100 + n as u16),
&forged_init(&b, n as u32 + 1, 0x11),
)
.one_intro()
.0,
);
}
let _ = b.feed(
t + Duration::from_secs(10),
v4(ip, 100),
&forged_init(&b, 0xDDDD, 0x55),
);
let fifth = b
.feed(
t + Duration::from_secs(11),
v4(ip, 500),
&forged_init(&b, 0xEEEE, 0x66),
)
.one_intro()
.0;
assert!(
b.present(ids[0]),
"the per-source cap evicted the refreshed entry (ruling 69)"
);
assert!(!b.present(ids[1]), "the oldest by last refresh survived");
assert!(b.present(fifth));
}
#[test]
fn a_cap_evicted_id_says_evicted_where_a_ttl_reaped_one_says_expired() {
let t = t0();
let (_a, mut b) = pair(t);
let ip = 5u8;
let mut ids = Vec::new();
for n in 0..INTRO_MAX_PER_SOURCE {
let now = t + Duration::from_secs(n as u64);
ids.push(
b.feed(
now,
v4(ip, 100 + n as u16),
&forged_init(&b, n as u32 + 1, 0x11),
)
.one_intro()
.0,
);
}
let now = t + Duration::from_secs(1);
let _ = b.feed(now, v4(ip, 500), &forged_init(&b, 0xEEEE, 0x66));
assert!(!b.present(ids[0]), "the per-source cap did not evict");
assert_eq!(
b.ep.read_identity(now, ids[0]).err(),
Some(IntroError::Evicted),
"a chain the per-source cap displaced one second after it parked did \
not outlive INTRO_TTL, and the old `Expired` said it had"
);
let _ = b.drain();
let (_c, mut d) = pair(t);
let id = d.feed(t, v4(6, 6), &forged_init(&d, 1, 0x22)).one_intro().0;
let after = t + INTRO_TTL;
let _ = d.timeout(after);
assert_eq!(
d.ep.read_identity(after, id).err(),
Some(IntroError::Expired),
"§6.3's expiry is still `Expired` — the eviction record must be \
written on the overflow path only, never inside `remove`"
);
let _ = d.drain();
}
#[test]
fn read_identity_frees_the_stage0_slot_and_the_chain_is_never_byte_replaced() {
let t = t0();
let (mut a, mut b) = pair(t);
let msg1 = real_msg1(&mut a, t, &b);
let original_index = init_sender_index(&msg1);
let consumed = b.feed(t, a.addr, &msg1).one_intro().0;
b.ep.read_identity(t, consumed).expect("readable");
let _ = b.drain();
let later = b.feed(
t + Duration::from_secs(1),
a.addr,
&forged_init(&b, 0x1234_5678, 0x77),
);
let (fresh, src) = later.one_intro();
assert_eq!(src, a.addr, "the slot was not freed for a new entry");
assert_ne!(
fresh, consumed,
"the later initiation reused the consumed IntroId"
);
assert_eq!(
b.ep.intro_sender_index(consumed),
Some(original_index),
"an unauthenticated mac1-valid packet clobbered DH-paid work"
);
assert_eq!(b.ep.intro_sender_index(fresh), Some(0x1234_5678));
}
#[test]
fn the_per_source_cap_counts_consumed_and_unconsumed_together() {
let t = t0();
let (mut a, mut b) = pair(t);
let msg1 = real_msg1(&mut a, t, &b);
let ip = 5u8;
let mut ids = Vec::new();
for n in 0..INTRO_MAX_PER_SOURCE {
let now = t + Duration::from_secs(n as u64);
ids.push(b.feed(now, v4(ip, 100 + n as u16), &msg1).one_intro().0);
}
let consumed_at = t + Duration::from_secs((INTRO_MAX_PER_SOURCE - 1) as u64);
b.ep.read_identity(consumed_at, ids[0]).expect("readable");
let _ = b.drain();
b.ep.read_identity(consumed_at, ids[1]).expect("readable");
let _ = b.drain();
assert_eq!(b.dhs.get(), 2, "read_identity is exactly one es per chain");
let fifth = b
.feed(
t + Duration::from_secs(9),
v4(ip, 900),
&forged_init(&b, 0xABCD, 0x11),
)
.one_intro()
.0;
let live = ids.iter().filter(|id| b.present(**id)).count();
assert_eq!(
live,
INTRO_MAX_PER_SOURCE - 1,
"consuming an entry bought the source an extra slot"
);
assert!(b.present(fifth));
assert!(
b.present(ids[0]) && b.present(ids[1]),
"eviction operates on the unconsumed tier only — a DH-paid chain was evicted"
);
}
#[test]
fn an_all_consumed_source_drops_the_arrival() {
let t = t0();
let (mut a, mut b) = pair(t);
let msg1 = real_msg1(&mut a, t, &b);
let ip = 5u8;
let mut ids = Vec::new();
for n in 0..INTRO_MAX_PER_SOURCE {
let id = b.feed(t, v4(ip, 100 + n as u16), &msg1).one_intro().0;
b.ep.read_identity(t, id).expect("readable");
let _ = b.drain();
ids.push(id);
}
let d = b.feed(
t + Duration::from_secs(1),
v4(ip, 900),
&forged_init(&b, 0xABCD, 0x11),
);
assert!(
d.is_silent(),
"the arrival was admitted or announced: {:?}",
d.outs
);
assert_eq!(
ids.iter().filter(|id| b.present(**id)).count(),
INTRO_MAX_PER_SOURCE,
"a consumed chain was evicted to make room"
);
assert_eq!(
b.feed(
t + Duration::from_secs(1),
v4(6, 100),
&forged_init(&b, 1, 0x22)
)
.intros()
.len(),
1
);
}
#[test]
fn overflow_never_evicts_a_consumed_chain() {
let t = t0();
let mut a = Ep::new(t, 7, 0x11, v4(1, 1), default_config());
let mut b = Ep::new(t, 9, 0x22, v4(2, 2), capped_config(2, 2));
let msg1 = real_msg1(&mut a, t, &b);
let consumed = b.feed(t, v4(11, 11), &msg1).one_intro().0;
b.ep.read_identity(t, consumed).expect("readable");
let _ = b.drain();
let unconsumed = b
.feed(
t + Duration::from_secs(1),
v4(12, 12),
&forged_init(&b, 2, 0x22),
)
.one_intro()
.0;
let arrival = b
.feed(
t + Duration::from_secs(2),
v4(13, 13),
&forged_init(&b, 3, 0x33),
)
.one_intro()
.0;
assert!(b.present(consumed), "overflow evicted a DH-paid chain");
assert!(
!b.present(unconsumed),
"overflow spared the unconsumed tier"
);
assert!(b.present(arrival));
}
#[test]
fn a_wholly_consumed_queue_drops_the_arrival() {
let t = t0();
let mut a = Ep::new(t, 7, 0x11, v4(1, 1), default_config());
let mut b = Ep::new(t, 9, 0x22, v4(2, 2), capped_config(2, 2));
let msg1 = real_msg1(&mut a, t, &b);
let mut ids = Vec::new();
for n in 0..2u8 {
let id = b.feed(t, v4(20 + n, 11), &msg1).one_intro().0;
b.ep.read_identity(t, id).expect("readable");
let _ = b.drain();
ids.push(id);
}
let d = b.feed(
t + Duration::from_secs(1),
v4(30, 30),
&forged_init(&b, 9, 0x99),
);
assert!(d.is_silent(), "the arrival was admitted: {:?}", d.outs);
assert!(ids.iter().all(|id| b.present(*id)));
}
#[test]
fn an_intro_lives_until_intro_ttl_and_not_past_it() {
let t = t0();
let (_a, mut b) = pair(t);
let id = b.feed(t, v4(5, 5), &forged_init(&b, 1, 0x11)).one_intro().0;
let _ = b.timeout(t + INTRO_TTL - Duration::from_nanos(1));
assert!(b.present(id), "the entry expired before INTRO_TTL");
let _ = b.timeout(t + INTRO_TTL + Duration::from_nanos(1));
assert!(!b.present(id), "the entry outlived INTRO_TTL");
}
#[test]
fn an_intro_expires_at_exactly_intro_ttl() {
let t = t0();
let (_a, mut b) = pair(t);
let id = b.feed(t, v4(5, 5), &forged_init(&b, 1, 0x11)).one_intro().0;
let d = b.timeout(t + INTRO_TTL);
assert!(!b.present(id), "the deadline did not fire at D");
assert!(d.is_silent(), "expiry is silent eviction: {:?}", d.outs);
assert_eq!(d.deadline, None, "an emptied queue arms nothing");
}
#[test]
fn a_refresh_moves_the_expiry_to_fifteen_seconds_after_it() {
let t = t0();
let (_a, mut b) = pair(t);
let src = v4(5, 5);
let id = b.feed(t, src, &forged_init(&b, 1, 0x11)).one_intro().0;
let refreshed_at = t + Duration::from_secs(10);
let d = b.feed(refreshed_at, src, &forged_init(&b, 2, 0x22));
assert_eq!(
d.deadline,
Some(refreshed_at + INTRO_TTL),
"the refresh did not move the deadline"
);
let _ = b.timeout(t + INTRO_TTL);
assert!(b.present(id), "the original park-time deadline still fired");
let _ = b.timeout(refreshed_at + INTRO_TTL - Duration::from_nanos(1));
assert!(b.present(id));
let _ = b.timeout(refreshed_at + INTRO_TTL);
assert!(!b.present(id), "the refreshed deadline did not fire");
}
#[test]
fn a_consumed_chain_expires_fifteen_seconds_after_its_initiation() {
let t = t0();
let (mut a, mut b) = pair(t);
let msg1 = real_msg1(&mut a, t, &b);
let id = b.feed(t, a.addr, &msg1).one_intro().0;
let consumed_at = t + Duration::from_secs(10);
b.ep.read_identity(consumed_at, id).expect("readable");
let _ = b.timeout(consumed_at);
assert!(b.present(id), "the chain died before its initiation's TTL");
let _ = b.timeout(t + INTRO_TTL - Duration::from_nanos(1));
assert!(b.present(id));
let _ = b.timeout(t + INTRO_TTL);
assert!(
!b.present(id),
"consumption restarted the TTL — a consumed chain's clock runs from the initiation"
);
assert!(matches!(
b.ep.authenticate(t + INTRO_TTL, id, &()),
Err(AuthError::Expired)
));
}
#[test]
fn the_staged_verbs_on_an_expired_id_report_expired() {
let t = t0();
let (_a, mut b) = pair(t);
let id = b.feed(t, v4(5, 5), &forged_init(&b, 1, 0x11)).one_intro().0;
let after = t + INTRO_TTL;
let _ = b.timeout(after);
assert!(matches!(
b.ep.read_identity(after, id),
Err(IntroError::Expired)
));
let _ = b.drain();
assert!(matches!(
b.ep.authenticate(after, id, &()),
Err(AuthError::Expired)
));
let _ = b.drain();
assert!(matches!(b.ep.accept(after, id), Err(AcceptError::Stale)));
let _ = b.drain();
b.ep.reject(after, id); assert!(b.drain().is_silent());
}
#[test]
fn per_source_counters_return_to_zero_when_the_queue_drains() {
let t = t0();
let (_a, mut b) = pair(t);
let ip = 5u8;
for round in 0..3u64 {
let base = t + Duration::from_secs(round * 100);
let mut ids = Vec::new();
let mut last_park = base;
for n in 0..INTRO_MAX_PER_SOURCE {
let park = base + Duration::from_millis(n as u64);
last_park = park;
let d = b.feed(
park,
v4(ip, 100 + n as u16),
&forged_init(&b, n as u32 + 1, 0x11),
);
assert_eq!(
d.intros().len(),
1,
"round {round} arrival {n} was refused — the counter leaked"
);
ids.push(d.one_intro().0);
}
let d = b.timeout(last_park + INTRO_TTL);
assert!(d.is_silent());
assert!(
ids.iter().all(|id| !b.present(*id)),
"round {round} left entries behind"
);
}
}
#[test]
fn an_established_index_still_routes_while_the_queue_is_saturated() {
let t = t0();
let (mut a, mut b) = pair(t);
let msg1 = real_msg1(&mut a, t, &b);
let id = b.feed(t, a.addr, &msg1).one_intro().0;
b.ep.read_identity(t, id).expect("readable");
let _ = b.drain();
b.ep.authenticate(t, id, &()).expect("authenticates");
let _ = b.drain();
let (conn, _core) = b.ep.accept(t, id).expect("accepts");
let msg2 = b.drain().one_transmit().1;
let (our_index, _theirs) = resp_indices(&msg2);
let before = b.dhs.get();
for n in 0..INTRO_QUEUE_CAP {
let src = v4_nth(
n / INTRO_MAX_PER_SOURCE,
4000 + (n % INTRO_MAX_PER_SOURCE) as u16,
);
let _ = b.feed(t, src, &forged_init(&b, n as u32 + 1, 0x33));
}
assert_eq!(b.dhs.get(), before, "the flood spent DH");
let (disp, _d) = b.datagram(t, a.addr, &data_packet(our_index, 1, 64));
assert_eq!(
disp,
Disposition::ForConnection(conn),
"a saturated queue stopped routing an established connection"
);
}
fn msg1_train(a: &mut Ep, t: Instant, b: &Ep, n: usize) -> Vec<Vec<u8>> {
let peer = b.public_static;
let (_conn, d) = a.connect(t, b.addr, &peer);
let mut out = vec![d.one_transmit().1];
let mut due = d.deadline.expect("a pending arms a retransmit");
while out.len() < n {
let d = a.timeout(due);
out.push(d.one_transmit().1);
due = d.deadline.expect("the next retransmit is armed");
}
out
}
fn ladder_to_proven(
b: &mut Ep,
now: Instant,
src: SocketAddr,
msg1: &[u8],
) -> (IntroId, Result<Timestamp, AuthError>) {
let id = b.feed(now, src, msg1).one_intro().0;
b.ep.read_identity(now, id)
.expect("a real msg1 is readable");
let _ = b.drain();
let r = b.ep.authenticate(now, id, &()).map(|(_pk, ts)| ts);
let _ = b.drain();
(id, r)
}
#[test]
fn the_guard_admits_only_a_strictly_greater_timestamp() {
let t = t0();
let (mut a, mut b) = pair(t);
let train = msg1_train(&mut a, t, &b, 3);
let (_id, mid) = ladder_to_proven(&mut b, t, v4(20, 1), &train[1]);
let ts_mid = mid.expect("the first admission passes vacuously");
let (_id, older) = ladder_to_proven(&mut b, t, v4(20, 2), &train[0]);
assert!(
matches!(older, Err(AuthError::Replay)),
"an older timestamp was admitted"
);
let (_id, equal) = ladder_to_proven(&mut b, t, v4(20, 3), &train[1]);
assert!(
matches!(equal, Err(AuthError::Replay)),
"an EQUAL timestamp was admitted — the comparison is not strict"
);
let (_id, newer) = ladder_to_proven(&mut b, t, v4(20, 4), &train[2]);
let ts_new = newer.expect("a strictly greater timestamp must be admitted");
assert!(ts_new > ts_mid, "the train is not monotone");
}
#[test]
fn authenticate_then_reject_leaves_the_guard_empty() {
let t = t0();
let (mut a, mut b) = pair(t);
let train = msg1_train(&mut a, t, &b, 2);
let (id, first) = ladder_to_proven(&mut b, t, v4(21, 1), &train[0]);
first.expect("first admission");
b.ep.reject(t, id);
let _ = b.drain();
let (_id, again) = ladder_to_proven(&mut b, t, v4(21, 2), &train[0]);
assert!(
again.is_ok(),
"the rejected chain left an orphan record behind: {again:?}"
);
}
#[test]
fn authenticate_then_reject_restores_a_prior_value() {
let t = t0();
let (mut a, mut b) = pair(t);
let train = msg1_train(&mut a, t, &b, 3);
let (id0, admitted) = ladder_to_proven(&mut b, t, v4(22, 1), &train[0]);
admitted.expect("first admission");
b.ep.accept(t, id0).expect("a fresh static accepts");
let _ = b.drain();
let (id2, high) = ladder_to_proven(&mut b, t, v4(22, 2), &train[2]);
high.expect("train[2] is strictly greater than train[0]");
b.ep.reject(t, id2);
let _ = b.drain();
let (_id, replay) = ladder_to_proven(&mut b, t, v4(22, 3), &train[0]);
assert!(
matches!(replay, Err(AuthError::Replay)),
"the revert removed the pre-existing entry instead of restoring it"
);
let (_id, middle) = ladder_to_proven(&mut b, t, v4(22, 4), &train[1]);
assert!(
middle.is_ok(),
"the rejected chain's record survived: {middle:?}"
);
}
#[test]
fn a_basis_refused_accept_restores_a_prior_value() {
let t = t0();
let (mut a, mut b) = pair(t);
let mut b2 = Ep::new(t, 9, 0x33, v4(3, 3), default_config());
let train = msg1_train(&mut b, t, &a, 3);
let (id0, admitted) = ladder_to_proven(&mut a, t, v4(42, 1), &train[0]);
let ts0 = admitted.expect("first admission");
let (conn0, _c) = a.ep.accept(t, id0).expect("a fresh static accepts");
let msg2 = a.drain().one_transmit().1;
let (our_index, _theirs) = resp_indices(&msg2);
a.ep.handle_connection_event(t, conn0, ToEndpoint::Retired { our_index });
let _ = a.drain();
assert_eq!(
a.ep.greatest(b.canonical()),
Some(ts0),
"§17.1: a retired connection releases its pin, not its record — \
without this the test below would be about an empty guard again"
);
let (conn1, d) = a.connect(t, b2.addr, &b2.public_static);
let msg1 = d.one_transmit().1;
let id = b2.feed(t, a.addr, &msg1).one_intro().0;
b2.ep.read_identity(t, id).expect("a real msg1 is readable");
let _ = b2.drain();
b2.ep.authenticate(t, id, &()).expect("authenticates");
let _ = b2.drain();
b2.ep.accept(t, id).expect("b2 holds no row for a");
let resp = b2.drain().one_transmit().1;
assert_eq!(
a.feed(t, b2.addr, &resp).installs(),
vec![conn1],
"the dial must complete, or the basis below is PENDING and the \
refusal is §6.4's tie-break rather than the basis rule"
);
assert_eq!(
a.ep.replacement_basis(b.canonical()),
Some(None),
"§17.4: a completed dial writes a LIVE row with a `None` basis"
);
let (id2, high) = ladder_to_proven(&mut a, t, v4(42, 2), &train[2]);
let ts2 = high.expect("train[2] is strictly greater than train[0]");
assert_eq!(
a.ep.greatest(b.canonical()),
Some(ts2),
"`authenticate()` writes provisionally — that write is what the \
refusal must undo"
);
assert!(
matches!(a.ep.accept(t, id2), Err(AcceptError::Stale)),
"§6.4: a `None` basis refuses every candidate, however new"
);
let _ = a.drain();
assert_eq!(
a.ep.greatest(b.canonical()),
Some(ts0),
"§17.1 mitigation (i) on the basis-refused accept arm: the \
pre-existing entry REVERTS, it is not emptied"
);
let (_id, replay) = ladder_to_proven(&mut a, t, v4(42, 3), &train[0]);
assert!(
matches!(replay, Err(AuthError::Replay)),
"the revert removed the pre-existing entry instead of restoring it, \
so a replay of the recorded initiation is admitted again: {replay:?}"
);
let (_id, middle) = ladder_to_proven(&mut a, t, v4(42, 4), &train[1]);
assert!(
middle.is_ok(),
"SECV5-6: a later genuine initiation with a timestamp BETWEEN the \
two must still be admitted — the refused chain's record survived: \
{middle:?}"
);
}
#[test]
fn authenticate_then_reject_clears_the_record_even_when_another_chain_pins_the_entry() {
let t = t0();
let (mut a, mut b) = pair(t);
let train = msg1_train(&mut a, t, &b, 2);
let (chain_a, admitted) = ladder_to_proven(&mut b, t, v4(31, 1), &train[1]);
let ts = admitted.expect("the first admission passes vacuously");
assert_eq!(
b.ep.greatest(a.canonical()),
Some(ts),
"authenticate did not record the timestamp"
);
let chain_b = b.feed(t, v4(31, 2), &train[0]).one_intro().0;
b.ep.read_identity(t, chain_b)
.expect("a real msg1 is readable");
let _ = b.drain();
b.ep.reject(t, chain_a);
let _ = b.drain();
assert_eq!(
b.ep.greatest(a.canonical()),
None,
"the record outlived the chain that wrote it because a second pin held the entry"
);
let (_id, again) = ladder_to_proven(&mut b, t, v4(31, 3), &train[1]);
assert!(
again.is_ok(),
"authenticate-then-drop minted an orphan while a second chain pinned the entry: {again:?}"
);
}
#[test]
fn a_claimed_chain_creates_no_guard_entry() {
let t = t0();
let (mut a, mut b) = pair(t);
let train = msg1_train(&mut a, t, &b, 2);
let id = b.feed(t, v4(32, 1), &train[1]).one_intro().0;
b.ep.read_identity(t, id).expect("a real msg1 is readable");
let _ = b.drain();
assert_eq!(b.dhs.get(), 1, "Claimed is one DH");
assert_eq!(
b.ep.greatest(a.canonical()),
None,
"reaching Claimed wrote a guard entry for an unproven, attacker-choosable static"
);
let (_id, older) = ladder_to_proven(&mut b, t, v4(32, 2), &train[0]);
assert!(
older.is_ok(),
"an older initiation was refused, so Claimed recorded something: {older:?}"
);
}
#[test]
fn cancelling_a_dial_does_not_release_a_pin_it_never_took() {
let t = t0();
let (mut a, mut b) = pair(t);
let (conn, d) = a.connect(t, b.addr, &b.public_static);
let index = init_sender_index(&d.one_transmit().1);
assert_eq!(
a.ep.greatest(b.canonical()),
None,
"a dial created a guard entry — every §17.1 write site is inbound and post-ss"
);
assert_eq!(
a.ep.guard_pins(b.canonical()),
0,
"a dial took a pin on a static we hold no entry for"
);
let inbound = real_msg1(&mut b, t, &a);
let at = t + Duration::from_secs(1);
let chain = a.feed(at, v4(2, 3), &inbound).one_intro().0;
let admitted = a.ep.authenticate(at, chain, &()).map(|(_pk, ts)| ts);
let _ = a.drain();
let ts = admitted.expect("we hold no entry for a static we dialled, so this passes vacuously");
assert_eq!(a.ep.greatest(b.canonical()), Some(ts));
assert_eq!(
a.ep.guard_pins(b.canonical()),
1,
"the mid-state's pin is the only one: the in-flight dial must not have \
acquired one retroactively when the entry appeared"
);
a.ep.handle_connection_event(t, conn, ToEndpoint::Retired { our_index: index });
let _ = a.drain();
assert_eq!(
a.ep.guard_pins(b.canonical()),
1,
"cancelling the dial released a pin it never took — §17.1's \
\"never evicted while a staged mid-state exists\" is now silently broken"
);
assert_eq!(
a.ep.greatest(b.canonical()),
Some(ts),
"cancelling the dial destroyed a record it never wrote"
);
let alive = at + INTRO_TTL - Duration::from_nanos(1);
let _ = a.timeout(alive);
let (_id, replay) = ladder_to_proven(&mut a, alive, v4(33, 1), &inbound);
assert!(
matches!(replay, Err(AuthError::Replay)),
"the entry lost its record while a staged mid-state still pinned it (§17.1): {replay:?}"
);
}
#[test]
fn a_dialled_static_holds_no_guard_entry() {
let t = t0();
let mut a = Ep::new(
t,
7,
0x11,
v4(1, 1),
frozen_clock_config(T_BASE_SECS + 10_000, 0),
);
let mut b = Ep::new(t, 9, 0x22, v4(2, 2), frozen_clock_config(T_BASE_SECS, 0));
let peer_b = b.public_static;
let (_conn, _d) = a.connect(t, b.addr, &peer_b);
let msg1_from_b = real_msg1(&mut b, t, &a);
let id = a.feed(t, v4(2, 3), &msg1_from_b).one_intro().0;
let r = a.ep.authenticate(t, id, &()).map(|(_pk, ts)| ts);
let _ = a.drain();
assert!(
r.is_ok(),
"the dial wrote a guard entry for a static we only dialled: {r:?}"
);
}
#[test]
fn two_initiations_under_a_frozen_clock_are_strictly_increasing() {
let t = t0();
let mut a = Ep::new(
t,
7,
0x11,
v4(1, 1),
frozen_clock_config(T_BASE_SECS, 500_000),
);
let mut b = Ep::new(t, 9, 0x22, v4(2, 2), default_config());
let train = msg1_train(&mut a, t, &b, 3);
let (_id, first) = ladder_to_proven(&mut b, t, v4(23, 1), &train[0]);
let t1 = first.expect("first admission");
let (_id, second) = ladder_to_proven(&mut b, t, v4(23, 2), &train[1]);
let t2 = second.expect("the forced increment makes the second admissible");
let (_id, third) = ladder_to_proven(&mut b, t, v4(23, 3), &train[2]);
let t3 = third.expect("and the third");
assert!(
t1 < t2 && t2 < t3,
"a frozen clock produced non-increasing initiation timestamps: {t1:?} {t2:?} {t3:?}"
);
}
#[test]
fn a_pinned_guard_entry_does_not_age_out() {
let t = t0();
let (mut a, mut b) = pair(t);
let train = msg1_train(&mut a, t, &b, 2);
let (id, admitted) = ladder_to_proven(&mut b, t, v4(24, 1), &train[1]);
admitted.expect("admission");
b.ep.accept(t, id).expect("accepts");
let _ = b.drain();
let much_later = t + TS_GUARD_ORPHAN_TTL * 3;
let _ = b.timeout(much_later);
let (_id, replay) = ladder_to_proven(&mut b, much_later, v4(24, 2), &train[1]);
assert!(
matches!(replay, Err(AuthError::Replay)),
"a pinned guard entry aged out under a live connection"
);
}
#[test]
fn an_orphaned_guard_entry_ages_out_at_ts_guard_orphan_ttl() {
let t = t0();
let (mut a, mut b) = pair(t);
let train = msg1_train(&mut a, t, &b, 2);
let (id, admitted) = ladder_to_proven(&mut b, t, v4(25, 1), &train[1]);
admitted.expect("admission");
let (conn, _core) = b.ep.accept(t, id).expect("accepts");
let msg2 = b.drain().one_transmit().1;
let (ours, _theirs) = resp_indices(&msg2);
b.ep.handle_connection_event(t, conn, ToEndpoint::Retired { our_index: ours });
let _ = b.drain();
let before = t + TS_GUARD_ORPHAN_TTL - Duration::from_nanos(1);
let _ = b.timeout(before);
let (_id, still) = ladder_to_proven(&mut b, before, v4(25, 2), &train[1]);
assert!(
matches!(still, Err(AuthError::Replay)),
"the orphan aged out early"
);
let after = t + TS_GUARD_ORPHAN_TTL;
let _ = b.timeout(after);
let (_id, gone) = ladder_to_proven(&mut b, after, v4(25, 3), &train[1]);
assert!(
gone.is_ok(),
"the orphan outlived TS_GUARD_ORPHAN_TTL: {gone:?}"
);
}
#[test]
fn the_endpoint_deadline_covers_guard_orphan_aging() {
let t = t0();
let (mut a, mut b) = pair(t);
let train = msg1_train(&mut a, t, &b, 1);
let (id, admitted) = ladder_to_proven(&mut b, t, v4(26, 1), &train[0]);
admitted.expect("admission");
let (conn, _core) = b.ep.accept(t, id).expect("accepts");
let msg2 = b.drain().one_transmit().1;
let (ours, _theirs) = resp_indices(&msg2);
b.ep.handle_connection_event(t, conn, ToEndpoint::Retired { our_index: ours });
let d = b.drain();
assert_eq!(
d.deadline,
Some(t + TS_GUARD_ORPHAN_TTL),
"orphan aging is not in the endpoint's min-deadline (§16.5)"
);
}
#[test]
fn accept_on_a_live_static_replaces_it_against_a_newer_basis() {
let t = t0();
let (mut a, mut b) = pair(t);
let train = msg1_train(&mut a, t, &b, 2);
let (first, admitted) = ladder_to_proven(&mut b, t, v4(27, 1), &train[0]);
admitted.expect("admission");
let (live, _core) = b.ep.accept(t, first).expect("the NONE row accepts");
let msg2 = b.drain().one_transmit().1;
let (ours, _theirs) = resp_indices(&msg2);
let (second, proven) = ladder_to_proven(&mut b, t, v4(27, 2), &train[1]);
assert!(
proven.is_ok(),
"a replacement candidate must still reach Proven: {proven:?}"
);
let (replacement, _core) =
b.ep.accept(t, second)
.expect("§6.4: a strictly newer candidate against a Some(t) basis replaces");
assert_ne!(
replacement, live,
"a **fresh** connection, never the old one"
);
let d = b.drain();
assert_eq!(
d.replaced(),
vec![live],
"§5.4: the teardown fires at the act that installs the replacement"
);
assert_eq!(d.transmits().len(), 1, "and msg2 goes out for the new one");
assert!(
d.installs().is_empty(),
"§16.4: `accept()` returns an established connection and is never followed by an `Install`"
);
let replaced_at = d
.outs
.iter()
.position(|o| matches!(o, EndpointOutput::Replaced(_)))
.expect("the teardown");
let msg2_at = d
.outs
.iter()
.position(|o| matches!(o, EndpointOutput::Transmit(_)))
.expect("msg2");
assert!(
replaced_at < msg2_at,
"§16.4's generation order: the teardown, then the replacement's msg2"
);
let (disp, _d) = b.datagram(t, a.addr, &data_packet(ours, 1, 64));
assert_eq!(
disp,
Disposition::ForConnection(live),
"the index route outlives the teardown by exactly one event"
);
b.ep.handle_connection_event(t, live, ToEndpoint::Retired { our_index: ours });
let (disp, _d) = b.datagram(t, a.addr, &data_packet(ours, 2, 64));
assert_eq!(disp, Disposition::Done, "the retired index routes nowhere");
assert!(
matches!(
b.ep.mint_pending(t, a.addr, a.public_static, ()),
Err(ConnectError::AlreadyConnected)
),
"§16.1: the static is the replacement's, and the old `Retired` did not release it"
);
}
#[test]
fn connect_to_a_static_with_a_live_connection_is_already_connected() {
let t = t0();
let (mut a, mut b) = pair(t);
let msg1 = real_msg1(&mut a, t, &b);
let id = b.feed(t, a.addr, &msg1).one_intro().0;
b.ep.read_identity(t, id).expect("readable");
let _ = b.drain();
b.ep.authenticate(t, id, &()).expect("authenticates");
let _ = b.drain();
b.ep.accept(t, id).expect("accepts");
let msg2 = b.drain().one_transmit().1;
let _ = a.feed(t, b.addr, &msg2);
let peer = b.public_static;
assert!(
matches!(
a.ep.mint_pending(t, b.addr, peer, ()),
Err(ConnectError::AlreadyConnected)
),
"a second connect() to a live static succeeded"
);
}
fn forged_resp(initiator: &Ep, sender_index: u32, receiver_index: u32, filler: u8) -> Vec<u8> {
let mut d = vec![filler; RESP_PACKET_LEN];
d[0] = PKT_HANDSHAKE_RESP;
d[1] = VERSION;
d[2..6].copy_from_slice(&sender_index.to_le_bytes());
d[6..10].copy_from_slice(&receiver_index.to_le_bytes());
let (preimage, tag) = d.split_at_mut(RESP_PACKET_LEN - MAC1_LEN);
let t = initiator.mac1_key().tag(preimage);
tag.copy_from_slice(&t);
d
}
fn genuine_msg2(b: &mut Ep, now: Instant, src: SocketAddr, msg1: &[u8]) -> Vec<u8> {
let id = b.feed(now, src, msg1).one_intro().0;
b.ep.read_identity(now, id)
.expect("a real msg1 is readable");
let _ = b.drain();
b.ep.authenticate(now, id, &()).expect("authenticates");
let _ = b.drain();
b.ep.accept(now, id).expect("a fresh static accepts");
let (to, data) = b.drain().one_transmit();
assert_eq!(to, src, "§5.6 anchors at the msg1 source address");
assert_eq!(data.len(), RESP_PACKET_LEN, "§3.3, exact (ruling 65)");
data
}
#[test]
fn connect_sends_exactly_one_init_to_the_dialled_address() {
let t = t0();
let (mut a, b) = pair(t);
let peer = b.public_static;
let (_conn, d) = a.connect(t, b.addr, &peer);
let (to, data) = d.one_transmit();
assert_eq!(to, b.addr);
assert_eq!(data.len(), INIT_PACKET_LEN);
assert_eq!(data[0], PKT_HANDSHAKE_INIT);
assert_eq!(data[1], VERSION);
assert_ne!(init_sender_index(&data), 0, "§17.3: indices are nonzero");
assert!(
d.installs().is_empty(),
"a dial installs nothing until msg2 completes it"
);
}
#[test]
fn every_retransmit_mints_a_fresh_index_and_a_fresh_ephemeral() {
let t = t0();
let (mut a, b) = pair(t);
let peer = b.public_static;
let (_conn, d) = a.connect(t, b.addr, &peer);
let mut packets = vec![d.one_transmit().1];
let mut due = d.deadline.expect("armed");
for _ in 0..8 {
let d = a.timeout(due);
packets.push(d.one_transmit().1);
due = d.deadline.expect("armed");
}
let mut indices: Vec<u32> = packets.iter().map(|p| init_sender_index(p)).collect();
assert!(indices.iter().all(|i| *i != 0), "§17.3: nonzero");
indices.sort_unstable();
let before = indices.len();
indices.dedup();
assert_eq!(indices.len(), before, "an index was reused across attempts");
let ephemerals: Vec<&[u8]> = packets.iter().map(|p| msg1_ephemeral(p)).collect();
for (i, e) in ephemerals.iter().enumerate() {
for (j, f) in ephemerals.iter().enumerate().skip(i + 1) {
assert_ne!(
e, f,
"attempts {i} and {j} share an ephemeral public key — \
§5.5 step 2 requires a fresh ephemeral for every initiation"
);
}
}
}
#[test]
fn the_retransmit_interval_is_five_seconds_plus_bounded_jitter_and_never_grows() {
let t = t0();
let (mut a, b) = pair(t);
let peer = b.public_static;
let (_conn, d) = a.connect(t, b.addr, &peer);
let lo = RETRANSMIT_BASE;
let hi = RETRANSMIT_BASE + RETRANSMIT_JITTER_MAX;
let mut prev = t;
let mut due = d.deadline.expect("armed");
let mut gaps = Vec::new();
for n in 0..12 {
let gap = due - prev;
assert!(
gap >= lo,
"interval {n} of {gap:?} is below RETRANSMIT_BASE"
);
assert!(
gap <= hi,
"interval {n} of {gap:?} exceeds RETRANSMIT_BASE + RETRANSMIT_JITTER_MAX \
— the schedule is not fixed-interval"
);
gaps.push(gap);
let d = a.timeout(due);
assert_eq!(d.transmits().len(), 1);
prev = due;
due = d.deadline.expect("armed");
}
let max = gaps.iter().max().copied().expect("gaps");
let min = gaps.iter().min().copied().expect("gaps");
assert!(
max - min <= RETRANSMIT_JITTER_MAX,
"the spread between intervals exceeds the jitter band: {min:?}..{max:?}"
);
}
#[test]
fn the_retransmit_jitter_is_drawn_afresh_for_every_attempt() {
let t = t0();
let (mut a, b) = pair(t);
let (_conn, d) = a.connect(t, b.addr, &b.public_static);
let mut prev = t;
let mut due = d.deadline.expect("a pending arms a retransmit");
let mut gaps = Vec::new();
for _ in 0..12 {
gaps.push(due - prev);
let d = a.timeout(due);
prev = due;
due = d.deadline.expect("armed");
}
assert!(
gaps.iter().any(|g| *g > RETRANSMIT_BASE),
"all {} intervals were exactly RETRANSMIT_BASE — §5.5 step 2's jitter \
is never drawn: {gaps:?}",
gaps.len()
);
assert!(
gaps.iter().any(|g| *g != gaps[0]),
"all {} intervals were identical — the jitter is drawn once and reused \
rather than per attempt: {gaps:?}",
gaps.len()
);
}
#[test]
fn the_dial_gives_up_at_exactly_handshake_giveup_and_transmits_nothing_there() {
let t = t0();
let (mut a, b) = pair(t);
let peer = b.public_static;
let (conn, d) = a.connect(t, b.addr, &peer);
let give_up = t + HANDSHAKE_GIVEUP;
let mut due = d.deadline.expect("armed");
let mut attempts = 1usize;
loop {
assert!(
due <= give_up,
"a deadline was announced past give-up: {due:?}"
);
let d = a.timeout(due);
let failures = d.failures();
if let [(id, err)] = failures.as_slice() {
assert_eq!(due, give_up, "give-up fired at the wrong instant");
assert_eq!(*id, conn);
assert_eq!(*err, ConnectError::TimedOut);
assert!(
d.transmits().is_empty(),
"a retransmit rode out on the give-up instant (§16.5)"
);
assert_eq!(d.deadline, None, "the pending's timers were not disarmed");
break;
}
assert_eq!(d.transmits().len(), 1, "attempt {attempts} did not fire");
attempts += 1;
due = d.deadline.expect("armed");
assert!(attempts < 100, "the train never gave up");
}
let lo = 1
+ (HANDSHAKE_GIVEUP.as_millis() / (RETRANSMIT_BASE + RETRANSMIT_JITTER_MAX).as_millis())
as usize;
let hi = 1 + (HANDSHAKE_GIVEUP.as_millis() / RETRANSMIT_BASE.as_millis()) as usize;
assert!(
(lo..=hi).contains(&attempts),
"{attempts} attempts is outside the {lo}..={hi} the interval band allows"
);
let after = a.timeout(give_up + HANDSHAKE_GIVEUP);
assert!(after.is_silent(), "{:?}", after.outs);
assert_eq!(after.deadline, None);
}
#[test]
fn msg2_from_a_different_address_still_completes() {
let t = t0();
let (mut a, mut b) = pair(t);
let msg1 = real_msg1(&mut a, t, &b);
let id = b.feed(t, a.addr, &msg1).one_intro().0;
b.ep.read_identity(t, id).expect("readable");
let _ = b.drain();
b.ep.authenticate(t, id, &()).expect("authenticates");
let _ = b.drain();
b.ep.accept(t, id).expect("accepts");
let msg2 = b.drain().one_transmit().1;
let d = a.feed(t, v4(200, 200), &msg2);
assert_eq!(
d.installs().len(),
1,
"completion was refused because the source address differed"
);
}
#[test]
fn completion_installs_exactly_once() {
let t = t0();
let (mut a, mut b) = pair(t);
let msg1 = real_msg1(&mut a, t, &b);
let id = b.feed(t, a.addr, &msg1).one_intro().0;
b.ep.read_identity(t, id).expect("readable");
let _ = b.drain();
b.ep.authenticate(t, id, &()).expect("authenticates");
let _ = b.drain();
b.ep.accept(t, id).expect("accepts");
let msg2 = b.drain().one_transmit().1;
assert_eq!(a.feed(t, b.addr, &msg2).installs().len(), 1);
let second = a.feed(t, b.addr, &msg2);
assert!(
second.installs().is_empty(),
"the same msg2 installed a second session"
);
}
#[test]
fn a_mac1_invalid_msg2_spends_nothing() {
let t = t0();
let (mut a, mut b) = pair(t);
let msg1 = real_msg1(&mut a, t, &b);
let index = init_sender_index(&msg1);
assert_eq!(a.dhs.get(), 2);
let mut bad = forged_resp(&a, 0x1234, index, 0x77);
let last = bad.len() - 1;
bad[last] ^= 0x01;
let d = a.feed(t, b.addr, &bad);
assert_eq!(a.dhs.get(), 2, "a mac1-invalid msg2 reached the crypto");
assert!(d.installs().is_empty());
let msg2 = genuine_msg2(&mut b, t, a.addr, &msg1);
let d = a.feed(t, b.addr, &msg2);
assert_eq!(
d.installs().len(),
1,
"the mac1-invalid msg2 spent the interval's completion attempt"
);
assert_eq!(a.dhs.get(), 4, "completion is ee + se");
}
#[test]
fn a_wrong_index_msg2_spends_nothing() {
let t = t0();
let (mut a, mut b) = pair(t);
let msg1 = real_msg1(&mut a, t, &b);
let index = init_sender_index(&msg1);
for wrong in [index ^ 0xFFFF_FFFF, index.wrapping_add(1), 0] {
let bad = forged_resp(&a, 0x1234, wrong, 0x77);
let d = a.feed(t, b.addr, &bad);
assert_eq!(
a.dhs.get(),
2,
"a msg2 for index {wrong:#010x} reached the crypto"
);
assert!(d.installs().is_empty());
}
let msg2 = genuine_msg2(&mut b, t, a.addr, &msg1);
let d = a.feed(t, b.addr, &msg2);
assert_eq!(
d.installs().len(),
1,
"a guessed-index msg2 spent the interval's completion attempt"
);
}
#[test]
fn a_wrong_length_msg2_spends_nothing() {
let t = t0();
let (mut a, mut b) = pair(t);
let msg1 = real_msg1(&mut a, t, &b);
let index = init_sender_index(&msg1);
let exact = forged_resp(&a, 0x1234, index, 0x77);
let short = &exact[..RESP_PACKET_LEN - 1];
let _ = a.feed(t, b.addr, short);
assert_eq!(a.dhs.get(), 2, "RESP_PACKET_LEN - 1 reached the crypto");
let mut long = exact.clone();
long.push(0x00);
let _ = a.feed(t, b.addr, &long);
assert_eq!(
a.dhs.get(),
2,
"RESP_PACKET_LEN + 1 reached the crypto — an exact check was relaxed to a minimum"
);
let msg2 = genuine_msg2(&mut b, t, a.addr, &msg1);
let d = a.feed(t, b.addr, &msg2);
assert_eq!(
d.installs().len(),
1,
"a wrong-length msg2 spent the interval's completion attempt"
);
}
#[test]
fn a_failed_completion_spends_the_attempt_and_the_next_retransmit_refreshes_it() {
let t = t0();
let (mut a, mut b) = pair(t);
let mut b2 = Ep::new(t, 9, 0x33, v4(2, 3), default_config());
assert_eq!(
b2.canonical(),
b.canonical(),
"the twin responder must share the static, or its msg2 cannot complete"
);
let first_msg1 = real_msg1(&mut a, t, &b);
let first_index = init_sender_index(&first_msg1);
let due = a.drain().deadline.expect("a pending arms a retransmit");
let d = a.feed(t, b.addr, &forged_resp(&a, 1, first_index, 0x31));
assert!(d.installs().is_empty(), "junk msg2 installed a session");
let genuine_first = genuine_msg2(&mut b, t, a.addr, &first_msg1);
let d = a.feed(t, b.addr, &genuine_first);
assert!(
d.installs().is_empty(),
"a second msg2 in one interval completed — the failed one did not spend the attempt"
);
let d = a.timeout(due);
let second_msg1 = d.one_transmit().1;
let second_index = init_sender_index(&second_msg1);
assert_ne!(first_index, second_index);
let d = a.feed(due, b.addr, &genuine_first);
assert!(
d.installs().is_empty(),
"a msg2 for a superseded attempt completed"
);
let genuine_second = genuine_msg2(&mut b2, due, a.addr, &second_msg1);
let d = a.feed(due, b.addr, &genuine_second);
assert_eq!(
d.installs().len(),
1,
"the next interval's attempt was not refreshed"
);
}
#[test]
fn data_on_an_unknown_index_touches_nothing() {
let t = t0();
let (_a, mut b) = pair(t);
let parked = b.feed(t, v4(5, 5), &forged_init(&b, 1, 0x11));
let deadline = parked.deadline;
let id = parked.one_intro().0;
for index in [0u32, 1, 0xDEAD_BEEF, u32::MAX] {
let (disp, d) = b.datagram(t, v4(9, 9), &data_packet(index, 7, 100));
assert_eq!(
disp,
Disposition::Done,
"index {index:#010x} routed somewhere"
);
assert!(d.is_silent(), "{:?}", d.outs);
assert_eq!(d.deadline, deadline, "an inert datagram moved a deadline");
}
assert_eq!(b.dhs.get(), 0);
assert!(b.present(id), "an inert datagram disturbed the queue");
}
#[test]
fn the_responder_answers_the_msg1_source_address() {
let t = t0();
let (mut a, mut b) = pair(t);
let msg1 = real_msg1(&mut a, t, &b);
let spoofed = v4(123, 45);
assert_ne!(spoofed, a.addr);
let id = b.feed(t, spoofed, &msg1).one_intro().0;
b.ep.read_identity(t, id).expect("readable");
let _ = b.drain();
b.ep.authenticate(t, id, &()).expect("authenticates");
let _ = b.drain();
b.ep.accept(t, id).expect("accepts");
let (to, data) = b.drain().one_transmit();
assert_eq!(
to, spoofed,
"msg2 went somewhere other than the msg1 source"
);
assert_eq!(data.len(), RESP_PACKET_LEN);
}
#[test]
fn the_response_header_answers_the_initiators_index() {
let t = t0();
let (mut a, mut b) = pair(t);
let msg1 = real_msg1(&mut a, t, &b);
let initiator_index = init_sender_index(&msg1);
let id = b.feed(t, a.addr, &msg1).one_intro().0;
b.ep.read_identity(t, id).expect("readable");
let _ = b.drain();
b.ep.authenticate(t, id, &()).expect("authenticates");
let _ = b.drain();
b.ep.accept(t, id).expect("accepts");
let msg2 = b.drain().one_transmit().1;
let (responder_index, answered) = resp_indices(&msg2);
assert_eq!(
answered, initiator_index,
"receiver_index does not answer the initiation"
);
assert_ne!(responder_index, 0, "§17.3: indices are nonzero");
assert_ne!(
responder_index, initiator_index,
"the responder echoed the initiator's index as its own"
);
}
#[test]
fn retired_cancels_the_pending_and_frees_the_static_for_an_immediate_redial() {
let t = t0();
let (mut a, b) = pair(t);
let peer = b.public_static;
let (conn, d) = a.connect(t, b.addr, &peer);
let index = init_sender_index(&d.one_transmit().1);
let due = d.deadline.expect("armed");
a.ep.handle_connection_event(t, conn, ToEndpoint::Retired { our_index: index });
let d = a.drain();
assert!(
d.failures().is_empty(),
"cancellation emitted a HandshakeFailed — a second resolution"
);
assert!(d.transmits().is_empty());
let d = a.timeout(due);
assert!(
d.is_silent(),
"the retransmit train survived cancellation: {:?}",
d.outs
);
let d = a.timeout(t + HANDSHAKE_GIVEUP);
assert!(
d.is_silent(),
"give-up fired for a cancelled pending: {:?}",
d.outs
);
assert!(
a.ep.mint_pending(t, b.addr, peer, ()).is_ok(),
"a redial after cancellation returned AlreadyConnected (S29)"
);
}
#[test]
fn a_redial_after_cancellation_still_emits_a_strictly_greater_timestamp() {
let t = t0();
let mut a = Ep::new(
t,
7,
0x11,
v4(1, 1),
frozen_clock_config(T_BASE_SECS, 12_345),
);
let mut b = Ep::new(t, 9, 0x22, v4(2, 2), default_config());
let peer = b.public_static;
let (conn, d) = a.connect(t, b.addr, &peer);
let first = d.one_transmit().1;
let index = init_sender_index(&first);
a.ep.handle_connection_event(t, conn, ToEndpoint::Retired { our_index: index });
let _ = a.drain();
let (_conn2, d) = a.connect(t, b.addr, &peer);
let second = d.one_transmit().1;
let (_id, ts1) = ladder_to_proven(&mut b, t, v4(30, 1), &first);
let ts1 = ts1.expect("first admission");
let (_id, ts2) = ladder_to_proven(&mut b, t, v4(30, 2), &second);
let ts2 = ts2.expect("the redial must be strictly greater to be admissible");
assert!(
ts2 > ts1,
"a new connection generation reused or regressed the timestamp: {ts1:?} then {ts2:?}"
);
}
#[test]
fn a_parked_decision_survives_unrelated_activity_until_its_ttl() {
let t = t0();
let (mut a, mut b) = pair(t);
let msg1 = real_msg1(&mut a, t, &b);
let id = b.feed(t, a.addr, &msg1).one_intro().0;
for n in 1..=140u64 {
let now = t + Duration::from_millis(n * 100);
let _ = b.timeout(now);
let _ = b.feed(now, v4(60, n as u16), &forged_init(&b, n as u32, 0x66));
let _ = b.datagram(now, v4(61, 1), &data_packet(0xABCD, n, 32));
}
assert!(b.present(id), "the parked chain did not survive the churn");
let after_churn = t + Duration::from_millis(140 * 100);
assert!(
b.ep.read_identity(after_churn, id).is_ok(),
"the decision could not still be taken"
);
let _ = b.drain();
let _ = b.timeout(t + INTRO_TTL);
assert!(!b.present(id), "the chain outlived INTRO_TTL");
}
#[test]
fn accept_records_a_some_basis_equal_to_the_msg1_timestamp() {
let t = t0();
let (mut a, mut b) = pair(t);
let train = msg1_train(&mut a, t, &b, 1);
assert_eq!(
b.ep.replacement_basis(a.canonical()),
None,
"a static with no connection has no static-map entry at all"
);
let (id, admitted) = ladder_to_proven(&mut b, t, v4(28, 1), &train[0]);
let ts = admitted.expect("admission");
assert_eq!(
b.ep.replacement_basis(a.canonical()),
None,
"§17.4: the basis is written at install — reaching Proven installs nothing"
);
b.ep.accept(t, id).expect("the NONE row accepts");
let _ = b.drain();
assert_eq!(
b.ep.replacement_basis(a.canonical()),
Some(Some(ts)),
"the responder's basis is not the timestamp of the msg1 that established it"
);
}
#[test]
fn connect_records_a_none_basis() {
let t = t0();
let (mut a, mut b) = pair(t);
let stranger = Ep::new(t, 11, 0x44, v4(3, 3), default_config());
let msg1 = real_msg1(&mut a, t, &b);
let msg2 = genuine_msg2(&mut b, t, a.addr, &msg1);
assert_eq!(a.feed(t, b.addr, &msg2).installs().len(), 1);
assert_eq!(
a.ep.replacement_basis(b.canonical()),
Some(None),
"a connection we dialled recorded a timestamp — msg2 carries none to record"
);
assert_eq!(
a.ep.replacement_basis(stranger.canonical()),
None,
"a static we never connected to has no entry at all"
);
}
#[test]
fn an_established_connection_contributes_no_hint() {
let t = t0();
let (mut a, mut b) = pair(t);
let c = Ep::new(t, 11, 0x44, v4(3, 3), default_config());
assert!(a.ep.hints().is_empty(), "an idle endpoint probes nothing");
let msg1 = real_msg1(&mut a, t, &b);
assert_eq!(
a.ep.hints(),
vec![b.addr],
"an in-flight dial's remote is the hint set"
);
let peer_c = c.public_static;
let _ = a.connect(t, c.addr, &peer_c);
assert_eq!(a.ep.hints(), vec![b.addr, c.addr]);
let msg2 = genuine_msg2(&mut b, t, a.addr, &msg1);
assert_eq!(a.feed(t, b.addr, &msg2).installs().len(), 1);
assert_eq!(
a.ep.hints(),
vec![c.addr],
"an established connection still contributes a hint"
);
}