oxedyne/fe2o3/fe2o3_shield/src/lib.rs
9.2 KiB, 21 runs
created by r1870400018:874, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | //! # Shield (Signed Hash In Every Little Datagram) |
| 2 | //! |
| 3 | //! A security-focused peer-to-peer networking protocol built on UDP with comprehensive DoS |
| 4 | //! resistance, post-quantum cryptography support, and flexible cryptographic scheme selection. |
| 5 | //! |
| 6 | //! ## Overview |
| 7 | //! |
| 8 | //! Shield implements a robust P2P protocol designed for hostile network environments, featuring: |
| 9 | //! - **Proof-of-work validation** with dynamic difficulty adjustment for DoS mitigation |
| 10 | //! - **3-stage handshake protocol** for secure session establishment |
| 11 | //! - **Post-quantum cryptography** options for future-proof security |
| 12 | //! - **Multi-layered guard system** with address and user-based protection |
| 13 | //! - **Flexible packet sizing** (700-1400 bytes) with automatic chunking for large messages |
| 14 | //! - **Generic protocol design** supporting custom ID lengths and cryptographic schemes |
| 15 | //! |
| 16 | //! ## Architecture |
| 17 | //! |
| 18 | //! The library is structured into two main modules: |
| 19 | //! |
| 20 | //! ### Server Protocol (`srv`) |
| 21 | //! Core protocol implementation with modular components: |
| 22 | //! - **Message system**: Packet handling, assembly, and handshake protocols |
| 23 | //! - **Guard system**: DoS protection with Monitor → Throttle → Blacklist state progression |
| 24 | //! - **Cryptographic schemes**: Pluggable encryption, signing, and hashing implementations |
| 25 | //! - **Proof-of-work engine**: Time-bounded PoW with linear difficulty scaling |
| 26 | //! - **Configuration management**: Runtime context and parameter tuning |
| 27 | //! |
| 28 | //! ### Application Layer (`app`) |
| 29 | //! High-level interfaces and tools: |
| 30 | //! - **Server wrapper**: Simplified server setup and management |
| 31 | //! - **REPL interface**: Interactive command processing |
| 32 | //! - **TUI support**: Text user interface components |
| 33 | //! - **Syntax parsing**: Command and configuration parsing |
| 34 | //! |
| 35 | //! ## Protocol Details |
| 36 | //! |
| 37 | //! ### Handshake Protocol |
| 38 | //! A 6-message exchange for secure session establishment. **Only the first |
| 39 | //! message of it is built**; see "Development status" below. |
| 40 | //! 1. **HReq1**: Initial request with signature public key |
| 41 | //! 2. **HResp1**: Server response with PoW challenge |
| 42 | //! 3. **HReq2**: Client authentication with PoW solution |
| 43 | //! 4. **HResp2**: Server KEM key exchange with session key |
| 44 | //! 5. **HReq3**: Client session confirmation |
| 45 | //! 6. **HResp3**: Server handshake completion |
| 46 | //! |
| 47 | //! ### Application payload exchange |
| 48 | //! A request and at most one answer, correlated by the message identifier in |
| 49 | //! the packet header and needing no session: |
| 50 | //! 1. **App request** (type 1,024): the caller's bytes, chunked across as many |
| 51 | //! packets as they take, each carrying its own proof of work and signature. |
| 52 | //! 2. **App reply** (type 1,025): what the receiving peer's handler said, |
| 53 | //! travelling under the identifier the request arrived with, back to the |
| 54 | //! address it arrived from. |
| 55 | //! |
| 56 | //! Message types at or above 2,048 are the library user's own. |
| 57 | //! |
| 58 | //! ### Packet Structure |
| 59 | //! - **UDP buffer**: 1,400 bytes (avoiding IP fragmentation) |
| 60 | //! - **Default packet**: 700 bytes (substantial headroom) |
| 61 | //! - **Chunking threshold**: 1,500 bytes (split into 1,000-byte chunks) |
| 62 | //! - **Minimum chunk**: 42 bytes (accounts for encryption overhead) |
| 63 | //! |
| 64 | //! ### DoS Protection |
| 65 | //! Multi-layered defence with configurable thresholds: |
| 66 | //! - **Rate limiting**: 30 requests/second baseline with throttling |
| 67 | //! - **Proof-of-work**: 0-30 zero-bit difficulty scaling with request volume |
| 68 | //! - **Address blacklisting**: 30 minutes to 3 days with randomised duration |
| 69 | //! - **Message assembly limits**: 128 total repetitions, 32 per packet |
| 70 | //! |
| 71 | //! ## Cryptographic Features |
| 72 | //! |
| 73 | //! ### Supported Schemes |
| 74 | //! - **Encryption**: AES-GCM, ChaCha20-Poly1305, post-quantum options |
| 75 | //! - **Key Exchange**: Classical and post-quantum KEM implementations |
| 76 | //! - **Signatures**: RSA, ECDSA, EdDSA, post-quantum signature schemes |
| 77 | //! - **Hashing**: SHA-256, BLAKE3, argon2 for proof-of-work |
| 78 | //! |
| 79 | //! ### Security Properties |
| 80 | //! What the wire gives a caller **today**: |
| 81 | //! - **Per-packet proof of work**: every packet carries one, bound to both |
| 82 | //! addresses, a challenge code and a timestamp within a horizon. |
| 83 | //! - **Per-packet signature**: every packet is signed, and an application |
| 84 | //! payload carries the key it was signed with, because there is no session |
| 85 | //! through which one could have been exchanged. |
| 86 | //! - **Rate limiting and blacklisting** per source address, on every packet. |
| 87 | //! |
| 88 | //! What the schemes are chosen for and the handshake would deliver, and which |
| 89 | //! **is not built yet**: forward secrecy through a KEM exchange, session |
| 90 | //! encryption, and post-quantum algorithm agility across all of it. A payload |
| 91 | //! that needs any of those must carry its own signature or its own encryption, |
| 92 | //! exactly as it would over an unencrypted stream. |
| 93 | //! |
| 94 | //! ## Usage Examples |
| 95 | //! |
| 96 | //! ### Carrying an application payload |
| 97 | //! |
| 98 | //! One peer listens and answers, the other dials and hears the answer on the |
| 99 | //! socket it dialled from. The bytes are the caller's; the protocol chunks, |
| 100 | //! proofs, signs and reassembles them without reading them. |
| 101 | //! |
| 102 | //! ```ignore |
| 103 | //! use oxedyne_fe2o3_shield::srv::{ |
| 104 | //! client::Client, |
| 105 | //! constant, |
| 106 | //! msg::{app::Answer, syntax as srv_syntax}, |
| 107 | //! server::Server, |
| 108 | //! }; |
| 109 | //! use oxedyne_fe2o3_core::prelude::*; |
| 110 | //! |
| 111 | //! // The listening peer. `bind` hands back the socket before the loop starts, |
| 112 | //! // so the address it landed on can be read and told to somebody. |
| 113 | //! async fn echo(payload: Vec<u8>, _from: std::net::SocketAddr) -> Outcome<Answer> { |
| 114 | //! Ok(Answer::Reply(payload)) |
| 115 | //! } |
| 116 | //! let (mut server, _cmd) = Server::new(context, res!(srv_syntax::base_msg())); |
| 117 | //! let sock = res!(server.bind().await); |
| 118 | //! let addr = res!(sock.local_addr(), IO, Network); |
| 119 | //! tokio::spawn(async move { let _ = server.run(sock, echo).await; }); |
| 120 | //! |
| 121 | //! // The dialling peer. A bind address of port zero is what a peer behind a |
| 122 | //! // household router wants: it dials out, and the answer comes back on the |
| 123 | //! // socket the question left on. |
| 124 | //! let client = res!(Client::bind(bind_addr, protocol, res!(srv_syntax::base_msg())).await); |
| 125 | //! let heard = res!(client.ask(addr, b"hello".to_vec(), constant::APP_REPLY_WAIT).await); |
| 126 | //! ``` |
| 127 | //! |
| 128 | //! ### Custom cryptographic configuration |
| 129 | //! |
| 130 | //! The wire schemes are chosen when the protocol is built. Any field left |
| 131 | //! [`Alt::Unspecified`](oxedyne_fe2o3_core::alt::Alt) falls back to the |
| 132 | //! crate's default for it. |
| 133 | //! |
| 134 | //! ```ignore |
| 135 | //! use oxedyne_fe2o3_shield::srv::schemes::WireSchemesInput; |
| 136 | //! use oxedyne_fe2o3_crypto::{enc::EncryptionScheme, sign::SignatureScheme}; |
| 137 | //! use oxedyne_fe2o3_core::{prelude::*, alt::Alt}; |
| 138 | //! |
| 139 | //! let schemes = WireSchemesInput { |
| 140 | //! enc: Alt::Specific(None::<EncryptionScheme>), |
| 141 | //! sign: Alt::Specific(Some(SignatureScheme::new_ed25519())), |
| 142 | //! ..Default::default() |
| 143 | //! }; |
| 144 | //! ``` |
| 145 | //! |
| 146 | //! ## Configuration Options |
| 147 | //! |
| 148 | //! Key parameters for tuning protocol behaviour: |
| 149 | //! - **Network**: UDP buffer size, packet sizes, chunking thresholds |
| 150 | //! - **Security**: PoW difficulty range, rate limiting thresholds |
| 151 | //! - **Session**: Handshake timeouts, session expiry intervals |
| 152 | //! - **Guard system**: Throttling limits, blacklist durations |
| 153 | //! |
| 154 | //! ## Performance Characteristics |
| 155 | //! |
| 156 | //! - **Throughput**: Optimised for 700-byte packets with minimal fragmentation |
| 157 | //! - **Latency**: 3-RTT handshake with configurable PoW difficulty |
| 158 | //! - **Memory**: ShardMap architecture for concurrent access scaling |
| 159 | //! - **CPU**: Efficient PoW validation with time-bounded challenges |
| 160 | //! |
| 161 | //! ## Development Status |
| 162 | //! |
| 163 | //! Built and exercised by tests: |
| 164 | //! - Multi-packet message assembly, and per-packet proof-of-work and signature |
| 165 | //! validation. |
| 166 | //! - The address guard: rate limiting, throttling and blacklisting, on every |
| 167 | //! packet whatever its type. |
| 168 | //! - An application payload path: request, reply and correlation, over a |
| 169 | //! server that answers and a client that hears. |
| 170 | //! - Flexible cryptographic scheme selection. |
| 171 | //! |
| 172 | //! Not built: |
| 173 | //! - **The handshake beyond its first message.** `HReq1` is sent, received and |
| 174 | //! recorded; `HResp1` has no encoder, and `HReq2`, `HResp2`, `HReq3` and |
| 175 | //! `HResp3` exist as discriminants and syntax declarations and as no types at |
| 176 | //! all. Nothing therefore establishes a session, and the session encryption |
| 177 | //! the wire schemes carry is never applied. |
| 178 | //! - **A difficulty a peer can be told.** Because nothing answers `HReq1`, a |
| 179 | //! dialling peer cannot learn the difficulty it is being asked for. A |
| 180 | //! deployment must therefore fix the difficulty -- set |
| 181 | //! `server_pow_zbits_min` equal to `server_pow_zbits_max` -- because a |
| 182 | //! difficulty that rises with the request rate would silently stop a peer |
| 183 | //! that has no way of hearing about the rise. |
| 184 | //! |
| 185 | //! APIs may change before the 1.0 release. |
| 186 | //! |
| 187 | //! ## Integration |
| 188 | //! |
| 189 | //! Shield integrates with the broader fe2o3 ecosystem: |
| 190 | //! - **fe2o3_crypto**: Cryptographic implementations and scheme selection |
| 191 | //! - **fe2o3_hash**: Hashing and proof-of-work functionality |
| 192 | //! - **fe2o3_net**: Network abstractions and protocol support |
| 193 | //! - **fe2o3_core**: Foundational error handling and data structures |
| 194 | //! - **fe2o3_jdat**: Serialisation and configuration management |
| 195 | //! |
| 196 | //! For detailed implementation examples and advanced configuration, see the |
| 197 | //! `examples/` directory and protocol specification documentation. |
| 198 | #![forbid(unsafe_code)] |
| 199 | pub mod app; |
| 200 | pub mod srv; |