mod cell;
mod codec;
mod crypto;
mod limiter;
mod protocol;
mod reducer;
mod send_outbox;
mod shell;
#[cfg(test)]
mod tests;
use bytes::Bytes;
pub use cell::OnionCellBucket;
pub use codec::OnionCircuitEvent;
pub use crypto::encode_initial_forward;
#[cfg(rings_browser)]
pub(crate) use crypto::encode_initial_forward_link;
pub use crypto::route_first_hop;
pub(crate) use crypto::send_backward;
#[cfg(rings_native)]
pub(crate) use crypto::OnionCircuitPath;
pub use protocol::OnionCircuitCapabilities;
pub use protocol::OnionCircuitProtocol;
pub use reducer::OnionCircuitEffect;
pub use reducer::OnionCircuitState;
use rings_core::dht::Did;
use rings_core::ecc::elgamal::impls::secp256k1::AeadCiphertext;
use rings_core::ecc::PublicKey;
use rings_core::message::MessageVerification;
pub(crate) use send_outbox::OnionLinkSender;
use serde::Deserialize;
use serde::Serialize;
pub use shell::OnionCircuitExitFrame;
pub use shell::OnionCircuitHandler;
pub use shell::OnionCircuitShell;
use super::OnionServiceName;
use crate::error::Result;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) struct OnionLink {
peer: Did,
recipient: PublicKey<33>,
}
impl OnionLink {
const fn new(peer: Did, recipient: PublicKey<33>) -> Self {
Self { peer, recipient }
}
}
pub const ONION_CIRCUIT_NAMESPACE: &str = "onion-circuit";
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum OnionCircuitSecurity {
LayeredAead,
}
pub const ONION_CIRCUIT_SECURITY: OnionCircuitSecurity = OnionCircuitSecurity::LayeredAead;
pub const MAX_ONION_CIRCUIT_HOPS: u8 = 8;
pub(super) const MAX_ONION_RELAY_CIRCUITS: usize = 1024;
pub(super) const ONION_RELAY_RETURN_TTL_MS: u128 = 120_000;
pub(super) const ONION_FORWARD_PAYLOAD_TTL_MS: u128 = 120_000;
pub(super) const ONION_FORWARD_EXPIRY_QUANTUM_MS: u128 = 30_000;
pub(super) const ONION_FORWARD_MAX_VALIDITY_MS: u128 =
ONION_FORWARD_PAYLOAD_TTL_MS + ONION_FORWARD_EXPIRY_QUANTUM_MS;
pub(super) const ONION_CRYPTO_LIMIT_WINDOW_MS: u128 = 60_000;
pub(super) const MAX_ONION_CRYPTO_OPS_PER_WINDOW: u32 = 4096;
pub(super) const MAX_ONION_CRYPTO_OPS_GLOBAL_PER_WINDOW: u32 = 8192;
pub(super) const MAX_ONION_CRYPTO_BYTES_PER_WINDOW: u64 = 256 * 1024 * 1024;
pub(super) const MAX_ONION_CRYPTO_BYTES_GLOBAL_PER_WINDOW: u64 = 512 * 1024 * 1024;
pub(super) const MAX_ONION_CRYPTO_PEERS: usize = 64;
pub(super) const ONION_AEAD_NAMESPACE: &str = "rings-node:onion-circuit:v1";
#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
pub struct OnionCircuitPayload {
pub service: OnionServiceName,
pub body: Bytes,
}
impl OnionCircuitPayload {
pub fn new(service: OnionServiceName, body: impl Into<Bytes>) -> Self {
Self {
service,
body: body.into(),
}
}
pub fn try_new(service: impl AsRef<str>, body: impl Into<Bytes>) -> Result<Self> {
Ok(Self::new(OnionServiceName::parse(service)?, body))
}
pub fn service(&self) -> &str {
self.service.as_str()
}
pub fn service_name(&self) -> &OnionServiceName {
&self.service
}
pub fn is_service(&self, service: &OnionServiceName) -> bool {
&self.service == service
}
pub fn matches_service(&self, service: &str) -> bool {
self.service.matches(service)
}
}
#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
pub struct OnionAuthenticatedPayload {
pub return_id: OnionReturnId,
pub nonce: OnionBackwardNonce,
pub sequence: OnionBackwardSequence,
pub authentication: MessageVerification,
pub payload: OnionCircuitPayload,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct OnionReturnId([u8; 16]);
impl OnionReturnId {
pub const fn new(bytes: [u8; 16]) -> Self {
Self(bytes)
}
pub fn random() -> Self {
Self(rand::random())
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct OnionBackwardNonce([u8; 16]);
impl OnionBackwardNonce {
pub const fn new(bytes: [u8; 16]) -> Self {
Self(bytes)
}
pub fn random() -> Self {
Self(rand::random())
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct OnionBackwardSequence(u64);
impl OnionBackwardSequence {
pub const FIRST: Self = Self(0);
pub const fn new(value: u64) -> Self {
Self(value)
}
pub const fn value(self) -> u64 {
self.0
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct OnionForwardNonce([u8; 16]);
impl OnionForwardNonce {
pub const fn new(bytes: [u8; 16]) -> Self {
Self(bytes)
}
pub fn random() -> Self {
Self(rand::random())
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct OnionForwardSequence(u64);
impl OnionForwardSequence {
pub const FIRST: Self = Self(0);
pub const fn new(value: u64) -> Self {
Self(value)
}
pub const fn value(self) -> u64 {
self.0
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct OnionVerifiedPayload {
pub return_id: OnionReturnId,
pub nonce: OnionBackwardNonce,
pub sequence: OnionBackwardSequence,
pub payload: OnionCircuitPayload,
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize, Eq, PartialEq)]
pub struct OnionClientReturn {
pub session_public_key: PublicKey<33>,
pub return_id: OnionReturnId,
}
impl OnionClientReturn {
pub fn new(session_public_key: PublicKey<33>) -> Self {
Self {
session_public_key,
return_id: OnionReturnId::random(),
}
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct OnionCircuitId([u8; 16]);
impl OnionCircuitId {
pub const fn new(bytes: [u8; 16]) -> Self {
Self(bytes)
}
pub fn random() -> Self {
Self(rand::random())
}
}
#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
pub struct OnionForwardFrame {
pub circuit_id: OnionCircuitId,
pub layer: AeadCiphertext,
}
#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
pub struct OnionBackwardFrame {
pub circuit_id: OnionCircuitId,
pub payload: AeadCiphertext,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct OnionBackwardPath {
pub circuit_id: OnionCircuitId,
pub return_peer: Did,
pub return_session_public_key: PublicKey<33>,
pub client: OnionClientReturn,
}
impl OnionBackwardPath {
pub const fn new(
circuit_id: OnionCircuitId,
return_peer: Did,
return_session_public_key: PublicKey<33>,
client: OnionClientReturn,
) -> Self {
Self {
circuit_id,
return_peer,
return_session_public_key,
client,
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
pub(super) enum OnionForwardLayer {
Relay {
next_hop: Did,
next_circuit_id: OnionCircuitId,
next_session_public_key: PublicKey<33>,
return_session_public_key: PublicKey<33>,
inner: AeadCiphertext,
},
Exit {
client: OnionClientReturn,
return_session_public_key: PublicKey<33>,
expires_at_ms: u128,
forward_nonce: OnionForwardNonce,
forward_sequence: OnionForwardSequence,
payload: OnionCircuitPayload,
},
}