hiss 0.4.0

Static, type-level Noise Protocol Framework with pluggable hardware-backed crypto.
Documentation
//! Runtime handshake state.
//!
//! The type-state plumbing for the handshake lives in the state machines
//! [`noise!`](crate::noise!) generates. They thread the same runtime
//! data, [`HandshakeInner`], through their token chains; the per-token
//! crypto operating on it is shared via [`process`](super::process).
//!
//! This module holds only that runtime struct and its shared
//! constructor [`HandshakeInner::new`] — the protocol-name +
//! `SymmetricState::initialize` + `mix_hash(prologue)` initialisation
//! every state machine (and the internal seal helpers) starts from.

use super::Protocol;
use super::cipher::Cipher;
use super::hash::Hash;
use super::pattern::Pattern;
use super::symmetric_state::SymmetricState;
use super::well_formed::DerivedHasPsk;
use crate::curve::Curve;
use crate::provider::CryptoKeyProvider;

// ── Runtime state shared across the state machines ────────────

/// The runtime handshake data, threaded through every type state of the
/// generated state machines.
///
/// Separated from the type-state wrappers so that the shared per-token
/// crypto in [`process`](super::process) can operate on it without
/// fighting ownership.
///
/// `pub` (but `#[doc(hidden)]`, re-exported only through
/// [`support`](super::support)) so that `hiss-macros`-generated state
/// machines — which expand in the caller's crate — can hold it. Its
/// fields stay `pub(crate)`.
#[doc(hidden)]
pub struct HandshakeInner<Cu, Ci, H, CP>
where
    Cu: Curve,
    Ci: Cipher,
    H: Hash,
    CP: CryptoKeyProvider<Cu>,
{
    pub(crate) symmetric: SymmetricState<Ci, H>,
    /// Our ephemeral private key (generated by the `E` token).
    pub(crate) e: Option<CP::PrivateKey>,
    /// Our ephemeral public key (derived from `e` during the `E` token).
    pub(crate) e_pub: Option<Cu::PublicKey>,
    /// Our static private key (provided by the `S` token).
    pub(crate) s: Option<CP::PrivateKey>,
    /// Our static public key (derived from `s`).
    pub(crate) s_pub: Option<Cu::PublicKey>,
    /// Remote party's ephemeral public key (received via `E` token).
    pub(crate) re: Option<Cu::PublicKey>,
    /// Remote party's static public key.
    pub(crate) rs: Option<Cu::PublicKey>,
    /// Whether the pattern includes a PSK modifier (affects `E` token
    /// behaviour — it additionally calls `mix_key` on the ephemeral
    /// public key).
    pub(crate) has_psk: bool,
    /// The crypto provider (key generation, DH, signing).
    pub(crate) provider: CP,
}

impl<Cu, Ci, H, CP> HandshakeInner<Cu, Ci, H, CP>
where
    Cu: Curve,
    Ci: Cipher,
    H: Hash,
    CP: CryptoKeyProvider<Cu>,
{
    /// Build the runtime handshake state for protocol `Proto` and the given
    /// provider, mixing the prologue into the handshake hash.
    ///
    /// This is the single source of the protocol-name + `mix_hash`
    /// initialisation shared by every generated state machine and by the
    /// internal seal helpers. The protocol
    /// descriptor `Proto` supplies the pattern/curve/cipher/hash names.
    pub(crate) fn new<Proto>(provider: CP, prologue: &[u8]) -> Self
    where
        Proto: Protocol<Curve = Cu, Cipher = Ci, Hash = H>,
    {
        let protocol_name = format!(
            "Noise_{}_{}_{}_{}",
            <Proto::Pattern as Pattern>::NAME,
            <Cu as Curve>::NAME,
            <Ci as Cipher>::NAME,
            <H as Hash>::NAME,
        );
        let mut symmetric = SymmetricState::<Ci, H>::initialize(&protocol_name);

        // Noise spec §5.3: MixHash(prologue).
        symmetric.mix_hash(prologue);

        HandshakeInner {
            symmetric,
            e: None,
            e_pub: None,
            s: None,
            s_pub: None,
            re: None,
            rs: None,
            has_psk: <Proto::Pattern as DerivedHasPsk>::HAS_PSK,
            provider,
        }
    }
}