diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..d68eb1a --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,156 @@ +# AGENTS.md - AI Coding Agent Guidelines + +Guidelines for AI coding agents working on the fiber-sphinx codebase. + +## Project Overview + +fiber-sphinx is a Rust implementation of the Sphinx mix network protocol for Fiber. +It implements onion message encryption/decryption for anonymous message routing. + +## Build, Test, and Lint Commands + +### Prerequisites +- Rust toolchain 1.76.0 (specified in `rust-toolchain.toml`) +- Components: rustfmt, clippy + +### Build +```bash +cargo build # Build the project +RUSTFLAGS="-Dwarnings" cargo build # Build with warnings as errors (CI mode) +``` + +### Test +```bash +cargo test # Run all tests +cargo test test_onion_packet_from_bytes # Run a specific test by name +cargo test test_derive # Run tests matching a pattern +cargo test test_create_onion_packet -- --nocapture # Run with output visible +``` + +### Lint and Format +```bash +cargo fmt # Format code (required before committing) +cargo fmt --check # Check formatting without changes +cargo clippy # Run clippy linter +RUSTFLAGS="-Dwarnings" cargo clippy # Clippy with warnings as errors (CI mode) +``` + +### Documentation +```bash +cargo doc --open # Generate and open documentation +``` + +## Code Style Guidelines + +### Rust Edition and Version +- **Edition**: 2021 +- **Minimum Rust Version**: 1.76.0 + +### Formatting +- Always run `cargo fmt` before committing +- Use rustfmt defaults (no custom configuration) + +### Imports +- Group: 1) Standard library 2) External crates (alphabetically) 3) Internal modules +- Use specific imports, not glob imports +- Nested imports are acceptable: `use secp256k1::{PublicKey, SecretKey}` + +### Naming Conventions +- **Types/Structs/Enums**: PascalCase (`OnionPacket`, `SphinxError`) +- **Functions/Methods**: snake_case (`derive_key`, `peel`) +- **Constants**: SCREAMING_SNAKE_CASE (`HMAC_KEY_RHO`, `CHACHA_NONCE`) +- **Variables**: snake_case (`session_key`, `hops_path`) +- **Generic Type Parameters**: Single uppercase letters (`C`, `F`, `T`) + +### Type Annotations +- Use explicit types for public APIs +- Use `[u8; 32]` for fixed-size byte arrays (keys, HMACs) +- Use `Vec` for variable-length byte data + +### Error Handling +- Use `thiserror` for error definitions +- Define errors with `#[derive(Error, Debug, Eq, PartialEq)]` +- Return `Result` for fallible operations +- Use `Option` for values that may not exist + +Example: +```rust +#[derive(Error, Debug, Eq, PartialEq)] +pub enum SphinxError { + #[error("The hops path does not match the hops data length")] + HopsLenMismatch, +} +``` + +### Documentation +- Use `//!` for module-level documentation +- Use `///` for function/struct documentation +- Include code examples in doc comments +- Document public APIs thoroughly + +### Function Patterns +- Use `&self` for methods that don't consume the struct +- Use `self` for consuming transforms (`into_bytes`, `peel`) +- Use generic constraints: `C: Signing` or `C: Verification` + +### Testing +- Tests in `src/tests.rs` module +- Naming: `test_` or `test_` +- Use `hex-conservative` for hex encoding/decoding +- Test both success and error cases + +### Cryptographic Patterns +- Use `Secp256k1::new()` for secp256k1 context +- Use `SharedSecret::new()` for ECDH operations +- Use ChaCha20 with 12-byte zero nonce: `[0u8; 12]` +- Use HMAC-SHA256 for key derivation and MAC computation + +### Memory and Safety +- Use `expect()` with descriptive messages for infallible operations +- Avoid `unwrap()` in library code; use `?` or proper error handling +- Use `#[inline]` for small, frequently-called functions + +## Project Structure + +``` +fiber-sphinx/ +├── Cargo.toml # Project manifest and dependencies +├── rust-toolchain.toml # Rust version specification +├── src/ +│ ├── lib.rs # Main library code and public API +│ └── tests.rs # Test module +├── docs/ +│ ├── spec.md # Protocol specification +│ ├── development.md # Development guide +│ └── CONTRIBUTING.md # Contribution guidelines +└── .github/workflows/ + ├── ci.yml # CI workflow (build, test, clippy) + └── cov.yml # Coverage workflow +``` + +## CI Requirements + +The CI runs on Rust 1.76.0, stable, beta, and nightly. All must pass: +- `cargo build` - Compilation with no errors +- `cargo test` - All tests pass +- `cargo clippy` - No warnings (with `-Dwarnings`) + +## Contributing Workflow + +1. Create branch from `develop` +2. Add tests for new code +3. Update documentation for API changes +4. Ensure tests pass and code lints +5. Run `cargo fmt` before committing + +## Dependencies + +### Runtime +- `secp256k1` (0.28.0) - Elliptic curve cryptography +- `sha2` (0.10.8) - SHA-256 hashing +- `hmac` (0.12.1) - HMAC implementation +- `chacha20` (0.9.1) - ChaCha20 stream cipher +- `thiserror` (1.0) - Error derive macro + +### Dev +- `hex-conservative` (0.2.1) - Hex encoding/decoding for tests diff --git a/Cargo.lock b/Cargo.lock index 37331c9..23ed530 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,22 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "bitcoin-io" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dee39a0ee5b4095224a0cfc6bf4cc1baf0f9624b96b367e53b66d974e51d953" + +[[package]] +name = "bitcoin_hashes" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26ec84b80c482df901772e931a9a681e26a1b9ee2302edeff23cb30328745c8b" +dependencies = [ + "bitcoin-io", + "hex-conservative", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -85,7 +101,7 @@ dependencies = [ [[package]] name = "fiber-sphinx" -version = "2.2.0" +version = "2.3.0" dependencies = [ "chacha20", "hex-conservative", @@ -105,6 +121,17 @@ dependencies = [ "version_check", ] +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "hex-conservative" version = "0.2.1" @@ -138,6 +165,15 @@ version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + [[package]] name = "proc-macro2" version = "1.0.86" @@ -149,28 +185,60 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.36" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "secp256k1" -version = "0.28.2" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" +checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" dependencies = [ + "bitcoin_hashes", + "rand", "secp256k1-sys", "serde", ] [[package]] name = "secp256k1-sys" -version = "0.9.2" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" dependencies = [ "cc", ] @@ -266,3 +334,29 @@ name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "zerocopy" +version = "0.8.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7456cf00f0685ad319c5b1693f291a650eaf345e941d082fc4e03df8a03996ac" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1328722bbf2115db7e19d69ebcc15e795719e2d66b60827c6a69a117365e37a0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index 4c7f71e..1156487 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,14 +1,14 @@ [package] name = "fiber-sphinx" -version = "2.2.0" +version = "2.3.0" edition = "2021" license-file = "COPYING.md" description = "A Rust implementation of the Sphinx mix network." documentation = "https://docs.rs/fiber-sphinx" -homepage = "https://github.com/cryptape/fiberer-sphinx" +homepage = "https://github.com/cryptape/fiber-sphinx" [dependencies] -secp256k1 = { version = "0.28.0", features = ["serde"] } +secp256k1 = { version = "0.30", features = ["serde"] } sha2 = "0.10.8" hmac = "0.12.1" thiserror = "1.0"