Commit Graph
28 Commits
Author SHA1 Message Date
Johnathan Corgan cd7064595d Session 64: Complete peer authentication handshake and wire RX loop
Fix promote_connection to transfer NoiseSession, session indices,
transport ID, and source address to ActivePeer. Populate peers_by_index
during promotion for O(1) encrypted frame dispatch.

Add responder-side promotion in handle_msg1 — after sending msg2, the
responder immediately promotes to ActivePeer since Noise IK completes
in one step for the responder side.

Wire run_rx_loop into the fips binary using tokio::select with Ctrl+C
shutdown signal, so the daemon actually processes incoming packets.

Add end-to-end integration test: two nodes with real UDP sockets
perform full Noise IK handshake and bidirectional encrypted frame
exchange (266 tests, all passing).
2026-02-10 17:40:13 +00:00
Johnathan Corgan 71f1db42e3 Truncate NodeAddr from 32 bytes to 16 bytes (first 128 bits of SHA-256)
128-bit truncated SHA-256 provides adequate collision resistance
(2^64 birthday bound, 2^128 pre-image) while cutting per-packet
header overhead nearly in half, aligning with Yggdrasil's approach
and IPv6 address size.

Code changes:
- NodeAddr inner type [u8; 32] → [u8; 16], from_pubkey takes first 16 bytes
- DATA_HEADER_SIZE 68 → 36, signing_bytes capacity 80 → 48
- proof_bytes capacity 40 → 24
- Updated all make_node_addr test helpers and size assertion tests

Doc changes:
- All wire format tables and offset calculations updated
- AncestryEntry size 112 → 96 bytes
- Packet size examples recalculated throughout
2026-02-06 14:32:15 +00:00
Johnathan Corgan dc12b4a82e Migrate session-layer addresses from FipsAddress to NodeAddr
Session packet headers use 32-byte NodeAddr (SHA-256 of pubkey) for
routing, not 16-byte FipsAddress (IPv6 ULA). Update all session-layer
structs (SessionDatagram, SessionSetup, SessionAck, DataPacket,
CoordsRequired, PathBroken) and CoordCache to use NodeAddr.

- DATA_HEADER_SIZE: 36 → 68 (two 32-byte addresses + 4 bytes overhead)
- CoordCache: HashMap key FipsAddress → NodeAddr
- Docs: fix header sizes in session-protocol and routing docs
- All 265 tests updated and passing
2026-02-06 13:48:36 +00:00
Johnathan Corgan 5e7342c57c Standardize naming conventions across docs and source
Rename NodeId to NodeAddr and npub to pubkey throughout documentation
and source code for consistency with the established identity model.
Add FIPS API vs IPv6 adapter overview to session protocol document.
Add transport address terminology note to wire protocol document.
2026-02-06 04:03:32 +00:00
Johnathan Corgan 7c8a5bd5ae Implement RX event loop with wire format dispatch
Wire format module (src/wire.rs):
- Discriminator-based packet framing (0x00/0x01/0x02)
- Header parsing: EncryptedHeader, Msg1Header, Msg2Header
- Serialization: build_msg1(), build_msg2(), build_encrypted()
- 11 unit tests for parsing and roundtrip

Session index tracking:
- PeerConnection: our_index, their_index, transport_id, source_addr
- ActivePeer: noise_session, indices, transport_id, current_addr
- Removed Clone from ActivePeer (NoiseSession nonce reuse risk)
- PromotionResult refactored to use NodeId instead of ActivePeer

Node RX event loop:
- run_rx_loop() with packet_rx channel consumption
- process_packet() discriminator dispatch
- handle_encrypted_frame() with O(1) index lookup
- handle_msg1() with rate limiting and inbound handshake
- handle_msg2() completing outbound handshakes
- dispatch_link_message() stub for link protocol

Infrastructure (from Session 56):
- IndexAllocator for random 32-bit session indices
- HandshakeRateLimiter with token bucket
- ReplayWindow for 2048-packet sliding window
- Bloom filter defaults updated to v1 spec

All 265 tests pass.
2026-02-02 17:20:06 +00:00
Johnathan Corgan 0076e9930c Session 48: Wire format design and logging improvements
Wire format:
- Add HandshakeMessageType enum (NoiseIKMsg1=0x01, NoiseIKMsg2=0x02)
- Define unified TLV framing for handshake and post-handshake messages
- Update fips-design.md and fips-protocol-flow.md with wire format details

Initialization:
- Defer TUN setup until after peer connections initiated
- Order: packet channel → transports → peers → TUN

Logging cleanup:
- Consolidate node/TUN info logs into aligned multi-line format
- TUN shutdown: single start/stop message, remove intermediate noise
- Remove ip link show callout and redundant Starting node message
- Change UDP transport stopped to debug level
2026-02-01 05:18:59 +00:00
Johnathan Corgan 8ba24c38ae Session 48: Initialization order and logging improvements
- Defer TUN setup until after peer connections initiated
- Split TUN packet/device logs into aligned multi-line format
- Remove ip link show debug callout from fips binary
2026-02-01 03:33:56 +00:00
Johnathan Corgan 58be9e2e59 Separate protocol layers: link vs session message types
Refactor protocol.rs to cleanly separate two protocol layers:

Link layer (hop-by-hop, peer-to-peer):
- LinkMessageType: TreeAnnounce, FilterAnnounce, LookupRequest,
  LookupResponse, SessionDatagram
- New SessionDatagram struct for encapsulating session payloads

Session layer (end-to-end):
- SessionMessageType: SessionSetup, SessionAck, DataPacket,
  CoordsRequired, PathBroken

Also:
- Remove obsolete Hello/Challenge/Auth/AuthAck types (replaced by Noise IK)
- Update all design docs for consistency with two-layer architecture
- Add "Link vs Session Encryption" documentation

All 219 tests pass.
2026-02-01 03:19:54 +00:00
Johnathan Corgan 9a6fa07e77 Session 46: Noise IK peer authentication implementation
Implement Noise Protocol Framework for peer authentication using the IK
pattern, which allows responders to learn initiator identity from the
encrypted handshake message.

Protocol: Noise_IK_secp256k1_ChaChaPoly_SHA256
- Message 1: 82 bytes (ephemeral + encrypted static)
- Message 2: 33 bytes (ephemeral only)

New noise.rs module (~600 lines):
- HandshakeState: Manages handshake for both initiator/responder roles
- NoiseSession: Post-handshake symmetric encryption
- CipherState: ChaCha20-Poly1305 with nonce counter
- SymmetricState: HKDF-SHA256 key derivation

PeerConnection integration:
- Simplified HandshakeState enum (Initial/SentMsg1/ReceivedMsg1/Complete/Failed)
- start_handshake(): Initiator generates msg1
- receive_handshake_init(): Responder processes msg1, discovers identity
- complete_handshake(): Initiator completes with msg2
- take_session(): Extract NoiseSession for ActivePeer

Identity helpers:
- Identity::keypair() for Noise operations
- PeerIdentity::from_pubkey_full() preserves parity for ECDH
- PeerIdentity::pubkey_full() returns full key or derives with even parity

Node changes:
- initiate_peer_connection() now starts handshake and sends msg1
- Method is async to use transport's async send

All 219 tests pass.
2026-02-01 01:28:01 +00:00
Johnathan Corgan 86c49dfb04 Implement PeerSlot architecture with two-phase peer lifecycle
Refactor peer management into two distinct phases:

PeerConnection (handshake phase):
- Indexed by LinkId (identity unknown for inbound connections)
- HandshakeState: AwaitingHello → SentHello → SentAuth → AwaitingAuthAck → Complete
- Tracks expected identity, retry count, timing

ActivePeer (authenticated phase):
- Indexed by NodeId (verified identity)
- ConnectivityState: Connected → Stale → Reconnecting → Disconnected
- Holds tree state, bloom filter, routing data

Cross-connection handling:
- Deterministic tie-breaker: smaller node_id's OUTBOUND wins
- PromotionResult enum for promotion outcomes
- Both nodes reach same conclusion independently

Node refactoring:
- Split storage: connections (by LinkId) + peers (by NodeId)
- Add addr_to_link reverse lookup for packet dispatch
- promote_connection() handles promotion with cross-connection detection
2026-02-01 00:50:47 +00:00
Johnathan Corgan a5a62b3768 Session 43: CLI config option and state machine design
Add command-line argument parsing with clap:
- -c/--config option to specify config file path
- Overrides default search path when provided
- Proper error handling for missing/invalid files

Improve logging:
- Peer connection log now uses separate log entries per field
- Better readability with aligned timestamps

Fix ICMPv6 error handling:
- Add multicast destination filter to should_send_icmp_error()
- Router Solicitation packets (ff02::2) now silently dropped
- Add test case for multicast destination

Add phase-based state machine design document:
- Document pattern where lifecycle phases use distinct structs in enum
- PeerSlot::Connecting(PeerConnection) -> PeerSlot::Active(ActivePeer)
- Benefits: type safety, memory efficiency, security
- Describes timeout handling and lookup table requirements
2026-01-31 23:33:02 +00:00
Johnathan Corgan d2851d8406 Add peer configuration and connection initiation
Config changes:
- Add ConnectPolicy enum (AutoConnect, OnDemand, Manual)
- Add PeerAddress struct (transport, addr, priority)
- Add PeerConfig struct (npub, alias, addresses, connect_policy)
- Add top-level 'peers' section to Config (after transports)
- Add accessor methods: peers(), auto_connect_peers()

Node changes:
- Add find_transport_for_type() to match transports by name
- Add initiate_peer_connections() called after transports start
- Add initiate_peer_connection() creates Link and Peer in Connecting state
- Node::start() now initiates connections to auto-connect peers

This completes the node startup sequence through step 5 (connect
to static peers). Peers are created in Connecting state; the auth
handshake implementation will transition them to Active.
2026-01-31 22:53:26 +00:00
Johnathan Corgan a317896367 Add transport instance naming and reorder node startup
- Add name field to UdpTransport for named config instances
- Add name() and local_addr() accessors to TransportHandle
- Update UdpTransport logging to include instance name
- Remove redundant Node-level transport startup logging
- Reorder Node::start() to initialize transports before TUN
2026-01-31 04:16:11 +00:00
Johnathan Corgan 4bbecccc11 Session 37: Transport-Node lifecycle integration
- Added TransportHandle enum for polymorphic transport dispatch
- Node now owns transports via HashMap<TransportId, TransportHandle>
- Added packet channel fields (packet_tx, packet_rx) to Node
- Transport initialization in Node::start() with graceful degradation
- Transport shutdown in Node::stop() before TUN cleanup
- Factory method create_transports() instantiates from config

Configuration redesign:
- New transports section with TransportInstances<T> enum
- Single instance: config directly under transport type (no naming overhead)
- Named instances: nested under instance names
- #[serde(deny_unknown_fields)] ensures correct untagged enum matching
- Instance names are Option<&str> - None for single, Some(name) for named

Updated Node transport methods:
- transport_count(), get_transport(), get_transport_mut()
- transport_ids(), packet_rx()

All 189 tests pass (4 new config parsing tests).
2026-01-31 01:20:13 +00:00
Johnathan Corgan d30865f60b Add UDP transport implementation
- Convert transport.rs to module directory (transport/mod.rs + transport/udp.rs)
- Add packet channel types for transport→Node communication:
  - ReceivedPacket struct with transport_id, remote_addr, data, timestamp
  - PacketTx/PacketRx type aliases for tokio mpsc channels
  - packet_channel() constructor function
- Add UdpConfig to config.rs (enabled, bind_addr, mtu)
- Implement UdpTransport with async lifecycle:
  - start_async(): binds socket, spawns receive loop
  - stop_async(): aborts receive task, closes socket
  - send_async(): sends packet with MTU validation
  - discover(): returns empty (peer config is node-level)
- Update lib.rs with new re-exports
- Add tokio net and time features to Cargo.toml

All 185 tests pass.
2026-01-30 21:02:33 +00:00
Johnathan Corgan c421dad525 Spanning tree init and Node lifecycle refactoring
Spanning tree initialization:
- TreeState now uses sequence=1 and current timestamp per protocol spec
- Added ParentDeclaration::sign() and TreeState::sign_declaration() methods
- Node initialization logs identity (node_id, address)

Node lifecycle refactoring:
- Moved TUN init and thread spawning into async Node::start()
- Moved TUN shutdown and thread cleanup into async Node::stop()
- Node owns I/O infrastructure (thread handles, TunTx channel)
- Removed: init_tun(), take_tun_device(), tun_device(), tun_device_mut()
- Added: tun_tx() accessor for packet sending

tun.rs:
- Added run_tun_reader() function (moved from binary)

fips.rs binary reduced from 230 to 117 lines. All 171 tests pass.
2026-01-30 17:40:33 +00:00
Johnathan Corgan 385033fcb7 Add ICMPv6 Destination Unreachable and TUN reader/writer architecture
- New icmp.rs module: builds RFC 4443 compliant ICMPv6 Type 1 Code 0
  responses with proper checksum and packet validation
- TUN reader/writer separation: fd duplication allows independent I/O
  on separate threads
- TunWriter services mpsc queue for multiple future packet sources
- Reader now sends ICMPv6 errors for unroutable packets instead of
  silently dropping them
- 171 tests passing
2026-01-30 05:25:28 +00:00
Johnathan Corgan db8aa5825d Session 33: TUN interface lifecycle management
- Add TUN interface detection on startup, delete existing before create
- Add proper interface deletion on shutdown via netlink
- Add TUN packet reader in separate thread with DEBUG logging
- Add graceful shutdown handling for expected "Bad address" error
- Add take_tun_device() to Node for reader ownership transfer
- Add shutdown_tun_interface() public function for cleanup by name
- Add tokio signal feature for Ctrl+C handling
2026-01-30 04:57:35 +00:00
Johnathan Corgan bfdc532058 Remove --wait mode from fips binary
No longer needed since lldb-gdbserver-start.sh launches the binary
directly via gdbserver mode.
2026-01-30 03:43:05 +00:00
Johnathan Corgan 4f8107be83 Add --wait flag and ip link debug output
- Add --wait / -w command-line flag for debugger attachment
- When --wait is set, daemon blocks after init with thread::park()
- Add ip link show output after TUN device creation for debugging
2026-01-30 00:46:17 +00:00
Johnathan Corgan 6d95bdc979 Add TUN interface with async netlink configuration
- Implement fips.rs binary with config loading, node creation, and logging
- Create src/tun.rs module (TunDevice, TunState, TunError)
- Use rtnetlink crate for IPv6 address configuration
- Make TunDevice::create() and Node::init_tun() async
- Add IPv6 disabled check with helpful error message
- Add rtnetlink, tokio, futures dependencies
- Single tokio current_thread runtime for entire driver

162 tests pass.
2026-01-29 22:12:27 +00:00
Johnathan Corgan 185fe50570 Restructure config to match sysctl-style paths
- Add NodeConfig wrapper: node.identity.nsec, node.leaf_only
- YAML structure mirrors architecture documentation exactly
- Move main.rs to src/bin/fips.rs (empty binary placeholder)
- Add "Connection Model" section to fips-transports.md documenting
  connectionless vs connection-oriented transport categories
- Fix clippy warnings (dead_code, clone_on_copy, assertions_on_constants)
2026-01-29 19:49:37 +00:00
Johnathan Corgan 6e343c35e5 Implement FIPS foundational entity structures
Add 7 new modules with all core data types for the mesh routing protocol:
- tree.rs: ParentDeclaration, TreeCoordinate, TreeState
- bloom.rs: BloomFilter (4KB/7 hash), BloomState with debouncing
- transport.rs: TransportId, LinkId, Link, Transport trait, LinkStats
- protocol.rs: Auth messages, TreeAnnounce, FilterAnnounce, LookupRequest/Response, SessionSetup, DataPacket
- cache.rs: CoordCache, RouteCache with LRU eviction and TTL expiry
- peer.rs: Peer lifecycle states, filter tracking, UpstreamPeer
- node.rs: Node container with resource limits

All entities have constructors, error types, and comprehensive tests (161 total).
Stub methods with todo!() for behavior to be implemented later.
No state machine logic, protocol handlers, or async code yet.
2026-01-29 18:49:11 +00:00
Johnathan Corgan b80b3fbecf Add YAML configuration system and nsec encoding
Configuration system:
- New config module with cascading file search
- Priority: ./fips.yaml > ~/.config/fips/ > ~/.fips.yaml > /etc/fips/
- Identity section with optional nsec (bech32 or hex format)
- Generate new keypair if nsec not configured

Identity module additions:
- encode_nsec() and decode_nsec() for NIP-19 bech32 format
- decode_secret() accepts both nsec and hex formats
- Identity::from_secret_str() constructor

Dependencies: serde, serde_yaml, dirs, hex

41 tests passing (20 identity + 15 config + 6 nsec)
2026-01-25 01:08:02 +00:00
Johnathan Corgan ac2f6a75c8 Add npub encoding and PeerIdentity to identity module
- Add bech32 dependency for NIP-19 npub encoding
- Add encode_npub/decode_npub functions
- Add Identity::npub() method
- Add PeerIdentity type for remote peers (public key only)
  - from_npub() constructor
  - verify() for signature verification
- Export new types from lib.rs
- Update main.rs with verbose authentication demo
- 20 tests passing
2026-01-25 00:40:59 +00:00
Johnathan Corgan db4989a790 Add Ipv6Addr conversion for FipsAddress 2026-01-25 00:03:19 +00:00
Johnathan Corgan 5c0e84f239 Add identity module with NodeId, FipsAddress, and auth challenge
Implements FIPS Identity System (Section 1 of design doc):
- NodeId: 32-byte SHA-256 hash of npub, with Ord for root election
- FipsAddress: 128-bit IPv6-compatible address (0xfd prefix)
- Identity: keypair holder with sign/verify methods
- AuthChallenge/AuthResponse: challenge-response authentication

All 11 tests passing.
2026-01-24 23:57:48 +00:00
Johnathan Corgan 6323c219b7 Initial FIPS project 2026-01-24 23:37:28 +00:00