Files
fips/src/identity/mod.rs
T
Johnathan Corgan d71e48b0f2 Module reorganization, identity test coverage, design doc corrections
Module reorganization:

- Split identity.rs (930 lines) into identity/ directory module:
  mod.rs, node_addr.rs, address.rs, peer.rs, local.rs, auth.rs,
  encoding.rs, tests.rs — following established bloom/, tree/, noise/
  pattern

- Group TUN, DNS, and ICMPv6 into upper/ module as the IPv6 adaptation
  layer: move tun.rs, icmp.rs, node/dns.rs into upper/

Identity test coverage (28 new tests, 52 total):

- Encoding error paths: invalid npub/nsec length, bad hex input
- NodeAddr: Debug, Display, as_slice, AsRef, Hash
- FipsAddress: from_slice, From trait, Debug, Display, Eq+Hash
- PeerIdentity: from_pubkey_full, pubkey_full parity paths, Debug
- Identity: keypair, pubkey_full, Debug
- AuthChallenge: from_bytes

Design doc corrections (fips-software-architecture.md):

- Identity struct: npub+nsec fields → keypair: Keypair with accessors
- Node struct: TunInterface → TunState, Transport → TransportHandle,
  Peer → PeerSlot
- Peer section: monolithic Peer → two-phase PeerSlot (PeerConnection +
  ActivePeer) with HandshakeState/ConnectivityState
- ActivePeer: npub → identity: PeerIdentity, ancestry Vec → Option,
  declaration/inbound_filter wrapped in Option
- BloomState: add 4 missing fields, fix update_debounce type
- DiscoveredPeer: field name and type corrections
2026-02-15 17:11:58 +00:00

84 lines
2.2 KiB
Rust

//! FIPS Identity System
//!
//! Node identity based on Nostr keypairs (secp256k1). The node_addr is derived
//! from the public key via SHA-256, and the FIPS address uses an IPv6-compatible
//! format with the 0xfd prefix.
mod address;
mod auth;
mod encoding;
mod local;
mod node_addr;
mod peer;
use sha2::{Digest, Sha256};
use thiserror::Error;
pub use address::FipsAddress;
pub use auth::{AuthChallenge, AuthResponse};
pub use encoding::{decode_npub, decode_nsec, decode_secret, encode_npub, encode_nsec};
pub use local::Identity;
pub use node_addr::NodeAddr;
pub use peer::PeerIdentity;
/// FIPS address prefix (IPv6 ULA range).
pub const FIPS_ADDRESS_PREFIX: u8 = 0xfd;
/// Errors that can occur in identity operations.
#[derive(Debug, Error)]
pub enum IdentityError {
#[error("invalid secret key: {0}")]
InvalidSecretKey(#[from] secp256k1::Error),
#[error("signature verification failed")]
SignatureVerificationFailed,
#[error("invalid node_addr length: expected 16, got {0}")]
InvalidNodeAddrLength(usize),
#[error("invalid address length: expected 16, got {0}")]
InvalidAddressLength(usize),
#[error("invalid address prefix: expected 0xfd, got 0x{0:02x}")]
InvalidAddressPrefix(u8),
#[error("bech32 encoding error: {0}")]
Bech32Encode(#[from] bech32::EncodeError),
#[error("bech32 decoding error: {0}")]
Bech32Decode(#[from] bech32::DecodeError),
#[error("invalid npub: expected 'npub' prefix, got '{0}'")]
InvalidNpubPrefix(String),
#[error("invalid npub: expected 32 bytes, got {0}")]
InvalidNpubLength(usize),
#[error("invalid nsec: expected 'nsec' prefix, got '{0}'")]
InvalidNsecPrefix(String),
#[error("invalid nsec: expected 32 bytes, got {0}")]
InvalidNsecLength(usize),
#[error("invalid hex encoding: {0}")]
InvalidHex(#[from] hex::FromHexError),
}
/// Compute SHA-256 hash of data.
fn sha256(data: &[u8]) -> [u8; 32] {
let mut hasher = Sha256::new();
hasher.update(data);
let result = hasher.finalize();
let mut hash = [0u8; 32];
hash.copy_from_slice(&result);
hash
}
/// Encode bytes as lowercase hex string.
fn hex_encode(bytes: &[u8]) -> String {
bytes.iter().map(|b| format!("{:02x}", b)).collect()
}
#[cfg(test)]
mod tests;