1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//! RPE2E — Repartee End-to-End encryption (v1.0)
//!
//! See `docs/plans/2026-04-10-e2e-encryption-architecture.md` for the full spec
//! and `docs/plans/2026-04-11-rpee2e-implementation.md` for the implementation
//! plan.
//!
//! Model summary:
//! - Twopart identity: `(fingerprint, handle=ident@host)`
//! - Per-sender per-channel symmetric keys
//! - Stateless per-chunk encryption (no reassembly)
//! - CTCP NOTICE handshake with KEYREQ/KEYRSP
//! - Strict handle check on decrypt path
// G13: replaced the old blanket `#![allow(...)]` with a module-level
// `#![expect(...)]` so the rustc lint engine complains the moment one
// of these categories stops firing — keeping the justification honest.
//
// Per-lint rationale:
//
// * `dead_code` — several helpers are part of the public crypto /
// keyring / manager API surface even though the current event
// pipeline does not call every one on the hot path. They stay
// available for script interop, follow-on features, and tests.
// `EphemeralKeypair`, `Identity::verifying_key`,
// `Keyring::clear_outgoing_pending_rotation`, and a few
// `E2eManager` accessors fall into this bucket.
// * `clippy::missing_const_for_fn` — a few small getters are fn, not
// const fn, so future versions can add per-instance state without a
// visible API break.
// * `clippy::unnecessary_wraps` — a handful of crypto helpers return
// `Result` even though today they never fail, so a future backend
// swap (different Ed25519 crate, hardware token, etc.) does not
// force a signature change through every call site.
// * `clippy::doc_markdown` — doc comments mention protocol tokens
// (KEYREQ, KEYRSP, REKEY, RPE2E01, CTCP) that are spec-level
// identifiers and read more naturally without backticks.
// * `clippy::significant_drop_tightening` — every keyring method
// grabs `self.db.lock()` as its first line and releases it when the
// single SQL statement returns. Tightening further buys nothing and
// hurts readability for no real contention win.
// * `clippy::type_complexity` — `Keyring::load_identity` returns a
// 4-tuple read straight from SQLite columns; a dedicated alias
// would obscure, not clarify.
pub use E2eError;
pub use E2eManager;
/// Protocol version string embedded in wire format and AAD.
pub const PROTO: &str = "RPE2E01";
/// Max chunks per logical message (hard cap for sender).
pub const MAX_CHUNKS: u8 = 16;
/// Max plaintext bytes per chunk before ciphertext expansion.
/// Chosen so that a chunk fits in ~400 bytes of IRC payload after base64.
pub const MAX_PLAINTEXT_PER_CHUNK: usize = 180;
/// Default replay-protection window for `ts` in AAD (seconds). Used by
/// `E2eManager::load_or_init_with_default` and tests — the runtime value
/// is plumbed through `E2eConfig::ts_tolerance_secs` into each
/// `E2eManager` instance, so the manager reads `self.ts_tolerance_secs`
/// rather than this constant when processing real traffic.
pub const DEFAULT_TS_TOLERANCE_SECS: i64 = 300;
/// Derive the keyring `channel` context for a conversation.
///
/// For real IRC channels (prefixes `#`, `&`, `!`, `+`) the target is
/// passed through unchanged. For private messages we construct the
/// pseudochannel `@<peer_handle>` per spec §6, where `peer_handle` is
/// the server-stamped `ident@host` of the remote peer. Two PMs from
/// peers that happen to share a nick across different hosts — or the
/// same peer reconnecting from a new host — therefore live under
/// distinct keyring rows instead of colliding under a bare nick.
///
/// Callers **must** pass the raw server-stamped peer handle
/// (`ident@host` as seen in the IRC prefix), never the peer's nick.
/// Passing a nick reintroduces the collision the pseudochannel exists
/// to prevent.