Files
Johnathan Corgan af2f8e7970 Run the rekey state machine on next's XX handshakes
The merge brought in the rekey state machine with master's link and
session profiles, which are built for the IK and XK handshakes. Next
runs Noise XX on both layers, so this replaces those profiles and
adapts both shells to them.

In fips-core, the link and session profiles are XX profiles. A link
rekey's final message is read in the core, which creates the completion
the machine takes from the inbound leg. The profiles are tested byte for
byte against the handshakes next sends today, so the wire format does
not change: the negotiation payload rides the same messages as before,
and a session rekey's ack and msg3 still carry none. The unused helper
that derived a pinned key from an x-only key is removed.

The session shell runs on the XX session profile. The temporary XX
profile uses the same rules as master's session profile: the initiator
probes before it commits, and the responder cuts over at msg3 and sends
a prompt. The spin bit stays removed.

On the link layer, next's existing inbound legs become the machine's
leg table. Each leg owns its index lease and releases it on every exit,
and a declared rekey is handed from the leg to the peer's link machine.
A link rekey now uses the delayed initiator cutover the machine
implements, instead of cutting over on the next tick, and next's msg3
resend loop is gone with the old rekey code. A second dial of a peer is
resolved by address order. node.rekey.enabled is removed, with a warning
when an old config still sets it. An inbound handshake refused at the peer
cap is counted as max_peers rather than bad_state.

Master's tests that check IK-only behaviour are deleted; the rest are
ported to XX and the delayed cutover, including the tests that keep
frames on a previous link session out of the new session's MMP. The
ignored-test inventory, the changelog, and the design and reference
docs describe next's tree.
2026-10-20 16:26:26 +00:00

84 lines
4.3 KiB
TOML

[package]
name = "fips-core"
# Versioned with the workspace's root package: this crate is not published on
# its own, and its version here is never bumped. Release version bumps edit the
# root Cargo.toml only.
version = "0.0.0"
edition = "2024"
license = "MIT"
publish = false
[dependencies]
# `alloc` only on secp256k1, bech32 and hex: their `std` features would link
# `std`, which the bare-metal build (testing/build-core-baremetal.sh) rejects.
# Without `rand`, `Secp256k1::new()` does not blind the context; the host
# blinds it through `identity::init_secp`.
secp256k1 = { version = "0.30", default-features = false, features = ["alloc"] }
bech32 = { version = "0.12", default-features = false, features = ["alloc"] }
hex = { version = "0.4", default-features = false, features = ["alloc"] }
# The `zeroize` features clear the SHA-256 and HMAC states on drop, which hold
# handshake secrets in `noise`. `hmac`'s feature only forwards to `digest`'s,
# which `sha2`'s also turns on; it is listed so the HMAC inside `hkdf` keeps it
# if `sha2`'s ever stops doing so.
sha2 = { version = "0.11", default-features = false, features = ["zeroize"] }
hkdf = { version = "0.13", default-features = false }
hmac = { version = "0.13", default-features = false, features = ["zeroize"] }
# `alloc` for the `Zeroizing<Vec<u8>>` guards in the secret key decoding;
# `zeroize_derive` for the Noise cipher and symmetric states.
zeroize = { version = "1.9", default-features = false, features = ["alloc", "zeroize_derive"] }
thiserror = { version = "2.0", default-features = false }
once_cell = { version = "1.21", default-features = false, features = ["race", "alloc"] }
# `MmpMode` derives Serialize and Deserialize for the node configuration.
# Builds without `std` or `alloc`.
serde = { version = "1.0", default-features = false, features = ["derive"] }
# `log` for the bloom false-positive estimate: `core` has no float logarithm.
# Default features (`arch`) as the root crate had them, so the implementation
# the estimate uses does not change.
libm = "0.2"
# The hash map for peer-chosen keys (`utils::hash`): `hashbrown`'s table with a
# SipHash-1-3 hasher keyed from the host, as `std`'s `HashMap` is built. No
# default hasher: `foldhash` is not keyed on targets without address-space
# randomization.
hashbrown = { version = "0.16", default-features = false }
siphasher = { version = "1.0", default-features = false }
# The AEAD backend that builds for every target (`noise::aead`).
chacha20poly1305 = { version = "0.10", default-features = false }
# The hosted AEAD backend, behind the `ring` feature: its assembly is faster,
# but it does not build for bare-metal targets. The AEAD needs neither of its
# defaults (`alloc`, `dev_urandom_fallback`).
ring = { version = "0.17", default-features = false, optional = true }
[features]
# Use `ring` for the AEAD instead of RustCrypto (`noise::aead::AeadKey`).
# Hosted builds turn it on; bare-metal builds must leave it off.
ring = ["dep:ring"]
# Test hooks in `proto`, `cache`, `noise` and `node`: methods and re-exports that
# only unit tests use to set up or inspect state. This crate's tests see them
# through `cfg(test)`; the root crate's tests see them because the root
# enables this feature from its `[dev-dependencies]` only. Never enable it
# outside tests.
test-hooks = []
# The slow rekey test suite: the guard-switch meta-test
# (`proto/rekey/tests/faults.rs`), which re-runs other tests under every fault
# switch. Off by default so every platform's test run skips it; GitHub CI's
# Linux job and local CI with --slow-tests turn it on, and the core's clippy
# passes lint the code it gates either way.
slow-tests = []
[dev-dependencies]
# Host-only test dependencies; tests may use `std`.
# Random keys for the test fixtures (`testutil::make_keypair`, the lookup
# tests) and the random source `testutil::TestEntropy`.
rand = "0.10.1"
# `sign_schnorr` for the protocol tests' signing fixtures, which secp256k1
# provides only with `rand` and `std`. Tests only: the library stays on
# `alloc`.
secp256k1 = { version = "0.30", default-features = false, features = ["rand", "std"] }
# `MmpMode`'s configuration spelling, checked with the parser the node
# configuration uses.
serde_yaml = "0.9"
# `serde_json::to_value` for the stats history's JSON form of a gap (NaN as
# `null`), as the control API serializes it.
serde_json = "1.0"