# 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.