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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
use super::*;
impl_veilid_log_facility!("rtab");
////////////////////////////////////////////////////////////////////////////////////////////////////
// Compiled Privacy Objects
/// An encrypted private/safety route hop
#[derive(Clone)]
pub(crate) struct RouteHopData {
/// The nonce used in the encryption ENC(Xn,DH(PKn,SKapr))
pub nonce: Nonce,
/// The encrypted blob
pub blob: Bytes,
}
impl fmt::Debug for RouteHopData {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RouteHopData")
.field("nonce", &self.nonce)
.field("blob", &format!("len={}", self.blob.len()))
.finish()
}
}
/// How to find a route node
#[derive(Clone, Debug)]
pub(crate) enum RouteNode {
/// Route node is optimized, no contact method information as this node id has been seen before
NodeId(NodeId),
/// Route node with full contact method information to ensure the peer is reachable
PeerInfo(Arc<PeerInfo>),
}
impl RouteNode {
pub fn node_ref(&self, routing_table: &RoutingTable) -> Option<NodeRef> {
match self {
RouteNode::NodeId(id) => {
//
match routing_table.lookup_node_id(id.clone()) {
Ok(nr) => nr,
Err(e) => {
veilid_log!(routing_table debug "failed to look up route node: {}", e);
None
}
}
}
RouteNode::PeerInfo(pi) => {
//
match routing_table.register_node_with_peer_info(pi.clone(), false) {
Ok(nr) => Some(nr.unfiltered()),
Err(e) => {
veilid_log!(routing_table debug "failed to register route node: {}", e);
None
}
}
}
}
}
pub fn describe(&self) -> String {
match self {
RouteNode::NodeId(id) => {
format!("{}", id)
}
RouteNode::PeerInfo(pi) => match pi.node_ids().first() {
Some(id) => format!("{}", id),
None => {
format!("?({})", pi.node_ids())
}
},
}
}
}
/// An unencrypted private/safety route hop
#[derive(Clone, Debug)]
pub(crate) struct RouteHop {
/// The location of the hop
pub node: RouteNode,
/// The encrypted blob to pass to the next hop as its data (None for stubs)
pub next_hop: Option<RouteHopData>,
}
/// The kind of hops a private route can have
#[derive(Clone, Debug)]
pub(crate) enum PrivateRouteHops {
/// The first hop of a private route, unencrypted, route_hops == total hop count
FirstHop(Box<RouteHop>),
/// Private route internal node. Has > 0 private route hops left but < total hop count
Data(RouteHopData),
/// Private route has ended (hop count = 0)
Empty,
}
/// A private route for receiver privacy
#[derive(Clone, Debug)]
pub(crate) struct PrivateRoute {
/// The public key used for the entire route
pub public_key: PublicKey,
pub hops: PrivateRouteHops,
}
impl PrivateRoute {
/// Stub route is the form used when no privacy is required, but you need to specify the destination for a safety route
pub fn new_stub(public_key: PublicKey, node: RouteNode) -> Self {
Self {
public_key,
hops: PrivateRouteHops::FirstHop(Box::new(RouteHop {
node,
next_hop: None,
})),
}
}
/// Check if this is a stub route
pub fn is_stub(&self) -> bool {
if let PrivateRouteHops::FirstHop(first_hop) = &self.hops {
return first_hop.next_hop.is_none();
}
false
}
/// Get the crypto kind in use for this route
pub fn crypto_kind(&self) -> CryptoKind {
self.public_key.kind()
}
/// Remove the first unencrypted hop if possible
pub fn split_first_hop(&self) -> (Option<RouteNode>, Self) {
let mut opt_route_node = None;
let out = Self {
public_key: self.public_key.clone(),
hops: match &self.hops {
PrivateRouteHops::FirstHop(first_hop) => {
opt_route_node = Some(first_hop.node.clone());
match first_hop.next_hop.as_ref() {
Some(rhd) => PrivateRouteHops::Data(rhd.clone()),
None => PrivateRouteHops::Empty,
}
}
PrivateRouteHops::Data(_) | PrivateRouteHops::Empty => self.hops.clone(),
},
};
(opt_route_node, out)
}
pub fn first_hop_node_id(&self) -> Option<NodeId> {
let PrivateRouteHops::FirstHop(pr_first_hop) = &self.hops else {
return None;
};
// Get the safety route to use from the spec
Some(match &pr_first_hop.node {
RouteNode::NodeId(n) => n.clone(),
RouteNode::PeerInfo(p) => p.node_ids().get(self.public_key.kind()).unwrap_or_log(),
})
}
}
impl fmt::Display for PrivateRoute {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"PR({:?}+{})",
self.public_key,
match &self.hops {
PrivateRouteHops::FirstHop(_) => {
format!(
"->{}",
self.first_hop_node_id()
.map(|n| n.to_string())
.unwrap_or_else(|| "None".to_owned())
)
}
PrivateRouteHops::Data(_) => {
"->?".to_owned()
}
PrivateRouteHops::Empty => {
"".to_owned()
}
}
)
}
}
#[derive(Clone, Debug)]
pub(crate) enum SafetyRouteHops {
/// Has >= 1 safety route hops
Data(RouteHopData),
/// Has 0 safety route hops
Private(Arc<PrivateRoute>),
}
#[derive(Clone, Debug)]
pub(crate) struct SafetyRoute {
pub public_key: PublicKey,
pub hops: SafetyRouteHops,
}
impl SafetyRoute {
/// Stub route is the form used when no privacy is required, but you need to directly contact a private route
pub fn new_stub(public_key: PublicKey, private_route: Arc<PrivateRoute>) -> Self {
// First hop should have already been popped off for stubbed safety routes since
// we are sending directly to the first hop
assert!(matches!(private_route.hops, PrivateRouteHops::Data(_)));
Self {
public_key,
hops: SafetyRouteHops::Private(private_route),
}
}
/// Check if this is a stub route
pub fn is_stub(&self) -> bool {
matches!(self.hops, SafetyRouteHops::Private(_))
}
/// Get the crypto kind in use for this route
pub fn crypto_kind(&self) -> CryptoKind {
self.public_key.kind()
}
}
impl fmt::Display for SafetyRoute {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"SR({:?}+{})",
self.public_key,
match &self.hops {
SafetyRouteHops::Data(_) => "".to_owned(),
SafetyRouteHops::Private(p) => format!("->{}", p),
}
)
}
}