tachyon-i2p 0.0.4

Safe async wrapper around i2pd-sys (native I2P `.b32.i2p` eepsite support)
Documentation
# tachyon-i2p

Safe async wrapper around [`i2pd-sys`](https://crates.io/crates/i2pd-sys), giving Tokio code a
`Destination` (an I2P eepsite identity, reachable at a `.b32.i2p` address) with an `I2pStream`
connection type that implements `AsyncRead`/`AsyncWrite` — no external `i2pd`/Java-I2P process,
no SAM bridge, no separate service to run alongside your binary.

> **Status:** pre-0.1 (`0.0.x`), developed alongside and consumed by the
> [`tachyon-web`]https://github.com/tachyon-web/ workspace. The API may still
> change without notice.

## Why it's `unsafe` internally

`libi2pd` (the underlying router, from [PurpleI2P/i2pd](https://github.com/PurpleI2P/i2pd)) is a
C++ library with no stable C ABI. `i2pd-sys` bridges it through a small hand-written `extern "C"`
shim, and this crate is where every `unsafe` call site into that shim lives, so consumers never
have to relax their own `forbid(unsafe_code)`. The public API exposes no `pub unsafe fn` and no
raw pointers, but that safety rests on this crate's own review of libi2pd's threading and
ownership contracts — documented at each `unsafe` block and in `i2pd-sys/shim/shim.h` — not on
anything the compiler checks.

## Usage

```rust,no_run
use tachyon_i2p::{I2pRouter, SigType, I2pError};

#[tokio::main]
async fn main() -> Result<(), I2pError> {
    let router = I2pRouter::start("my-eepsite").await?;
    let mut dest = router
        .destination_from_keys_file("my-eepsite.keys", true, SigType::default(), &[])
        .await?;
    println!("reachable at http://{}", dest.b32_address());

    loop {
        let _stream = dest.accept().await?; // implements AsyncRead + AsyncWrite
        // ... spawn a task to serve it ...
    }
}
```

The keys file is this destination's private identity — anyone who obtains it can impersonate
the eepsite. It is created owner-only (`0600`) and written atomically; back it up accordingly,
and reuse the same path across restarts to keep the same `.b32.i2p` address.

Only one `I2pRouter` may run per process at a time — libi2pd keeps its router context as a
process-wide global. Starting a new one after the previous router has been dropped works.

## Network participation

This crate runs a real I2P router, so it has a position in the network beyond hosting your own
destinations. Defaults:

| | |
|---|---|
| Transit tunnels | Carried. |
| Bandwidth | 256 KB/s, whole router. |
| Floodfill | Off. |
| Config files | None read. `libi2pd` only parses `i2pd.conf` in upstream's daemon. |

Transit means carrying *other* users' tunnels, and is unrelated to your own destinations, which
work either way. It defaults to on because a router that relays nothing gives an observer no
cover traffic: every byte crossing your link is then yours, which makes correlating your service
easier, and the refusal is itself a fingerprint. Turn it off when bandwidth is metered, or when
the risk you care about is a memory-safety bug in `libi2pd` rather than traffic analysis.

`RouterConfig` is the only way to change any of this — the settings are read as the router comes
up, so there is no equivalent on a running one:

```rust,no_run
use tachyon_i2p::{I2pRouter, RouterConfig, I2pError};

#[tokio::main]
async fn main() -> Result<(), I2pError> {
    let _router = I2pRouter::start_with_config(
        "my-eepsite",
        // Keep carrying transit, but bound what it costs.
        RouterConfig::default()
            .bandwidth_limit_kbps(512)
            .transit_share_percent(25)
            .max_transit_tunnels(500),
    )
    .await?;
    Ok(())
}
```

Building without the default `transit` feature is the stronger form of `accepts_transit(false)`:
`libi2pd`'s tunnel build-request path is compiled out, so no transit tunnel can exist whatever
`RouterConfig` says. `I2pRouter::supports_transit()` reports which build you got.

## Crypto backend: `aws-lc` (default) vs `fips`

Both mirror `i2pd-sys`'s features of the same name: `aws-lc` links regular AWS-LC, `fips` links
the FIPS 140-3-validated AWS-LC-FIPS module instead. At least one must be enabled — building with
neither is a compile error, not a silently crypto-less router.

For `fips`, prefer `default-features = false, features = ["fips"]`. Cargo features are additive,
so a dependent crate reaching for `aws-lc` can still switch it back on; if both end up enabled,
`fips` wins. See the "FIPS" section of [`i2pd-sys`'s README](https://crates.io/crates/i2pd-sys)
for what it does and does not get you before reaching for it to satisfy a compliance requirement.

The third feature, `transit` (also default), is the compile-time half of
[Network participation](#network-participation) above.

## License

Licensed under either of

- [Apache License, Version 2.0]https://github.com/tachyon-web/i2p/blob/main/LICENSE-APACHE
- [MIT license]https://github.com/tachyon-web/i2p/blob/main/LICENSE-MIT

at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in
this crate, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
additional terms or conditions.