Variable Length Keys

This commit is contained in:
Christien Rioux 2025-07-06 18:55:17 -04:00
parent b52e64e56a
commit 67be63c91c
171 changed files with 12847 additions and 10261 deletions

33
Cargo.lock generated
View file

@ -870,6 +870,9 @@ name = "bytes"
version = "1.10.1" version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "capnp" name = "capnp"
@ -4574,6 +4577,26 @@ dependencies = [
"thiserror 1.0.69", "thiserror 1.0.69",
] ]
[[package]]
name = "ref-cast"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf"
dependencies = [
"ref-cast-impl",
]
[[package]]
name = "ref-cast-impl"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.101",
]
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.11.1" version = "1.11.1"
@ -4890,11 +4913,12 @@ dependencies = [
[[package]] [[package]]
name = "schemars" name = "schemars"
version = "0.8.22" version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" checksum = "1375ba8ef45a6f15d83fa8748f1079428295d403d6ea991d09ab100155fbc06d"
dependencies = [ dependencies = [
"dyn-clone", "dyn-clone",
"ref-cast",
"schemars_derive", "schemars_derive",
"serde", "serde",
"serde_json", "serde_json",
@ -4902,9 +4926,9 @@ dependencies = [
[[package]] [[package]]
name = "schemars_derive" name = "schemars_derive"
version = "0.8.22" version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" checksum = "2b13ed22d6d49fe23712e068770b5c4df4a693a2b02eeff8e7ca3135627a24f6"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -6412,6 +6436,7 @@ dependencies = [
"backtrace", "backtrace",
"blake3", "blake3",
"bosion", "bosion",
"bytes 1.10.1",
"capnp", "capnp",
"capnpc", "capnpc",
"cfg-if 1.0.0", "cfg-if 1.0.0",

View file

@ -45,8 +45,22 @@ rt-tokio = [
] ]
# Crypto support features # Crypto support features
enable-crypto-vld0 = [ "ed25519-dalek", "x25519-dalek", "curve25519-dalek", "blake3", "chacha20poly1305", "chacha20", "argon2" ] enable-crypto-vld0 = [
enable-crypto-none = [ "ed25519-dalek", "curve25519-dalek", "blake3", "argon2", "digest" ] "ed25519-dalek",
"x25519-dalek",
"curve25519-dalek",
"blake3",
"chacha20poly1305",
"chacha20",
"argon2",
]
enable-crypto-none = [
"ed25519-dalek",
"curve25519-dalek",
"blake3",
"argon2",
"digest",
]
# Debugging and testing features # Debugging and testing features
verbose-tracing = [] verbose-tracing = []
@ -134,7 +148,7 @@ blake3 = { version = "1.8.2", optional = true }
chacha20poly1305 = { version = "0.10.1", optional = true } chacha20poly1305 = { version = "0.10.1", optional = true }
chacha20 = { version = "0.9.1", optional = true } chacha20 = { version = "0.9.1", optional = true }
argon2 = { version = "0.5.3", optional = true } argon2 = { version = "0.5.3", optional = true }
digest = { version = "0.10.7", optional = true, features = [ "rand_core" ]} digest = { version = "0.10.7", optional = true, features = ["rand_core"] }
# Network # Network
async-std-resolver = { version = "0.24.4", optional = true } async-std-resolver = { version = "0.24.4", optional = true }
@ -147,7 +161,7 @@ serde_json = { version = "1.0.140" }
serde-big-array = "0.5.1" serde-big-array = "0.5.1"
json = "0.12.4" json = "0.12.4"
data-encoding = { version = "2.8.0" } data-encoding = { version = "2.8.0" }
schemars = "0.8.22" schemars = "1.0.3"
lz4_flex = { version = "0.11.3", default-features = false, features = [ lz4_flex = { version = "0.11.3", default-features = false, features = [
"safe-encode", "safe-encode",
"safe-decode", "safe-decode",
@ -155,6 +169,7 @@ lz4_flex = { version = "0.11.3", default-features = false, features = [
indent = "0.1.1" indent = "0.1.1"
sanitize-filename = "0.5.0" sanitize-filename = "0.5.0"
serde_with = "3.12.0" serde_with = "3.12.0"
bytes = { version = "1.10.1", features = ["serde"] }
# Dependencies for native builds only # Dependencies for native builds only
# Linux, Windows, Mac, iOS, Android # Linux, Windows, Mac, iOS, Android

View file

@ -233,7 +233,7 @@ async fn open_route(
if val.is_empty() { if val.is_empty() {
break; break;
} }
try_again_loop(|| async { rc.app_message(Target::PrivateRoute(route_id), val.as_bytes().to_vec()).await }) try_again_loop(|| async { rc.app_message(Target::RouteId(route_id.clone()), val.as_bytes().to_vec()).await })
.await?; .await?;
} else { } else {
break; break;

View file

@ -1,50 +1,59 @@
@0x8ffce8033734ab02; @0x8ffce8033734ab02;
# IDs And Hashes # Typed IDs and Hashes
############################## ##############################
struct Key256 @0xdde44e3286f6a90d { # DHT Record Key
u0 @0 :UInt64; struct RecordKey @0xcd55475a98deb0c1 {
u1 @1 :UInt64; kind @0 :CryptoKind;
u2 @2 :UInt64; value @1 :Data;
u3 @3 :UInt64;
} }
struct Signature512 @0x806749043a129c12 { # Blockstore Block Id
u0 @0 :UInt64; struct BlockId @0xed3678a9e4771a22 {
u1 @1 :UInt64; kind @0 :CryptoKind;
u2 @2 :UInt64; value @1 :Data;
u3 @3 :UInt64;
u4 @4 :UInt64;
u5 @5 :UInt64;
u6 @6 :UInt64;
u7 @7 :UInt64;
} }
struct Nonce24 @0xb6260db25d8d7dfc { # Node Id (hash of node public key)
u0 @0 :UInt64; struct NodeId @0xce9822f1cebca1bb {
u1 @1 :UInt64; kind @0 :CryptoKind;
u2 @2 :UInt64; value @1 :Data;
} }
using PublicKey = Key256; # Node id / Hash / DHT key / Route id, etc # Public Key
using Nonce = Nonce24; # One-time encryption nonce struct PublicKey @0xfc522f2dbdf30cee {
using Signature = Signature512; # Signature block kind @0 :CryptoKind;
using TunnelID = UInt64; # Id for tunnels value @1 :Data;
}
# DHT Route Id
struct RouteId @0xc8ae026d91da0ae6 {
kind @0 :CryptoKind;
value @1 :Data;
}
# Signature
struct Signature @0xf06fa6e2ac8726a2 {
kind @0 :CryptoKind;
value @1 :Data;
}
# Untyped generic one-time encryption nonce
struct Nonce @0x9b00866db77b59f6 {
value @0 :Data;
}
# Convenience Typedefs
################################################################
using TunnelId = UInt64; # Id for tunnels
using CryptoKind = UInt32; # FOURCC code for cryptography type using CryptoKind = UInt32; # FOURCC code for cryptography type
using ValueSeqNum = UInt32; # sequence numbers for values using ValueSeqNum = UInt32; # sequence numbers for values
using Subkey = UInt32; # subkey index for dht using Subkey = UInt32; # subkey index for dht
using Capability = UInt32; # FOURCC code for capability using Capability = UInt32; # FOURCC code for capability
struct TypedKey @0xe2d567a9f1e61b29 {
kind @0 :CryptoKind;
key @1 :PublicKey;
}
struct TypedSignature @0x963170c7298e3884 {
kind @0 :CryptoKind;
signature @1 :Signature;
}
# Node Dial Info # Node Dial Info
################################################################ ################################################################
@ -122,7 +131,7 @@ struct SignalInfoReverseConnect @0xd9ebd3bd0d46e013 {
# Private Routes # Private Routes
############################## ##############################
struct RouteHopData @0x8ce231f9d1b7adf2 { struct RouteHopData @0x9d45cb1880e79fdb {
nonce @0 :Nonce; # nonce for encrypted blob nonce @0 :Nonce; # nonce for encrypted blob
blob @1 :Data; # encrypted blob with ENC(nonce,DH(PK,SK)) blob @1 :Data; # encrypted blob with ENC(nonce,DH(PK,SK))
# if this is a safety route RouteHopData, there is a single byte tag appended to the end of the encrypted blob # if this is a safety route RouteHopData, there is a single byte tag appended to the end of the encrypted blob
@ -134,7 +143,7 @@ struct RouteHopData @0x8ce231f9d1b7adf2 {
struct RouteHop @0xf8f672d75cce0c3b { struct RouteHop @0xf8f672d75cce0c3b {
node :union { node :union {
nodeId @0 :PublicKey; # node id key only for established routes (kind is the same as the pr or sr it is part of) nodeId @0 :NodeId; # node id key only for established routes (kind is the same as the pr or sr it is part of)
peerInfo @1 :PeerInfo; # full peer info for this hop to establish the route peerInfo @1 :PeerInfo; # full peer info for this hop to establish the route
} }
nextHop @2 :RouteHopData; # optional: If this the end of a private route, this field will not exist nextHop @2 :RouteHopData; # optional: If this the end of a private route, this field will not exist
@ -142,21 +151,19 @@ struct RouteHop @0xf8f672d75cce0c3b {
} }
struct PrivateRoute @0x8a83fccb0851e776 { struct PrivateRoute @0x8a83fccb0851e776 {
publicKey @0 :TypedKey; # private route public key (unique per private route) publicKey @0 :PublicKey; # private route public key (unique per private route)
hopCount @1 :UInt8; # Count of hops left in the private route (for timeout calculation purposes only)
hops :union { hops :union {
firstHop @2 :RouteHop; # first hop of a private route is unencrypted (hopcount > 0) firstHop @1 :RouteHop; # first hop of a private route is unencrypted (hopcount > 0)
data @3 :RouteHopData; # private route has more hops (hopcount > 0 && hopcount < total_hopcount) data @2 :RouteHopData; # private route has more hops (hopcount > 0 && hopcount < total_hopcount)
empty @4 :Void; # private route has ended (hopcount = 0) empty @3 :Void; # private route has ended (hopcount = 0)
} }
} }
struct SafetyRoute @0xf554734d07cb5d59 { struct SafetyRoute @0xf554734d07cb5d59 {
publicKey @0 :TypedKey; # safety route public key (unique per safety route) publicKey @0 :PublicKey; # safety route public key (unique per safety route)
hopCount @1 :UInt8; # Count of hops left in the safety route (for timeout calculation purposes only)
hops :union { hops :union {
data @2 :RouteHopData; # safety route has more hops data @1 :RouteHopData; # safety route has more hops
private @3 :PrivateRoute; # safety route has ended and private route follows private @2 :PrivateRoute; # safety route has ended and private route follows
} }
} }
@ -220,18 +227,18 @@ struct NodeInfo @0xe125d847e3f9f419 {
dialInfoDetailList @6 :List(DialInfoDetail); # inbound dial info details for this node dialInfoDetailList @6 :List(DialInfoDetail); # inbound dial info details for this node
} }
struct SignedDirectNodeInfo @0xe0e7ea3e893a3dd7 { struct SignedDirectNodeInfo @0xa70f85e77dafc0cd {
nodeInfo @0 :NodeInfo; # node info nodeInfo @0 :NodeInfo; # node info
timestamp @1 :UInt64; # when signed node info was generated timestamp @1 :UInt64; # when signed node info was generated
signatures @2 :List(TypedSignature); # signatures signatures @2 :List(Signature); # signatures
} }
struct SignedRelayedNodeInfo @0xb39e8428ccd87cbb { struct SignedRelayedNodeInfo @0x8b193d500b11573f {
nodeInfo @0 :NodeInfo; # node info nodeInfo @0 :NodeInfo; # node info
relayIds @1 :List(TypedKey); # node ids for relay relayIds @1 :List(NodeId); # node ids for relay
relayInfo @2 :SignedDirectNodeInfo; # signed node info for relay relayInfo @2 :SignedDirectNodeInfo; # signed node info for relay
timestamp @3 :UInt64; # when signed node info was generated timestamp @3 :UInt64; # when signed node info was generated
signatures @4 :List(TypedSignature); # signatures signatures @4 :List(Signature); # signatures
} }
struct SignedNodeInfo @0xd2478ce5f593406a { struct SignedNodeInfo @0xd2478ce5f593406a {
@ -241,12 +248,12 @@ struct SignedNodeInfo @0xd2478ce5f593406a {
} }
} }
struct PeerInfo @0xfe2d722d5d3c4bcb { struct PeerInfo @0xb33ceb3dd583dbf7 {
nodeIds @0 :List(TypedKey); # node ids for 'closer peer' nodeIds @0 :List(NodeId); # node ids for 'closer peer'
signedNodeInfo @1 :SignedNodeInfo; # signed node info for 'closer peer' signedNodeInfo @1 :SignedNodeInfo; # signed node info for 'closer peer'
} }
struct RoutedOperation @0xcbcb8535b839e9dd { struct RoutedOperation @0xa074e6662fe5aa92 {
sequencing @0 :Sequencing; # sequencing preference to use to pass the message along sequencing @0 :Sequencing; # sequencing preference to use to pass the message along
signatures @1 :List(Signature); # signatures from nodes that have handled the private route signatures @1 :List(Signature); # signatures from nodes that have handled the private route
nonce @2 :Nonce; # nonce Xmsg nonce @2 :Nonce; # nonce Xmsg
@ -272,8 +279,8 @@ struct OperationReturnReceipt @0xeb0fb5b5a9160eeb {
receipt @0 :Data; # receipt being returned to its origin receipt @0 :Data; # receipt being returned to its origin
} }
struct OperationFindNodeQ @0xfdef788fe9623bcd { struct OperationFindNodeQ @0xca524d602e9d86ca {
nodeId @0 :TypedKey; # node id to locate nodeId @0 :NodeId; # node id to locate
capabilities @1 :List(Capability); # required capabilities returned peers must have capabilities @1 :List(Capability); # required capabilities returned peers must have
} }
@ -303,13 +310,13 @@ struct SubkeyRange @0xf592dac0a4d0171c {
end @1 :Subkey; # the end of a subkey range end @1 :Subkey; # the end of a subkey range
} }
struct SignedValueData @0xb4b7416f169f2a3d { struct SignedValueData @0xff3944efaaf7fc18 {
seq @0 :ValueSeqNum; # sequence number of value seq @0 :ValueSeqNum; # sequence number of value
data @1 :Data; # value or subvalue contents data @1 :Data; # value or subvalue contents
writer @2 :PublicKey; # the public key of the writer writer @2 :PublicKey; # the public key of the writer
signature @3 :Signature; # signature of data at this subkey, using the writer key (which may be the same as the owner key) signature @3 :Signature; # signature of data at this subkey, using the writer key (which may be the same as the owner key)
# signature covers: # signature covers:
# * ownerKey # * owner public key
# * subkey # * subkey
# * sequence number # * sequence number
# * data # * data
@ -325,8 +332,8 @@ struct SignedValueDescriptor @0xe7911cd3f9e1b0e7 {
} }
struct OperationGetValueQ @0xf88a5b6da5eda5d0 { struct OperationGetValueQ @0x8c176d26517ea24d {
key @0 :TypedKey; # DHT Key = Hash(ownerKeyKind) of: [ ownerKeyValue, schema ] key @0 :RecordKey; # DHT Key = Hash(ownerKeyKind) of: [ ownerKeyValue, schema ]
subkey @1 :Subkey; # the index of the subkey subkey @1 :Subkey; # the index of the subkey
wantDescriptor @2 :Bool; # whether or not to include the descriptor for the key wantDescriptor @2 :Bool; # whether or not to include the descriptor for the key
} }
@ -339,7 +346,7 @@ struct OperationGetValueA @0xd896bb46f2e0249f {
} }
struct OperationSetValueQ @0xbac06191ff8bdbc5 { struct OperationSetValueQ @0xbac06191ff8bdbc5 {
key @0 :TypedKey; # DHT Key = Hash(ownerKeyKind) of: [ ownerKeyValue, schema ] key @0 :RecordKey; # DHT Key = Hash(ownerKeyKind) of: [ ownerKeyValue, schema ]
subkey @1 :Subkey; # the index of the subkey subkey @1 :Subkey; # the index of the subkey
value @2 :SignedValueData; # value or subvalue contents (older or equal seq number gets dropped) value @2 :SignedValueData; # value or subvalue contents (older or equal seq number gets dropped)
descriptor @3 :SignedValueDescriptor; # optional: the descriptor if needed descriptor @3 :SignedValueDescriptor; # optional: the descriptor if needed
@ -352,7 +359,7 @@ struct OperationSetValueA @0x9378d0732dc95be2 {
} }
struct OperationWatchValueQ @0xf9a5a6c547b9b228 { struct OperationWatchValueQ @0xf9a5a6c547b9b228 {
key @0 :TypedKey; # key for value to watch key @0 :RecordKey; # key for value to watch
subkeys @1 :List(SubkeyRange); # subkey range to watch (up to 512 subranges). An empty range here should not be specified unless cancelling a watch (count=0). subkeys @1 :List(SubkeyRange); # subkey range to watch (up to 512 subranges). An empty range here should not be specified unless cancelling a watch (count=0).
expiration @2 :UInt64; # requested timestamp when this watch will expire in usec since epoch (watch can return less, 0 for max) expiration @2 :UInt64; # requested timestamp when this watch will expire in usec since epoch (watch can return less, 0 for max)
count @3 :UInt32; # requested number of changes to watch for (0 = cancel, 1 = single shot, 2+ = counter, UINT32_MAX = continuous) count @3 :UInt32; # requested number of changes to watch for (0 = cancel, 1 = single shot, 2+ = counter, UINT32_MAX = continuous)
@ -369,7 +376,7 @@ struct OperationWatchValueA @0xa726cab7064ba893 {
} }
struct OperationInspectValueQ @0xdef712d2fd16f55a { struct OperationInspectValueQ @0xdef712d2fd16f55a {
key @0 :TypedKey; # DHT Key = Hash(ownerKeyKind) of: [ ownerKeyValue, schema ] key @0 :RecordKey; # DHT Key = Hash(ownerKeyKind) of: [ ownerKeyValue, schema ]
subkeys @1 :List(SubkeyRange); # subkey range to inspect (up to 512 total subkeys), if empty this implies 0..=511 subkeys @1 :List(SubkeyRange); # subkey range to inspect (up to 512 total subkeys), if empty this implies 0..=511
wantDescriptor @2 :Bool; # whether or not to include the descriptor for the key wantDescriptor @2 :Bool; # whether or not to include the descriptor for the key
} }
@ -381,7 +388,7 @@ struct OperationInspectValueA @0xb8b57faf960ee102 {
} }
struct OperationValueChanged @0xd1c59ebdd8cc1bf6 { struct OperationValueChanged @0xd1c59ebdd8cc1bf6 {
key @0 :TypedKey; # key for value that changed key @0 :RecordKey; # key for value that changed
subkeys @1 :List(SubkeyRange); # subkey range that changed (up to 512 ranges at a time, if empty this is a watch expiration notice) subkeys @1 :List(SubkeyRange); # subkey range that changed (up to 512 ranges at a time, if empty this is a watch expiration notice)
count @2 :UInt32; # remaining changes left (0 means watch has expired) count @2 :UInt32; # remaining changes left (0 means watch has expired)
watchId @3 :UInt64; # watch id this value change came from watchId @3 :UInt64; # watch id this value change came from
@ -389,7 +396,8 @@ struct OperationValueChanged @0xd1c59ebdd8cc1bf6 {
} }
struct OperationSupplyBlockQ @0xadbf4c542d749971 { struct OperationSupplyBlockQ @0xadbf4c542d749971 {
blockId @0 :TypedKey; # hash of the block we can supply blockId @0 :BlockId; # hash of the block we can supply
routeId @1 :RouteId; # the private route endpoint for this block supplier
} }
struct OperationSupplyBlockA @0xf003822e83b5c0d7 { struct OperationSupplyBlockA @0xf003822e83b5c0d7 {
@ -398,13 +406,13 @@ struct OperationSupplyBlockA @0xf003822e83b5c0d7 {
} }
struct OperationFindBlockQ @0xaf4353ff004c7156 { struct OperationFindBlockQ @0xaf4353ff004c7156 {
blockId @0 :TypedKey; # hash of the block to locate blockId @0 :BlockId; # hash of the block to locate
} }
struct OperationFindBlockA @0xc51455bc4915465d { struct OperationFindBlockA @0xc51455bc4915465d {
data @0 :Data; # Optional: the actual block data if we have that block ourselves data @0 :Data; # Optional: the actual block data if we have that block ourselves
# null if we don't have a block to return # null if we don't have a block to return
suppliers @1 :List(PeerInfo); # returned list of suppliers if we have them suppliers @1 :List(RouteId); # returned list of supplier private route ids if we have them
peers @2 :List(PeerInfo); # returned 'closer peer' information peers @2 :List(PeerInfo); # returned 'closer peer' information
} }
@ -429,24 +437,24 @@ enum TunnelError @0xb82c6bfb1ec38c7c {
struct TunnelEndpoint @0xc2602aa983cc337d { struct TunnelEndpoint @0xc2602aa983cc337d {
mode @0 :TunnelEndpointMode; # what kind of endpoint this is mode @0 :TunnelEndpointMode; # what kind of endpoint this is
description @1 :Text; # endpoint description (TODO) description @1 :Data; # endpoint description (TODO)
} }
struct FullTunnel @0x9821c3dc75373f63 { struct FullTunnel @0x9821c3dc75373f63 {
id @0 :TunnelID; # tunnel id to use everywhere id @0 :TunnelId; # tunnel id to use everywhere
timeout @1 :UInt64; # duration from last data when this expires if no data is sent or received timeout @1 :UInt64; # duration from last data when this expires if no data is sent or received
local @2 :TunnelEndpoint; # local endpoint local @2 :TunnelEndpoint; # local endpoint
remote @3 :TunnelEndpoint; # remote endpoint remote @3 :TunnelEndpoint; # remote endpoint
} }
struct PartialTunnel @0x827a7ebc02be2fc8 { struct PartialTunnel @0x827a7ebc02be2fc8 {
id @0 :TunnelID; # tunnel id to use everywhere id @0 :TunnelId; # tunnel id to use everywhere
timeout @1 :UInt64; # timestamp when this expires if not completed timeout @1 :UInt64; # timestamp when this expires if not completed
local @2 :TunnelEndpoint; # local endpoint local @2 :TunnelEndpoint; # local endpoint
} }
struct OperationStartTunnelQ @0xa9c49afce44187af { struct OperationStartTunnelQ @0xa9c49afce44187af {
id @0 :TunnelID; # tunnel id to use everywhere id @0 :TunnelId; # tunnel id to use everywhere
localMode @1 :TunnelEndpointMode; # what kind of local endpoint mode is being requested localMode @1 :TunnelEndpointMode; # what kind of local endpoint mode is being requested
depth @2 :UInt8; # the number of nodes in the tunnel depth @2 :UInt8; # the number of nodes in the tunnel
} }
@ -459,7 +467,7 @@ struct OperationStartTunnelA @0x818162e4cc61bf1e {
} }
struct OperationCompleteTunnelQ @0xe978594588eb950b { struct OperationCompleteTunnelQ @0xe978594588eb950b {
id @0 :TunnelID; # tunnel id to use everywhere id @0 :TunnelId; # tunnel id to use everywhere
localMode @1 :TunnelEndpointMode; # what kind of local endpoint mode is being requested localMode @1 :TunnelEndpointMode; # what kind of local endpoint mode is being requested
depth @2 :UInt8; # the number of nodes in the tunnel depth @2 :UInt8; # the number of nodes in the tunnel
endpoint @3 :TunnelEndpoint; # the remote endpoint to complete endpoint @3 :TunnelEndpoint; # the remote endpoint to complete
@ -473,12 +481,12 @@ struct OperationCompleteTunnelA @0x84090791bb765f2a {
} }
struct OperationCancelTunnelQ @0xae2811ae0a003738 { struct OperationCancelTunnelQ @0xae2811ae0a003738 {
id @0 :TunnelID; # the tunnel id to cancel id @0 :TunnelId; # the tunnel id to cancel
} }
struct OperationCancelTunnelA @0xbba23c992eff97bc { struct OperationCancelTunnelA @0xbba23c992eff97bc {
union { union {
tunnel @0 :TunnelID; # the tunnel id that was cancelled tunnel @0 :TunnelId; # the tunnel id that was cancelled
error @1 :TunnelError; # if we couldn't cancel, why not error @1 :TunnelError; # if we couldn't cancel, why not
} }
} }
@ -501,6 +509,7 @@ struct Question @0xd8510bc33492ef70 {
watchValueQ @7 :OperationWatchValueQ; watchValueQ @7 :OperationWatchValueQ;
inspectValueQ @8 :OperationInspectValueQ; inspectValueQ @8 :OperationInspectValueQ;
# Blockstore operations
# #[cfg(feature="unstable-blockstore")] # #[cfg(feature="unstable-blockstore")]
# supplyBlockQ @9 :OperationSupplyBlockQ; # supplyBlockQ @9 :OperationSupplyBlockQ;
# findBlockQ @10 :OperationFindBlockQ; # findBlockQ @10 :OperationFindBlockQ;
@ -542,9 +551,10 @@ struct Answer @0xacacb8b6988c1058 {
watchValueA @5 :OperationWatchValueA; watchValueA @5 :OperationWatchValueA;
inspectValueA @6 :OperationInspectValueA; inspectValueA @6 :OperationInspectValueA;
# Blockstore operations
# #[cfg(feature="unstable-blockstore")] # #[cfg(feature="unstable-blockstore")]
#supplyBlockA @7 :OperationSupplyBlockA; # supplyBlockA @7 :OperationSupplyBlockA;
#findBlockA @8 :OperationFindBlockA; # findBlockA @8 :OperationFindBlockA;
# Tunnel operations # Tunnel operations
# #[cfg(feature="unstable-tunnels")] # #[cfg(feature="unstable-tunnels")]

File diff suppressed because it is too large Load diff

View file

@ -16,7 +16,6 @@ pub trait CryptoSystem {
// Generation // Generation
fn random_bytes(&self, len: u32) -> Vec<u8>; fn random_bytes(&self, len: u32) -> Vec<u8>;
fn default_salt_length(&self) -> u32;
fn hash_password(&self, password: &[u8], salt: &[u8]) -> VeilidAPIResult<String>; fn hash_password(&self, password: &[u8], salt: &[u8]) -> VeilidAPIResult<String>;
fn verify_password(&self, password: &[u8], password_hash: &str) -> VeilidAPIResult<bool>; fn verify_password(&self, password: &[u8], password_hash: &str) -> VeilidAPIResult<bool>;
fn derive_shared_secret( fn derive_shared_secret(
@ -38,9 +37,9 @@ pub trait CryptoSystem {
domain: &[u8], domain: &[u8],
) -> VeilidAPIResult<BareSharedSecret> { ) -> VeilidAPIResult<BareSharedSecret> {
let dh = self.compute_dh(key, secret)?; let dh = self.compute_dh(key, secret)?;
Ok(BareSharedSecret::from(self.generate_hash( Ok(BareSharedSecret::from(
&[&dh.bytes, domain, VEILID_DOMAIN_API].concat(), self.generate_hash(&[&dh, domain, VEILID_DOMAIN_API].concat()),
))) ))
} }
fn generate_keypair(&self) -> BareKeyPair; fn generate_keypair(&self) -> BareKeyPair;
fn generate_hash(&self, data: &[u8]) -> BareHashDigest; fn generate_hash(&self, data: &[u8]) -> BareHashDigest;
@ -50,6 +49,76 @@ pub trait CryptoSystem {
) -> VeilidAPIResult<BarePublicKey>; ) -> VeilidAPIResult<BarePublicKey>;
// Validation // Validation
fn shared_secret_length(&self) -> usize;
fn nonce_length(&self) -> usize;
fn hash_digest_length(&self) -> usize;
fn public_key_length(&self) -> usize;
fn secret_key_length(&self) -> usize;
fn signature_length(&self) -> usize;
fn default_salt_length(&self) -> usize;
fn aead_overhead(&self) -> usize;
fn check_shared_secret(&self, secret: &BareSharedSecret) -> VeilidAPIResult<()> {
if secret.len() != self.shared_secret_length() {
apibail_generic!(format!(
"invalid shared secret length: {} != {}",
secret.len(),
self.shared_secret_length()
));
}
Ok(())
}
fn check_nonce(&self, nonce: &BareNonce) -> VeilidAPIResult<()> {
if nonce.len() != self.nonce_length() {
apibail_generic!(format!(
"invalid nonce length: {} != {}",
nonce.len(),
self.nonce_length()
));
}
Ok(())
}
fn check_hash_digest(&self, hash: &BareHashDigest) -> VeilidAPIResult<()> {
if hash.len() != self.hash_digest_length() {
apibail_generic!(format!(
"invalid hash digest length: {} != {}",
hash.len(),
self.hash_digest_length()
));
}
Ok(())
}
fn check_public_key(&self, key: &BarePublicKey) -> VeilidAPIResult<()> {
if key.len() != self.public_key_length() {
apibail_generic!(format!(
"invalid public key length: {} != {}",
key.len(),
self.public_key_length()
));
}
Ok(())
}
fn check_secret_key(&self, key: &BareSecretKey) -> VeilidAPIResult<()> {
if key.len() != self.secret_key_length() {
apibail_generic!(format!(
"invalid secret key length: {} != {}",
key.len(),
self.secret_key_length()
));
}
Ok(())
}
fn check_signature(&self, signature: &BareSignature) -> VeilidAPIResult<()> {
if signature.len() != self.signature_length() {
apibail_generic!(format!(
"invalid signature length: {} != {}",
signature.len(),
self.signature_length()
));
}
Ok(())
}
fn validate_keypair(&self, key: &BarePublicKey, secret: &BareSecretKey) -> bool; fn validate_keypair(&self, key: &BarePublicKey, secret: &BareSecretKey) -> bool;
fn validate_hash(&self, data: &[u8], hash: &BareHashDigest) -> bool; fn validate_hash(&self, data: &[u8], hash: &BareHashDigest) -> bool;
fn validate_hash_reader( fn validate_hash_reader(
@ -76,7 +145,6 @@ pub trait CryptoSystem {
) -> VeilidAPIResult<bool>; ) -> VeilidAPIResult<bool>;
// AEAD Encrypt/Decrypt // AEAD Encrypt/Decrypt
fn aead_overhead(&self) -> usize;
fn decrypt_in_place_aead( fn decrypt_in_place_aead(
&self, &self,
body: &mut Vec<u8>, body: &mut Vec<u8>,
@ -112,24 +180,24 @@ pub trait CryptoSystem {
body: &mut [u8], body: &mut [u8],
nonce: &BareNonce, nonce: &BareNonce,
shared_secret: &BareSharedSecret, shared_secret: &BareSharedSecret,
); ) -> VeilidAPIResult<()>;
fn crypt_b2b_no_auth( fn crypt_b2b_no_auth(
&self, &self,
in_buf: &[u8], in_buf: &[u8],
out_buf: &mut [u8], out_buf: &mut [u8],
nonce: &BareNonce, nonce: &BareNonce,
shared_secret: &BareSharedSecret, shared_secret: &BareSharedSecret,
); ) -> VeilidAPIResult<()>;
fn crypt_no_auth_aligned_8( fn crypt_no_auth_aligned_8(
&self, &self,
body: &[u8], body: &[u8],
nonce: &BareNonce, nonce: &BareNonce,
shared_secret: &BareSharedSecret, shared_secret: &BareSharedSecret,
) -> Vec<u8>; ) -> VeilidAPIResult<Vec<u8>>;
fn crypt_no_auth_unaligned( fn crypt_no_auth_unaligned(
&self, &self,
body: &[u8], body: &[u8],
nonce: &BareNonce, nonce: &BareNonce,
shared_secret: &BareSharedSecret, shared_secret: &BareSharedSecret,
) -> Vec<u8>; ) -> VeilidAPIResult<Vec<u8>>;
} }

View file

@ -20,9 +20,9 @@ pub fn cache_to_bytes(cache: &DHCache) -> Vec<u8> {
let cnt: usize = cache.len(); let cnt: usize = cache.len();
let mut out: Vec<u8> = Vec::with_capacity(cnt * (32 + 32 + 32)); let mut out: Vec<u8> = Vec::with_capacity(cnt * (32 + 32 + 32));
for e in cache.iter() { for e in cache.iter() {
out.extend(&e.0.key.bytes); out.extend_from_slice(&e.0.key);
out.extend(&e.0.secret.bytes); out.extend_from_slice(&e.0.secret);
out.extend(&e.1.shared_secret.bytes); out.extend_from_slice(&e.1.shared_secret);
} }
let mut rev: Vec<u8> = Vec::with_capacity(out.len()); let mut rev: Vec<u8> = Vec::with_capacity(out.len());
for d in out.chunks(32 + 32 + 32).rev() { for d in out.chunks(32 + 32 + 32).rev() {

View file

@ -130,32 +130,33 @@ impl Envelope {
.into(); .into();
// Get nonce and sender node id // Get nonce and sender node id
let nonce_slice: [u8; NONCE_LENGTH] = data[0x12..0x2A] let mut nonce_slice: [u8; VLD0_NONCE_LENGTH] = data[0x12..0x2A]
.try_into() .try_into()
.map_err(VeilidAPIError::internal)?; .map_err(VeilidAPIError::internal)?;
let sender_id_slice: [u8; PUBLIC_KEY_LENGTH] = data[0x2A..0x4A] let mut sender_id_slice: [u8; VLD0_HASH_DIGEST_LENGTH] = data[0x2A..0x4A]
.try_into() .try_into()
.map_err(VeilidAPIError::internal)?; .map_err(VeilidAPIError::internal)?;
let recipient_id_slice: [u8; PUBLIC_KEY_LENGTH] = data[0x4A..0x6A] let mut recipient_id_slice: [u8; VLD0_HASH_DIGEST_LENGTH] = data[0x4A..0x6A]
.try_into() .try_into()
.map_err(VeilidAPIError::internal)?; .map_err(VeilidAPIError::internal)?;
let mut nonce: BareNonce = BareNonce::new(nonce_slice);
let mut sender_id = BareNodeId::new(sender_id_slice);
let mut recipient_id = BareNodeId::new(recipient_id_slice);
// Apply network key (not the best, but it will keep networks from colliding without much overhead) // Apply network key (not the best, but it will keep networks from colliding without much overhead)
if let Some(nk) = network_key.as_ref() { if let Some(nk) = network_key.as_ref() {
for n in 0..NONCE_LENGTH { for n in 0..VLD0_NONCE_LENGTH {
nonce.bytes[n] ^= nk.bytes[n]; nonce_slice[n] ^= nk[n];
} }
for n in 0..CRYPTO_KEY_LENGTH { for n in 0..VLD0_HASH_DIGEST_LENGTH {
sender_id.bytes[n] ^= nk.bytes[n]; sender_id_slice[n] ^= nk[n];
} }
for n in 0..CRYPTO_KEY_LENGTH { for n in 0..VLD0_HASH_DIGEST_LENGTH {
recipient_id.bytes[n] ^= nk.bytes[n]; recipient_id_slice[n] ^= nk[n];
} }
} }
let nonce: BareNonce = BareNonce::new(&nonce_slice);
let sender_id = BareNodeId::new(&sender_id_slice);
let recipient_id = BareNodeId::new(&recipient_id_slice);
// Ensure sender_id and recipient_id are not the same // Ensure sender_id and recipient_id are not the same
if sender_id == recipient_id { if sender_id == recipient_id {
apibail_parse_error!( apibail_parse_error!(
@ -173,7 +174,11 @@ impl Envelope {
// Validate signature // Validate signature
if !vcrypto if !vcrypto
.verify(&sender_id.into(), &data[0..(data.len() - 64)], &signature) .verify(
&sender_id.clone().into(),
&data[0..(data.len() - 64)],
&signature,
)
.map_err(VeilidAPIError::internal)? .map_err(VeilidAPIError::internal)?
{ {
apibail_parse_error!("signature verification of envelope failed", signature); apibail_parse_error!("signature verification of envelope failed", signature);
@ -202,17 +207,24 @@ impl Envelope {
let vcrypto = crypto let vcrypto = crypto
.get(self.crypto_kind) .get(self.crypto_kind)
.expect("need to ensure only valid crypto kinds here"); .expect("need to ensure only valid crypto kinds here");
let mut dh_secret = vcrypto.cached_dh(&self.sender_id.into(), node_id_secret)?; let mut dh_secret = vcrypto.cached_dh(&self.sender_id.clone().into(), node_id_secret)?;
// Apply network key // Apply network key
if let Some(nk) = network_key.as_ref() { if let Some(nk) = network_key.as_ref() {
for n in 0..CRYPTO_KEY_LENGTH { let mut dh_secret_bytes = dh_secret.to_vec();
dh_secret.bytes[n] ^= nk.bytes[n];
for n in 0..VLD0_SHARED_SECRET_LENGTH {
dh_secret_bytes[n] ^= nk[n];
} }
dh_secret = BareSharedSecret::new(&dh_secret_bytes);
} }
// Decrypt message without authentication // Decrypt message without authentication
let body = let body = vcrypto.crypt_no_auth_aligned_8(
vcrypto.crypt_no_auth_aligned_8(&data[0x6A..data.len() - 64], &self.nonce, &dh_secret); &data[0x6A..data.len() - 64],
&self.nonce,
&dh_secret,
)?;
// Decompress body // Decompress body
let body = decompress_size_prepended(&body, Some(MAX_ENVELOPE_SIZE))?; let body = decompress_size_prepended(&body, Some(MAX_ENVELOPE_SIZE))?;
@ -252,7 +264,7 @@ impl Envelope {
let vcrypto = crypto let vcrypto = crypto
.get(self.crypto_kind) .get(self.crypto_kind)
.expect("need to ensure only valid crypto kinds here"); .expect("need to ensure only valid crypto kinds here");
let mut dh_secret = vcrypto.cached_dh(&self.recipient_id.into(), node_id_secret)?; let mut dh_secret = vcrypto.cached_dh(&self.recipient_id.clone().into(), node_id_secret)?;
// Write envelope body // Write envelope body
let mut data = vec![0u8; envelope_size]; let mut data = vec![0u8; envelope_size];
@ -268,30 +280,34 @@ impl Envelope {
// Write timestamp // Write timestamp
data[0x0A..0x12].copy_from_slice(&self.timestamp.as_u64().to_le_bytes()); data[0x0A..0x12].copy_from_slice(&self.timestamp.as_u64().to_le_bytes());
// Write nonce // Write nonce
data[0x12..0x2A].copy_from_slice(&self.nonce.bytes); data[0x12..0x2A].copy_from_slice(&self.nonce);
// Write sender node id // Write sender node id
data[0x2A..0x4A].copy_from_slice(&self.sender_id.bytes); data[0x2A..0x4A].copy_from_slice(&self.sender_id);
// Write recipient node id // Write recipient node id
data[0x4A..0x6A].copy_from_slice(&self.recipient_id.bytes); data[0x4A..0x6A].copy_from_slice(&self.recipient_id);
// Apply network key (not the best, but it will keep networks from colliding without much overhead) // Apply network key (not the best, but it will keep networks from colliding without much overhead)
if let Some(nk) = network_key.as_ref() { if let Some(nk) = network_key.as_ref() {
for n in 0..SECRET_KEY_LENGTH { let mut dh_secret_bytes = dh_secret.to_vec();
dh_secret.bytes[n] ^= nk.bytes[n];
for n in 0..VLD0_SHARED_SECRET_LENGTH {
dh_secret_bytes[n] ^= nk[n];
} }
for n in 0..NONCE_LENGTH { for n in 0..VLD0_NONCE_LENGTH {
data[0x12 + n] ^= nk.bytes[n]; data[0x12 + n] ^= nk[n];
} }
for n in 0..CRYPTO_KEY_LENGTH { for n in 0..VLD0_HASH_DIGEST_LENGTH {
data[0x2A + n] ^= nk.bytes[n]; data[0x2A + n] ^= nk[n];
} }
for n in 0..CRYPTO_KEY_LENGTH { for n in 0..VLD0_HASH_DIGEST_LENGTH {
data[0x4A + n] ^= nk.bytes[n]; data[0x4A + n] ^= nk[n];
} }
dh_secret = BareSharedSecret::new(&dh_secret_bytes);
} }
// Encrypt message // Encrypt message
let encrypted_body = vcrypto.crypt_no_auth_unaligned(&body, &self.nonce, &dh_secret); let encrypted_body = vcrypto.crypt_no_auth_unaligned(&body, &self.nonce, &dh_secret)?;
// Write body // Write body
if !encrypted_body.is_empty() { if !encrypted_body.is_empty() {
@ -300,13 +316,13 @@ impl Envelope {
// Sign the envelope // Sign the envelope
let signature = vcrypto.sign( let signature = vcrypto.sign(
&self.sender_id.into(), &self.sender_id.clone().into(),
node_id_secret, node_id_secret,
&data[0..(envelope_size - 64)], &data[0..(envelope_size - 64)],
)?; )?;
// Append the signature // Append the signature
data[(envelope_size - 64)..].copy_from_slice(&signature.bytes); data[(envelope_size - 64)..].copy_from_slice(&signature);
Ok(data) Ok(data)
} }
@ -326,24 +342,24 @@ impl Envelope {
#[expect(dead_code)] #[expect(dead_code)]
pub fn get_nonce(&self) -> BareNonce { pub fn get_nonce(&self) -> BareNonce {
self.nonce self.nonce.clone()
} }
#[expect(dead_code)] #[expect(dead_code)]
pub fn get_sender_id(&self) -> BareNodeId { pub fn get_bare_sender_id(&self) -> BareNodeId {
self.sender_id self.sender_id.clone()
} }
pub fn get_sender_typed_id(&self) -> NodeId { pub fn get_sender_id(&self) -> NodeId {
NodeId::new(self.crypto_kind, self.sender_id) NodeId::new(self.crypto_kind, self.sender_id.clone())
} }
#[expect(dead_code)] #[expect(dead_code)]
pub fn get_recipient_id(&self) -> BareNodeId { pub fn get_bare_recipient_id(&self) -> BareNodeId {
self.recipient_id self.recipient_id.clone()
} }
pub fn get_recipient_typed_id(&self) -> NodeId { pub fn get_recipient_id(&self) -> NodeId {
NodeId::new(self.crypto_kind, self.recipient_id) NodeId::new(self.crypto_kind, self.recipient_id.clone())
} }
} }

View file

@ -62,10 +62,7 @@ impl AsyncCryptoSystemGuard<'_> {
pub async fn random_bytes(&self, len: u32) -> Vec<u8> { pub async fn random_bytes(&self, len: u32) -> Vec<u8> {
yielding(|| self.guard.random_bytes(len)).await yielding(|| self.guard.random_bytes(len)).await
} }
#[must_use]
pub fn default_salt_length(&self) -> u32 {
self.guard.default_salt_length()
}
pub async fn hash_password(&self, password: &[u8], salt: &[u8]) -> VeilidAPIResult<String> { pub async fn hash_password(&self, password: &[u8], salt: &[u8]) -> VeilidAPIResult<String> {
yielding(|| self.guard.hash_password(password, salt)).await yielding(|| self.guard.hash_password(password, salt)).await
} }
@ -104,7 +101,7 @@ impl AsyncCryptoSystemGuard<'_> {
) -> VeilidAPIResult<BareSharedSecret> { ) -> VeilidAPIResult<BareSharedSecret> {
let dh = self.compute_dh(key, secret).await?; let dh = self.compute_dh(key, secret).await?;
Ok(BareSharedSecret::from( Ok(BareSharedSecret::from(
self.generate_hash(&[&dh.bytes, domain, VEILID_DOMAIN_API].concat()) self.generate_hash(&[&dh, domain, VEILID_DOMAIN_API].concat())
.await, .await,
)) ))
} }
@ -125,6 +122,56 @@ impl AsyncCryptoSystemGuard<'_> {
} }
// Validation // Validation
#[must_use]
pub fn shared_secret_length(&self) -> usize {
self.guard.shared_secret_length()
}
#[must_use]
pub fn nonce_length(&self) -> usize {
self.guard.nonce_length()
}
#[must_use]
pub fn hash_digest_length(&self) -> usize {
self.guard.hash_digest_length()
}
#[must_use]
pub fn public_key_length(&self) -> usize {
self.guard.public_key_length()
}
#[must_use]
pub fn secret_key_length(&self) -> usize {
self.guard.secret_key_length()
}
#[must_use]
pub fn signature_length(&self) -> usize {
self.guard.signature_length()
}
#[must_use]
pub fn aead_overhead(&self) -> usize {
self.guard.aead_overhead()
}
#[must_use]
pub fn default_salt_length(&self) -> usize {
self.guard.default_salt_length()
}
pub fn check_shared_secret(&self, secret: &BareSharedSecret) -> VeilidAPIResult<()> {
self.guard.check_shared_secret(secret)
}
pub fn check_nonce(&self, nonce: &BareNonce) -> VeilidAPIResult<()> {
self.guard.check_nonce(nonce)
}
pub fn check_hash_digest(&self, hash: &BareHashDigest) -> VeilidAPIResult<()> {
self.guard.check_hash_digest(hash)
}
pub fn check_public_key(&self, key: &BarePublicKey) -> VeilidAPIResult<()> {
self.guard.check_public_key(key)
}
pub fn check_secret_key(&self, key: &BareSecretKey) -> VeilidAPIResult<()> {
self.guard.check_secret_key(key)
}
pub fn check_signature(&self, signature: &BareSignature) -> VeilidAPIResult<()> {
self.guard.check_signature(signature)
}
pub async fn validate_keypair(&self, key: &BarePublicKey, secret: &BareSecretKey) -> bool { pub async fn validate_keypair(&self, key: &BarePublicKey, secret: &BareSecretKey) -> bool {
yielding(|| self.guard.validate_keypair(key, secret)).await yielding(|| self.guard.validate_keypair(key, secret)).await
} }
@ -165,11 +212,6 @@ impl AsyncCryptoSystemGuard<'_> {
} }
// AEAD Encrypt/Decrypt // AEAD Encrypt/Decrypt
#[must_use]
pub fn aead_overhead(&self) -> usize {
self.guard.aead_overhead()
}
pub async fn decrypt_in_place_aead( pub async fn decrypt_in_place_aead(
&self, &self,
body: &mut Vec<u8>, body: &mut Vec<u8>,
@ -232,7 +274,7 @@ impl AsyncCryptoSystemGuard<'_> {
body: &mut [u8], body: &mut [u8],
nonce: &BareNonce, nonce: &BareNonce,
shared_secret: &BareSharedSecret, shared_secret: &BareSharedSecret,
) { ) -> VeilidAPIResult<()> {
yielding(|| { yielding(|| {
self.guard self.guard
.crypt_in_place_no_auth(body, nonce, shared_secret) .crypt_in_place_no_auth(body, nonce, shared_secret)
@ -246,7 +288,7 @@ impl AsyncCryptoSystemGuard<'_> {
out_buf: &mut [u8], out_buf: &mut [u8],
nonce: &BareNonce, nonce: &BareNonce,
shared_secret: &BareSharedSecret, shared_secret: &BareSharedSecret,
) { ) -> VeilidAPIResult<()> {
yielding(|| { yielding(|| {
self.guard self.guard
.crypt_b2b_no_auth(in_buf, out_buf, nonce, shared_secret) .crypt_b2b_no_auth(in_buf, out_buf, nonce, shared_secret)
@ -259,7 +301,7 @@ impl AsyncCryptoSystemGuard<'_> {
body: &[u8], body: &[u8],
nonce: &BareNonce, nonce: &BareNonce,
shared_secret: &BareSharedSecret, shared_secret: &BareSharedSecret,
) -> Vec<u8> { ) -> VeilidAPIResult<Vec<u8>> {
yielding(|| { yielding(|| {
self.guard self.guard
.crypt_no_auth_aligned_8(body, nonce, shared_secret) .crypt_no_auth_aligned_8(body, nonce, shared_secret)
@ -272,7 +314,7 @@ impl AsyncCryptoSystemGuard<'_> {
body: &[u8], body: &[u8],
nonce: &BareNonce, nonce: &BareNonce,
shared_secret: &BareSharedSecret, shared_secret: &BareSharedSecret,
) -> Vec<u8> { ) -> VeilidAPIResult<Vec<u8>> {
yielding(|| { yielding(|| {
self.guard self.guard
.crypt_no_auth_unaligned(body, nonce, shared_secret) .crypt_no_auth_unaligned(body, nonce, shared_secret)

View file

@ -8,6 +8,7 @@ mod types;
pub mod crypto_system; pub mod crypto_system;
#[cfg(feature = "enable-crypto-none")] #[cfg(feature = "enable-crypto-none")]
pub(crate) mod none; pub(crate) mod none;
#[doc(hidden)] #[doc(hidden)]
pub mod tests; pub mod tests;
#[cfg(feature = "enable-crypto-vld0")] #[cfg(feature = "enable-crypto-vld0")]
@ -22,11 +23,11 @@ pub(crate) use receipt::*;
pub use types::*; pub use types::*;
#[cfg(feature = "enable-crypto-none")] #[cfg(feature = "enable-crypto-none")]
pub use none::CRYPTO_KIND_NONE; pub use none::sizes::*;
#[cfg(feature = "enable-crypto-none")] #[cfg(feature = "enable-crypto-none")]
pub(crate) use none::*; pub(crate) use none::*;
#[cfg(feature = "enable-crypto-vld0")] #[cfg(feature = "enable-crypto-vld0")]
pub use vld0::CRYPTO_KIND_VLD0; pub use vld0::sizes::*;
#[cfg(feature = "enable-crypto-vld0")] #[cfg(feature = "enable-crypto-vld0")]
pub(crate) use vld0::*; pub(crate) use vld0::*;
@ -70,6 +71,7 @@ pub type EnvelopeVersion = u8;
pub const VALID_ENVELOPE_VERSIONS: [EnvelopeVersion; 1] = [0u8]; pub const VALID_ENVELOPE_VERSIONS: [EnvelopeVersion; 1] = [0u8];
/// Number of envelope versions to keep on structures if many are present beyond the ones we consider valid /// Number of envelope versions to keep on structures if many are present beyond the ones we consider valid
pub const MAX_ENVELOPE_VERSIONS: usize = 3; pub const MAX_ENVELOPE_VERSIONS: usize = 3;
/// Return the best envelope version we support /// Return the best envelope version we support
#[must_use] #[must_use]
pub fn best_envelope_version() -> EnvelopeVersion { pub fn best_envelope_version() -> EnvelopeVersion {
@ -154,7 +156,7 @@ impl Crypto {
self.config().with(|c| { self.config().with(|c| {
for ck in VALID_CRYPTO_KINDS { for ck in VALID_CRYPTO_KINDS {
if let Some(nid) = c.network.routing_table.node_id.get(ck) { if let Some(nid) = c.network.routing_table.node_id.get(ck) {
cache_validity_key.append(&mut nid.value.bytes.to_vec()); cache_validity_key.extend_from_slice(nid.ref_value());
} }
} }
}); });
@ -270,12 +272,12 @@ impl Crypto {
let mut out = PublicKeyGroup::with_capacity(public_keys.len()); let mut out = PublicKeyGroup::with_capacity(public_keys.len());
for sig in typed_signatures { for sig in typed_signatures {
for nid in public_keys { for nid in public_keys {
if nid.kind == sig.kind { if nid.kind() == sig.kind() {
if let Some(vcrypto) = self.get(sig.kind) { if let Some(vcrypto) = self.get(sig.kind()) {
if !vcrypto.verify(&nid.value, data, &sig.value)? { if !vcrypto.verify(nid.ref_value(), data, sig.ref_value())? {
return Ok(None); return Ok(None);
} }
out.add(*nid); out.add(nid.clone());
} }
} }
} }
@ -297,8 +299,9 @@ impl Crypto {
{ {
let mut out = Vec::<R>::with_capacity(typed_key_pairs.len()); let mut out = Vec::<R>::with_capacity(typed_key_pairs.len());
for kp in typed_key_pairs { for kp in typed_key_pairs {
if let Some(vcrypto) = self.get(kp.kind) { if let Some(vcrypto) = self.get(kp.kind()) {
let sig = vcrypto.sign(&kp.value.key, &kp.value.secret, data)?; let sig =
vcrypto.sign(kp.ref_value().ref_key(), kp.ref_value().ref_secret(), data)?;
out.push(transform(kp, sig)) out.push(transform(kp, sig))
} }
} }
@ -331,13 +334,15 @@ impl Crypto {
) -> VeilidAPIResult<BareSharedSecret> { ) -> VeilidAPIResult<BareSharedSecret> {
Ok( Ok(
match self.inner.lock().dh_cache.entry(DHCacheKey { match self.inner.lock().dh_cache.entry(DHCacheKey {
key: *key, key: key.clone(),
secret: *secret, secret: secret.clone(),
}) { }) {
Entry::Occupied(e) => e.get().shared_secret, Entry::Occupied(e) => e.get().shared_secret.clone(),
Entry::Vacant(e) => { Entry::Vacant(e) => {
let shared_secret = vcrypto.compute_dh(key, secret)?; let shared_secret = vcrypto.compute_dh(key, secret)?;
e.insert(DHCacheValue { shared_secret }); e.insert(DHCacheValue {
shared_secret: shared_secret.clone(),
});
shared_secret shared_secret
} }
}, },
@ -404,7 +409,7 @@ impl Crypto {
if let (Some(node_id), Some(node_id_secret)) = (node_id, node_id_secret) { if let (Some(node_id), Some(node_id_secret)) = (node_id, node_id_secret) {
// Validate node id // Validate node id
if !vcrypto if !vcrypto
.validate_keypair(&node_id.value.into(), &node_id_secret.value) .validate_keypair(&node_id.value().into(), &node_id_secret.value())
.await .await
{ {
apibail_generic!(format!( apibail_generic!(format!(
@ -418,8 +423,8 @@ impl Crypto {
veilid_log!(self debug "generating new node_id_{}", ck); veilid_log!(self debug "generating new node_id_{}", ck);
let kp = vcrypto.generate_keypair().await; let kp = vcrypto.generate_keypair().await;
( (
NodeId::new(ck, kp.key.into()), NodeId::new(ck, kp.key().into()),
SecretKey::new(ck, kp.secret), SecretKey::new(ck, kp.secret()),
) )
}; };
veilid_log!(self info "Node Id: {}", node_id); veilid_log!(self info "Node Id: {}", node_id);
@ -451,8 +456,8 @@ impl Crypto {
let (node_id, node_id_secret) = { let (node_id, node_id_secret) = {
let kp = vcrypto.generate_keypair().await; let kp = vcrypto.generate_keypair().await;
( (
NodeId::new(ck, kp.key.into()), NodeId::new(ck, kp.key().into()),
SecretKey::new(ck, kp.secret), SecretKey::new(ck, kp.secret()),
) )
}; };
#[cfg(not(test))] #[cfg(not(test))]

View file

@ -1,51 +1,72 @@
pub mod sizes;
use super::*; use super::*;
use argon2::password_hash::Salt; use argon2::password_hash::Salt;
use data_encoding::BASE64URL_NOPAD; use data_encoding::BASE64URL_NOPAD;
use digest::rand_core::RngCore; use digest::rand_core::RngCore;
use digest::Digest; use digest::Digest;
const AEAD_OVERHEAD: usize = PUBLIC_KEY_LENGTH; const NONE_AEAD_OVERHEAD: usize = NONE_PUBLIC_KEY_LENGTH;
pub const CRYPTO_KIND_NONE: CryptoKind = CryptoKind(*b"NONE"); pub const CRYPTO_KIND_NONE: CryptoKind = CryptoKind(*b"NONE");
pub use sizes::*;
pub fn none_generate_keypair() -> BareKeyPair { pub fn none_generate_keypair() -> BareKeyPair {
let mut csprng = VeilidRng {}; let mut csprng = VeilidRng {};
let mut pub_bytes = [0u8; PUBLIC_KEY_LENGTH]; let mut pub_bytes = [0u8; NONE_PUBLIC_KEY_LENGTH];
let mut sec_bytes = [0u8; SECRET_KEY_LENGTH]; let mut sec_bytes = [0u8; NONE_SECRET_KEY_LENGTH];
csprng.fill_bytes(&mut pub_bytes); csprng.fill_bytes(&mut pub_bytes);
for n in 0..PUBLIC_KEY_LENGTH { for n in 0..NONE_PUBLIC_KEY_LENGTH {
sec_bytes[n] = !pub_bytes[n]; sec_bytes[n] = !pub_bytes[n];
} }
let dht_key = BarePublicKey::new(pub_bytes); let dht_key = BarePublicKey::new(&pub_bytes);
let dht_key_secret = BareSecretKey::new(sec_bytes); let dht_key_secret = BareSecretKey::new(&sec_bytes);
BareKeyPair::new(dht_key, dht_key_secret) BareKeyPair::new(dht_key, dht_key_secret)
} }
fn do_xor_32(a: &[u8], b: &[u8]) -> [u8; 32] { fn do_xor_32(a: &[u8], b: &[u8]) -> VeilidAPIResult<[u8; 32]> {
if a.len() != 32 || b.len() != 32 {
apibail_generic!("wrong key length");
}
let mut out = [0u8; 32]; let mut out = [0u8; 32];
for n in 0..32 { for n in 0..32 {
out[n] = a[n] ^ b[n]; out[n] = a[n] ^ b[n];
} }
out Ok(out)
} }
fn do_xor_inplace(a: &mut [u8], key: &[u8]) { fn do_xor_inplace(a: &mut [u8], key: &[u8]) -> VeilidAPIResult<()> {
if a.len() != 32 || key.is_empty() {
apibail_generic!("wrong key length");
}
for n in 0..a.len() { for n in 0..a.len() {
a[n] ^= key[n % key.len()]; a[n] ^= key[n % key.len()];
} }
Ok(())
} }
fn do_xor_b2b(a: &[u8], b: &mut [u8], key: &[u8]) { fn do_xor_b2b(a: &[u8], b: &mut [u8], key: &[u8]) -> VeilidAPIResult<()> {
if a.len() != 32 || b.len() != 32 || key.is_empty() {
apibail_generic!("wrong key length");
}
for n in 0..a.len() { for n in 0..a.len() {
b[n] = a[n] ^ key[n % key.len()]; b[n] = a[n] ^ key[n % key.len()];
} }
Ok(())
} }
fn is_bytes_eq_32(a: &[u8], v: u8) -> bool { fn is_bytes_eq_32(a: &[u8], v: u8) -> VeilidAPIResult<bool> {
if a.len() != 32 {
apibail_generic!("wrong key length");
}
for n in 0..32 { for n in 0..32 {
if a[n] != v { if a[n] != v {
return false; return Ok(false);
} }
} }
true Ok(true)
} }
/// None CryptoSystem /// None CryptoSystem
@ -86,9 +107,6 @@ impl CryptoSystem for CryptoSystemNONE {
random_bytes(bytes.as_mut()); random_bytes(bytes.as_mut());
bytes bytes
} }
fn default_salt_length(&self) -> u32 {
4
}
fn hash_password(&self, password: &[u8], salt: &[u8]) -> VeilidAPIResult<String> { fn hash_password(&self, password: &[u8], salt: &[u8]) -> VeilidAPIResult<String> {
if salt.len() < Salt::MIN_LENGTH || salt.len() > Salt::MAX_LENGTH { if salt.len() < Salt::MIN_LENGTH || salt.len() > Salt::MAX_LENGTH {
apibail_generic!("invalid salt length"); apibail_generic!("invalid salt length");
@ -106,7 +124,7 @@ impl CryptoSystem for CryptoSystemNONE {
let Ok(salt) = BASE64URL_NOPAD.decode(salt.as_bytes()) else { let Ok(salt) = BASE64URL_NOPAD.decode(salt.as_bytes()) else {
apibail_generic!("invalid salt"); apibail_generic!("invalid salt");
}; };
return Ok(&self.hash_password(password, &salt)? == password_hash); Ok(self.hash_password(password, &salt)? == password_hash)
} }
fn derive_shared_secret( fn derive_shared_secret(
@ -118,33 +136,33 @@ impl CryptoSystem for CryptoSystemNONE {
apibail_generic!("invalid salt length"); apibail_generic!("invalid salt length");
} }
Ok(BareSharedSecret::new( Ok(BareSharedSecret::new(
*blake3::hash(self.hash_password(password, salt)?.as_bytes()).as_bytes(), blake3::hash(self.hash_password(password, salt)?.as_bytes()).as_bytes(),
)) ))
} }
fn random_nonce(&self) -> BareNonce { fn random_nonce(&self) -> BareNonce {
let mut nonce = [0u8; NONCE_LENGTH]; let mut nonce = [0u8; NONE_NONCE_LENGTH];
random_bytes(&mut nonce); random_bytes(&mut nonce);
BareNonce::new(nonce) BareNonce::new(&nonce)
} }
fn random_shared_secret(&self) -> BareSharedSecret { fn random_shared_secret(&self) -> BareSharedSecret {
let mut s = [0u8; SHARED_SECRET_LENGTH]; let mut s = [0u8; NONE_SHARED_SECRET_LENGTH];
random_bytes(&mut s); random_bytes(&mut s);
BareSharedSecret::new(s) BareSharedSecret::new(&s)
} }
fn compute_dh( fn compute_dh(
&self, &self,
key: &BarePublicKey, key: &BarePublicKey,
secret: &BareSecretKey, secret: &BareSecretKey,
) -> VeilidAPIResult<BareSharedSecret> { ) -> VeilidAPIResult<BareSharedSecret> {
let s = do_xor_32(&key.bytes, &secret.bytes); let s = do_xor_32(key, secret)?;
Ok(BareSharedSecret::new(s)) Ok(BareSharedSecret::new(&s))
} }
fn generate_keypair(&self) -> BareKeyPair { fn generate_keypair(&self) -> BareKeyPair {
none_generate_keypair() none_generate_keypair()
} }
fn generate_hash(&self, data: &[u8]) -> BareHashDigest { fn generate_hash(&self, data: &[u8]) -> BareHashDigest {
BareHashDigest::new(*blake3::hash(data).as_bytes()) BareHashDigest::new(blake3::hash(data).as_bytes())
} }
fn generate_hash_reader( fn generate_hash_reader(
&self, &self,
@ -152,10 +170,35 @@ impl CryptoSystem for CryptoSystemNONE {
) -> VeilidAPIResult<BarePublicKey> { ) -> VeilidAPIResult<BarePublicKey> {
let mut hasher = blake3::Hasher::new(); let mut hasher = blake3::Hasher::new();
std::io::copy(reader, &mut hasher).map_err(VeilidAPIError::generic)?; std::io::copy(reader, &mut hasher).map_err(VeilidAPIError::generic)?;
Ok(BarePublicKey::new(*hasher.finalize().as_bytes())) Ok(BarePublicKey::new(hasher.finalize().as_bytes()))
} }
// Validation // Validation
fn default_salt_length(&self) -> usize {
4
}
fn shared_secret_length(&self) -> usize {
NONE_SHARED_SECRET_LENGTH
}
fn nonce_length(&self) -> usize {
NONE_NONCE_LENGTH
}
fn hash_digest_length(&self) -> usize {
NONE_HASH_DIGEST_LENGTH
}
fn aead_overhead(&self) -> usize {
NONE_AEAD_OVERHEAD
}
fn public_key_length(&self) -> usize {
NONE_PUBLIC_KEY_LENGTH
}
fn secret_key_length(&self) -> usize {
NONE_SECRET_KEY_LENGTH
}
fn signature_length(&self) -> usize {
NONE_SIGNATURE_LENGTH
}
fn validate_keypair(&self, dht_key: &BarePublicKey, dht_key_secret: &BareSecretKey) -> bool { fn validate_keypair(&self, dht_key: &BarePublicKey, dht_key_secret: &BareSecretKey) -> bool {
let data = vec![0u8; 512]; let data = vec![0u8; 512];
let Ok(sig) = self.sign(dht_key, dht_key_secret, &data) else { let Ok(sig) = self.sign(dht_key, dht_key_secret, &data) else {
@ -168,7 +211,7 @@ impl CryptoSystem for CryptoSystemNONE {
} }
fn validate_hash(&self, data: &[u8], dht_key: &BareHashDigest) -> bool { fn validate_hash(&self, data: &[u8], dht_key: &BareHashDigest) -> bool {
let bytes = *blake3::hash(data).as_bytes(); let bytes = *blake3::hash(data).as_bytes();
bytes == dht_key.bytes bytes == dht_key.bytes()
} }
fn validate_hash_reader( fn validate_hash_reader(
&self, &self,
@ -178,17 +221,17 @@ impl CryptoSystem for CryptoSystemNONE {
let mut hasher = blake3::Hasher::new(); let mut hasher = blake3::Hasher::new();
std::io::copy(reader, &mut hasher).map_err(VeilidAPIError::generic)?; std::io::copy(reader, &mut hasher).map_err(VeilidAPIError::generic)?;
let bytes = *hasher.finalize().as_bytes(); let bytes = *hasher.finalize().as_bytes();
Ok(bytes == dht_key.bytes) Ok(bytes == dht_key.bytes())
} }
// Distance Metric // Distance Metric
fn distance(&self, key1: &BareHashDigest, key2: &BareHashDigest) -> BareHashDistance { fn distance(&self, key1: &BareHashDigest, key2: &BareHashDigest) -> BareHashDistance {
let mut bytes = [0u8; HASH_DIGEST_LENGTH]; let mut bytes = [0u8; NONE_HASH_DIGEST_LENGTH];
for (n, byte) in bytes.iter_mut().enumerate() { for (n, byte) in bytes.iter_mut().enumerate() {
*byte = key1.bytes[n] ^ key2.bytes[n]; *byte = key1[n] ^ key2[n];
} }
BareHashDistance::new(bytes) BareHashDistance::new(&bytes)
} }
// Authentication // Authentication
@ -198,7 +241,7 @@ impl CryptoSystem for CryptoSystemNONE {
dht_key_secret: &BareSecretKey, dht_key_secret: &BareSecretKey,
data: &[u8], data: &[u8],
) -> VeilidAPIResult<BareSignature> { ) -> VeilidAPIResult<BareSignature> {
if !is_bytes_eq_32(&do_xor_32(&dht_key.bytes, &dht_key_secret.bytes), 0xFFu8) { if !is_bytes_eq_32(&do_xor_32(dht_key, dht_key_secret)?, 0xFFu8)? {
return Err(VeilidAPIError::parse_error( return Err(VeilidAPIError::parse_error(
"Keypair is invalid", "Keypair is invalid",
"invalid keys", "invalid keys",
@ -208,14 +251,15 @@ impl CryptoSystem for CryptoSystemNONE {
let mut dig = Blake3Digest512::new(); let mut dig = Blake3Digest512::new();
dig.update(data); dig.update(data);
let sig = dig.finalize(); let sig = dig.finalize();
let in_sig_bytes: [u8; SIGNATURE_LENGTH] = sig.into(); let in_sig_bytes: [u8; NONE_SIGNATURE_LENGTH] = sig.into();
let mut sig_bytes = [0u8; SIGNATURE_LENGTH]; let mut sig_bytes = [0u8; NONE_SIGNATURE_LENGTH];
sig_bytes[0..32].copy_from_slice(&in_sig_bytes[0..32]); sig_bytes[0..32].copy_from_slice(&in_sig_bytes[0..32]);
sig_bytes[32..64].copy_from_slice(&do_xor_32(&in_sig_bytes[32..64], &dht_key_secret.bytes)); sig_bytes[32..64].copy_from_slice(&do_xor_32(&in_sig_bytes[32..64], dht_key_secret)?);
let dht_sig = BareSignature::new(sig_bytes.into()); let dht_sig = BareSignature::new(&sig_bytes);
println!("DEBUG dht_sig: {:?}", dht_sig); println!("DEBUG dht_sig: {:?}", dht_sig);
Ok(dht_sig) Ok(dht_sig)
} }
fn verify( fn verify(
&self, &self,
dht_key: &BarePublicKey, dht_key: &BarePublicKey,
@ -225,27 +269,23 @@ impl CryptoSystem for CryptoSystemNONE {
let mut dig = Blake3Digest512::new(); let mut dig = Blake3Digest512::new();
dig.update(data); dig.update(data);
let sig = dig.finalize(); let sig = dig.finalize();
let in_sig_bytes: [u8; SIGNATURE_LENGTH] = sig.into(); let in_sig_bytes: [u8; NONE_SIGNATURE_LENGTH] = sig.into();
let mut verify_bytes = [0u8; SIGNATURE_LENGTH]; let mut verify_bytes = [0u8; NONE_SIGNATURE_LENGTH];
verify_bytes[0..32] verify_bytes[0..32].copy_from_slice(&do_xor_32(&in_sig_bytes[0..32], &signature[0..32])?);
.copy_from_slice(&do_xor_32(&in_sig_bytes[0..32], &signature.bytes[0..32]));
verify_bytes[32..64] verify_bytes[32..64]
.copy_from_slice(&do_xor_32(&in_sig_bytes[32..64], &signature.bytes[32..64])); .copy_from_slice(&do_xor_32(&in_sig_bytes[32..64], &signature[32..64])?);
if !is_bytes_eq_32(&verify_bytes[0..32], 0u8) { if !is_bytes_eq_32(&verify_bytes[0..32], 0u8)? {
return Ok(false); return Ok(false);
} }
if !is_bytes_eq_32(&do_xor_32(&verify_bytes[32..64], &dht_key.bytes), 0xFFu8) { if !is_bytes_eq_32(&do_xor_32(&verify_bytes[32..64], dht_key)?, 0xFFu8)? {
return Ok(false); return Ok(false);
} }
return Ok(true); Ok(true)
} }
// AEAD Encrypt/Decrypt // AEAD Encrypt/Decrypt
fn aead_overhead(&self) -> usize {
AEAD_OVERHEAD
}
fn decrypt_in_place_aead( fn decrypt_in_place_aead(
&self, &self,
body: &mut Vec<u8>, body: &mut Vec<u8>,
@ -253,19 +293,18 @@ impl CryptoSystem for CryptoSystemNONE {
shared_secret: &BareSharedSecret, shared_secret: &BareSharedSecret,
_associated_data: Option<&[u8]>, _associated_data: Option<&[u8]>,
) -> VeilidAPIResult<()> { ) -> VeilidAPIResult<()> {
let mut blob = nonce.bytes.to_vec(); let mut blob = nonce.to_vec();
blob.extend_from_slice(&[0u8; 8]); blob.extend_from_slice(&[0u8; 8]);
let blob = do_xor_32(&blob, &shared_secret.bytes); let blob = do_xor_32(&blob, shared_secret)?;
if body.len() < AEAD_OVERHEAD { if body.len() < NONE_AEAD_OVERHEAD {
return Err(VeilidAPIError::generic("invalid length")); return Err(VeilidAPIError::generic("invalid length"));
} }
if &body[body.len() - AEAD_OVERHEAD..] != &blob { if body[body.len() - NONE_AEAD_OVERHEAD..] != blob {
return Err(VeilidAPIError::generic("invalid keyblob")); return Err(VeilidAPIError::generic("invalid keyblob"));
} }
body.truncate(body.len() - AEAD_OVERHEAD); body.truncate(body.len() - NONE_AEAD_OVERHEAD);
do_xor_inplace(body, &blob); do_xor_inplace(body, &blob)
Ok(())
} }
fn decrypt_aead( fn decrypt_aead(
@ -289,10 +328,10 @@ impl CryptoSystem for CryptoSystemNONE {
shared_secret: &BareSharedSecret, shared_secret: &BareSharedSecret,
_associated_data: Option<&[u8]>, _associated_data: Option<&[u8]>,
) -> VeilidAPIResult<()> { ) -> VeilidAPIResult<()> {
let mut blob = nonce.bytes.to_vec(); let mut blob = nonce.to_vec();
blob.extend_from_slice(&[0u8; 8]); blob.extend_from_slice(&[0u8; 8]);
let blob = do_xor_32(&blob, &shared_secret.bytes); let blob = do_xor_32(&blob, shared_secret)?;
do_xor_inplace(body, &blob); do_xor_inplace(body, &blob)?;
body.append(&mut blob.to_vec()); body.append(&mut blob.to_vec());
Ok(()) Ok(())
} }
@ -317,11 +356,11 @@ impl CryptoSystem for CryptoSystemNONE {
body: &mut [u8], body: &mut [u8],
nonce: &BareNonce, nonce: &BareNonce,
shared_secret: &BareSharedSecret, shared_secret: &BareSharedSecret,
) { ) -> VeilidAPIResult<()> {
let mut blob = nonce.bytes.to_vec(); let mut blob = nonce.to_vec();
blob.extend_from_slice(&[0u8; 8]); blob.extend_from_slice(&[0u8; 8]);
let blob = do_xor_32(&blob, &shared_secret.bytes); let blob = do_xor_32(&blob, shared_secret)?;
do_xor_inplace(body, &blob); do_xor_inplace(body, &blob)
} }
fn crypt_b2b_no_auth( fn crypt_b2b_no_auth(
@ -330,11 +369,11 @@ impl CryptoSystem for CryptoSystemNONE {
out_buf: &mut [u8], out_buf: &mut [u8],
nonce: &BareNonce, nonce: &BareNonce,
shared_secret: &BareSharedSecret, shared_secret: &BareSharedSecret,
) { ) -> VeilidAPIResult<()> {
let mut blob = nonce.bytes.to_vec(); let mut blob = nonce.to_vec();
blob.extend_from_slice(&[0u8; 8]); blob.extend_from_slice(&[0u8; 8]);
let blob = do_xor_32(&blob, &shared_secret.bytes); let blob = do_xor_32(&blob, shared_secret)?;
do_xor_b2b(in_buf, out_buf, &blob); do_xor_b2b(in_buf, out_buf, &blob)
} }
fn crypt_no_auth_aligned_8( fn crypt_no_auth_aligned_8(
@ -342,10 +381,10 @@ impl CryptoSystem for CryptoSystemNONE {
in_buf: &[u8], in_buf: &[u8],
nonce: &BareNonce, nonce: &BareNonce,
shared_secret: &BareSharedSecret, shared_secret: &BareSharedSecret,
) -> Vec<u8> { ) -> VeilidAPIResult<Vec<u8>> {
let mut out_buf = unsafe { aligned_8_u8_vec_uninit(in_buf.len()) }; let mut out_buf = unsafe { aligned_8_u8_vec_uninit(in_buf.len()) };
self.crypt_b2b_no_auth(in_buf, &mut out_buf, nonce, shared_secret); self.crypt_b2b_no_auth(in_buf, &mut out_buf, nonce, shared_secret)?;
out_buf Ok(out_buf)
} }
fn crypt_no_auth_unaligned( fn crypt_no_auth_unaligned(
@ -353,9 +392,9 @@ impl CryptoSystem for CryptoSystemNONE {
in_buf: &[u8], in_buf: &[u8],
nonce: &BareNonce, nonce: &BareNonce,
shared_secret: &BareSharedSecret, shared_secret: &BareSharedSecret,
) -> Vec<u8> { ) -> VeilidAPIResult<Vec<u8>> {
let mut out_buf = unsafe { unaligned_u8_vec_uninit(in_buf.len()) }; let mut out_buf = unsafe { unaligned_u8_vec_uninit(in_buf.len()) };
self.crypt_b2b_no_auth(in_buf, &mut out_buf, nonce, shared_secret); self.crypt_b2b_no_auth(in_buf, &mut out_buf, nonce, shared_secret)?;
out_buf Ok(out_buf)
} }
} }

View file

@ -0,0 +1,12 @@
/// Length of a crypto key in bytes
pub const NONE_PUBLIC_KEY_LENGTH: usize = 32;
/// Length of a secret key in bytes
pub const NONE_SECRET_KEY_LENGTH: usize = 32;
/// Length of a signature in bytes
pub const NONE_SIGNATURE_LENGTH: usize = 64;
/// Length of a nonce in bytes
pub const NONE_NONCE_LENGTH: usize = 24;
/// Length of a hash digest in bytes
pub const NONE_HASH_DIGEST_LENGTH: usize = 32;
/// Length of a shared secret in bytes
pub const NONE_SHARED_SECRET_LENGTH: usize = 32;

View file

@ -125,7 +125,11 @@ impl Receipt {
// Validate signature // Validate signature
if !vcrypto if !vcrypto
.verify(&sender_id.into(), &data[0..(data.len() - 64)], &signature) .verify(
&sender_id.clone().into(),
&data[0..(data.len() - 64)],
&signature,
)
.map_err(VeilidAPIError::generic)? .map_err(VeilidAPIError::generic)?
{ {
apibail_parse_error!("signature failure in receipt", signature); apibail_parse_error!("signature failure in receipt", signature);
@ -178,9 +182,9 @@ impl Receipt {
// Write size // Write size
data[0x08..0x0A].copy_from_slice(&(receipt_size as u16).to_le_bytes()); data[0x08..0x0A].copy_from_slice(&(receipt_size as u16).to_le_bytes());
// Write nonce // Write nonce
data[0x0A..0x22].copy_from_slice(&self.nonce.bytes); data[0x0A..0x22].copy_from_slice(&self.nonce);
// Write sender node id // Write sender node id
data[0x22..0x42].copy_from_slice(&self.sender_id.bytes); data[0x22..0x42].copy_from_slice(&self.sender_id);
// Write extra data // Write extra data
if !self.extra_data.is_empty() { if !self.extra_data.is_empty() {
data[0x42..(receipt_size - 64)].copy_from_slice(self.extra_data.as_slice()); data[0x42..(receipt_size - 64)].copy_from_slice(self.extra_data.as_slice());
@ -188,13 +192,13 @@ impl Receipt {
// Sign the receipt // Sign the receipt
let signature = vcrypto let signature = vcrypto
.sign( .sign(
&self.sender_id.into(), &self.sender_id.clone().into(),
secret, secret,
&data[0..(receipt_size - 64)], &data[0..(receipt_size - 64)],
) )
.map_err(VeilidAPIError::generic)?; .map_err(VeilidAPIError::generic)?;
// Append the signature // Append the signature
data[(receipt_size - 64)..].copy_from_slice(&signature.bytes); data[(receipt_size - 64)..].copy_from_slice(&signature);
Ok(data) Ok(data)
} }
@ -210,17 +214,17 @@ impl Receipt {
} }
pub fn get_nonce(&self) -> BareNonce { pub fn get_nonce(&self) -> BareNonce {
self.nonce self.nonce.clone()
} }
#[expect(dead_code)] #[expect(dead_code)]
pub fn get_sender_id(&self) -> BareNodeId { pub fn get_bare_sender_id(&self) -> BareNodeId {
self.sender_id self.sender_id.clone()
} }
#[expect(dead_code)] #[expect(dead_code)]
pub fn get_sender_typed_id(&self) -> NodeId { pub fn get_sender_id(&self) -> NodeId {
NodeId::new(self.crypto_kind, self.sender_id) NodeId::new(self.crypto_kind, self.sender_id.clone())
} }
#[must_use] #[must_use]

View file

@ -118,7 +118,10 @@ pub async fn test_no_auth(vcrypto: &AsyncCryptoSystemGuard<'_>) {
let mut body = LOREM_IPSUM.to_vec(); let mut body = LOREM_IPSUM.to_vec();
let body2 = body.clone(); let body2 = body.clone();
let size_before_encrypt = body.len(); let size_before_encrypt = body.len();
vcrypto.crypt_in_place_no_auth(&mut body, &n1, &ss1).await; vcrypto
.crypt_in_place_no_auth(&mut body, &n1, &ss1)
.await
.expect("should succeed");
let size_after_encrypt = body.len(); let size_after_encrypt = body.len();
assert_eq!( assert_eq!(
@ -128,32 +131,51 @@ pub async fn test_no_auth(vcrypto: &AsyncCryptoSystemGuard<'_>) {
let mut body3 = body.clone(); let mut body3 = body.clone();
let mut body4 = body.clone(); let mut body4 = body.clone();
vcrypto.crypt_in_place_no_auth(&mut body, &n1, &ss1).await; vcrypto
.crypt_in_place_no_auth(&mut body, &n1, &ss1)
.await
.expect("should succeed");
assert_eq!(body, body2, "result after decrypt should be the same"); assert_eq!(body, body2, "result after decrypt should be the same");
vcrypto.crypt_in_place_no_auth(&mut body3, &n2, &ss1).await; vcrypto
.crypt_in_place_no_auth(&mut body3, &n2, &ss1)
.await
.expect("should succeed");
assert_ne!(body3, body, "decrypt should not be equal with wrong nonce"); assert_ne!(body3, body, "decrypt should not be equal with wrong nonce");
vcrypto.crypt_in_place_no_auth(&mut body4, &n1, &ss2).await; vcrypto
.crypt_in_place_no_auth(&mut body4, &n1, &ss2)
.await
.expect("should succeed");
assert_ne!(body4, body, "decrypt should not be equal with wrong secret"); assert_ne!(body4, body, "decrypt should not be equal with wrong secret");
let body5 = vcrypto let body5 = vcrypto
.crypt_no_auth_unaligned(LOREM_IPSUM, &n1, &ss1) .crypt_no_auth_unaligned(LOREM_IPSUM, &n1, &ss1)
.await; .await
let body6 = vcrypto.crypt_no_auth_unaligned(&body5, &n1, &ss1).await; .unwrap();
let body6 = vcrypto
.crypt_no_auth_unaligned(&body5, &n1, &ss1)
.await
.unwrap();
let body7 = vcrypto let body7 = vcrypto
.crypt_no_auth_unaligned(LOREM_IPSUM, &n1, &ss1) .crypt_no_auth_unaligned(LOREM_IPSUM, &n1, &ss1)
.await; .await
.unwrap();
assert_eq!(body6, LOREM_IPSUM); assert_eq!(body6, LOREM_IPSUM);
assert_eq!(body5, body7); assert_eq!(body5, body7);
let body5 = vcrypto let body5 = vcrypto
.crypt_no_auth_aligned_8(LOREM_IPSUM, &n1, &ss1) .crypt_no_auth_aligned_8(LOREM_IPSUM, &n1, &ss1)
.await; .await
let body6 = vcrypto.crypt_no_auth_aligned_8(&body5, &n1, &ss1).await; .unwrap();
let body6 = vcrypto
.crypt_no_auth_aligned_8(&body5, &n1, &ss1)
.await
.unwrap();
let body7 = vcrypto let body7 = vcrypto
.crypt_no_auth_aligned_8(LOREM_IPSUM, &n1, &ss1) .crypt_no_auth_aligned_8(LOREM_IPSUM, &n1, &ss1)
.await; .await
.unwrap();
assert_eq!(body6, LOREM_IPSUM); assert_eq!(body6, LOREM_IPSUM);
assert_eq!(body5, body7); assert_eq!(body5, body7);
} }

View file

@ -3,8 +3,8 @@ use core::convert::TryFrom;
static LOREM_IPSUM:&str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. "; static LOREM_IPSUM:&str = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. ";
static CHEEZBURGER: &str = "I can has cheezburger"; static CHEEZBURGER: &str = "I can has cheezburger";
static EMPTY_KEY: [u8; PUBLIC_KEY_LENGTH] = [0u8; PUBLIC_KEY_LENGTH]; static EMPTY_KEY: [u8; VLD0_PUBLIC_KEY_LENGTH] = [0u8; VLD0_PUBLIC_KEY_LENGTH];
static EMPTY_KEY_SECRET: [u8; SECRET_KEY_LENGTH] = [0u8; SECRET_KEY_LENGTH]; static EMPTY_KEY_SECRET: [u8; VLD0_SECRET_KEY_LENGTH] = [0u8; VLD0_SECRET_KEY_LENGTH];
pub async fn test_generate_secret(vcrypto: &AsyncCryptoSystemGuard<'_>) { pub async fn test_generate_secret(vcrypto: &AsyncCryptoSystemGuard<'_>) {
// Verify keys generate // Verify keys generate
@ -12,8 +12,8 @@ pub async fn test_generate_secret(vcrypto: &AsyncCryptoSystemGuard<'_>) {
let (dht_key2, dht_key_secret2) = vcrypto.generate_keypair().await.into_split(); let (dht_key2, dht_key_secret2) = vcrypto.generate_keypair().await.into_split();
// Verify byte patterns are different between public and secret // Verify byte patterns are different between public and secret
assert_ne!(dht_key.bytes, dht_key_secret.bytes); assert_ne!(dht_key.bytes(), dht_key_secret.bytes());
assert_ne!(dht_key2.bytes, dht_key_secret2.bytes); assert_ne!(dht_key2.bytes(), dht_key_secret2.bytes());
// Verify the keys and secrets are different across keypairs // Verify the keys and secrets are different across keypairs
assert_ne!(dht_key, dht_key2); assert_ne!(dht_key, dht_key2);
@ -142,8 +142,8 @@ pub async fn test_sign_and_verify(vcrypto: &AsyncCryptoSystemGuard<'_>) {
pub async fn test_key_conversions(vcrypto: &AsyncCryptoSystemGuard<'_>) { pub async fn test_key_conversions(vcrypto: &AsyncCryptoSystemGuard<'_>) {
// Test default key // Test default key
let (dht_key, dht_key_secret) = (BarePublicKey::default(), BareSecretKey::default()); let (dht_key, dht_key_secret) = (BarePublicKey::default(), BareSecretKey::default());
assert_eq!(dht_key.bytes, EMPTY_KEY); assert!(dht_key.bytes().is_empty());
assert_eq!(dht_key_secret.bytes, EMPTY_KEY_SECRET); assert!(dht_key_secret.bytes().is_empty());
let dht_key_string = String::from(&dht_key); let dht_key_string = String::from(&dht_key);
trace!("dht_key_string: {:?}", dht_key_string); trace!("dht_key_string: {:?}", dht_key_string);
let dht_key_string2 = String::from(&dht_key); let dht_key_string2 = String::from(&dht_key);
@ -193,28 +193,18 @@ pub async fn test_key_conversions(vcrypto: &AsyncCryptoSystemGuard<'_>) {
// Assert string roundtrip // Assert string roundtrip
assert_eq!(String::from(&dht_key2_back), dht_key2_string); assert_eq!(String::from(&dht_key2_back), dht_key2_string);
// These conversions should fail // These conversions should fail
assert!(BarePublicKey::try_from("whatever").is_err()); assert!(BarePublicKey::try_from("whatever!").is_err());
assert!(BareSecretKey::try_from("whatever").is_err()); assert!(BareSecretKey::try_from("whatever!").is_err());
assert!(BarePublicKey::try_from("").is_err());
assert!(BareSecretKey::try_from("").is_err());
assert!(BarePublicKey::try_from(" ").is_err()); assert!(BarePublicKey::try_from(" ").is_err());
assert!(BareSecretKey::try_from(" ").is_err()); assert!(BareSecretKey::try_from(" ").is_err());
assert!(BarePublicKey::try_from(
"qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"
)
.is_err());
assert!(BareSecretKey::try_from(
"qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"
)
.is_err());
} }
pub async fn test_encode_decode(vcrypto: &AsyncCryptoSystemGuard<'_>) { pub async fn test_encode_decode(vcrypto: &AsyncCryptoSystemGuard<'_>) {
let dht_key = BarePublicKey::try_decode("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA").unwrap(); let dht_key = BarePublicKey::try_decode("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA").unwrap();
let dht_key_secret = let dht_key_secret =
BareSecretKey::try_decode("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA").unwrap(); BareSecretKey::try_decode("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA").unwrap();
let dht_key_b = BarePublicKey::new(EMPTY_KEY); let dht_key_b = BarePublicKey::new(&EMPTY_KEY);
let dht_key_secret_b = BareSecretKey::new(EMPTY_KEY_SECRET); let dht_key_secret_b = BareSecretKey::new(&EMPTY_KEY_SECRET);
assert_eq!(dht_key, dht_key_b); assert_eq!(dht_key, dht_key_b);
assert_eq!(dht_key_secret, dht_key_secret_b); assert_eq!(dht_key_secret, dht_key_secret_b);
@ -247,7 +237,7 @@ pub async fn test_encode_decode(vcrypto: &AsyncCryptoSystemGuard<'_>) {
assert_eq!(dht_key_secret2, d2s); assert_eq!(dht_key_secret2, d2s);
// Failures // Failures
let f1 = BareSecretKey::try_decode("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); let f1 = BareSecretKey::try_decode("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!");
assert!(f1.is_err()); assert!(f1.is_err());
let f2 = BareSecretKey::try_decode("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&"); let f2 = BareSecretKey::try_decode("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&");
assert!(f2.is_err()); assert!(f2.is_err());
@ -259,6 +249,7 @@ pub fn test_typed_convert(vcrypto: &AsyncCryptoSystemGuard<'_>) {
vcrypto.kind() vcrypto.kind()
); );
let tk1 = PublicKey::from_str(&tks1).expect("failed"); let tk1 = PublicKey::from_str(&tks1).expect("failed");
assert!(vcrypto.check_public_key(tk1.ref_value()).is_ok());
let tks1x = tk1.to_string(); let tks1x = tk1.to_string();
assert_eq!(tks1, tks1x); assert_eq!(tks1, tks1x);
@ -266,29 +257,35 @@ pub fn test_typed_convert(vcrypto: &AsyncCryptoSystemGuard<'_>) {
"{}:7lxDEabK_qgjbe38RtBa3IZLrud84P6NhGP-pRTZzd", "{}:7lxDEabK_qgjbe38RtBa3IZLrud84P6NhGP-pRTZzd",
vcrypto.kind() vcrypto.kind()
); );
let _tk2 = PublicKey::from_str(&tks2).expect_err("succeeded when it shouldnt have"); let _tk2 = PublicKey::from_str(&tks2).expect_err("should fail");
let tks3 = "XXXX:7lxDEabK_qgjbe38RtBa3IZLrud84P6NhGP-pRTZzdQ".to_string(); let tks3 = format!(
"{}:7lxDEabK_qgjbe38RtBa3IZLrud84P6NhGP-pRTZ",
vcrypto.kind()
);
let tk3 = PublicKey::from_str(&tks3).expect("failed"); let tk3 = PublicKey::from_str(&tks3).expect("failed");
let tks3x = tk3.to_string(); assert!(vcrypto.check_public_key(tk3.ref_value()).is_err());
assert_eq!(tks3, tks3x);
let tks4 = "XXXX:7lxDEabK_qgjbe38RtBa3IZLrud84P6NhGP-pRTZzd".to_string(); let tks4 = "XXXX:7lxDEabK_qgjbe38RtBa3IZLrud84P6NhGP-pRTZzdQ".to_string();
let _tk4 = PublicKey::from_str(&tks4).expect_err("succeeded when it shouldnt have"); let tk4 = PublicKey::from_str(&tks4).expect("failed");
let tks4x = tk4.to_string();
assert_eq!(tks4, tks4x);
// Enable this when we switch crypto to using typed keys too
//assert!(vcrypto.check_public_key(&tk4).is_err());
let tks5 = "XXX:7lxDEabK_qgjbe38RtBa3IZLrud84P6NhGP-pRTZzdQ".to_string(); let tks5 = "XXX:7lxDEabK_qgjbe38RtBa3IZLrud84P6NhGP-pRTZzdQ".to_string();
let _tk5 = PublicKey::from_str(&tks5).expect_err("succeeded when it shouldnt have"); let _tk5 = PublicKey::from_str(&tks5).expect_err("should fail");
let tks6 = "7lxDEabK_qgjbe38RtBa3IZLrud84P6NhGP-pRTZzdQ".to_string(); let tks6 = "7lxDEabK_qgjbe38RtBa3IZLrud84P6NhGP-pRTZzdQ".to_string();
let tk6 = PublicKey::from_str(&tks6).expect("failed"); let tk6 = PublicKey::from_str(&tks6).expect("failed");
let tks6x = tk6.to_string(); let tks6x = tk6.to_string();
assert!(tks6x.ends_with(&tks6)); assert!(tks6x.ends_with(&tks6));
let b = Vec::from(tk6); let b = Vec::from(tk6.clone());
let tk7 = PublicKey::try_from(b).expect("should succeed"); let tk7 = PublicKey::try_from(b).expect("should succeed");
assert_eq!(tk7, tk6); assert_eq!(tk7, tk6);
let b = Vec::from(tk6); let b = Vec::from(tk6.clone());
let tk8 = PublicKey::try_from(b.as_slice()).expect("should succeed"); let tk8 = PublicKey::try_from(b.as_slice()).expect("should succeed");
assert_eq!(tk8, tk6); assert_eq!(tk8, tk6);
} }
@ -303,12 +300,12 @@ async fn test_hash(vcrypto: &AsyncCryptoSystemGuard<'_>) {
let k5 = vcrypto.generate_hash(LOREM_IPSUM.as_bytes()).await; let k5 = vcrypto.generate_hash(LOREM_IPSUM.as_bytes()).await;
let k6 = vcrypto.generate_hash(CHEEZBURGER.as_bytes()).await; let k6 = vcrypto.generate_hash(CHEEZBURGER.as_bytes()).await;
s.insert(k1); s.insert(k1.clone());
s.insert(k2); s.insert(k2.clone());
s.insert(k3); s.insert(k3.clone());
s.insert(k4); s.insert(k4.clone());
s.insert(k5); s.insert(k5.clone());
s.insert(k6); s.insert(k6.clone());
assert_eq!(s.len(), 6); assert_eq!(s.len(), 6);
let v1 = vcrypto.generate_hash("abc".as_bytes()).await; let v1 = vcrypto.generate_hash("abc".as_bytes()).await;
@ -390,23 +387,23 @@ async fn test_operations(vcrypto: &AsyncCryptoSystemGuard<'_>) {
} }
pub fn test_public_key_ordering() { pub fn test_public_key_ordering() {
let k1 = BarePublicKey::new([ let k1 = BarePublicKey::new(&[
128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0,
]); ]);
let k2 = BarePublicKey::new([ let k2 = BarePublicKey::new(&[
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0,
]); ]);
let k3 = BarePublicKey::new([ let k3 = BarePublicKey::new(&[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 128, 0, 128,
]); ]);
let k4 = BarePublicKey::new([ let k4 = BarePublicKey::new(&[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 0, 1,
]); ]);
let k5 = BarePublicKey::new([ let k5 = BarePublicKey::new(&[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0,
]); ]);

View file

@ -1,71 +1,21 @@
use super::*; use super::*;
use core::cmp::{Eq, Ord, PartialEq, PartialOrd}; use core::cmp::{Eq, Ord, PartialEq, PartialOrd};
use core::convert::{TryFrom, TryInto}; use core::convert::TryFrom;
use core::fmt; use core::fmt;
use core::hash::Hash; use core::hash::Hash;
use bytes::{Bytes, BytesMut};
use data_encoding::BASE64URL_NOPAD; use data_encoding::BASE64URL_NOPAD;
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
/// Length of a crypto key in bytes
#[allow(dead_code)]
pub const CRYPTO_KEY_LENGTH: usize = 32;
/// Length of a crypto key in bytes after encoding to base64url
#[allow(dead_code)]
pub const CRYPTO_KEY_LENGTH_ENCODED: usize = 43;
/// Length of a crypto key in bytes
#[allow(dead_code)]
pub const PUBLIC_KEY_LENGTH: usize = CRYPTO_KEY_LENGTH;
/// Length of a crypto key in bytes after encoding to base64url
#[allow(dead_code)]
pub const PUBLIC_KEY_LENGTH_ENCODED: usize = CRYPTO_KEY_LENGTH_ENCODED;
/// Length of a secret key in bytes
#[allow(dead_code)]
pub const SECRET_KEY_LENGTH: usize = CRYPTO_KEY_LENGTH;
/// Length of a secret key in bytes after encoding to base64url
#[allow(dead_code)]
pub const SECRET_KEY_LENGTH_ENCODED: usize = CRYPTO_KEY_LENGTH_ENCODED;
/// Length of a signature in bytes
#[allow(dead_code)]
pub const SIGNATURE_LENGTH: usize = 64;
/// Length of a signature in bytes after encoding to base64url
#[allow(dead_code)]
pub const SIGNATURE_LENGTH_ENCODED: usize = 86;
/// Length of a nonce in bytes
#[allow(dead_code)]
pub const NONCE_LENGTH: usize = 24;
/// Length of a nonce in bytes after encoding to base64url
#[allow(dead_code)]
pub const NONCE_LENGTH_ENCODED: usize = 32;
/// Length of a hash digest in bytes
#[allow(dead_code)]
pub const HASH_DIGEST_LENGTH: usize = CRYPTO_KEY_LENGTH;
/// Length of a hash digest in bytes after encoding to base64url
#[allow(dead_code)]
pub const HASH_DIGEST_LENGTH_ENCODED: usize = CRYPTO_KEY_LENGTH_ENCODED;
/// Length of a shared secret in bytes
#[allow(dead_code)]
pub const SHARED_SECRET_LENGTH: usize = HASH_DIGEST_LENGTH;
/// Length of a shared secret in bytes after encoding to base64url
#[allow(dead_code)]
pub const SHARED_SECRET_LENGTH_ENCODED: usize = HASH_DIGEST_LENGTH_ENCODED;
/// Length of a route id in bytes
#[allow(dead_code)]
pub const ROUTE_ID_LENGTH: usize = HASH_DIGEST_LENGTH;
/// Length of a route id in bytes after encoding to base64url
#[allow(dead_code)]
pub const ROUTE_ID_LENGTH_ENCODED: usize = HASH_DIGEST_LENGTH_ENCODED;
//////////////////////////////////////////////////////////////////////
pub trait Encodable pub trait Encodable
where where
Self: Sized, Self: Sized,
{ {
fn encode(&self) -> String; fn encode(&self) -> String;
fn encoded_len() -> usize; fn encoded_len(&self) -> usize;
fn try_decode<S: AsRef<str>>(input: S) -> VeilidAPIResult<Self> { fn try_decode<S: AsRef<str>>(input: S) -> VeilidAPIResult<Self> {
let b = input.as_ref().as_bytes(); let b = input.as_ref().as_bytes();
Self::try_decode_bytes(b) Self::try_decode_bytes(b)
@ -73,11 +23,25 @@ where
fn try_decode_bytes(b: &[u8]) -> VeilidAPIResult<Self>; fn try_decode_bytes(b: &[u8]) -> VeilidAPIResult<Self>;
} }
//////////////////////////////////////////////////////////////////////
pub trait ByteArrayType
where
Self: Sized,
{
fn len(&self) -> usize;
fn is_empty(&self) -> bool;
fn bytes(&self) -> &[u8];
fn bit(&self, index: usize) -> bool;
fn first_nonzero_bit(&self) -> Option<usize>;
fn nibble(&self, index: usize) -> u8;
fn first_nonzero_nibble(&self) -> Option<(usize, u8)>;
}
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
macro_rules! byte_array_type { macro_rules! byte_array_type {
($name:ident, $size:expr, $encoded_size:expr) => { ($name:ident) => {
#[derive(Clone, Copy, Hash, PartialOrd, Ord, PartialEq, Eq)] #[derive(Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
#[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), derive(Tsify))]
#[cfg_attr( #[cfg_attr(
all(target_arch = "wasm32", target_os = "unknown"), all(target_arch = "wasm32", target_os = "unknown"),
@ -90,7 +54,110 @@ macro_rules! byte_array_type {
all(target_arch = "wasm32", target_os = "unknown"), all(target_arch = "wasm32", target_os = "unknown"),
tsify(type = "string") tsify(type = "string")
)] )]
pub bytes: [u8; $size], bytes: Bytes,
}
impl $name {
pub fn new(data: &[u8]) -> Self {
Self {
bytes: Bytes::copy_from_slice(data),
}
}
fn new_from_bytes(bytes: Bytes) -> Self {
Self { bytes }
}
}
impl Default for $name {
fn default() -> Self {
Self {
bytes: Bytes::new(),
}
}
}
impl ByteArrayType for $name {
fn len(&self) -> usize {
self.bytes.len()
}
fn is_empty(&self) -> bool {
self.bytes.is_empty()
}
fn bytes(&self) -> &[u8] {
&self.bytes
}
// Big endian bit ordering
#[must_use]
fn bit(&self, index: usize) -> bool {
let bi = index / 8;
let ti = 7 - (index % 8);
((self.bytes[bi] >> ti) & 1) != 0
}
#[must_use]
fn first_nonzero_bit(&self) -> Option<usize> {
for i in 0..self.bytes.len() {
let b = self.bytes[i];
if b != 0 {
for n in 0..8 {
if ((b >> (7 - n)) & 1u8) != 0u8 {
return Some((i * 8) + n);
}
}
unreachable!("nonzero byte must have nonzero bit");
}
}
None
}
// Big endian nibble ordering
#[must_use]
fn nibble(&self, index: usize) -> u8 {
let bi = index / 2;
if index & 1 == 0 {
(self.bytes[bi] >> 4) & 0xFu8
} else {
self.bytes[bi] & 0xFu8
}
}
#[must_use]
fn first_nonzero_nibble(&self) -> Option<(usize, u8)> {
for i in 0..(self.bytes.len() * 2) {
let n = self.nibble(i);
if n != 0 {
return Some((i, n));
}
}
None
}
}
impl Encodable for $name {
fn encode(&self) -> String {
BASE64URL_NOPAD.encode(&self.bytes)
}
fn encoded_len(&self) -> usize {
BASE64URL_NOPAD.encode_len(self.bytes.len())
}
fn try_decode_bytes(b: &[u8]) -> VeilidAPIResult<Self> {
if b.len() == 0 {
return Ok(Self::default());
}
let decode_len = BASE64URL_NOPAD
.decode_len(b.len())
.map_err(|_| VeilidAPIError::generic("failed to get decode length"))?;
let mut bytes = BytesMut::zeroed(decode_len);
let bytes_len = BASE64URL_NOPAD
.decode_mut(b, &mut bytes)
.map_err(|_| VeilidAPIError::generic("failed to decode"))?;
bytes.truncate(bytes_len);
Ok(Self::new_from_bytes(bytes.freeze()))
}
}
impl core::ops::Deref for $name {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.bytes
}
} }
impl serde::Serialize for $name { impl serde::Serialize for $name {
@ -109,103 +176,10 @@ macro_rules! byte_array_type {
D: serde::Deserializer<'de>, D: serde::Deserializer<'de>,
{ {
let s = <String as serde::Deserialize>::deserialize(deserializer)?; let s = <String as serde::Deserialize>::deserialize(deserializer)?;
if s == "" { Self::try_decode(s.as_str()).map_err(serde::de::Error::custom)
return Ok($name::default());
}
$name::try_decode(s.as_str()).map_err(serde::de::Error::custom)
} }
} }
impl Default for $name {
fn default() -> Self {
Self {
bytes: [0u8; $size],
}
}
}
impl $name {
pub fn new(bytes: [u8; $size]) -> Self {
Self { bytes }
}
// Big endian bit ordering
#[must_use]
pub fn bit(&self, index: usize) -> bool {
assert!(index < ($size * 8));
let bi = index / 8;
let ti = 7 - (index % 8);
((self.bytes[bi] >> ti) & 1) != 0
}
#[must_use]
pub fn first_nonzero_bit(&self) -> Option<usize> {
for i in 0..$size {
let b = self.bytes[i];
if b != 0 {
for n in 0..8 {
if ((b >> (7 - n)) & 1u8) != 0u8 {
return Some((i * 8) + n);
}
}
panic!("wtf")
}
}
None
}
// Big endian nibble ordering
#[must_use]
pub fn nibble(&self, index: usize) -> u8 {
assert!(index < ($size * 2));
let bi = index / 2;
if index & 1 == 0 {
(self.bytes[bi] >> 4) & 0xFu8
} else {
self.bytes[bi] & 0xFu8
}
}
#[must_use]
pub fn first_nonzero_nibble(&self) -> Option<(usize, u8)> {
for i in 0..($size * 2) {
let n = self.nibble(i);
if n != 0 {
return Some((i, n));
}
}
None
}
}
impl Encodable for $name {
fn encode(&self) -> String {
BASE64URL_NOPAD.encode(&self.bytes)
}
fn encoded_len() -> usize {
$encoded_size
}
fn try_decode_bytes(b: &[u8]) -> VeilidAPIResult<Self> {
let mut bytes = [0u8; $size];
let res = BASE64URL_NOPAD.decode_len(b.len());
match res {
Ok(v) => {
if v != $size {
apibail_generic!("Incorrect length in decode");
}
}
Err(_) => {
apibail_generic!("Failed to decode");
}
}
let res = BASE64URL_NOPAD.decode_mut(b, &mut bytes);
match res {
Ok(_) => Ok(Self::new(bytes)),
Err(_) => apibail_generic!("Failed to decode"),
}
}
}
impl fmt::Display for $name { impl fmt::Display for $name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.encode()) write!(f, "{}", self.encode())
@ -237,7 +211,7 @@ macro_rules! byte_array_type {
impl TryFrom<String> for $name { impl TryFrom<String> for $name {
type Error = VeilidAPIError; type Error = VeilidAPIError;
fn try_from(value: String) -> Result<Self, Self::Error> { fn try_from(value: String) -> Result<Self, Self::Error> {
$name::try_from(value.as_str()) Self::try_from(value.as_str())
} }
} }
@ -247,43 +221,30 @@ macro_rules! byte_array_type {
Self::try_decode(value) Self::try_decode(value)
} }
} }
impl TryFrom<&[u8]> for $name {
type Error = VeilidAPIError;
fn try_from(v: &[u8]) -> Result<Self, Self::Error> {
let vl = v.len();
Ok(Self {
bytes: v.try_into().map_err(|_| {
VeilidAPIError::generic(format!(
"Expected a slice of length {} but it was {}",
$size, vl
))
})?,
})
}
}
impl TryFrom<Vec<u8>> for $name {
type Error = VeilidAPIError;
fn try_from(v: Vec<u8>) -> Result<Self, Self::Error> {
let vl = v.len();
Ok(Self {
bytes: v.try_into().map_err(|_| {
VeilidAPIError::generic(format!(
"Expected a vec of length {} but it was {}",
$size, vl
))
})?,
})
}
}
impl From<$name> for Vec<u8> { impl From<$name> for Vec<u8> {
fn from(value: $name) -> Self { fn from(value: $name) -> Self {
value.bytes.to_vec() value.bytes().to_vec()
} }
} }
impl AsRef<[u8]> for $name { impl AsRef<[u8]> for $name {
fn as_ref(&self) -> &[u8] { fn as_ref(&self) -> &[u8] {
&self.bytes self.bytes()
}
}
impl From<&[u8]> for $name {
fn from(v: &[u8]) -> Self {
Self {
bytes: Bytes::copy_from_slice(v),
}
}
}
impl From<Vec<u8>> for $name {
fn from(v: Vec<u8>) -> Self {
Self {
bytes: Bytes::from(v),
}
} }
} }
}; };
@ -291,80 +252,53 @@ macro_rules! byte_array_type {
///////////////////////////////////////// /////////////////////////////////////////
byte_array_type!(BarePublicKey, PUBLIC_KEY_LENGTH, PUBLIC_KEY_LENGTH_ENCODED); byte_array_type!(BarePublicKey);
byte_array_type!(BareSecretKey, SECRET_KEY_LENGTH, SECRET_KEY_LENGTH_ENCODED); byte_array_type!(BareSecretKey);
byte_array_type!(BareSignature, SIGNATURE_LENGTH, SIGNATURE_LENGTH_ENCODED); byte_array_type!(BareSignature);
byte_array_type!(BareNonce, NONCE_LENGTH, NONCE_LENGTH_ENCODED); byte_array_type!(BareNonce);
/* /*
Notes: Notes:
- These are actually BareHashDigest types, but not interchangable: - These are actually BareHashDigest types, but not interchangable:
- BareRouteId (eventually will be a BareRecordKey type with DHT Routes)
- BareRecordKey
- BareSharedSecret - BareSharedSecret
- BareRecordKey
- BareRouteId (eventually will be a BareRecordKey type with DHT Routes)
- BareNodeId (constructible from BarePublicKey)
- BareMemberId (constructible from BarePublicKey)
*/ */
// BareHashDigest sub-types // BareHashDigest sub-types
byte_array_type!( byte_array_type!(BareHashDigest);
BareHashDigest, byte_array_type!(BareSharedSecret);
HASH_DIGEST_LENGTH, byte_array_type!(BareRecordKey);
HASH_DIGEST_LENGTH_ENCODED byte_array_type!(BareHashDistance);
); byte_array_type!(BareRouteId);
byte_array_type!( byte_array_type!(BareNodeId);
BareSharedSecret, byte_array_type!(BareMemberId);
SHARED_SECRET_LENGTH,
SHARED_SECRET_LENGTH_ENCODED
);
byte_array_type!(BareRouteId, ROUTE_ID_LENGTH, ROUTE_ID_LENGTH_ENCODED);
byte_array_type!(
BareRecordKey,
HASH_DIGEST_LENGTH,
HASH_DIGEST_LENGTH_ENCODED
);
byte_array_type!(
BareHashDistance,
HASH_DIGEST_LENGTH,
HASH_DIGEST_LENGTH_ENCODED
);
// BareNodeId is currently the same as BarePublicKey, but will eventually be a sub-type of BareHashDigest.
byte_array_type!(BareNodeId, PUBLIC_KEY_LENGTH, PUBLIC_KEY_LENGTH_ENCODED);
#[expect(dead_code)]
trait HashCoordinate {
fn from_hash_coordinate(hash_digest: BareHashDigest) -> Self;
fn to_hash_coordinate(&self) -> BareHashDigest;
}
// Temporary adapters for converting to/from BareHashDigest types // Temporary adapters for converting to/from BareHashDigest types
// Removing these will show where there's still issues. // Removing these will show where there's still issues.
impl From<BareHashDigest> for BareSharedSecret { impl From<BareHashDigest> for BareSharedSecret {
fn from(value: BareHashDigest) -> Self { fn from(value: BareHashDigest) -> Self {
Self::new(value.bytes) Self::new(value.bytes())
} }
} }
impl From<BareHashDigest> for BareRecordKey { impl From<BareHashDigest> for BareRecordKey {
fn from(value: BareHashDigest) -> Self { fn from(value: BareHashDigest) -> Self {
Self::new(value.bytes) Self::new(value.bytes())
} }
} }
impl From<BareRecordKey> for BareHashDigest { impl From<BareRecordKey> for BareHashDigest {
fn from(value: BareRecordKey) -> Self { fn from(value: BareRecordKey) -> Self {
Self::new(value.bytes) Self::new(value.bytes())
} }
} }
impl From<BareNodeId> for BareHashDigest { impl From<BareNodeId> for BareHashDigest {
fn from(value: BareNodeId) -> Self { fn from(value: BareNodeId) -> Self {
Self::new(value.bytes) Self::new(value.bytes())
}
}
impl From<BareHashDigest> for BarePublicKey {
fn from(value: BareHashDigest) -> Self {
Self::new(value.bytes)
} }
} }
@ -374,12 +308,12 @@ impl From<BareHashDigest> for BarePublicKey {
*/ */
impl From<BarePublicKey> for BareNodeId { impl From<BarePublicKey> for BareNodeId {
fn from(value: BarePublicKey) -> Self { fn from(value: BarePublicKey) -> Self {
Self::new(value.bytes) Self::new(value.bytes())
} }
} }
impl From<BareNodeId> for BarePublicKey { impl From<BareNodeId> for BarePublicKey {
fn from(value: BareNodeId) -> Self { fn from(value: BareNodeId) -> Self {
Self::new(value.bytes) Self::new(value.bytes())
} }
} }

View file

@ -1,13 +1,13 @@
use super::*; use super::*;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[must_use] #[must_use]
pub struct CryptoTyped<K> pub struct CryptoTyped<K>
where where
K: Clone + Copy + fmt::Debug + PartialEq + Eq + Hash, K: Clone + fmt::Debug + PartialEq + Eq + Hash,
{ {
pub kind: CryptoKind, kind: CryptoKind,
pub value: K, value: K,
} }
cfg_if::cfg_if! { cfg_if::cfg_if! {
@ -21,15 +21,29 @@ export type CryptoTyped<TCryptoKey extends string> = `${CryptoKind}:${TCryptoKey
impl<K> CryptoTyped<K> impl<K> CryptoTyped<K>
where where
K: Clone + Copy + fmt::Debug + PartialEq + Eq + Hash, K: Clone + fmt::Debug + PartialEq + Eq + Hash,
{ {
pub fn new(kind: CryptoKind, value: K) -> Self { pub fn new(kind: CryptoKind, value: K) -> Self {
Self { kind, value } Self { kind, value }
} }
pub fn kind(&self) -> CryptoKind {
self.kind
}
pub fn value(&self) -> K {
self.value.clone()
}
pub fn ref_value(&self) -> &K {
&self.value
}
pub fn into_value(self) -> K {
self.value
}
} }
impl<K> PartialOrd for CryptoTyped<K> impl<K> PartialOrd for CryptoTyped<K>
where where
K: Clone + Copy + fmt::Debug + PartialEq + Eq + Hash, K: Clone + fmt::Debug + PartialEq + Eq + Hash,
K: Ord + PartialOrd, K: Ord + PartialOrd,
{ {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
@ -39,7 +53,7 @@ where
impl<K> Ord for CryptoTyped<K> impl<K> Ord for CryptoTyped<K>
where where
K: Clone + Copy + fmt::Debug + PartialEq + Eq + Hash, K: Clone + fmt::Debug + PartialEq + Eq + Hash,
K: Ord + PartialOrd, K: Ord + PartialOrd,
{ {
fn cmp(&self, other: &Self) -> cmp::Ordering { fn cmp(&self, other: &Self) -> cmp::Ordering {
@ -53,7 +67,7 @@ where
impl<K> fmt::Display for CryptoTyped<K> impl<K> fmt::Display for CryptoTyped<K>
where where
K: Clone + Copy + fmt::Debug + PartialEq + Eq + Hash, K: Clone + fmt::Debug + PartialEq + Eq + Hash,
K: fmt::Display, K: fmt::Display,
{ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
@ -63,29 +77,27 @@ where
impl<K> FromStr for CryptoTyped<K> impl<K> FromStr for CryptoTyped<K>
where where
K: Clone + Copy + fmt::Debug + PartialEq + Eq + Hash, K: Clone + fmt::Debug + PartialEq + Eq + Hash,
K: Encodable, K: Encodable,
{ {
type Err = VeilidAPIError; type Err = VeilidAPIError;
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
let b = s.as_bytes(); let b = s.as_bytes();
if b.len() == (5 + K::encoded_len()) && b[4..5] == b":"[..] { if b.len() > 5 && b[4..5] == b":"[..] {
let kind: CryptoKind = b[0..4].try_into().expect("should not fail to convert"); let kind: CryptoKind = b[0..4].try_into().expect("should not fail to convert");
let value = K::try_decode_bytes(&b[5..])?; let value = K::try_decode_bytes(&b[5..])?;
Ok(Self { kind, value }) Ok(Self { kind, value })
} else if b.len() == K::encoded_len() { } else {
let kind = best_crypto_kind(); let kind = best_crypto_kind();
let value = K::try_decode_bytes(b)?; let value = K::try_decode_bytes(b)?;
Ok(Self { kind, value }) Ok(Self { kind, value })
} else {
apibail_generic!("invalid cryptotyped format");
} }
} }
} }
impl<K> TryFrom<String> for CryptoTyped<K> impl<K> TryFrom<String> for CryptoTyped<K>
where where
K: Clone + Copy + fmt::Debug + PartialEq + Eq + Hash, K: Clone + fmt::Debug + PartialEq + Eq + Hash,
K: Encodable, K: Encodable,
{ {
type Error = VeilidAPIError; type Error = VeilidAPIError;
@ -97,7 +109,7 @@ where
impl<K> TryFrom<&str> for CryptoTyped<K> impl<K> TryFrom<&str> for CryptoTyped<K>
where where
K: Clone + Copy + fmt::Debug + PartialEq + Eq + Hash, K: Clone + fmt::Debug + PartialEq + Eq + Hash,
K: Encodable, K: Encodable,
{ {
type Error = VeilidAPIError; type Error = VeilidAPIError;
@ -109,8 +121,8 @@ where
impl<'a, K> TryFrom<&'a [u8]> for CryptoTyped<K> impl<'a, K> TryFrom<&'a [u8]> for CryptoTyped<K>
where where
K: Clone + Copy + fmt::Debug + PartialEq + Eq + Hash, K: Clone + fmt::Debug + PartialEq + Eq + Hash,
K: TryFrom<&'a [u8], Error = VeilidAPIError>, K: From<&'a [u8]>,
{ {
type Error = VeilidAPIError; type Error = VeilidAPIError;
@ -119,15 +131,15 @@ where
apibail_generic!("invalid cryptotyped format"); apibail_generic!("invalid cryptotyped format");
} }
let kind: CryptoKind = b[0..4].try_into()?; let kind: CryptoKind = b[0..4].try_into()?;
let value: K = b[4..].try_into()?; let value: K = b[4..].into();
Ok(Self { kind, value }) Ok(Self { kind, value })
} }
} }
impl<K> TryFrom<Vec<u8>> for CryptoTyped<K> impl<K> TryFrom<Vec<u8>> for CryptoTyped<K>
where where
K: Clone + Copy + fmt::Debug + PartialEq + Eq + Hash, K: Clone + fmt::Debug + PartialEq + Eq + Hash,
K: for<'a> TryFrom<&'a [u8], Error = VeilidAPIError>, K: for<'a> From<&'a [u8]>,
{ {
type Error = VeilidAPIError; type Error = VeilidAPIError;
@ -138,7 +150,7 @@ where
impl<K> From<CryptoTyped<K>> for Vec<u8> impl<K> From<CryptoTyped<K>> for Vec<u8>
where where
K: Clone + Copy + fmt::Debug + PartialEq + Eq + Hash, K: Clone + fmt::Debug + PartialEq + Eq + Hash,
K: AsRef<[u8]>, K: AsRef<[u8]>,
{ {
fn from(v: CryptoTyped<K>) -> Self { fn from(v: CryptoTyped<K>) -> Self {
@ -150,7 +162,7 @@ where
impl<'de, K> Deserialize<'de> for CryptoTyped<K> impl<'de, K> Deserialize<'de> for CryptoTyped<K>
where where
K: Clone + Copy + fmt::Debug + PartialEq + Eq + Hash, K: Clone + fmt::Debug + PartialEq + Eq + Hash,
K: Encodable, K: Encodable,
{ {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
@ -163,7 +175,7 @@ where
} }
impl<K> Serialize for CryptoTyped<K> impl<K> Serialize for CryptoTyped<K>
where where
K: Clone + Copy + fmt::Debug + PartialEq + Eq + Hash, K: Clone + fmt::Debug + PartialEq + Eq + Hash,
K: fmt::Display, K: fmt::Display,
{ {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@ -173,3 +185,25 @@ where
serializer.collect_str(self) serializer.collect_str(self)
} }
} }
impl CryptoTyped<BareKeyPair> {
pub fn new_from_parts(key: PublicKey, bare_secret: BareSecretKey) -> Self {
Self {
kind: key.kind(),
value: BareKeyPair::new(key.value(), bare_secret),
}
}
pub fn key(&self) -> PublicKey {
PublicKey::new(self.kind, self.ref_value().key())
}
pub fn secret(&self) -> SecretKey {
SecretKey::new(self.kind, self.ref_value().secret())
}
pub fn bare_secret(&self) -> BareSecretKey {
self.ref_value().secret()
}
pub fn ref_bare_secret(&self) -> &BareSecretKey {
self.ref_value().ref_secret()
}
}

View file

@ -5,7 +5,6 @@ use super::*;
pub struct CryptoTypedGroup<K> pub struct CryptoTypedGroup<K>
where where
K: Clone K: Clone
+ Copy
+ fmt::Debug + fmt::Debug
+ fmt::Display + fmt::Display
+ FromStr + FromStr
@ -31,7 +30,6 @@ export type CryptoTypedGroup<TCryptoKey extends string> = Array<CryptoTyped<TCry
impl<K> CryptoTypedGroup<K> impl<K> CryptoTypedGroup<K>
where where
K: Clone K: Clone
+ Copy
+ fmt::Debug + fmt::Debug
+ fmt::Display + fmt::Display
+ FromStr + FromStr
@ -55,7 +53,7 @@ where
pub fn kinds(&self) -> Vec<CryptoKind> { pub fn kinds(&self) -> Vec<CryptoKind> {
let mut out = Vec::new(); let mut out = Vec::new();
for tk in &self.items { for tk in &self.items {
out.push(tk.kind); out.push(tk.kind());
} }
out.sort_by(compare_crypto_kind); out.sort_by(compare_crypto_kind);
out out
@ -64,17 +62,17 @@ where
pub fn keys(&self) -> Vec<K> { pub fn keys(&self) -> Vec<K> {
let mut out = Vec::new(); let mut out = Vec::new();
for tk in &self.items { for tk in &self.items {
out.push(tk.value); out.push(tk.value());
} }
out out
} }
#[must_use] #[must_use]
pub fn get(&self, kind: CryptoKind) -> Option<CryptoTyped<K>> { pub fn get(&self, kind: CryptoKind) -> Option<CryptoTyped<K>> {
self.items.iter().find(|x| x.kind == kind).copied() self.items.iter().find(|x| x.kind() == kind).cloned()
} }
pub fn add(&mut self, typed_key: CryptoTyped<K>) { pub fn add(&mut self, typed_key: CryptoTyped<K>) {
for x in &mut self.items { for x in &mut self.items {
if x.kind == typed_key.kind { if x.kind() == typed_key.kind() {
*x = typed_key; *x = typed_key;
return; return;
} }
@ -85,17 +83,17 @@ where
pub fn add_all(&mut self, typed_keys: &[CryptoTyped<K>]) { pub fn add_all(&mut self, typed_keys: &[CryptoTyped<K>]) {
'outer: for typed_key in typed_keys { 'outer: for typed_key in typed_keys {
for x in &mut self.items { for x in &mut self.items {
if x.kind == typed_key.kind { if x.kind() == typed_key.kind() {
*x = *typed_key; *x = typed_key.clone();
continue 'outer; continue 'outer;
} }
} }
self.items.push(*typed_key); self.items.push(typed_key.clone());
} }
self.items.sort() self.items.sort()
} }
pub fn remove(&mut self, kind: CryptoKind) -> Option<CryptoTyped<K>> { pub fn remove(&mut self, kind: CryptoKind) -> Option<CryptoTyped<K>> {
if let Some(idx) = self.items.iter().position(|x| x.kind == kind) { if let Some(idx) = self.items.iter().position(|x| x.kind() == kind) {
return Some(self.items.remove(idx)); return Some(self.items.remove(idx));
} }
None None
@ -110,8 +108,8 @@ where
pub fn best(&self) -> Option<CryptoTyped<K>> { pub fn best(&self) -> Option<CryptoTyped<K>> {
self.items self.items
.iter() .iter()
.find(|k| VALID_CRYPTO_KINDS.contains(&k.kind)) .find(|k| VALID_CRYPTO_KINDS.contains(&k.kind()))
.copied() .cloned()
} }
#[must_use] #[must_use]
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
@ -137,7 +135,7 @@ where
} }
pub fn contains_value(&self, value: &K) -> bool { pub fn contains_value(&self, value: &K) -> bool {
for tk in &self.items { for tk in &self.items {
if tk.value == *value { if tk.ref_value() == value {
return true; return true;
} }
} }
@ -148,7 +146,6 @@ where
impl<K> core::ops::Deref for CryptoTypedGroup<K> impl<K> core::ops::Deref for CryptoTypedGroup<K>
where where
K: Clone K: Clone
+ Copy
+ fmt::Debug + fmt::Debug
+ fmt::Display + fmt::Display
+ FromStr + FromStr
@ -170,7 +167,6 @@ where
impl<K> fmt::Display for CryptoTypedGroup<K> impl<K> fmt::Display for CryptoTypedGroup<K>
where where
K: Clone K: Clone
+ Copy
+ fmt::Debug + fmt::Debug
+ fmt::Display + fmt::Display
+ FromStr + FromStr
@ -198,7 +194,6 @@ where
impl<K> FromStr for CryptoTypedGroup<K> impl<K> FromStr for CryptoTypedGroup<K>
where where
K: Clone K: Clone
+ Copy
+ fmt::Debug + fmt::Debug
+ fmt::Display + fmt::Display
+ FromStr + FromStr
@ -229,7 +224,6 @@ where
impl<K> From<CryptoTyped<K>> for CryptoTypedGroup<K> impl<K> From<CryptoTyped<K>> for CryptoTypedGroup<K>
where where
K: Clone K: Clone
+ Copy
+ fmt::Debug + fmt::Debug
+ fmt::Display + fmt::Display
+ FromStr + FromStr
@ -249,7 +243,6 @@ where
impl<K> From<Vec<CryptoTyped<K>>> for CryptoTypedGroup<K> impl<K> From<Vec<CryptoTyped<K>>> for CryptoTypedGroup<K>
where where
K: Clone K: Clone
+ Copy
+ fmt::Debug + fmt::Debug
+ fmt::Display + fmt::Display
+ FromStr + FromStr
@ -269,7 +262,6 @@ where
impl<K> From<&[CryptoTyped<K>]> for CryptoTypedGroup<K> impl<K> From<&[CryptoTyped<K>]> for CryptoTypedGroup<K>
where where
K: Clone K: Clone
+ Copy
+ fmt::Debug + fmt::Debug
+ fmt::Display + fmt::Display
+ FromStr + FromStr
@ -289,7 +281,6 @@ where
impl<K> From<CryptoTypedGroup<K>> for Vec<CryptoTyped<K>> impl<K> From<CryptoTypedGroup<K>> for Vec<CryptoTyped<K>>
where where
K: Clone K: Clone
+ Copy
+ fmt::Debug + fmt::Debug
+ fmt::Display + fmt::Display
+ FromStr + FromStr

View file

@ -1,10 +1,10 @@
use super::*; use super::*;
#[derive(Clone, Copy, Default, PartialOrd, Ord, PartialEq, Eq, Hash)] #[derive(Clone, Default, PartialOrd, Ord, PartialEq, Eq, Hash)]
#[must_use] #[must_use]
pub struct BareKeyPair { pub struct BareKeyPair {
pub key: BarePublicKey, key: BarePublicKey,
pub secret: BareSecretKey, secret: BareSecretKey,
} }
cfg_if::cfg_if! { cfg_if::cfg_if! {
@ -20,8 +20,23 @@ impl BareKeyPair {
pub fn new(key: BarePublicKey, secret: BareSecretKey) -> Self { pub fn new(key: BarePublicKey, secret: BareSecretKey) -> Self {
Self { key, secret } Self { key, secret }
} }
pub fn key(&self) -> BarePublicKey {
self.key.clone()
}
pub fn secret(&self) -> BareSecretKey {
self.secret.clone()
}
pub fn ref_key(&self) -> &BarePublicKey {
&self.key
}
pub fn ref_secret(&self) -> &BareSecretKey {
&self.secret
}
pub fn split(&self) -> (BarePublicKey, BareSecretKey) { pub fn split(&self) -> (BarePublicKey, BareSecretKey) {
(self.key, self.secret) (self.key.clone(), self.secret.clone())
}
pub fn ref_split(&self) -> (&BarePublicKey, &BareSecretKey) {
(&self.key, &self.secret)
} }
pub fn into_split(self) -> (BarePublicKey, BareSecretKey) { pub fn into_split(self) -> (BarePublicKey, BareSecretKey) {
(self.key, self.secret) (self.key, self.secret)
@ -32,15 +47,19 @@ impl Encodable for BareKeyPair {
fn encode(&self) -> String { fn encode(&self) -> String {
format!("{}:{}", self.key.encode(), self.secret.encode()) format!("{}:{}", self.key.encode(), self.secret.encode())
} }
fn encoded_len() -> usize { fn encoded_len(&self) -> usize {
BarePublicKey::encoded_len() + 1 + BareSecretKey::encoded_len() self.key.encoded_len() + 1 + self.secret.encoded_len()
} }
fn try_decode_bytes(b: &[u8]) -> VeilidAPIResult<Self> { fn try_decode_bytes(b: &[u8]) -> VeilidAPIResult<Self> {
if b.len() != Self::encoded_len() { let parts: Vec<_> = b.split(|x| *x == b':').collect();
apibail_parse_error!("input has wrong encoded length", format!("len={}", b.len())); if parts.len() != 2 {
apibail_parse_error!(
"input has incorrect parts",
format!("parts={}", parts.len())
);
} }
let key = BarePublicKey::try_decode_bytes(&b[0..BarePublicKey::encoded_len()])?; let key = BarePublicKey::try_decode_bytes(parts[0])?;
let secret = BareSecretKey::try_decode_bytes(&b[(BarePublicKey::encoded_len() + 1)..])?; let secret = BareSecretKey::try_decode_bytes(parts[1])?;
Ok(BareKeyPair { key, secret }) Ok(BareKeyPair { key, secret })
} }
} }

View file

@ -63,13 +63,15 @@ pub type Signature = CryptoTyped<BareSignature>;
#[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), declare)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), declare)]
pub type SharedSecret = CryptoTyped<BareSharedSecret>; pub type SharedSecret = CryptoTyped<BareSharedSecret>;
#[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), declare)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), declare)]
pub type RouteId = CryptoTyped<BareRouteId>; pub type HashDigest = CryptoTyped<BareHashDigest>;
#[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), declare)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), declare)]
pub type RecordKey = CryptoTyped<BareRecordKey>; pub type RecordKey = CryptoTyped<BareRecordKey>;
#[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), declare)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), declare)]
pub type NodeId = CryptoTyped<BareNodeId>; pub type NodeId = CryptoTyped<BareNodeId>;
#[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), declare)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), declare)]
pub type HashDigest = CryptoTyped<BareHashDigest>; pub type RouteId = CryptoTyped<BareRouteId>;
#[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), declare)]
pub type MemberId = CryptoTyped<BareMemberId>;
#[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), declare)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), declare)]
pub type PublicKeyGroup = CryptoTypedGroup<BarePublicKey>; pub type PublicKeyGroup = CryptoTypedGroup<BarePublicKey>;
@ -82,48 +84,50 @@ pub type SignatureGroup = CryptoTypedGroup<BareSignature>;
#[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), declare)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), declare)]
pub type SharedSecretGroup = CryptoTypedGroup<BareSharedSecret>; pub type SharedSecretGroup = CryptoTypedGroup<BareSharedSecret>;
#[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), declare)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), declare)]
pub type RouteIdGroup = CryptoTypedGroup<BareRouteId>; pub type HashDigestGroup = CryptoTypedGroup<BareHashDigest>;
#[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), declare)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), declare)]
pub type RecordKeyGroup = CryptoTypedGroup<BareRecordKey>; pub type RecordKeyGroup = CryptoTypedGroup<BareRecordKey>;
#[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), declare)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), declare)]
pub type NodeIdGroup = CryptoTypedGroup<BareNodeId>; pub type NodeIdGroup = CryptoTypedGroup<BareNodeId>;
#[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), declare)] #[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), declare)]
pub type HashDigestGroup = CryptoTypedGroup<BareHashDigest>; pub type RouteIdGroup = CryptoTypedGroup<BareRouteId>;
#[cfg_attr(all(target_arch = "wasm32", target_os = "unknown"), declare)]
pub type MemberIdGroup = CryptoTypedGroup<BareMemberId>;
impl From<NodeId> for HashDigest { impl From<NodeId> for HashDigest {
fn from(value: NodeId) -> Self { fn from(value: NodeId) -> Self {
HashDigest::new(value.kind, value.value.into()) HashDigest::new(value.kind(), value.into_value().into())
} }
} }
impl From<RecordKey> for HashDigest { impl From<RecordKey> for HashDigest {
fn from(value: RecordKey) -> Self { fn from(value: RecordKey) -> Self {
HashDigest::new(value.kind, value.value.into()) HashDigest::new(value.kind(), value.into_value().into())
} }
} }
impl From<NodeId> for PublicKey { impl From<NodeId> for PublicKey {
fn from(value: NodeId) -> Self { fn from(value: NodeId) -> Self {
PublicKey::new(value.kind, value.value.into()) PublicKey::new(value.kind(), value.into_value().into())
} }
} }
impl From<PublicKey> for NodeId { impl From<PublicKey> for NodeId {
fn from(value: PublicKey) -> Self { fn from(value: PublicKey) -> Self {
NodeId::new(value.kind, value.value.into()) NodeId::new(value.kind(), value.into_value().into())
} }
} }
impl From<NodeIdGroup> for PublicKeyGroup { impl From<NodeIdGroup> for PublicKeyGroup {
fn from(value: NodeIdGroup) -> Self { fn from(value: NodeIdGroup) -> Self {
let items: Vec<PublicKey> = value.iter().map(|node_id| (*node_id).into()).collect(); let items: Vec<PublicKey> = value.iter().map(|node_id| node_id.clone().into()).collect();
PublicKeyGroup::from(items) PublicKeyGroup::from(items)
} }
} }
impl From<PublicKeyGroup> for NodeIdGroup { impl From<PublicKeyGroup> for NodeIdGroup {
fn from(value: PublicKeyGroup) -> Self { fn from(value: PublicKeyGroup) -> Self {
let items: Vec<NodeId> = value.iter().map(|node_id| (*node_id).into()).collect(); let items: Vec<NodeId> = value.iter().map(|node_id| node_id.clone().into()).collect();
NodeIdGroup::from(items) NodeIdGroup::from(items)
} }
} }

View file

@ -1,3 +1,5 @@
pub mod sizes;
use super::*; use super::*;
use argon2::{ use argon2::{
@ -13,25 +15,32 @@ use curve25519_dalek::digest::Digest;
use ed25519_dalek as ed; use ed25519_dalek as ed;
use x25519_dalek as xd; use x25519_dalek as xd;
const VEILID_DOMAIN_SIGN: &[u8] = b"VLD0_SIGN"; const VLD0_DOMAIN_SIGN: &[u8] = b"VLD0_SIGN";
const VEILID_DOMAIN_CRYPT: &[u8] = b"VLD0_CRYPT"; const VLD0_DOMAIN_CRYPT: &[u8] = b"VLD0_CRYPT";
const AEAD_OVERHEAD: usize = 16; const VLD0_AEAD_OVERHEAD: usize = 16;
pub const CRYPTO_KIND_VLD0: CryptoKind = CryptoKind(*b"VLD0"); pub const CRYPTO_KIND_VLD0: CryptoKind = CryptoKind(*b"VLD0");
pub use sizes::*;
fn public_to_x25519_pk(public: &BarePublicKey) -> VeilidAPIResult<xd::PublicKey> { fn public_to_x25519_pk(public: &BarePublicKey) -> VeilidAPIResult<xd::PublicKey> {
let pk_ed = ed::VerifyingKey::from_bytes(&public.bytes).map_err(VeilidAPIError::internal)?; let pk_ed = ed::VerifyingKey::from_bytes(
public
.bytes()
.try_into()
.map_err(VeilidAPIError::internal)?,
)
.map_err(VeilidAPIError::internal)?;
Ok(xd::PublicKey::from(*pk_ed.to_montgomery().as_bytes())) Ok(xd::PublicKey::from(*pk_ed.to_montgomery().as_bytes()))
} }
fn secret_to_x25519_sk(secret: &BareSecretKey) -> VeilidAPIResult<xd::StaticSecret> { fn secret_to_x25519_sk(secret: &BareSecretKey) -> VeilidAPIResult<xd::StaticSecret> {
// NOTE: ed::SigningKey.to_scalar() does not produce an unreduced scalar, we want the raw bytes here // NOTE: ed::SigningKey.to_scalar() does not produce an unreduced scalar, we want the raw bytes here
// See https://github.com/dalek-cryptography/curve25519-dalek/issues/565 // See https://github.com/dalek-cryptography/curve25519-dalek/issues/565
let hash: [u8; SIGNATURE_LENGTH] = ed::Sha512::default() let hash: [u8; VLD0_SIGNATURE_LENGTH] = ed::Sha512::default()
.chain_update(secret.bytes) .chain_update(secret.bytes())
.finalize() .finalize()
.into(); .into();
let mut output = [0u8; SECRET_KEY_LENGTH]; let mut output = [0u8; VLD0_SECRET_KEY_LENGTH];
output.copy_from_slice(&hash[..SECRET_KEY_LENGTH]); output.copy_from_slice(&hash[..VLD0_SECRET_KEY_LENGTH]);
Ok(xd::StaticSecret::from(output)) Ok(xd::StaticSecret::from(output))
} }
@ -40,8 +49,8 @@ pub(crate) fn vld0_generate_keypair() -> BareKeyPair {
let mut csprng = VeilidRng {}; let mut csprng = VeilidRng {};
let signing_key = ed::SigningKey::generate(&mut csprng); let signing_key = ed::SigningKey::generate(&mut csprng);
let verifying_key = signing_key.verifying_key(); let verifying_key = signing_key.verifying_key();
let public_key = BarePublicKey::new(verifying_key.to_bytes()); let public_key = BarePublicKey::new(&verifying_key.to_bytes());
let secret_key = BareSecretKey::new(signing_key.to_bytes()); let secret_key = BareSecretKey::new(&signing_key.to_bytes());
BareKeyPair::new(public_key, secret_key) BareKeyPair::new(public_key, secret_key)
} }
@ -86,9 +95,7 @@ impl CryptoSystem for CryptoSystemVLD0 {
random_bytes(bytes.as_mut()); random_bytes(bytes.as_mut());
bytes bytes
} }
fn default_salt_length(&self) -> u32 {
16
}
#[instrument(level = "trace", target = "crypto", skip_all)] #[instrument(level = "trace", target = "crypto", skip_all)]
fn hash_password(&self, password: &[u8], salt: &[u8]) -> VeilidAPIResult<String> { fn hash_password(&self, password: &[u8], salt: &[u8]) -> VeilidAPIResult<String> {
if salt.len() < Salt::MIN_LENGTH || salt.len() > Salt::MAX_LENGTH { if salt.len() < Salt::MIN_LENGTH || salt.len() > Salt::MAX_LENGTH {
@ -129,25 +136,25 @@ impl CryptoSystem for CryptoSystemVLD0 {
// Argon2 with default params (Argon2id v19) // Argon2 with default params (Argon2id v19)
let argon2 = Argon2::default(); let argon2 = Argon2::default();
let mut output_key_material = [0u8; SHARED_SECRET_LENGTH]; let mut output_key_material = [0u8; VLD0_SHARED_SECRET_LENGTH];
argon2 argon2
.hash_password_into(password, salt, &mut output_key_material) .hash_password_into(password, salt, &mut output_key_material)
.map_err(VeilidAPIError::generic)?; .map_err(VeilidAPIError::generic)?;
Ok(BareSharedSecret::new(output_key_material)) Ok(BareSharedSecret::new(&output_key_material))
} }
#[instrument(level = "trace", target = "crypto", skip_all)] #[instrument(level = "trace", target = "crypto", skip_all)]
fn random_nonce(&self) -> BareNonce { fn random_nonce(&self) -> BareNonce {
let mut nonce = [0u8; NONCE_LENGTH]; let mut nonce = [0u8; VLD0_NONCE_LENGTH];
random_bytes(&mut nonce); random_bytes(&mut nonce);
BareNonce::new(nonce) BareNonce::new(&nonce)
} }
#[instrument(level = "trace", target = "crypto", skip_all)] #[instrument(level = "trace", target = "crypto", skip_all)]
fn random_shared_secret(&self) -> BareSharedSecret { fn random_shared_secret(&self) -> BareSharedSecret {
let mut s = [0u8; SHARED_SECRET_LENGTH]; let mut s = [0u8; VLD0_SHARED_SECRET_LENGTH];
random_bytes(&mut s); random_bytes(&mut s);
BareSharedSecret::new(s) BareSharedSecret::new(&s)
} }
#[instrument(level = "trace", target = "crypto", skip_all)] #[instrument(level = "trace", target = "crypto", skip_all)]
@ -162,11 +169,11 @@ impl CryptoSystem for CryptoSystemVLD0 {
let dh_bytes = sk_xd.diffie_hellman(&pk_xd).to_bytes(); let dh_bytes = sk_xd.diffie_hellman(&pk_xd).to_bytes();
let mut hasher = blake3::Hasher::new(); let mut hasher = blake3::Hasher::new();
hasher.update(VEILID_DOMAIN_CRYPT); hasher.update(VLD0_DOMAIN_CRYPT);
hasher.update(&dh_bytes); hasher.update(&dh_bytes);
let output = hasher.finalize(); let output = hasher.finalize();
Ok(BareSharedSecret::new(*output.as_bytes())) Ok(BareSharedSecret::new(output.as_bytes()))
} }
#[instrument(level = "trace", target = "crypto", skip_all)] #[instrument(level = "trace", target = "crypto", skip_all)]
@ -176,7 +183,7 @@ impl CryptoSystem for CryptoSystemVLD0 {
#[instrument(level = "trace", target = "crypto", skip_all)] #[instrument(level = "trace", target = "crypto", skip_all)]
fn generate_hash(&self, data: &[u8]) -> BareHashDigest { fn generate_hash(&self, data: &[u8]) -> BareHashDigest {
BareHashDigest::new(*blake3::hash(data).as_bytes()) BareHashDigest::new(blake3::hash(data).as_bytes())
} }
#[instrument(level = "trace", target = "crypto", skip_all)] #[instrument(level = "trace", target = "crypto", skip_all)]
@ -186,10 +193,35 @@ impl CryptoSystem for CryptoSystemVLD0 {
) -> VeilidAPIResult<BarePublicKey> { ) -> VeilidAPIResult<BarePublicKey> {
let mut hasher = blake3::Hasher::new(); let mut hasher = blake3::Hasher::new();
std::io::copy(reader, &mut hasher).map_err(VeilidAPIError::generic)?; std::io::copy(reader, &mut hasher).map_err(VeilidAPIError::generic)?;
Ok(BarePublicKey::new(*hasher.finalize().as_bytes())) Ok(BarePublicKey::new(hasher.finalize().as_bytes()))
} }
// Validation // Validation
fn shared_secret_length(&self) -> usize {
VLD0_SHARED_SECRET_LENGTH
}
fn nonce_length(&self) -> usize {
VLD0_NONCE_LENGTH
}
fn hash_digest_length(&self) -> usize {
VLD0_HASH_DIGEST_LENGTH
}
fn public_key_length(&self) -> usize {
VLD0_PUBLIC_KEY_LENGTH
}
fn secret_key_length(&self) -> usize {
VLD0_SECRET_KEY_LENGTH
}
fn signature_length(&self) -> usize {
VLD0_SIGNATURE_LENGTH
}
fn default_salt_length(&self) -> usize {
16
}
fn aead_overhead(&self) -> usize {
VLD0_AEAD_OVERHEAD
}
#[instrument(level = "trace", target = "crypto", skip_all)] #[instrument(level = "trace", target = "crypto", skip_all)]
fn validate_keypair(&self, public_key: &BarePublicKey, secret_key: &BareSecretKey) -> bool { fn validate_keypair(&self, public_key: &BarePublicKey, secret_key: &BareSecretKey) -> bool {
let data = vec![0u8; 512]; let data = vec![0u8; 512];
@ -206,7 +238,7 @@ impl CryptoSystem for CryptoSystemVLD0 {
fn validate_hash(&self, data: &[u8], hash_digest: &BareHashDigest) -> bool { fn validate_hash(&self, data: &[u8], hash_digest: &BareHashDigest) -> bool {
let bytes = *blake3::hash(data).as_bytes(); let bytes = *blake3::hash(data).as_bytes();
bytes == hash_digest.bytes bytes == hash_digest.bytes()
} }
#[instrument(level = "trace", target = "crypto", skip_all)] #[instrument(level = "trace", target = "crypto", skip_all)]
@ -218,19 +250,19 @@ impl CryptoSystem for CryptoSystemVLD0 {
let mut hasher = blake3::Hasher::new(); let mut hasher = blake3::Hasher::new();
std::io::copy(reader, &mut hasher).map_err(VeilidAPIError::generic)?; std::io::copy(reader, &mut hasher).map_err(VeilidAPIError::generic)?;
let bytes = *hasher.finalize().as_bytes(); let bytes = *hasher.finalize().as_bytes();
Ok(bytes == hash_digest.bytes) Ok(bytes == hash_digest.bytes())
} }
// Distance Metric // Distance Metric
#[instrument(level = "trace", target = "crypto", skip_all)] #[instrument(level = "trace", target = "crypto", skip_all)]
fn distance(&self, hash1: &BareHashDigest, hash2: &BareHashDigest) -> BareHashDistance { fn distance(&self, hash1: &BareHashDigest, hash2: &BareHashDigest) -> BareHashDistance {
let mut bytes = [0u8; CRYPTO_KEY_LENGTH]; let mut bytes = [0u8; VLD0_HASH_DIGEST_LENGTH];
(0..CRYPTO_KEY_LENGTH).for_each(|n| { (0..VLD0_HASH_DIGEST_LENGTH).for_each(|n| {
bytes[n] = hash1.bytes[n] ^ hash2.bytes[n]; bytes[n] = hash1[n] ^ hash2[n];
}); });
BareHashDistance::new(bytes) BareHashDistance::new(&bytes)
} }
// Authentication // Authentication
@ -241,11 +273,11 @@ impl CryptoSystem for CryptoSystemVLD0 {
secret_key: &BareSecretKey, secret_key: &BareSecretKey,
data: &[u8], data: &[u8],
) -> VeilidAPIResult<BareSignature> { ) -> VeilidAPIResult<BareSignature> {
let mut kpb: [u8; SECRET_KEY_LENGTH + PUBLIC_KEY_LENGTH] = let mut kpb: [u8; VLD0_SECRET_KEY_LENGTH + VLD0_PUBLIC_KEY_LENGTH] =
[0u8; SECRET_KEY_LENGTH + PUBLIC_KEY_LENGTH]; [0u8; VLD0_SECRET_KEY_LENGTH + VLD0_PUBLIC_KEY_LENGTH];
kpb[..SECRET_KEY_LENGTH].copy_from_slice(&secret_key.bytes); kpb[..VLD0_SECRET_KEY_LENGTH].copy_from_slice(secret_key);
kpb[SECRET_KEY_LENGTH..].copy_from_slice(&public_key.bytes); kpb[VLD0_SECRET_KEY_LENGTH..].copy_from_slice(public_key);
let keypair = ed::SigningKey::from_keypair_bytes(&kpb) let keypair = ed::SigningKey::from_keypair_bytes(&kpb)
.map_err(|e| VeilidAPIError::parse_error("Keypair is invalid", e))?; .map_err(|e| VeilidAPIError::parse_error("Keypair is invalid", e))?;
@ -253,10 +285,10 @@ impl CryptoSystem for CryptoSystemVLD0 {
dig.update(data); dig.update(data);
let sig_bytes = keypair let sig_bytes = keypair
.sign_prehashed(dig, Some(VEILID_DOMAIN_SIGN)) .sign_prehashed(dig, Some(VLD0_DOMAIN_SIGN))
.map_err(VeilidAPIError::internal)?; .map_err(VeilidAPIError::internal)?;
let sig = BareSignature::new(sig_bytes.to_bytes()); let sig = BareSignature::new(&sig_bytes.to_bytes());
if !self.verify(public_key, data, &sig)? { if !self.verify(public_key, data, &sig)? {
apibail_internal!("newly created signature does not verify"); apibail_internal!("newly created signature does not verify");
@ -271,15 +303,25 @@ impl CryptoSystem for CryptoSystemVLD0 {
data: &[u8], data: &[u8],
signature: &BareSignature, signature: &BareSignature,
) -> VeilidAPIResult<bool> { ) -> VeilidAPIResult<bool> {
let pk = ed::VerifyingKey::from_bytes(&public_key.bytes) let pk = ed::VerifyingKey::from_bytes(
.map_err(|e| VeilidAPIError::parse_error("Public key is invalid", e))?; public_key
let sig = ed::Signature::from_bytes(&signature.bytes); .bytes()
.try_into()
.map_err(VeilidAPIError::internal)?,
)
.map_err(|e| VeilidAPIError::parse_error("Public key is invalid", e))?;
let sig = ed::Signature::from_bytes(
signature
.bytes()
.try_into()
.map_err(VeilidAPIError::internal)?,
);
let mut dig: ed::Sha512 = ed::Sha512::default(); let mut dig: ed::Sha512 = ed::Sha512::default();
dig.update(data); dig.update(data);
if pk if pk
.verify_prehashed_strict(dig, Some(VEILID_DOMAIN_SIGN), &sig) .verify_prehashed_strict(dig, Some(VLD0_DOMAIN_SIGN), &sig)
.is_err() .is_err()
{ {
return Ok(false); return Ok(false);
@ -288,10 +330,6 @@ impl CryptoSystem for CryptoSystemVLD0 {
} }
// AEAD Encrypt/Decrypt // AEAD Encrypt/Decrypt
fn aead_overhead(&self) -> usize {
AEAD_OVERHEAD
}
#[instrument(level = "trace", target = "crypto", skip_all)] #[instrument(level = "trace", target = "crypto", skip_all)]
fn decrypt_in_place_aead( fn decrypt_in_place_aead(
&self, &self,
@ -300,8 +338,15 @@ impl CryptoSystem for CryptoSystemVLD0 {
shared_secret: &BareSharedSecret, shared_secret: &BareSharedSecret,
associated_data: Option<&[u8]>, associated_data: Option<&[u8]>,
) -> VeilidAPIResult<()> { ) -> VeilidAPIResult<()> {
let key = ch::Key::from(shared_secret.bytes); let shared_secret_bytes: [u8; VLD0_SHARED_SECRET_LENGTH] = shared_secret
let xnonce = ch::XNonce::from(nonce.bytes); .bytes()
.try_into()
.map_err(VeilidAPIError::internal)?;
let nonce_bytes: [u8; VLD0_NONCE_LENGTH] =
nonce.bytes().try_into().map_err(VeilidAPIError::internal)?;
let key = ch::Key::from(shared_secret_bytes);
let xnonce = ch::XNonce::from(nonce_bytes);
let aead = ch::XChaCha20Poly1305::new(&key); let aead = ch::XChaCha20Poly1305::new(&key);
aead.decrypt_in_place(&xnonce, associated_data.unwrap_or(b""), body) aead.decrypt_in_place(&xnonce, associated_data.unwrap_or(b""), body)
.map_err(map_to_string) .map_err(map_to_string)
@ -331,8 +376,15 @@ impl CryptoSystem for CryptoSystemVLD0 {
shared_secret: &BareSharedSecret, shared_secret: &BareSharedSecret,
associated_data: Option<&[u8]>, associated_data: Option<&[u8]>,
) -> VeilidAPIResult<()> { ) -> VeilidAPIResult<()> {
let key = ch::Key::from(shared_secret.bytes); let shared_secret_bytes: [u8; VLD0_SHARED_SECRET_LENGTH] = shared_secret
let xnonce = ch::XNonce::from(nonce.bytes); .bytes()
.try_into()
.map_err(VeilidAPIError::internal)?;
let nonce_bytes: [u8; VLD0_NONCE_LENGTH] =
nonce.bytes().try_into().map_err(VeilidAPIError::internal)?;
let key = ch::Key::from(shared_secret_bytes);
let xnonce = ch::XNonce::from(nonce_bytes);
let aead = ch::XChaCha20Poly1305::new(&key); let aead = ch::XChaCha20Poly1305::new(&key);
aead.encrypt_in_place(&xnonce, associated_data.unwrap_or(b""), body) aead.encrypt_in_place(&xnonce, associated_data.unwrap_or(b""), body)
@ -362,10 +414,19 @@ impl CryptoSystem for CryptoSystemVLD0 {
body: &mut [u8], body: &mut [u8],
nonce: &BareNonce, nonce: &BareNonce,
shared_secret: &BareSharedSecret, shared_secret: &BareSharedSecret,
) { ) -> VeilidAPIResult<()> {
let mut cipher = let shared_secret_bytes: [u8; VLD0_SHARED_SECRET_LENGTH] = shared_secret
<XChaCha20 as KeyIvInit>::new(&shared_secret.bytes.into(), &nonce.bytes.into()); .bytes()
.try_into()
.map_err(VeilidAPIError::internal)?;
let nonce_bytes: [u8; VLD0_NONCE_LENGTH] =
nonce.bytes().try_into().map_err(VeilidAPIError::internal)?;
let key = ch::Key::from(shared_secret_bytes);
let xnonce = ch::XNonce::from(nonce_bytes);
let mut cipher = <XChaCha20 as KeyIvInit>::new(&key, &xnonce);
cipher.apply_keystream(body); cipher.apply_keystream(body);
Ok(())
} }
#[instrument(level = "trace", target = "crypto", skip_all)] #[instrument(level = "trace", target = "crypto", skip_all)]
@ -375,10 +436,21 @@ impl CryptoSystem for CryptoSystemVLD0 {
out_buf: &mut [u8], out_buf: &mut [u8],
nonce: &BareNonce, nonce: &BareNonce,
shared_secret: &BareSharedSecret, shared_secret: &BareSharedSecret,
) { ) -> VeilidAPIResult<()> {
let mut cipher = let shared_secret_bytes: [u8; VLD0_SHARED_SECRET_LENGTH] = shared_secret
<XChaCha20 as KeyIvInit>::new(&shared_secret.bytes.into(), &nonce.bytes.into()); .bytes()
cipher.apply_keystream_b2b(in_buf, out_buf).unwrap(); .try_into()
.map_err(VeilidAPIError::internal)?;
let nonce_bytes: [u8; VLD0_NONCE_LENGTH] =
nonce.bytes().try_into().map_err(VeilidAPIError::internal)?;
let key = ch::Key::from(shared_secret_bytes);
let xnonce = ch::XNonce::from(nonce_bytes);
let mut cipher = <XChaCha20 as KeyIvInit>::new(&key, &xnonce);
cipher
.apply_keystream_b2b(in_buf, out_buf)
.map_err(VeilidAPIError::generic)?;
Ok(())
} }
#[instrument(level = "trace", target = "crypto", skip_all)] #[instrument(level = "trace", target = "crypto", skip_all)]
@ -387,10 +459,10 @@ impl CryptoSystem for CryptoSystemVLD0 {
in_buf: &[u8], in_buf: &[u8],
nonce: &BareNonce, nonce: &BareNonce,
shared_secret: &BareSharedSecret, shared_secret: &BareSharedSecret,
) -> Vec<u8> { ) -> VeilidAPIResult<Vec<u8>> {
let mut out_buf = unsafe { aligned_8_u8_vec_uninit(in_buf.len()) }; let mut out_buf = unsafe { aligned_8_u8_vec_uninit(in_buf.len()) };
self.crypt_b2b_no_auth(in_buf, &mut out_buf, nonce, shared_secret); self.crypt_b2b_no_auth(in_buf, &mut out_buf, nonce, shared_secret)?;
out_buf Ok(out_buf)
} }
#[instrument(level = "trace", target = "crypto", skip_all)] #[instrument(level = "trace", target = "crypto", skip_all)]
@ -399,9 +471,9 @@ impl CryptoSystem for CryptoSystemVLD0 {
in_buf: &[u8], in_buf: &[u8],
nonce: &BareNonce, nonce: &BareNonce,
shared_secret: &BareSharedSecret, shared_secret: &BareSharedSecret,
) -> Vec<u8> { ) -> VeilidAPIResult<Vec<u8>> {
let mut out_buf = unsafe { unaligned_u8_vec_uninit(in_buf.len()) }; let mut out_buf = unsafe { unaligned_u8_vec_uninit(in_buf.len()) };
self.crypt_b2b_no_auth(in_buf, &mut out_buf, nonce, shared_secret); self.crypt_b2b_no_auth(in_buf, &mut out_buf, nonce, shared_secret)?;
out_buf Ok(out_buf)
} }
} }

View file

@ -0,0 +1,12 @@
/// Length of a crypto key in bytes
pub const VLD0_PUBLIC_KEY_LENGTH: usize = 32;
/// Length of a secret key in bytes
pub const VLD0_SECRET_KEY_LENGTH: usize = 32;
/// Length of a signature in bytes
pub const VLD0_SIGNATURE_LENGTH: usize = 64;
/// Length of a nonce in bytes
pub const VLD0_NONCE_LENGTH: usize = 24;
/// Length of a hash digest in bytes
pub const VLD0_HASH_DIGEST_LENGTH: usize = 32;
/// Length of a shared secret in bytes
pub const VLD0_SHARED_SECRET_LENGTH: usize = 32;

View file

@ -184,7 +184,7 @@ impl AddressFilter {
if cur_ts.as_u64().saturating_sub(value.timestamp.as_u64()) if cur_ts.as_u64().saturating_sub(value.timestamp.as_u64())
> self.punishment_duration_min as u64 * 60_000_000u64 > self.punishment_duration_min as u64 * 60_000_000u64
{ {
dead_keys.push(*key); dead_keys.push(key.clone());
} }
} }
for key in dead_keys { for key in dead_keys {
@ -310,7 +310,7 @@ impl AddressFilter {
} }
pub fn punish_node_id(&self, node_id: NodeId, reason: PunishmentReason) { pub fn punish_node_id(&self, node_id: NodeId, reason: PunishmentReason) {
if let Ok(Some(nr)) = self.routing_table().lookup_node_ref(node_id) { if let Ok(Some(nr)) = self.routing_table().lookup_node_ref(node_id.clone()) {
// make the entry dead if it's punished // make the entry dead if it's punished
nr.operate_mut(|_rti, e| e.set_punished(Some(reason))); nr.operate_mut(|_rti, e| e.set_punished(Some(reason)));
} }

View file

@ -156,7 +156,7 @@ impl BootstrapRecord {
let crypto = network_manager.crypto(); let crypto = network_manager.crypto();
let sig = match crypto.generate_signatures(v1.as_bytes(), &[signing_key_pair], |kp, sig| { let sig = match crypto.generate_signatures(v1.as_bytes(), &[signing_key_pair], |kp, sig| {
Signature::new(kp.kind, sig).to_string() Signature::new(kp.kind(), sig).to_string()
}) { }) {
Ok(v) => { Ok(v) => {
let Some(sig) = v.first().cloned() else { let Some(sig) = v.first().cloned() else {
@ -393,13 +393,13 @@ impl BootstrapRecord {
// Validate signature against any signing keys if we have them // Validate signature against any signing keys if we have them
if !signing_keys.is_empty() { if !signing_keys.is_empty() {
let mut validated = false; let mut validated = false;
for key in signing_keys.iter().copied() { for key in signing_keys {
if let Some(valid_keys) = network_manager.crypto().verify_signatures( if let Some(valid_keys) = network_manager.crypto().verify_signatures(
&[key], &[key.clone()],
signed_str.as_bytes(), signed_str.as_bytes(),
&[sig], &[sig.clone()],
)? { )? {
if valid_keys.contains(&key) { if valid_keys.contains(key) {
validated = true; validated = true;
break; break;
} }

View file

@ -286,7 +286,7 @@ impl NetworkManager {
Some( Some(
bcs.derive_shared_secret( bcs.derive_shared_secret(
network_key_password.as_bytes(), network_key_password.as_bytes(),
&bcs.generate_hash(network_key_password.as_bytes()).bytes, &bcs.generate_hash(network_key_password.as_bytes()),
) )
.expect("failed to derive network key"), .expect("failed to derive network key"),
) )
@ -616,9 +616,9 @@ impl NetworkManager {
let receipt = Receipt::try_new( let receipt = Receipt::try_new(
best_envelope_version(), best_envelope_version(),
node_id.kind, node_id.kind(),
nonce, nonce,
node_id.value, node_id.value(),
extra_data, extra_data,
)?; )?;
let out = receipt let out = receipt
@ -656,9 +656,9 @@ impl NetworkManager {
let receipt = Receipt::try_new( let receipt = Receipt::try_new(
best_envelope_version(), best_envelope_version(),
node_id.kind, node_id.kind(),
nonce, nonce,
node_id.value, node_id.value(),
extra_data, extra_data,
)?; )?;
let out = receipt let out = receipt
@ -881,7 +881,7 @@ impl NetworkManager {
// DH to get encryption key // DH to get encryption key
let routing_table = self.routing_table(); let routing_table = self.routing_table();
let crypto = self.crypto(); let crypto = self.crypto();
let Some(vcrypto) = crypto.get(dest_node_id.kind) else { let Some(vcrypto) = crypto.get(dest_node_id.kind()) else {
bail!("should not have a destination with incompatible crypto here"); bail!("should not have a destination with incompatible crypto here");
}; };
@ -895,11 +895,11 @@ impl NetworkManager {
// Encode envelope // Encode envelope
let envelope = Envelope::new( let envelope = Envelope::new(
version, version,
node_id.kind, node_id.kind(),
ts, ts,
nonce, nonce,
node_id.value, node_id.value(),
dest_node_id.value, dest_node_id.value(),
); );
envelope envelope
.to_encrypted_data(&crypto, body.as_ref(), &node_id_secret, &self.network_key) .to_encrypted_data(&crypto, body.as_ref(), &node_id_secret, &self.network_key)
@ -1101,15 +1101,15 @@ impl NetworkManager {
let rpc = self.rpc_processor(); let rpc = self.rpc_processor();
// See if this sender is punished, if so, ignore the packet // See if this sender is punished, if so, ignore the packet
let sender_id = envelope.get_sender_typed_id(); let sender_id = envelope.get_sender_id();
if self.address_filter().is_node_id_punished(sender_id) { if self.address_filter().is_node_id_punished(sender_id.clone()) {
return Ok(false); return Ok(false);
} }
// Peek at header and see if we need to relay this // Peek at header and see if we need to relay this
// If the recipient id is not our node id, then it needs relaying // If the recipient id is not our node id, then it needs relaying
let recipient_id = envelope.get_recipient_typed_id(); let recipient_id = envelope.get_recipient_id();
if !routing_table.matches_own_node_id(&[recipient_id]) { if !routing_table.matches_own_node_id(&[recipient_id.clone()]) {
// See if the source node is allowed to resolve nodes // See if the source node is allowed to resolve nodes
// This is a costly operation, so only outbound-relay permitted // This is a costly operation, so only outbound-relay permitted
// nodes are allowed to do this, for example PWA users // nodes are allowed to do this, for example PWA users
@ -1119,10 +1119,13 @@ impl NetworkManager {
// xxx: that 'localnetwork' routing domain nodes could be allowed to // xxx: that 'localnetwork' routing domain nodes could be allowed to
// xxx: full relay as well as client_allowlist nodes... // xxx: full relay as well as client_allowlist nodes...
let some_relay_nr = if self.check_client_allowlist(sender_id) { let some_relay_nr = if self.check_client_allowlist(sender_id.clone()) {
// Full relay allowed, do a full resolve_node // Full relay allowed, do a full resolve_node
match rpc match rpc
.resolve_node(recipient_id, SafetySelection::Unsafe(Sequencing::default())) .resolve_node(
recipient_id.clone(),
SafetySelection::Unsafe(Sequencing::default()),
)
.await .await
{ {
Ok(v) => v.map(|nr| nr.default_filtered()), Ok(v) => v.map(|nr| nr.default_filtered()),

View file

@ -231,7 +231,7 @@ impl ReceiptManager {
let receipt_inner = v.lock(); let receipt_inner = v.lock();
if receipt_inner.expiration_ts <= now { if receipt_inner.expiration_ts <= now {
// Expire this receipt // Expire this receipt
expired_nonces.push(*k); expired_nonces.push(k.clone());
} else if new_next_oldest_ts.is_none() } else if new_next_oldest_ts.is_none()
|| receipt_inner.expiration_ts < new_next_oldest_ts.unwrap() || receipt_inner.expiration_ts < new_next_oldest_ts.unwrap()
{ {

View file

@ -503,7 +503,7 @@ impl NetworkManager {
if target_node_ref if target_node_ref
.node_ids() .node_ids()
.iter() .iter()
.any(|nid| self.address_filter().is_node_id_punished(*nid)) .any(|nid| self.address_filter().is_node_id_punished(nid.clone()))
{ {
return Ok(None); return Ok(None);
} }
@ -647,7 +647,11 @@ impl NetworkManager {
ContactMethod::Direct(di) => Some(NodeContactMethodKind::Direct(di)), ContactMethod::Direct(di) => Some(NodeContactMethodKind::Direct(di)),
ContactMethod::SignalReverse(relay_key, target_key) => { ContactMethod::SignalReverse(relay_key, target_key) => {
let mut relay_nr = routing_table let mut relay_nr = routing_table
.lookup_and_filter_noderef(relay_key, routing_domain.into(), dial_info_filter)? .lookup_and_filter_noderef(
relay_key.clone(),
routing_domain.into(),
dial_info_filter,
)?
.ok_or_else(|| { .ok_or_else(|| {
eyre!( eyre!(
"couldn't look up relay for signal reverse: {} with filter {:?}", "couldn't look up relay for signal reverse: {} with filter {:?}",
@ -702,7 +706,11 @@ impl NetworkManager {
} }
ContactMethod::SignalHolePunch(relay_key, target_key) => { ContactMethod::SignalHolePunch(relay_key, target_key) => {
let mut relay_nr = routing_table let mut relay_nr = routing_table
.lookup_and_filter_noderef(relay_key, routing_domain.into(), dial_info_filter)? .lookup_and_filter_noderef(
relay_key.clone(),
routing_domain.into(),
dial_info_filter,
)?
.ok_or_else(|| { .ok_or_else(|| {
eyre!( eyre!(
"couldn't look up relay for hole punch: {} with filter {:?}", "couldn't look up relay for hole punch: {} with filter {:?}",
@ -732,7 +740,11 @@ impl NetworkManager {
} }
ContactMethod::InboundRelay(relay_key) => { ContactMethod::InboundRelay(relay_key) => {
let mut relay_nr = routing_table let mut relay_nr = routing_table
.lookup_and_filter_noderef(relay_key, routing_domain.into(), dial_info_filter)? .lookup_and_filter_noderef(
relay_key.clone(),
routing_domain.into(),
dial_info_filter,
)?
.ok_or_else(|| { .ok_or_else(|| {
eyre!( eyre!(
"couldn't look up relay for inbound relay: {} with filter {:?}", "couldn't look up relay for inbound relay: {} with filter {:?}",
@ -745,7 +757,11 @@ impl NetworkManager {
} }
ContactMethod::OutboundRelay(relay_key) => { ContactMethod::OutboundRelay(relay_key) => {
let mut relay_nr = routing_table let mut relay_nr = routing_table
.lookup_and_filter_noderef(relay_key, routing_domain.into(), dial_info_filter)? .lookup_and_filter_noderef(
relay_key.clone(),
routing_domain.into(),
dial_info_filter,
)?
.ok_or_else(|| { .ok_or_else(|| {
eyre!( eyre!(
"couldn't look up relay for outbound relay: {} with filter {:?}", "couldn't look up relay for outbound relay: {} with filter {:?}",

View file

@ -127,7 +127,7 @@ impl NetworkManager {
if let Ok(Some(nr)) = routing_table.lookup_node_ref(k) { if let Ok(Some(nr)) = routing_table.lookup_node_ref(k) {
let peer_stats = nr.peer_stats(); let peer_stats = nr.peer_stats();
let peer = PeerTableData { let peer = PeerTableData {
node_ids: nr.node_ids().iter().copied().collect(), node_ids: nr.node_ids().iter().cloned().collect(),
peer_address: v.last_connection.remote().to_string(), peer_address: v.last_connection.remote().to_string(),
peer_stats, peer_stats,
}; };

View file

@ -77,10 +77,14 @@ pub async fn test_bootstrap_v1() {
println!("signing_key_pairs: {:?}", signing_key_pairs); println!("signing_key_pairs: {:?}", signing_key_pairs);
let signing_keys = signing_key_pairs let signing_keys = signing_key_pairs
.iter() .iter()
.map(|skp| PublicKey::new(skp.kind, skp.value.key)) .map(|skp| PublicKey::new(skp.kind(), skp.ref_value().key()))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let v1str = bsrec let v1str = bsrec
.to_v1_string(&network_manager, &dial_info_converter, signing_key_pairs[0]) .to_v1_string(
&network_manager,
&dial_info_converter,
signing_key_pairs[0].clone(),
)
.await .await
.expect("should make string"); .expect("should make string");
let bsrec2 = BootstrapRecord::new_from_v1_str( let bsrec2 = BootstrapRecord::new_from_v1_str(

View file

@ -31,11 +31,11 @@ pub async fn test_signed_node_info() {
let keypair = vcrypto.generate_keypair(); let keypair = vcrypto.generate_keypair();
let sni = SignedDirectNodeInfo::make_signatures( let sni = SignedDirectNodeInfo::make_signatures(
&crypto, &crypto,
vec![KeyPair::new(ck, keypair)], vec![KeyPair::new(ck, keypair.clone())],
node_info.clone(), node_info.clone(),
) )
.unwrap(); .unwrap();
let tks: PublicKeyGroup = PublicKey::new(ck, keypair.key).into(); let tks: PublicKeyGroup = PublicKey::new(ck, keypair.key()).into();
let tks_node_ids = NodeIdGroup::from(tks.clone()); let tks_node_ids = NodeIdGroup::from(tks.clone());
let oldtkslen = tks.len(); let oldtkslen = tks.len();
let sdni = SignedDirectNodeInfo::new( let sdni = SignedDirectNodeInfo::new(
@ -49,7 +49,7 @@ pub async fn test_signed_node_info() {
// Test incorrect validation // Test incorrect validation
let keypair1 = vcrypto.generate_keypair(); let keypair1 = vcrypto.generate_keypair();
let tks1: PublicKeyGroup = PublicKey::new(ck, keypair1.key).into(); let tks1: PublicKeyGroup = PublicKey::new(ck, keypair1.key()).into();
let sdni = SignedDirectNodeInfo::new( let sdni = SignedDirectNodeInfo::new(
node_info.clone(), node_info.clone(),
sni.timestamp(), sni.timestamp(),
@ -63,7 +63,7 @@ pub async fn test_signed_node_info() {
PublicKey::new(fake_crypto_kind, BarePublicKey::default()).into(); PublicKey::new(fake_crypto_kind, BarePublicKey::default()).into();
let mut sigsfake = sni.signatures().to_vec(); let mut sigsfake = sni.signatures().to_vec();
sigsfake.push(Signature::new(fake_crypto_kind, BareSignature::default())); sigsfake.push(Signature::new(fake_crypto_kind, BareSignature::default()));
tksfake.add(PublicKey::new(ck, keypair.key)); tksfake.add(PublicKey::new(ck, keypair.key()));
let sdnifake = let sdnifake =
SignedDirectNodeInfo::new(node_info.clone(), sni.timestamp(), sigsfake.clone()); SignedDirectNodeInfo::new(node_info.clone(), sni.timestamp(), sigsfake.clone());
let tksfake_validated = sdnifake.validate(&tksfake.into(), &crypto).unwrap(); let tksfake_validated = sdnifake.validate(&tksfake.into(), &crypto).unwrap();
@ -86,12 +86,12 @@ pub async fn test_signed_node_info() {
// Test correct validation // Test correct validation
let keypair2 = vcrypto.generate_keypair(); let keypair2 = vcrypto.generate_keypair();
let tks2: PublicKeyGroup = PublicKey::new(ck, keypair2.key).into(); let tks2: PublicKeyGroup = PublicKey::new(ck, keypair2.key()).into();
let oldtks2len = tks2.len(); let oldtks2len = tks2.len();
let sni2 = SignedRelayedNodeInfo::make_signatures( let sni2 = SignedRelayedNodeInfo::make_signatures(
&crypto, &crypto,
vec![KeyPair::new(ck, keypair2)], vec![KeyPair::new(ck, keypair2.clone())],
node_info2.clone(), node_info2.clone(),
tks_node_ids.clone(), tks_node_ids.clone(),
sni.clone(), sni.clone(),
@ -111,7 +111,7 @@ pub async fn test_signed_node_info() {
// Test incorrect validation // Test incorrect validation
let keypair3 = vcrypto.generate_keypair(); let keypair3 = vcrypto.generate_keypair();
let tks3: PublicKeyGroup = PublicKey::new(ck, keypair3.key).into(); let tks3: PublicKeyGroup = PublicKey::new(ck, keypair3.key()).into();
let srni = SignedRelayedNodeInfo::new( let srni = SignedRelayedNodeInfo::new(
node_info2.clone(), node_info2.clone(),
@ -128,7 +128,7 @@ pub async fn test_signed_node_info() {
PublicKey::new(fake_crypto_kind, BarePublicKey::default()).into(); PublicKey::new(fake_crypto_kind, BarePublicKey::default()).into();
let mut sigsfake3 = sni2.signatures().to_vec(); let mut sigsfake3 = sni2.signatures().to_vec();
sigsfake3.push(Signature::new(fake_crypto_kind, BareSignature::default())); sigsfake3.push(Signature::new(fake_crypto_kind, BareSignature::default()));
tksfake3.add(PublicKey::new(ck, keypair2.key)); tksfake3.add(PublicKey::new(ck, keypair2.key()));
let srnifake = SignedRelayedNodeInfo::new( let srnifake = SignedRelayedNodeInfo::new(
node_info2.clone(), node_info2.clone(),
tks.clone().into(), tks.clone().into(),

View file

@ -69,7 +69,7 @@ impl Bucket {
entry_index as u32 entry_index as u32
}); });
entries.push(SerializedBucketEntryData { entries.push(SerializedBucketEntryData {
key: *k, key: k.clone(),
value: *entry_index, value: *entry_index,
}); });
} }
@ -83,7 +83,10 @@ impl Bucket {
veilid_log!(self trace "Node added: {}:{}", self.kind, node_id_key); veilid_log!(self trace "Node added: {}:{}", self.kind, node_id_key);
// Add new entry // Add new entry
let entry = Arc::new(BucketEntry::new(NodeId::new(self.kind, node_id_key))); let entry = Arc::new(BucketEntry::new(NodeId::new(
self.kind,
node_id_key.clone(),
)));
self.entries.insert(node_id_key, entry.clone()); self.entries.insert(node_id_key, entry.clone());
// Return the new entry // Return the new entry
@ -132,8 +135,11 @@ impl Bucket {
let mut extra_entries = bucket_len - bucket_depth; let mut extra_entries = bucket_len - bucket_depth;
// Get the sorted list of entries by their kick order // Get the sorted list of entries by their kick order
let mut sorted_entries: Vec<(BareNodeId, Arc<BucketEntry>)> = let mut sorted_entries: Vec<(BareNodeId, Arc<BucketEntry>)> = self
self.entries.iter().map(|(k, v)| (*k, v.clone())).collect(); .entries
.iter()
.map(|(k, v)| (k.clone(), v.clone()))
.collect();
let cur_ts = Timestamp::now(); let cur_ts = Timestamp::now();
sorted_entries.sort_by(|a, b| -> core::cmp::Ordering { sorted_entries.sort_by(|a, b| -> core::cmp::Ordering {
if a.0 == b.0 { if a.0 == b.0 {

View file

@ -295,13 +295,13 @@ impl BucketEntryInner {
/// Results Err() if this operation would add more crypto kinds than we support /// Results Err() if this operation would add more crypto kinds than we support
pub fn add_node_id(&mut self, node_id: NodeId) -> EyreResult<Option<NodeId>> { pub fn add_node_id(&mut self, node_id: NodeId) -> EyreResult<Option<NodeId>> {
let total_node_id_count = self.validated_node_ids.len() + self.unsupported_node_ids.len(); let total_node_id_count = self.validated_node_ids.len() + self.unsupported_node_ids.len();
let node_ids = if VALID_CRYPTO_KINDS.contains(&node_id.kind) { let node_ids = if VALID_CRYPTO_KINDS.contains(&node_id.kind()) {
&mut self.validated_node_ids &mut self.validated_node_ids
} else { } else {
&mut self.unsupported_node_ids &mut self.unsupported_node_ids
}; };
if let Some(old_node_id) = node_ids.get(node_id.kind) { if let Some(old_node_id) = node_ids.get(node_id.kind()) {
// If this was already there we do nothing // If this was already there we do nothing
if old_node_id == node_id { if old_node_id == node_id {
return Ok(None); return Ok(None);
@ -1223,7 +1223,7 @@ pub(crate) struct BucketEntry {
impl BucketEntry { impl BucketEntry {
pub(super) fn new(first_node_id: NodeId) -> Self { pub(super) fn new(first_node_id: NodeId) -> Self {
// First node id should always be one we support since TypedKeySets are sorted and we must have at least one supported key // First node id should always be one we support since TypedKeySets are sorted and we must have at least one supported key
assert!(VALID_CRYPTO_KINDS.contains(&first_node_id.kind)); assert!(VALID_CRYPTO_KINDS.contains(&first_node_id.kind()));
let now = Timestamp::now(); let now = Timestamp::now();
let inner = BucketEntryInner { let inner = BucketEntryInner {

View file

@ -217,7 +217,7 @@ impl RoutingTable {
if !filtered_entries.is_empty() { if !filtered_entries.is_empty() {
out += &format!("{} Bucket #{}:\n", ck, b); out += &format!("{} Bucket #{}:\n", ck, b);
for e in filtered_entries { for e in filtered_entries {
let node = *e.0; let node = e.0.clone();
let can_be_relay = e.1.with(inner, |_rti, e| relay_node_filter(e)); let can_be_relay = e.1.with(inner, |_rti, e| relay_node_filter(e));
let is_relay = inner let is_relay = inner

View file

@ -1,17 +1,17 @@
use super::*; use super::*;
impl RoutingTable { impl RoutingTable {
/// Utility to find the closest nodes to a particular key, preferring reliable nodes first, /// Utility to find the closest nodes to a particular hash coordinate, preferring reliable nodes first,
/// including possibly our own node and nodes further away from the key than our own, /// including possibly our own node and nodes further away from the key than our own,
/// returning their peer info /// returning their peer info
#[instrument(level = "trace", target = "rtab", skip_all)] #[instrument(level = "trace", target = "rtab", skip_all)]
pub fn find_preferred_closest_peers( pub fn find_preferred_closest_peers(
&self, &self,
routing_domain: RoutingDomain, routing_domain: RoutingDomain,
key: NodeId, hash_coordinate: &HashDigest,
capabilities: &[VeilidCapability], capabilities: &[VeilidCapability],
) -> NetworkResult<Vec<Arc<PeerInfo>>> { ) -> NetworkResult<Vec<Arc<PeerInfo>>> {
if Crypto::validate_crypto_kind(key.kind).is_err() { if Crypto::validate_crypto_kind(hash_coordinate.kind()).is_err() {
return NetworkResult::invalid_message("invalid crypto kind"); return NetworkResult::invalid_message("invalid crypto kind");
} }
@ -48,7 +48,7 @@ impl RoutingTable {
let closest_nodes = match self.find_preferred_closest_nodes( let closest_nodes = match self.find_preferred_closest_nodes(
node_count, node_count,
key.into(), hash_coordinate.clone(),
filters, filters,
// transform // transform
|rti, entry| { |rti, entry| {
@ -57,7 +57,10 @@ impl RoutingTable {
) { ) {
Ok(v) => v, Ok(v) => v,
Err(e) => { Err(e) => {
error!("failed to find closest nodes for key {}: {}", key, e); error!(
"failed to find closest nodes for key {}: {}",
hash_coordinate, e
);
return NetworkResult::invalid_message("failed to find closest nodes for key"); return NetworkResult::invalid_message("failed to find closest nodes for key");
} }
}; };
@ -72,11 +75,11 @@ impl RoutingTable {
pub fn find_preferred_peers_closer_to_key( pub fn find_preferred_peers_closer_to_key(
&self, &self,
routing_domain: RoutingDomain, routing_domain: RoutingDomain,
key: RecordKey, hash_coordinate: &HashDigest,
required_capabilities: Vec<VeilidCapability>, required_capabilities: Vec<VeilidCapability>,
) -> NetworkResult<Vec<Arc<PeerInfo>>> { ) -> NetworkResult<Vec<Arc<PeerInfo>>> {
// add node information for the requesting node to our routing table // add node information for the requesting node to our routing table
let crypto_kind = key.kind; let crypto_kind = hash_coordinate.kind();
let own_node_id = self.node_id(crypto_kind); let own_node_id = self.node_id(crypto_kind);
// find N nodes closest to the target node in our routing table // find N nodes closest to the target node in our routing table
@ -88,10 +91,11 @@ impl RoutingTable {
let vcrypto = &vcrypto; let vcrypto = &vcrypto;
let own_distance = vcrypto.distance( let own_distance = vcrypto.distance(
&BareHashDigest::from(own_node_id.value), &BareHashDigest::from(own_node_id.value()),
&BareHashDigest::from(key.value), &hash_coordinate.value(),
); );
let value = hash_coordinate.value();
let filter = Box::new( let filter = Box::new(
move |rti: &RoutingTableInner, opt_entry: Option<Arc<BucketEntry>>| { move |rti: &RoutingTableInner, opt_entry: Option<Arc<BucketEntry>>| {
// Exclude our own node // Exclude our own node
@ -115,10 +119,8 @@ impl RoutingTable {
let Some(entry_node_id) = e.node_ids().get(crypto_kind) else { let Some(entry_node_id) = e.node_ids().get(crypto_kind) else {
return false; return false;
}; };
let entry_distance = vcrypto.distance( let entry_distance = vcrypto
&BareHashDigest::from(entry_node_id.value), .distance(&BareHashDigest::from(entry_node_id.value()), &value.clone());
&BareHashDigest::from(key.value),
);
if entry_distance >= own_distance { if entry_distance >= own_distance {
return false; return false;
} }
@ -135,7 +137,7 @@ impl RoutingTable {
// //
let closest_nodes = match self.find_preferred_closest_nodes( let closest_nodes = match self.find_preferred_closest_nodes(
node_count, node_count,
key.into(), hash_coordinate.clone(),
filters, filters,
// transform // transform
|rti, entry| { |rti, entry| {
@ -146,7 +148,10 @@ impl RoutingTable {
) { ) {
Ok(v) => v, Ok(v) => v,
Err(e) => { Err(e) => {
error!("failed to find closest nodes for key {}: {}", key, e); error!(
"failed to find closest nodes for key {}: {}",
hash_coordinate, e
);
return NetworkResult::invalid_message("failed to find closest nodes for key"); return NetworkResult::invalid_message("failed to find closest nodes for key");
} }
}; };
@ -155,8 +160,8 @@ impl RoutingTable {
// This same test is used on the other side so we vet things here // This same test is used on the other side so we vet things here
let valid = match Self::verify_peers_closer( let valid = match Self::verify_peers_closer(
vcrypto, vcrypto,
own_node_id.into(), &own_node_id.clone().into(),
key.into(), &hash_coordinate.clone(),
&closest_nodes, &closest_nodes,
) { ) {
Ok(v) => v, Ok(v) => v,
@ -167,7 +172,7 @@ impl RoutingTable {
if !valid { if !valid {
error!( error!(
"non-closer peers returned: own_node_id={:#?} key={:#?} closest_nodes={:#?}", "non-closer peers returned: own_node_id={:#?} key={:#?} closest_nodes={:#?}",
own_node_id, key, closest_nodes own_node_id, hash_coordinate, closest_nodes
); );
} }
@ -178,23 +183,23 @@ impl RoutingTable {
#[instrument(level = "trace", target = "rtab", skip_all, err)] #[instrument(level = "trace", target = "rtab", skip_all, err)]
pub fn verify_peers_closer( pub fn verify_peers_closer(
vcrypto: &crypto::CryptoSystemGuard<'_>, vcrypto: &crypto::CryptoSystemGuard<'_>,
key_far: HashDigest, key_far: &HashDigest,
key_near: HashDigest, key_near: &HashDigest,
peers: &[Arc<PeerInfo>], peers: &[Arc<PeerInfo>],
) -> EyreResult<bool> { ) -> EyreResult<bool> {
let kind = vcrypto.kind(); let kind = vcrypto.kind();
if key_far.kind != kind || key_near.kind != kind { if key_far.kind() != kind || key_near.kind() != kind {
bail!("keys all need the same cryptosystem"); bail!("keys all need the same cryptosystem");
} }
let mut closer = true; let mut closer = true;
let d_far = vcrypto.distance(&key_far.value, &key_near.value); let d_far = vcrypto.distance(key_far.ref_value(), key_near.ref_value());
for peer in peers { for peer in peers {
let Some(key_peer) = peer.node_ids().get(kind) else { let Some(key_peer) = peer.node_ids().get(kind) else {
bail!("peers need to have a key with the same cryptosystem"); bail!("peers need to have a key with the same cryptosystem");
}; };
let d_near = vcrypto.distance(&key_near.value, &key_peer.value.into()); let d_near = vcrypto.distance(key_near.ref_value(), &key_peer.value().into());
if d_far < d_near { if d_far < d_near {
let warning = format!( let warning = format!(
r#"peer: {} r#"peer: {}
@ -203,9 +208,9 @@ far (self): {}
d_near: {} d_near: {}
d_far: {} d_far: {}
cmp: {:?}"#, cmp: {:?}"#,
key_peer.value, key_peer,
key_near.value, key_near,
key_far.value, key_far,
d_near, d_near,
d_far, d_far,
d_near.cmp(&d_far) d_near.cmp(&d_far)

View file

@ -35,6 +35,12 @@ impl_veilid_log_facility!("rtab");
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
/// Routing table bucket count (one per bit per 32 byte node id)
pub const BUCKET_COUNT: usize = 256;
/// Fixed length for NodeId in bytes
#[expect(dead_code)]
pub const NODE_ID_LENGTH: usize = 32;
/// Minimum number of nodes we need, per crypto kind, per routing domain, or we trigger a bootstrap /// Minimum number of nodes we need, per crypto kind, per routing domain, or we trigger a bootstrap
pub const MIN_BOOTSTRAP_CONNECTIVITY_PEERS: usize = 4; pub const MIN_BOOTSTRAP_CONNECTIVITY_PEERS: usize = 4;
/// Set of routing domains that use the bootstrap mechanism /// Set of routing domains that use the bootstrap mechanism
@ -312,7 +318,7 @@ impl RoutingTable {
pub fn node_id_secret_key(&self, kind: CryptoKind) -> BareSecretKey { pub fn node_id_secret_key(&self, kind: CryptoKind) -> BareSecretKey {
self.config() self.config()
.with(|c| c.network.routing_table.node_id_secret.get(kind).unwrap()) .with(|c| c.network.routing_table.node_id_secret.get(kind).unwrap())
.value .value()
} }
pub fn node_ids(&self) -> NodeIdGroup { pub fn node_ids(&self) -> NodeIdGroup {
@ -325,7 +331,7 @@ impl RoutingTable {
for ck in VALID_CRYPTO_KINDS { for ck in VALID_CRYPTO_KINDS {
tkps.push(KeyPair::new( tkps.push(KeyPair::new(
ck, ck,
BareKeyPair::new(self.node_id(ck).value.into(), self.node_id_secret_key(ck)), BareKeyPair::new(self.node_id(ck).value().into(), self.node_id_secret_key(ck)),
)); ));
} }
tkps tkps
@ -333,8 +339,8 @@ impl RoutingTable {
pub fn matches_own_node_id(&self, node_ids: &[NodeId]) -> bool { pub fn matches_own_node_id(&self, node_ids: &[NodeId]) -> bool {
for ni in node_ids { for ni in node_ids {
if let Some(v) = self.node_ids().get(ni.kind) { if let Some(v) = self.node_ids().get(ni.kind()) {
if v.value == ni.value { if v.ref_value() == ni.ref_value() {
return true; return true;
} }
} }
@ -344,22 +350,52 @@ impl RoutingTable {
pub fn matches_own_node_id_key(&self, node_id_key: &BareNodeId) -> bool { pub fn matches_own_node_id_key(&self, node_id_key: &BareNodeId) -> bool {
for tk in self.node_ids().iter() { for tk in self.node_ids().iter() {
if tk.value == *node_id_key { if tk.ref_value() == node_id_key {
return true; return true;
} }
} }
false false
} }
pub fn calculate_bucket_index(&self, node_id: &NodeId) -> BucketIndex { /// Produce node id from public key
pub fn generate_node_id(&self, public_key: &PublicKey) -> VeilidAPIResult<NodeId> {
if public_key.ref_value().len() == NODE_ID_LENGTH {
return Ok(NodeId::new(
public_key.kind(),
BareNodeId::new(public_key.ref_value()),
));
}
let crypto = self.crypto(); let crypto = self.crypto();
let self_node_id_key = self.node_id(node_id.kind).value; let Some(vcrypto) = crypto.get(public_key.kind()) else {
let vcrypto = crypto.get(node_id.kind).unwrap(); apibail_generic!("unsupported cryptosystem");
};
let idhash = vcrypto.generate_hash(public_key.ref_value());
assert!(
idhash.len() >= NODE_ID_LENGTH,
"generate_hash needs to produce at least {} bytes",
NODE_ID_LENGTH
);
Ok(NodeId::new(
public_key.kind(),
BareNodeId::new(&idhash[0..NODE_ID_LENGTH]),
))
}
pub fn calculate_bucket_index(&self, node_id: &NodeId) -> BucketIndex {
assert_eq!(
node_id.ref_value().len() * 8,
BUCKET_COUNT,
"NodeId should be hashed down to BUCKET_COUNT bits"
);
let crypto = self.crypto();
let self_node_id_key = self.node_id(node_id.kind()).value();
let vcrypto = crypto.get(node_id.kind()).unwrap();
( (
node_id.kind, node_id.kind(),
vcrypto vcrypto
.distance( .distance(
&BareHashDigest::from(node_id.value), &BareHashDigest::from(node_id.value()),
&BareHashDigest::from(self_node_id_key), &BareHashDigest::from(self_node_id_key),
) )
.first_nonzero_bit() .first_nonzero_bit()
@ -427,20 +463,18 @@ impl RoutingTable {
let c = config.get(); let c = config.get();
for ck in VALID_CRYPTO_KINDS { for ck in VALID_CRYPTO_KINDS {
if let Some(nid) = c.network.routing_table.node_id.get(ck) { if let Some(nid) = c.network.routing_table.node_id.get(ck) {
cache_validity_key.append(&mut nid.value.bytes.to_vec()); cache_validity_key.extend_from_slice(nid.ref_value());
} }
} }
for b in &c.network.routing_table.bootstrap { for b in &c.network.routing_table.bootstrap {
cache_validity_key.append(&mut b.as_bytes().to_vec()); cache_validity_key.extend_from_slice(b.as_bytes());
} }
cache_validity_key.append( cache_validity_key.extend_from_slice(
&mut c c.network
.network
.network_key_password .network_key_password
.clone() .clone()
.unwrap_or_default() .unwrap_or_default()
.as_bytes() .as_bytes(),
.to_vec(),
); );
}; };
@ -515,7 +549,7 @@ impl RoutingTable {
veilid_log!(inner warn "crypto kind is not valid, not loading routing table"); veilid_log!(inner warn "crypto kind is not valid, not loading routing table");
return Ok(()); return Ok(());
} }
if v.len() != PUBLIC_KEY_LENGTH * 8 { if v.len() != BUCKET_COUNT {
veilid_log!(inner warn "bucket count is different, not loading routing table"); veilid_log!(inner warn "bucket count is different, not loading routing table");
return Ok(()); return Ok(());
} }
@ -665,7 +699,7 @@ impl RoutingTable {
fn queue_bucket_kicks(&self, node_ids: NodeIdGroup) { fn queue_bucket_kicks(&self, node_ids: NodeIdGroup) {
for node_id in node_ids.iter() { for node_id in node_ids.iter() {
// Skip node ids we didn't add to buckets // Skip node ids we didn't add to buckets
if !VALID_CRYPTO_KINDS.contains(&node_id.kind) { if !VALID_CRYPTO_KINDS.contains(&node_id.kind()) {
continue; continue;
} }
@ -677,7 +711,7 @@ impl RoutingTable {
/// Resolve an existing routing table entry using any crypto kind and return a reference to it /// Resolve an existing routing table entry using any crypto kind and return a reference to it
pub fn lookup_any_node_ref(&self, node_id_key: BareNodeId) -> EyreResult<Option<NodeRef>> { pub fn lookup_any_node_ref(&self, node_id_key: BareNodeId) -> EyreResult<Option<NodeRef>> {
self.inner.read().lookup_any_node_ref(node_id_key) self.inner.read().lookup_bare_node_ref(node_id_key)
} }
/// Resolve an existing routing table entry and return a reference to it /// Resolve an existing routing table entry and return a reference to it
@ -748,22 +782,22 @@ impl RoutingTable {
{ {
let inner = self.inner.read(); let inner = self.inner.read();
for (k, _v) in &inner.recent_peers { for (k, _v) in &inner.recent_peers {
recent_peers.push(*k); recent_peers.push(k.clone());
} }
} }
// look up each node and make sure the connection is still live // look up each node and make sure the connection is still live
// (uses same logic as send_data, ensuring last_connection works for UDP) // (uses same logic as send_data, ensuring last_connection works for UDP)
for e in &recent_peers { for node_id in &recent_peers {
let mut dead = true; let mut dead = true;
if let Ok(Some(nr)) = self.lookup_node_ref(*e) { if let Ok(Some(nr)) = self.lookup_node_ref(node_id.clone()) {
if let Some(last_connection) = nr.last_flow() { if let Some(last_connection) = nr.last_flow() {
out.push((*e, RecentPeersEntry { last_connection })); out.push((node_id.clone(), RecentPeersEntry { last_connection }));
dead = false; dead = false;
} }
} }
if dead { if dead {
dead_peers.push(e); dead_peers.push(node_id);
} }
} }

View file

@ -26,7 +26,7 @@ impl fmt::Debug for RouteHopData {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) enum RouteNode { pub(crate) enum RouteNode {
/// Route node is optimized, no contact method information as this node id has been seen before /// Route node is optimized, no contact method information as this node id has been seen before
BareNodeId(BareNodeId), NodeId(NodeId),
/// Route node with full contact method information to ensure the peer is reachable /// Route node with full contact method information to ensure the peer is reachable
PeerInfo(Arc<PeerInfo>), PeerInfo(Arc<PeerInfo>),
} }
@ -34,20 +34,16 @@ pub(crate) enum RouteNode {
impl RouteNode { impl RouteNode {
pub fn validate(&self, crypto: &Crypto) -> VeilidAPIResult<()> { pub fn validate(&self, crypto: &Crypto) -> VeilidAPIResult<()> {
match self { match self {
RouteNode::BareNodeId(_) => Ok(()), RouteNode::NodeId(_) => Ok(()),
RouteNode::PeerInfo(pi) => pi.validate(crypto), RouteNode::PeerInfo(pi) => pi.validate(crypto),
} }
} }
pub fn node_ref( pub fn node_ref(&self, routing_table: &RoutingTable) -> Option<NodeRef> {
&self,
routing_table: &RoutingTable,
crypto_kind: CryptoKind,
) -> Option<NodeRef> {
match self { match self {
RouteNode::BareNodeId(id) => { RouteNode::NodeId(id) => {
// //
match routing_table.lookup_node_ref(NodeId::new(crypto_kind, *id)) { match routing_table.lookup_node_ref(id.clone()) {
Ok(nr) => nr, Ok(nr) => nr,
Err(e) => { Err(e) => {
veilid_log!(routing_table debug "failed to look up route node: {}", e); veilid_log!(routing_table debug "failed to look up route node: {}", e);
@ -68,15 +64,15 @@ impl RouteNode {
} }
} }
pub fn describe(&self, crypto_kind: CryptoKind) -> String { pub fn describe(&self) -> String {
match self { match self {
RouteNode::BareNodeId(id) => { RouteNode::NodeId(id) => {
format!("{}", NodeId::new(crypto_kind, *id)) format!("{}", id)
} }
RouteNode::PeerInfo(pi) => match pi.node_ids().get(crypto_kind) { RouteNode::PeerInfo(pi) => match pi.node_ids().best() {
Some(id) => format!("{}", id), Some(id) => format!("{}", id),
None => { None => {
format!("({})?{}", crypto_kind, pi.node_ids()) format!("?({})", pi.node_ids())
} }
}, },
} }
@ -122,7 +118,6 @@ impl PrivateRouteHops {
pub(crate) struct PrivateRoute { pub(crate) struct PrivateRoute {
/// The public key used for the entire route /// The public key used for the entire route
pub public_key: PublicKey, pub public_key: PublicKey,
pub hop_count: u8,
pub hops: PrivateRouteHops, pub hops: PrivateRouteHops,
} }
@ -131,7 +126,6 @@ impl PrivateRoute {
pub fn new_stub(public_key: PublicKey, node: RouteNode) -> Self { pub fn new_stub(public_key: PublicKey, node: RouteNode) -> Self {
Self { Self {
public_key, public_key,
hop_count: 1,
hops: PrivateRouteHops::FirstHop(Box::new(RouteHop { hops: PrivateRouteHops::FirstHop(Box::new(RouteHop {
node, node,
next_hop: None, next_hop: None,
@ -153,7 +147,7 @@ impl PrivateRoute {
/// Get the crypto kind in use for this route /// Get the crypto kind in use for this route
pub fn crypto_kind(&self) -> CryptoKind { pub fn crypto_kind(&self) -> CryptoKind {
self.public_key.kind self.public_key.kind()
} }
/// Remove the first unencrypted hop if possible /// Remove the first unencrypted hop if possible
@ -162,13 +156,6 @@ impl PrivateRoute {
PrivateRouteHops::FirstHop(first_hop) => { PrivateRouteHops::FirstHop(first_hop) => {
let first_hop_node = first_hop.node.clone(); let first_hop_node = first_hop.node.clone();
// Reduce hop count
if self.hop_count > 0 {
self.hop_count -= 1;
} else {
error!("hop count should not be 0 for first hop");
}
// Go to next hop // Go to next hop
self.hops = match first_hop.next_hop.take() { self.hops = match first_hop.next_hop.take() {
Some(rhd) => PrivateRouteHops::Data(rhd), Some(rhd) => PrivateRouteHops::Data(rhd),
@ -189,8 +176,8 @@ impl PrivateRoute {
// Get the safety route to use from the spec // Get the safety route to use from the spec
Some(match &pr_first_hop.node { Some(match &pr_first_hop.node {
RouteNode::BareNodeId(n) => NodeId::new(self.public_key.kind, *n), RouteNode::NodeId(n) => n.clone(),
RouteNode::PeerInfo(p) => p.node_ids().get(self.public_key.kind).unwrap(), RouteNode::PeerInfo(p) => p.node_ids().get(self.public_key.kind()).unwrap(),
}) })
} }
} }
@ -199,9 +186,8 @@ impl fmt::Display for PrivateRoute {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!( write!(
f, f,
"PR({:?}+{}{})", "PR({:?}+{})",
self.public_key, self.public_key,
self.hop_count,
match &self.hops { match &self.hops {
PrivateRouteHops::FirstHop(_) => { PrivateRouteHops::FirstHop(_) => {
format!( format!(
@ -233,7 +219,6 @@ pub(crate) enum SafetyRouteHops {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) struct SafetyRoute { pub(crate) struct SafetyRoute {
pub public_key: PublicKey, pub public_key: PublicKey,
pub hop_count: u8,
pub hops: SafetyRouteHops, pub hops: SafetyRouteHops,
} }
@ -245,7 +230,6 @@ impl SafetyRoute {
assert!(matches!(private_route.hops, PrivateRouteHops::Data(_))); assert!(matches!(private_route.hops, PrivateRouteHops::Data(_)));
Self { Self {
public_key, public_key,
hop_count: 0,
hops: SafetyRouteHops::Private(private_route), hops: SafetyRouteHops::Private(private_route),
} }
} }
@ -257,7 +241,7 @@ impl SafetyRoute {
/// Get the crypto kind in use for this route /// Get the crypto kind in use for this route
pub fn crypto_kind(&self) -> CryptoKind { pub fn crypto_kind(&self) -> CryptoKind {
self.public_key.kind self.public_key.kind()
} }
} }
@ -265,9 +249,8 @@ impl fmt::Display for SafetyRoute {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!( write!(
f, f,
"SR({:?}+{}{})", "SR({:?}+{})",
self.public_key, self.public_key,
self.hop_count,
match &self.hops { match &self.hops {
SafetyRouteHops::Data(_) => "".to_owned(), SafetyRouteHops::Data(_) => "".to_owned(),
SafetyRouteHops::Private(p) => format!("->{}", p), SafetyRouteHops::Private(p) => format!("->{}", p),

View file

@ -168,7 +168,7 @@ impl RouteSpecStore {
directions: DirectionSet, directions: DirectionSet,
avoid_nodes: &[NodeId], avoid_nodes: &[NodeId],
automatic: bool, automatic: bool,
) -> VeilidAPIResult<BareRouteId> { ) -> VeilidAPIResult<RouteId> {
let inner = &mut *self.inner.lock(); let inner = &mut *self.inner.lock();
let routing_table = self.routing_table(); let routing_table = self.routing_table();
let rti = &mut *routing_table.inner.write(); let rti = &mut *routing_table.inner.write();
@ -195,7 +195,7 @@ impl RouteSpecStore {
directions: DirectionSet, directions: DirectionSet,
avoid_nodes: &[NodeId], avoid_nodes: &[NodeId],
automatic: bool, automatic: bool,
) -> VeilidAPIResult<BareRouteId> { ) -> VeilidAPIResult<RouteId> {
use core::cmp::Ordering; use core::cmp::Ordering;
if safety_spec.preferred_route.is_some() { if safety_spec.preferred_route.is_some() {
@ -488,20 +488,21 @@ impl RouteSpecStore {
// Get the hop cache key for a particular route permutation // Get the hop cache key for a particular route permutation
// uses the same algorithm as RouteSetSpecDetail::make_cache_key // uses the same algorithm as RouteSetSpecDetail::make_cache_key
let route_permutation_to_hop_cache = let route_permutation_to_hop_cache =
|_rti: &RoutingTableInner, nodes: &[NodeRef], perm: &[usize]| -> Vec<u8> { |_rti: &RoutingTableInner, nodes: &[NodeRef], perm: &[usize]| -> Option<Vec<u8>> {
let mut cache: Vec<u8> = Vec::with_capacity(perm.len() * PUBLIC_KEY_LENGTH); let mut cachelen = 0usize;
let mut nodebytes = Vec::<BareNodeId>::with_capacity(perm.len());
for n in perm { for n in perm {
cache.extend_from_slice( let b = nodes[*n].locked(rti).best_node_id()?.value();
&nodes[*n] cachelen += b.len();
.locked(rti) nodebytes.push(b);
.best_node_id()
.map(|bni| bni.value.bytes)
.unwrap_or_default(),
);
} }
cache let mut cache: Vec<u8> = Vec::with_capacity(cachelen);
for b in nodebytes {
cache.extend_from_slice(&b);
}
Some(cache)
}; };
let cache_key = route_permutation_to_hop_cache(rti, &nodes, permutation); let cache_key = route_permutation_to_hop_cache(rti, &nodes, permutation)?;
// Skip routes we have already seen // Skip routes we have already seen
if inner.cache.contains_route(&cache_key) { if inner.cache.contains_route(&cache_key) {
@ -641,23 +642,16 @@ impl RouteSpecStore {
for crypto_kind in crypto_kinds.iter().copied() { for crypto_kind in crypto_kinds.iter().copied() {
let vcrypto = crypto.get(crypto_kind).unwrap(); let vcrypto = crypto.get(crypto_kind).unwrap();
let keypair = vcrypto.generate_keypair(); let keypair = vcrypto.generate_keypair();
let hops: Vec<BareNodeId> = route_nodes let hops: Vec<NodeId> = route_nodes
.iter() .iter()
.map(|v| { .map(|v| nodes[*v].locked(rti).node_ids().get(crypto_kind).unwrap())
nodes[*v]
.locked(rti)
.node_ids()
.get(crypto_kind)
.unwrap()
.value
})
.collect(); .collect();
route_set.insert( route_set.insert(
keypair.key, keypair.key(),
RouteSpecDetail { RouteSpecDetail {
crypto_kind, crypto_kind,
secret_key: keypair.secret, secret_key: keypair.secret(),
hops, hops,
}, },
); );
@ -680,7 +674,7 @@ impl RouteSpecStore {
inner.cache.add_to_cache(rti, &rssd); inner.cache.add_to_cache(rti, &rssd);
// Keep route in spec store // Keep route in spec store
inner.content.add_detail(id, rssd); inner.content.add_detail(id.clone(), rssd);
Ok(id) Ok(id)
} }
@ -690,9 +684,9 @@ impl RouteSpecStore {
pub fn with_signature_validated_route<F, R>( pub fn with_signature_validated_route<F, R>(
&self, &self,
public_key: &PublicKey, public_key: &PublicKey,
signatures: &[BareSignature], signatures: &[Signature],
data: &[u8], data: &[u8],
last_hop_id: BareNodeId, last_hop_id: &NodeId,
callback: F, callback: F,
) -> Option<R> ) -> Option<R>
where where
@ -701,21 +695,21 @@ impl RouteSpecStore {
{ {
let inner = &*self.inner.lock(); let inner = &*self.inner.lock();
let crypto = self.crypto(); let crypto = self.crypto();
let Some(vcrypto) = crypto.get(public_key.kind) else { let Some(vcrypto) = crypto.get(public_key.kind()) else {
veilid_log!(self debug "can't handle route with public key: {:?}", public_key); veilid_log!(self debug "can't handle route with public key: {:?}", public_key);
return None; return None;
}; };
let Some(rsid) = inner.content.get_id_by_key(&public_key.value) else { let Some(rsid) = inner.content.get_id_by_key(public_key.ref_value()) else {
veilid_log!(self debug target: "network_result", "route id does not exist: {:?}", public_key.value); veilid_log!(self debug target: "network_result", "route id does not exist: {:?}", public_key.ref_value());
return None; return None;
}; };
let Some(rssd) = inner.content.get_detail(&rsid) else { let Some(rssd) = inner.content.get_detail(&rsid) else {
veilid_log!(self debug "route detail does not exist: {:?}", rsid); veilid_log!(self debug "route detail does not exist: {:?}", rsid);
return None; return None;
}; };
let Some(rsd) = rssd.get_route_by_key(&public_key.value) else { let Some(rsd) = rssd.get_route_by_key(public_key.ref_value()) else {
veilid_log!(self debug "route set {:?} does not have key: {:?}", rsid, public_key.value); veilid_log!(self debug "route set {:?} does not have key: {:?}", rsid, public_key.ref_value());
return None; return None;
}; };
@ -727,24 +721,28 @@ impl RouteSpecStore {
} }
// Validate signatures to ensure the route was handled by the nodes and not messed with // Validate signatures to ensure the route was handled by the nodes and not messed with
// This is in private route (reverse) order as we are receiving over the route // This is in private route (reverse) order as we are receiving over the route
for (hop_n, hop_public_key) in rsd.hops.iter().rev().enumerate() { for (hop_n, hop_node_id) in rsd.hops.iter().rev().enumerate() {
// The last hop is not signed, as the whole packet is signed // The last hop is not signed, as the whole packet is signed
if hop_n == signatures.len() { if hop_n == signatures.len() {
// Verify the node we received the routed operation from is the last hop in our route // Verify the node we received the routed operation from is the last hop in our route
if *hop_public_key != last_hop_id { if hop_node_id != last_hop_id {
veilid_log!(self debug "received routed operation from the wrong hop ({} should be {}) on private route {}", hop_public_key.encode(), last_hop_id.encode(), public_key); veilid_log!(self debug "received routed operation from the wrong hop ({} should be {}) on private route {}", hop_node_id, last_hop_id, public_key);
return None; return None;
} }
} else { } else {
// Verify a signature for a hop node along the route // Verify a signature for a hop node along the route
match vcrypto.verify(&(*hop_public_key).into(), data, &signatures[hop_n]) { match vcrypto.verify(
&hop_node_id.ref_value().clone().into(),
data,
signatures[hop_n].ref_value(),
) {
Ok(true) => {} Ok(true) => {}
Ok(false) => { Ok(false) => {
veilid_log!(self debug "invalid signature for hop {} at {} on private route {}", hop_n, hop_public_key, public_key); veilid_log!(self debug "invalid signature for hop {} at {} on private route {}", hop_n, hop_node_id, public_key);
return None; return None;
} }
Err(e) => { Err(e) => {
veilid_log!(self debug "error verifying signature for hop {} at {} on private route {}: {}", hop_n, hop_public_key, public_key, e); veilid_log!(self debug "error verifying signature for hop {} at {} on private route {}: {}", hop_n, hop_node_id, public_key, e);
return None; return None;
} }
} }
@ -757,7 +755,7 @@ impl RouteSpecStore {
#[instrument(level = "trace", target = "route", skip(self), ret, err)] #[instrument(level = "trace", target = "route", skip(self), ret, err)]
async fn test_allocated_route( async fn test_allocated_route(
&self, &self,
private_route_id: BareRouteId, private_route_id: RouteId,
) -> VeilidAPIResult<Option<bool>> { ) -> VeilidAPIResult<Option<bool>> {
// Make loopback route to test with // Make loopback route to test with
let (dest, hops) = { let (dest, hops) = {
@ -836,10 +834,7 @@ impl RouteSpecStore {
} }
#[instrument(level = "trace", target = "route", skip(self), ret, err)] #[instrument(level = "trace", target = "route", skip(self), ret, err)]
async fn test_remote_route( async fn test_remote_route(&self, private_route_id: RouteId) -> VeilidAPIResult<Option<bool>> {
&self,
private_route_id: BareRouteId,
) -> VeilidAPIResult<Option<bool>> {
// Make private route test // Make private route test
let dest = { let dest = {
// Get the route to test // Get the route to test
@ -882,7 +877,7 @@ impl RouteSpecStore {
/// Release an allocated route that is no longer in use /// Release an allocated route that is no longer in use
#[instrument(level = "trace", target = "route", skip(self), ret)] #[instrument(level = "trace", target = "route", skip(self), ret)]
fn release_allocated_route(&self, id: BareRouteId) -> bool { fn release_allocated_route(&self, id: RouteId) -> bool {
let mut inner = self.inner.lock(); let mut inner = self.inner.lock();
let Some(rssd) = inner.content.remove_detail(&id) else { let Some(rssd) = inner.content.remove_detail(&id) else {
return false; return false;
@ -899,7 +894,7 @@ impl RouteSpecStore {
} }
/// Check if a route id is remote or not /// Check if a route id is remote or not
pub fn is_route_id_remote(&self, id: &BareRouteId) -> bool { pub fn is_route_id_remote(&self, id: &RouteId) -> bool {
let inner = &mut *self.inner.lock(); let inner = &mut *self.inner.lock();
let cur_ts = Timestamp::now(); let cur_ts = Timestamp::now();
inner inner
@ -910,7 +905,7 @@ impl RouteSpecStore {
/// Test an allocated route for continuity /// Test an allocated route for continuity
#[instrument(level = "trace", target = "route", skip(self), ret, err)] #[instrument(level = "trace", target = "route", skip(self), ret, err)]
pub async fn test_route(&self, id: BareRouteId) -> VeilidAPIResult<Option<bool>> { pub async fn test_route(&self, id: RouteId) -> VeilidAPIResult<Option<bool>> {
let is_remote = self.is_route_id_remote(&id); let is_remote = self.is_route_id_remote(&id);
if is_remote { if is_remote {
self.test_remote_route(id).await self.test_remote_route(id).await
@ -921,7 +916,7 @@ impl RouteSpecStore {
/// Release an allocated or remote route that is no longer in use /// Release an allocated or remote route that is no longer in use
#[instrument(level = "trace", target = "route", skip(self), ret)] #[instrument(level = "trace", target = "route", skip(self), ret)]
pub fn release_route(&self, id: BareRouteId) -> bool { pub fn release_route(&self, id: RouteId) -> bool {
let is_remote = self.is_route_id_remote(&id); let is_remote = self.is_route_id_remote(&id);
if is_remote { if is_remote {
self.release_remote_private_route(id) self.release_remote_private_route(id)
@ -943,7 +938,7 @@ impl RouteSpecStore {
sequencing: Sequencing, sequencing: Sequencing,
directions: DirectionSet, directions: DirectionSet,
avoid_nodes: &[NodeId], avoid_nodes: &[NodeId],
) -> Option<BareRouteId> { ) -> Option<RouteId> {
let cur_ts = Timestamp::now(); let cur_ts = Timestamp::now();
let mut routes = Vec::new(); let mut routes = Vec::new();
@ -993,13 +988,13 @@ impl RouteSpecStore {
}); });
// Return the best one if we got one // Return the best one if we got one
routes.first().map(|r| *r.0) routes.first().map(|r| r.0.clone())
} }
/// List all allocated routes /// List all allocated routes
pub fn list_allocated_routes<F, R>(&self, mut filter: F) -> Vec<R> pub fn list_allocated_routes<F, R>(&self, mut filter: F) -> Vec<R>
where where
F: FnMut(&BareRouteId, &RouteSetSpecDetail) -> Option<R>, F: FnMut(&RouteId, &RouteSetSpecDetail) -> Option<R>,
{ {
let inner = self.inner.lock(); let inner = self.inner.lock();
let mut out = Vec::with_capacity(inner.content.get_detail_count()); let mut out = Vec::with_capacity(inner.content.get_detail_count());
@ -1014,7 +1009,7 @@ impl RouteSpecStore {
/// List all allocated routes /// List all allocated routes
pub fn list_remote_routes<F, R>(&self, mut filter: F) -> Vec<R> pub fn list_remote_routes<F, R>(&self, mut filter: F) -> Vec<R>
where where
F: FnMut(&BareRouteId, &RemotePrivateRouteInfo) -> Option<R>, F: FnMut(&RouteId, &RemotePrivateRouteInfo) -> Option<R>,
{ {
let inner = self.inner.lock(); let inner = self.inner.lock();
let cur_ts = Timestamp::now(); let cur_ts = Timestamp::now();
@ -1031,7 +1026,7 @@ impl RouteSpecStore {
} }
/// Get the debug description of a route /// Get the debug description of a route
pub fn debug_route(&self, id: &BareRouteId) -> Option<String> { pub fn debug_route(&self, id: &RouteId) -> Option<String> {
let inner = &mut *self.inner.lock(); let inner = &mut *self.inner.lock();
let cur_ts = Timestamp::now(); let cur_ts = Timestamp::now();
if let Some(rpri) = inner.cache.peek_remote_private_route(cur_ts, id) { if let Some(rpri) = inner.cache.peek_remote_private_route(cur_ts, id) {
@ -1046,7 +1041,7 @@ impl RouteSpecStore {
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
/// Choose the best private route from a private route set to communicate with /// Choose the best private route from a private route set to communicate with
pub fn best_remote_private_route(&self, id: &BareRouteId) -> Option<PrivateRoute> { pub fn best_remote_private_route(&self, id: &RouteId) -> Option<PrivateRoute> {
let inner = &mut *self.inner.lock(); let inner = &mut *self.inner.lock();
let cur_ts = Timestamp::now(); let cur_ts = Timestamp::now();
let rpri = inner.cache.get_remote_private_route(cur_ts, id)?; let rpri = inner.cache.get_remote_private_route(cur_ts, id)?;
@ -1075,18 +1070,8 @@ impl RouteSpecStore {
let Some(vcrypto) = crypto.get(crypto_kind) else { let Some(vcrypto) = crypto.get(crypto_kind) else {
apibail_generic!("crypto not supported for route"); apibail_generic!("crypto not supported for route");
}; };
let pr_pubkey = private_route.public_key.value; let pr_pubkey = private_route.public_key.value();
let pr_hopcount = private_route.hop_count as usize;
let max_route_hop_count = self.max_route_hop_count;
// Check private route hop count isn't larger than the max route hop count plus one for the 'first hop' header
if pr_hopcount > (max_route_hop_count + 1) {
apibail_invalid_argument!(
"private route hop count too long",
"private_route.hop_count",
pr_hopcount
);
}
// See if we are using a safety route, if not, short circuit this operation // See if we are using a safety route, if not, short circuit this operation
let safety_spec = match safety_selection { let safety_spec = match safety_selection {
// Safety route spec to use // Safety route spec to use
@ -1098,9 +1083,9 @@ impl RouteSpecStore {
}; };
let opt_first_hop = match pr_first_hop_node { let opt_first_hop = match pr_first_hop_node {
RouteNode::BareNodeId(id) => rti RouteNode::NodeId(id) => {
.lookup_node_ref(NodeId::new(crypto_kind, id)) rti.lookup_node_ref(id).map_err(VeilidAPIError::internal)?
.map_err(VeilidAPIError::internal)?, }
RouteNode::PeerInfo(pi) => Some( RouteNode::PeerInfo(pi) => Some(
rti.register_node_with_peer_info(pi, false) rti.register_node_with_peer_info(pi, false)
.map_err(VeilidAPIError::internal)? .map_err(VeilidAPIError::internal)?
@ -1139,7 +1124,7 @@ impl RouteSpecStore {
&& safety_spec.preferred_route == opt_private_route_id && safety_spec.preferred_route == opt_private_route_id
{ {
// Private route is also safety route during loopback test // Private route is also safety route during loopback test
pr_pubkey pr_pubkey.clone()
} else { } else {
let Some(avoid_node_id) = private_route.first_hop_node_id() else { let Some(avoid_node_id) = private_route.first_hop_node_id() else {
apibail_generic!("compiled private route should have first hop"); apibail_generic!("compiled private route should have first hop");
@ -1181,13 +1166,13 @@ impl RouteSpecStore {
.merge_filter(NodeRefFilter::new().with_routing_domain(RoutingDomain::PublicInternet)); .merge_filter(NodeRefFilter::new().with_routing_domain(RoutingDomain::PublicInternet));
// Get the safety route secret key // Get the safety route secret key
let secret = safety_rsd.secret_key; let secret = safety_rsd.secret_key.clone();
// See if we have a cached route we can use // See if we have a cached route we can use
if optimize { if optimize {
if let Some(safety_route) = inner if let Some(safety_route) = inner
.cache .cache
.lookup_compiled_route_cache(sr_pubkey, pr_pubkey) .lookup_compiled_route_cache(sr_pubkey.clone(), pr_pubkey.clone())
{ {
// Build compiled route // Build compiled route
let compiled_route = CompiledRoute { let compiled_route = CompiledRoute {
@ -1227,7 +1212,7 @@ impl RouteSpecStore {
blob_data = { blob_data = {
// Encrypt the previous blob ENC(nonce, DH(PKhop,SKsr)) // Encrypt the previous blob ENC(nonce, DH(PKhop,SKsr))
let dh_secret = vcrypto let dh_secret = vcrypto
.cached_dh(&safety_rsd.hops[h].into(), &safety_rsd.secret_key) .cached_dh(&safety_rsd.hops[h].value().into(), &safety_rsd.secret_key)
.map_err(VeilidAPIError::internal)?; .map_err(VeilidAPIError::internal)?;
let enc_msg_data = vcrypto let enc_msg_data = vcrypto
.encrypt_aead(blob_data.as_slice(), &nonce, &dh_secret, None) .encrypt_aead(blob_data.as_slice(), &nonce, &dh_secret, None)
@ -1243,10 +1228,10 @@ impl RouteSpecStore {
let route_hop = RouteHop { let route_hop = RouteHop {
node: if optimize { node: if optimize {
// Optimized, no peer info, just the dht key // Optimized, no peer info, just the dht key
RouteNode::BareNodeId(safety_rsd.hops[h]) RouteNode::NodeId(safety_rsd.hops[h].clone())
} else { } else {
// Full peer info, required until we are sure the route has been fully established // Full peer info, required until we are sure the route has been fully established
let node_id = NodeId::new(safety_rsd.crypto_kind, safety_rsd.hops[h]); let node_id = safety_rsd.hops[h].clone();
let pi = rti let pi = rti
.with_node_entry(node_id, |entry| { .with_node_entry(node_id, |entry| {
entry.with(rti, |_rti, e| { entry.with(rti, |_rti, e| {
@ -1279,7 +1264,7 @@ impl RouteSpecStore {
// Encode first RouteHopData // Encode first RouteHopData
let dh_secret = vcrypto let dh_secret = vcrypto
.cached_dh(&safety_rsd.hops[0].into(), &safety_rsd.secret_key) .cached_dh(&safety_rsd.hops[0].value().into(), &safety_rsd.secret_key)
.map_err(VeilidAPIError::internal)?; .map_err(VeilidAPIError::internal)?;
let enc_msg_data = vcrypto let enc_msg_data = vcrypto
.encrypt_aead(blob_data.as_slice(), &nonce, &dh_secret, None) .encrypt_aead(blob_data.as_slice(), &nonce, &dh_secret, None)
@ -1295,8 +1280,7 @@ impl RouteSpecStore {
// Build safety route // Build safety route
let safety_route = SafetyRoute { let safety_route = SafetyRoute {
public_key: PublicKey::new(crypto_kind, sr_pubkey), public_key: PublicKey::new(crypto_kind, sr_pubkey.clone()),
hop_count: safety_spec.hop_count as u8,
hops, hops,
}; };
@ -1304,7 +1288,7 @@ impl RouteSpecStore {
if optimize { if optimize {
inner inner
.cache .cache
.add_to_compiled_route_cache(pr_pubkey, safety_route.clone()); .add_to_compiled_route_cache(pr_pubkey.clone(), safety_route.clone());
} }
// Build compiled route // Build compiled route
@ -1348,13 +1332,13 @@ impl RouteSpecStore {
} }
// See if the preferred route is here // See if the preferred route is here
if let Some(preferred_route) = safety_spec.preferred_route { if let Some(preferred_route) = &safety_spec.preferred_route {
if let Some(preferred_rssd) = inner.content.get_detail(&preferred_route) { if let Some(preferred_rssd) = inner.content.get_detail(preferred_route) {
// Only use the preferred route if it has the desired crypto kind // Only use the preferred route if it has the desired crypto kind
if let Some(preferred_key) = preferred_rssd.get_route_set_keys().get(crypto_kind) { if let Some(preferred_key) = preferred_rssd.get_route_set_keys().get(crypto_kind) {
// Only use the preferred route if it doesn't contain the avoid nodes // Only use the preferred route if it doesn't contain the avoid nodes
if !preferred_rssd.contains_nodes(avoid_nodes) { if !preferred_rssd.contains_nodes(avoid_nodes) {
return Ok(preferred_key.value); return Ok(preferred_key.value());
} }
} }
} }
@ -1393,7 +1377,7 @@ impl RouteSpecStore {
.get_route_set_keys() .get_route_set_keys()
.get(crypto_kind) .get(crypto_kind)
.unwrap() .unwrap()
.value; .value();
Ok(sr_pubkey) Ok(sr_pubkey)
} }
@ -1455,7 +1439,7 @@ impl RouteSpecStore {
rsd.crypto_kind rsd.crypto_kind
); );
}; };
RouteNode::BareNodeId(node_id.value) RouteNode::NodeId(node_id)
} else { } else {
RouteNode::PeerInfo(published_peer_info) RouteNode::PeerInfo(published_peer_info)
}, },
@ -1476,7 +1460,7 @@ impl RouteSpecStore {
}; };
// Encrypt the previous blob ENC(nonce, DH(PKhop,SKpr)) // Encrypt the previous blob ENC(nonce, DH(PKhop,SKpr))
let dh_secret = vcrypto.cached_dh(&rsd.hops[h].into(), &rsd.secret_key)?; let dh_secret = vcrypto.cached_dh(&rsd.hops[h].value().into(), &rsd.secret_key)?;
let enc_msg_data = let enc_msg_data =
vcrypto.encrypt_aead(blob_data.as_slice(), &nonce, &dh_secret, None)?; vcrypto.encrypt_aead(blob_data.as_slice(), &nonce, &dh_secret, None)?;
let route_hop_data = RouteHopData { let route_hop_data = RouteHopData {
@ -1487,10 +1471,10 @@ impl RouteSpecStore {
route_hop = RouteHop { route_hop = RouteHop {
node: if optimized { node: if optimized {
// Optimized, no peer info, just the dht key // Optimized, no peer info, just the dht key
RouteNode::BareNodeId(rsd.hops[h]) RouteNode::NodeId(rsd.hops[h].clone())
} else { } else {
// Full peer info, required until we are sure the route has been fully established // Full peer info, required until we are sure the route has been fully established
let node_id = NodeId::new(rsd.crypto_kind, rsd.hops[h]); let node_id = rsd.hops[h].clone();
let pi = rti let pi = rti
.with_node_entry(node_id, |entry| { .with_node_entry(node_id, |entry| {
entry.with(rti, |_rti, e| { entry.with(rti, |_rti, e| {
@ -1508,9 +1492,7 @@ impl RouteSpecStore {
} }
let private_route = PrivateRoute { let private_route = PrivateRoute {
public_key: PublicKey::new(rsd.crypto_kind, *key), public_key: PublicKey::new(rsd.crypto_kind, key.clone()),
// add hop for 'FirstHop'
hop_count: (hop_count + 1).try_into().unwrap(),
hops: PrivateRouteHops::FirstHop(Box::new(route_hop)), hops: PrivateRouteHops::FirstHop(Box::new(route_hop)),
}; };
Ok(private_route) Ok(private_route)
@ -1549,7 +1531,7 @@ impl RouteSpecStore {
#[instrument(level = "trace", target = "route", skip_all)] #[instrument(level = "trace", target = "route", skip_all)]
pub fn assemble_private_routes( pub fn assemble_private_routes(
&self, &self,
id: &BareRouteId, id: &RouteId,
optimized: Option<bool>, optimized: Option<bool>,
) -> VeilidAPIResult<Vec<PrivateRoute>> { ) -> VeilidAPIResult<Vec<PrivateRoute>> {
let inner = &*self.inner.lock(); let inner = &*self.inner.lock();
@ -1572,7 +1554,7 @@ impl RouteSpecStore {
/// It is safe to import the same route more than once and it will return the same route id /// It is safe to import the same route more than once and it will return the same route id
/// Returns a route set id /// Returns a route set id
#[instrument(level = "trace", target = "route", skip_all)] #[instrument(level = "trace", target = "route", skip_all)]
pub fn import_remote_private_route_blob(&self, blob: Vec<u8>) -> VeilidAPIResult<BareRouteId> { pub fn import_remote_private_route_blob(&self, blob: Vec<u8>) -> VeilidAPIResult<RouteId> {
let cur_ts = Timestamp::now(); let cur_ts = Timestamp::now();
// decode the pr blob // decode the pr blob
@ -1597,7 +1579,7 @@ impl RouteSpecStore {
inner inner
.cache .cache
.cache_remote_private_route(cur_ts, id, private_routes); .cache_remote_private_route(cur_ts, id.clone(), private_routes);
Ok(id) Ok(id)
} }
@ -1609,7 +1591,7 @@ impl RouteSpecStore {
pub fn add_remote_private_route( pub fn add_remote_private_route(
&self, &self,
private_route: PrivateRoute, private_route: PrivateRoute,
) -> VeilidAPIResult<BareRouteId> { ) -> VeilidAPIResult<RouteId> {
let cur_ts = Timestamp::now(); let cur_ts = Timestamp::now();
// Make a single route set // Make a single route set
@ -1634,20 +1616,20 @@ impl RouteSpecStore {
inner inner
.cache .cache
.cache_remote_private_route(cur_ts, id, private_routes); .cache_remote_private_route(cur_ts, id.clone(), private_routes);
Ok(id) Ok(id)
} }
/// Release a remote private route that is no longer in use /// Release a remote private route that is no longer in use
#[instrument(level = "trace", target = "route", skip_all)] #[instrument(level = "trace", target = "route", skip_all)]
pub fn release_remote_private_route(&self, id: BareRouteId) -> bool { pub fn release_remote_private_route(&self, id: RouteId) -> bool {
let inner = &mut *self.inner.lock(); let inner = &mut *self.inner.lock();
inner.cache.remove_remote_private_route(id) inner.cache.remove_remote_private_route(id)
} }
/// Get a route id for a route's public key /// Get a route id for a route's public key
pub fn get_route_id_for_key(&self, key: &BarePublicKey) -> Option<BareRouteId> { pub fn get_route_id_for_key(&self, key: &BarePublicKey) -> Option<RouteId> {
let inner = &mut *self.inner.lock(); let inner = &mut *self.inner.lock();
// Check for local route // Check for local route
if let Some(id) = inner.content.get_id_by_key(key) { if let Some(id) = inner.content.get_id_by_key(key) {
@ -1740,7 +1722,10 @@ impl RouteSpecStore {
let inner = &mut *self.inner.lock(); let inner = &mut *self.inner.lock();
// Check for stub route // Check for stub route
if self.routing_table().matches_own_node_id_key(&(*key).into()) { if self
.routing_table()
.matches_own_node_id_key(&key.clone().into())
{
return None; return None;
} }
@ -1778,7 +1763,7 @@ impl RouteSpecStore {
/// Mark route as published /// Mark route as published
/// When first deserialized, routes must be re-published in order to ensure they remain /// When first deserialized, routes must be re-published in order to ensure they remain
/// in the RouteSpecStore. /// in the RouteSpecStore.
pub fn mark_route_published(&self, id: &BareRouteId, published: bool) -> VeilidAPIResult<()> { pub fn mark_route_published(&self, id: &RouteId, published: bool) -> VeilidAPIResult<()> {
let inner = &mut *self.inner.lock(); let inner = &mut *self.inner.lock();
let Some(rssd) = inner.content.get_detail_mut(id) else { let Some(rssd) = inner.content.get_detail_mut(id) else {
apibail_invalid_target!("route does not exist"); apibail_invalid_target!("route does not exist");
@ -1886,55 +1871,67 @@ impl RouteSpecStore {
Ok(out) Ok(out)
} }
/// Generate BareRouteId from typed key set of route public keys /// Generate RouteId from typed key set of route public keys
fn generate_allocated_route_id( fn generate_allocated_route_id(&self, rssd: &RouteSetSpecDetail) -> VeilidAPIResult<RouteId> {
&self,
rssd: &RouteSetSpecDetail,
) -> VeilidAPIResult<BareRouteId> {
let route_set_keys = rssd.get_route_set_keys(); let route_set_keys = rssd.get_route_set_keys();
let crypto = self.crypto(); let crypto = self.crypto();
let mut idbytes = Vec::with_capacity(PUBLIC_KEY_LENGTH * route_set_keys.len()); let pkbyteslen = route_set_keys
.iter()
.fold(0, |acc, x| acc + x.ref_value().len());
let mut pkbytes = Vec::with_capacity(pkbyteslen);
let mut best_kind: Option<CryptoKind> = None; let mut best_kind: Option<CryptoKind> = None;
for tk in route_set_keys.iter() { for tk in route_set_keys.iter() {
if best_kind.is_none() if best_kind.is_none()
|| compare_crypto_kind(&tk.kind, best_kind.as_ref().unwrap()) == cmp::Ordering::Less || compare_crypto_kind(&tk.kind(), best_kind.as_ref().unwrap())
== cmp::Ordering::Less
{ {
best_kind = Some(tk.kind); best_kind = Some(tk.kind());
} }
idbytes.extend_from_slice(&tk.value.bytes); pkbytes.extend_from_slice(tk.ref_value());
} }
let Some(best_kind) = best_kind else { let Some(best_kind) = best_kind else {
apibail_internal!("no compatible crypto kinds in route"); apibail_internal!("no compatible crypto kinds in route");
}; };
let vcrypto = crypto.get(best_kind).unwrap(); let vcrypto = crypto.get(best_kind).unwrap();
Ok(BareRouteId::new(vcrypto.generate_hash(&idbytes).bytes)) Ok(RouteId::new(
vcrypto.kind(),
BareRouteId::new(vcrypto.generate_hash(&pkbytes).bytes()),
))
} }
/// Generate BareRouteId from set of private routes /// Generate RouteId from set of private routes
fn generate_remote_route_id( fn generate_remote_route_id(
&self, &self,
private_routes: &[PrivateRoute], private_routes: &[PrivateRoute],
) -> VeilidAPIResult<BareRouteId> { ) -> VeilidAPIResult<RouteId> {
let crypto = self.crypto(); let crypto = self.crypto();
let mut idbytes = Vec::with_capacity(PUBLIC_KEY_LENGTH * private_routes.len()); let pkbyteslen = private_routes
.iter()
.fold(0, |acc, x| acc + x.public_key.ref_value().len());
let mut pkbytes = Vec::with_capacity(pkbyteslen);
let mut best_kind: Option<CryptoKind> = None; let mut best_kind: Option<CryptoKind> = None;
for private_route in private_routes { for private_route in private_routes {
if best_kind.is_none() if best_kind.is_none()
|| compare_crypto_kind(&private_route.public_key.kind, best_kind.as_ref().unwrap()) || compare_crypto_kind(
== cmp::Ordering::Less &private_route.public_key.kind(),
best_kind.as_ref().unwrap(),
) == cmp::Ordering::Less
{ {
best_kind = Some(private_route.public_key.kind); best_kind = Some(private_route.public_key.kind());
} }
idbytes.extend_from_slice(&private_route.public_key.value.bytes); pkbytes.extend_from_slice(private_route.public_key.ref_value());
} }
let Some(best_kind) = best_kind else { let Some(best_kind) = best_kind else {
apibail_internal!("no compatible crypto kinds in route"); apibail_internal!("no compatible crypto kinds in route");
}; };
let vcrypto = crypto.get(best_kind).unwrap(); let vcrypto = crypto.get(best_kind).unwrap();
Ok(BareRouteId::new(vcrypto.generate_hash(&idbytes).bytes)) Ok(RouteId::new(
vcrypto.kind(),
BareRouteId::new(vcrypto.generate_hash(&pkbytes).bytes()),
))
} }
} }

View file

@ -35,7 +35,7 @@ impl RemotePrivateRouteInfo {
acc acc
} }
}) })
.filter(|x| VALID_CRYPTO_KINDS.contains(&x.public_key.kind)) .filter(|x| VALID_CRYPTO_KINDS.contains(&x.public_key.kind()))
.cloned() .cloned()
} }
pub fn get_stats(&self) -> &RouteStats { pub fn get_stats(&self) -> &RouteStats {

View file

@ -7,7 +7,7 @@ pub struct RouteSpecDetail {
/// Secret key /// Secret key
pub secret_key: BareSecretKey, pub secret_key: BareSecretKey,
/// Route hops (node id keys) /// Route hops (node id keys)
pub hops: Vec<BareNodeId>, pub hops: Vec<NodeId>,
} }
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
@ -60,12 +60,12 @@ impl RouteSetSpecDetail {
pub fn get_route_set_keys(&self) -> PublicKeyGroup { pub fn get_route_set_keys(&self) -> PublicKeyGroup {
let mut tks = PublicKeyGroup::new(); let mut tks = PublicKeyGroup::new();
for (k, v) in &self.route_set { for (k, v) in &self.route_set {
tks.add(PublicKey::new(v.crypto_kind, *k)); tks.add(PublicKey::new(v.crypto_kind, k.clone()));
} }
tks tks
} }
pub fn get_best_route_set_key(&self) -> Option<BarePublicKey> { pub fn get_best_route_set_key(&self) -> Option<BarePublicKey> {
self.get_route_set_keys().best().map(|k| k.value) self.get_route_set_keys().best().map(|k| k.value())
} }
pub fn set_hop_node_refs(&mut self, node_refs: Vec<NodeRef>) { pub fn set_hop_node_refs(&mut self, node_refs: Vec<NodeRef>) {
self.hop_node_refs = node_refs; self.hop_node_refs = node_refs;
@ -112,7 +112,7 @@ impl RouteSetSpecDetail {
pub fn contains_nodes(&self, nodes: &[NodeId]) -> bool { pub fn contains_nodes(&self, nodes: &[NodeId]) -> bool {
for tk in nodes { for tk in nodes {
for rsd in self.route_set.values() { for rsd in self.route_set.values() {
if rsd.crypto_kind == tk.kind && rsd.hops.contains(&tk.value) { if rsd.crypto_kind == tk.kind() && rsd.hops.contains(tk) {
return true; return true;
} }
} }
@ -124,17 +124,21 @@ impl RouteSetSpecDetail {
} }
/// Generate a key for the cache that can be used to uniquely identify this route's contents /// Generate a key for the cache that can be used to uniquely identify this route's contents
pub fn make_cache_key(&self, rti: &RoutingTableInner) -> Vec<u8> { pub fn make_cache_key(&self, rti: &RoutingTableInner) -> Option<Vec<u8>> {
let hops = &self.hop_node_refs; let hops = &self.hop_node_refs;
let mut cache: Vec<u8> = Vec::with_capacity(hops.len() * PUBLIC_KEY_LENGTH);
let mut cachelen = 0usize;
let mut nodebytes = Vec::<BareNodeId>::with_capacity(hops.len());
for hop in hops { for hop in hops {
cache.extend_from_slice( let b = hop.locked(rti).best_node_id()?.value();
&hop.locked(rti) cachelen += b.len();
.best_node_id() nodebytes.push(b);
.map(|bni| bni.value.bytes)
.unwrap_or_default(),
);
} }
cache let mut cache: Vec<u8> = Vec::with_capacity(cachelen);
for b in nodebytes {
cache.extend_from_slice(&b);
}
Some(cache)
} }
} }

View file

@ -26,21 +26,21 @@ pub struct RouteSpecStoreCache {
/// Registry accessor /// Registry accessor
registry: VeilidComponentRegistry, registry: VeilidComponentRegistry,
/// How many times nodes have been used /// How many times nodes have been used
used_nodes: HashMap<BareNodeId, usize>, used_nodes: HashMap<NodeId, usize>,
/// How many times nodes have been used at the terminal point of a route /// How many times nodes have been used at the terminal point of a route
used_end_nodes: HashMap<BareNodeId, usize>, used_end_nodes: HashMap<NodeId, usize>,
/// Route spec hop cache, used to quickly disqualify routes /// Route spec hop cache, used to quickly disqualify routes
hop_cache: HashSet<Vec<u8>>, hop_cache: HashSet<Vec<u8>>,
/// Remote private routes we've imported and statistics /// Remote private routes we've imported and statistics
remote_private_route_set_cache: LruCache<BareRouteId, RemotePrivateRouteInfo>, remote_private_route_set_cache: LruCache<RouteId, RemotePrivateRouteInfo>,
/// Remote private route ids indexed by route's public key /// Remote private route ids indexed by route's public key
remote_private_routes_by_key: HashMap<BarePublicKey, BareRouteId>, remote_private_routes_by_key: HashMap<BarePublicKey, RouteId>,
/// Compiled route cache /// Compiled route cache
compiled_route_cache: LruCache<CompiledRouteCacheKey, SafetyRoute>, compiled_route_cache: LruCache<CompiledRouteCacheKey, SafetyRoute>,
/// List of dead allocated routes /// List of dead allocated routes
dead_routes: Vec<BareRouteId>, dead_routes: Vec<RouteId>,
/// List of dead remote routes /// List of dead remote routes
dead_remote_routes: Vec<BareRouteId>, dead_remote_routes: Vec<RouteId>,
} }
impl_veilid_component_registry_accessor!(RouteSpecStoreCache); impl_veilid_component_registry_accessor!(RouteSpecStoreCache);
@ -62,19 +62,21 @@ impl RouteSpecStoreCache {
/// add an allocated route set to our cache via its cache key /// add an allocated route set to our cache via its cache key
pub fn add_to_cache(&mut self, rti: &RoutingTableInner, rssd: &RouteSetSpecDetail) { pub fn add_to_cache(&mut self, rti: &RoutingTableInner, rssd: &RouteSetSpecDetail) {
let cache_key = rssd.make_cache_key(rti); let Some(cache_key) = rssd.make_cache_key(rti) else {
panic!("all routes should have a cache key");
};
if !self.hop_cache.insert(cache_key) { if !self.hop_cache.insert(cache_key) {
panic!("route should never be inserted twice"); panic!("route should never be inserted twice");
} }
for (_pk, rsd) in rssd.iter_route_set() { for (_pk, rsd) in rssd.iter_route_set() {
for h in &rsd.hops { for h in &rsd.hops {
self.used_nodes self.used_nodes
.entry(*h) .entry(h.clone())
.and_modify(|e| *e += 1) .and_modify(|e| *e += 1)
.or_insert(1); .or_insert(1);
} }
self.used_end_nodes self.used_end_nodes
.entry(*rsd.hops.last().unwrap()) .entry(rsd.hops.last().unwrap().clone())
.and_modify(|e| *e += 1) .and_modify(|e| *e += 1)
.or_insert(1); .or_insert(1);
} }
@ -89,10 +91,12 @@ impl RouteSpecStoreCache {
pub fn remove_from_cache( pub fn remove_from_cache(
&mut self, &mut self,
rti: &RoutingTableInner, rti: &RoutingTableInner,
id: BareRouteId, id: RouteId,
rssd: &RouteSetSpecDetail, rssd: &RouteSetSpecDetail,
) -> bool { ) -> bool {
let cache_key = rssd.make_cache_key(rti); let Some(cache_key) = rssd.make_cache_key(rti) else {
panic!("all routes should have a cache key");
};
// Remove from hop cache // Remove from hop cache
if !self.hop_cache.remove(&cache_key) { if !self.hop_cache.remove(&cache_key) {
@ -101,7 +105,7 @@ impl RouteSpecStoreCache {
for (pk, rsd) in rssd.iter_route_set() { for (pk, rsd) in rssd.iter_route_set() {
for h in &rsd.hops { for h in &rsd.hops {
// Remove from used nodes cache // Remove from used nodes cache
match self.used_nodes.entry(*h) { match self.used_nodes.entry(h.clone()) {
std::collections::hash_map::Entry::Occupied(mut o) => { std::collections::hash_map::Entry::Occupied(mut o) => {
*o.get_mut() -= 1; *o.get_mut() -= 1;
if *o.get() == 0 { if *o.get() == 0 {
@ -114,7 +118,7 @@ impl RouteSpecStoreCache {
} }
} }
// Remove from end nodes cache // Remove from end nodes cache
match self.used_end_nodes.entry(*rsd.hops.last().unwrap()) { match self.used_end_nodes.entry(rsd.hops.last().cloned().unwrap()) {
std::collections::hash_map::Entry::Occupied(mut o) => { std::collections::hash_map::Entry::Occupied(mut o) => {
*o.get_mut() -= 1; *o.get_mut() -= 1;
if *o.get() == 0 { if *o.get() == 0 {
@ -141,27 +145,23 @@ impl RouteSpecStoreCache {
/// calculate how many times a node with a particular node id set has been used anywhere in the path of our allocated routes /// calculate how many times a node with a particular node id set has been used anywhere in the path of our allocated routes
pub fn get_used_node_count(&self, node_ids: &NodeIdGroup) -> usize { pub fn get_used_node_count(&self, node_ids: &NodeIdGroup) -> usize {
node_ids.iter().fold(0usize, |acc, k| { node_ids.iter().fold(0usize, |acc, k| {
acc + self.used_nodes.get(&k.value).cloned().unwrap_or_default() acc + self.used_nodes.get(k).cloned().unwrap_or_default()
}) })
} }
/// calculate how many times a node with a particular node id set has been used at the end of the path of our allocated routes /// calculate how many times a node with a particular node id set has been used at the end of the path of our allocated routes
pub fn get_used_end_node_count(&self, node_ids: &NodeIdGroup) -> usize { pub fn get_used_end_node_count(&self, node_ids: &NodeIdGroup) -> usize {
node_ids.iter().fold(0usize, |acc, k| { node_ids.iter().fold(0usize, |acc, k| {
acc + self acc + self.used_end_nodes.get(k).cloned().unwrap_or_default()
.used_end_nodes
.get(&k.value)
.cloned()
.unwrap_or_default()
}) })
} }
/// add remote private route to caches /// add remote private route to caches
fn add_remote_private_route(&mut self, id: BareRouteId, rprinfo: RemotePrivateRouteInfo) { fn add_remote_private_route(&mut self, id: RouteId, rprinfo: RemotePrivateRouteInfo) {
// also store in id by key table // also store in id by key table
for private_route in rprinfo.get_private_routes() { for private_route in rprinfo.get_private_routes() {
self.remote_private_routes_by_key self.remote_private_routes_by_key
.insert(private_route.public_key.value, id); .insert(private_route.public_key.value(), id.clone());
} }
let mut dead = None; let mut dead = None;
@ -179,21 +179,21 @@ impl RouteSpecStoreCache {
for dead_private_route in dead_rpri.get_private_routes() { for dead_private_route in dead_rpri.get_private_routes() {
let _ = self let _ = self
.remote_private_routes_by_key .remote_private_routes_by_key
.remove(&dead_private_route.public_key.value) .remove(dead_private_route.public_key.ref_value())
.unwrap(); .unwrap();
self.invalidate_compiled_route_cache(&dead_private_route.public_key.value); self.invalidate_compiled_route_cache(dead_private_route.public_key.ref_value());
} }
self.dead_remote_routes.push(dead_id); self.dead_remote_routes.push(dead_id);
} }
} }
/// iterate all of the remote private routes we have in the cache /// iterate all of the remote private routes we have in the cache
pub fn get_remote_private_route_ids(&self, cur_ts: Timestamp) -> Vec<BareRouteId> { pub fn get_remote_private_route_ids(&self, cur_ts: Timestamp) -> Vec<RouteId> {
self.remote_private_route_set_cache self.remote_private_route_set_cache
.iter() .iter()
.filter_map(|(id, rpri)| { .filter_map(|(id, rpri)| {
if !rpri.did_expire(cur_ts) { if !rpri.did_expire(cur_ts) {
Some(*id) Some(id.clone())
} else { } else {
None None
} }
@ -206,7 +206,7 @@ impl RouteSpecStoreCache {
pub fn get_remote_private_route( pub fn get_remote_private_route(
&mut self, &mut self,
cur_ts: Timestamp, cur_ts: Timestamp,
id: &BareRouteId, id: &RouteId,
) -> Option<&RemotePrivateRouteInfo> { ) -> Option<&RemotePrivateRouteInfo> {
if let Some(rpri) = self.remote_private_route_set_cache.get_mut(id) { if let Some(rpri) = self.remote_private_route_set_cache.get_mut(id) {
if !rpri.did_expire(cur_ts) { if !rpri.did_expire(cur_ts) {
@ -222,7 +222,7 @@ impl RouteSpecStoreCache {
pub fn get_remote_private_route_mut( pub fn get_remote_private_route_mut(
&mut self, &mut self,
cur_ts: Timestamp, cur_ts: Timestamp,
id: &BareRouteId, id: &RouteId,
) -> Option<&mut RemotePrivateRouteInfo> { ) -> Option<&mut RemotePrivateRouteInfo> {
if let Some(rpri) = self.remote_private_route_set_cache.get_mut(id) { if let Some(rpri) = self.remote_private_route_set_cache.get_mut(id) {
if !rpri.did_expire(cur_ts) { if !rpri.did_expire(cur_ts) {
@ -238,7 +238,7 @@ impl RouteSpecStoreCache {
pub fn peek_remote_private_route( pub fn peek_remote_private_route(
&self, &self,
cur_ts: Timestamp, cur_ts: Timestamp,
id: &BareRouteId, id: &RouteId,
) -> Option<&RemotePrivateRouteInfo> { ) -> Option<&RemotePrivateRouteInfo> {
if let Some(rpri) = self.remote_private_route_set_cache.peek(id) { if let Some(rpri) = self.remote_private_route_set_cache.peek(id) {
if !rpri.did_expire(cur_ts) { if !rpri.did_expire(cur_ts) {
@ -253,7 +253,7 @@ impl RouteSpecStoreCache {
pub fn peek_remote_private_route_mut( pub fn peek_remote_private_route_mut(
&mut self, &mut self,
cur_ts: Timestamp, cur_ts: Timestamp,
id: &BareRouteId, id: &RouteId,
) -> Option<&mut RemotePrivateRouteInfo> { ) -> Option<&mut RemotePrivateRouteInfo> {
if let Some(rpri) = self.remote_private_route_set_cache.peek_mut(id) { if let Some(rpri) = self.remote_private_route_set_cache.peek_mut(id) {
if !rpri.did_expire(cur_ts) { if !rpri.did_expire(cur_ts) {
@ -265,7 +265,7 @@ impl RouteSpecStoreCache {
} }
/// look up a remote private route id by one of the route public keys /// look up a remote private route id by one of the route public keys
pub fn get_remote_private_route_id_by_key(&self, key: &BarePublicKey) -> Option<BareRouteId> { pub fn get_remote_private_route_id_by_key(&self, key: &BarePublicKey) -> Option<RouteId> {
self.remote_private_routes_by_key.get(key).cloned() self.remote_private_routes_by_key.get(key).cloned()
} }
@ -276,7 +276,7 @@ impl RouteSpecStoreCache {
pub fn cache_remote_private_route( pub fn cache_remote_private_route(
&mut self, &mut self,
cur_ts: Timestamp, cur_ts: Timestamp,
id: BareRouteId, id: RouteId,
private_routes: Vec<PrivateRoute>, private_routes: Vec<PrivateRoute>,
) { ) {
// get id for this route set // get id for this route set
@ -292,7 +292,7 @@ impl RouteSpecStoreCache {
// New remote private route cache entry // New remote private route cache entry
let rpri = RemotePrivateRouteInfo::new(private_routes, cur_ts); let rpri = RemotePrivateRouteInfo::new(private_routes, cur_ts);
self.add_remote_private_route(id, rpri); self.add_remote_private_route(id.clone(), rpri);
if self.peek_remote_private_route_mut(cur_ts, &id).is_none() { if self.peek_remote_private_route_mut(cur_ts, &id).is_none() {
panic!("remote private route should exist"); panic!("remote private route should exist");
}; };
@ -300,16 +300,16 @@ impl RouteSpecStoreCache {
} }
/// remove a remote private route from the cache /// remove a remote private route from the cache
pub fn remove_remote_private_route(&mut self, id: BareRouteId) -> bool { pub fn remove_remote_private_route(&mut self, id: RouteId) -> bool {
let Some(rprinfo) = self.remote_private_route_set_cache.remove(&id) else { let Some(rprinfo) = self.remote_private_route_set_cache.remove(&id) else {
return false; return false;
}; };
for private_route in rprinfo.get_private_routes() { for private_route in rprinfo.get_private_routes() {
let _ = self let _ = self
.remote_private_routes_by_key .remote_private_routes_by_key
.remove(&private_route.public_key.value) .remove(private_route.public_key.ref_value())
.unwrap(); .unwrap();
self.invalidate_compiled_route_cache(&private_route.public_key.value); self.invalidate_compiled_route_cache(private_route.public_key.ref_value());
} }
self.dead_remote_routes.push(id); self.dead_remote_routes.push(id);
true true
@ -322,8 +322,8 @@ impl RouteSpecStoreCache {
safety_route: SafetyRoute, safety_route: SafetyRoute,
) { ) {
let key = CompiledRouteCacheKey { let key = CompiledRouteCacheKey {
sr_pubkey: safety_route.public_key.value, sr_pubkey: safety_route.public_key.value(),
pr_pubkey, pr_pubkey: pr_pubkey.clone(),
}; };
if let Some(v) = self.compiled_route_cache.insert(key, safety_route) { if let Some(v) = self.compiled_route_cache.insert(key, safety_route) {
@ -358,7 +358,7 @@ impl RouteSpecStoreCache {
} }
/// Take the dead local and remote routes so we can update clients /// Take the dead local and remote routes so we can update clients
pub fn take_dead_routes(&mut self) -> Option<(Vec<BareRouteId>, Vec<BareRouteId>)> { pub fn take_dead_routes(&mut self) -> Option<(Vec<RouteId>, Vec<RouteId>)> {
if self.dead_routes.is_empty() && self.dead_remote_routes.is_empty() { if self.dead_routes.is_empty() && self.dead_remote_routes.is_empty() {
// Nothing to do // Nothing to do
return None; return None;

View file

@ -4,9 +4,9 @@ use super::*;
#[derive(Debug, Clone, Default, Serialize, Deserialize)] #[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub(super) struct RouteSpecStoreContent { pub(super) struct RouteSpecStoreContent {
/// All of the route sets we have allocated so far indexed by key (many to one) /// All of the route sets we have allocated so far indexed by key (many to one)
id_by_key: HashMap<BarePublicKey, BareRouteId>, id_by_key: HashMap<BarePublicKey, RouteId>,
/// All of the route sets we have allocated so far /// All of the route sets we have allocated so far
details: HashMap<BareRouteId, RouteSetSpecDetail>, details: HashMap<RouteId, RouteSetSpecDetail>,
} }
impl RouteSpecStoreContent { impl RouteSpecStoreContent {
@ -24,19 +24,18 @@ impl RouteSpecStoreContent {
for (rsid, rssd) in content.details.iter_mut() { for (rsid, rssd) in content.details.iter_mut() {
// Get best route since they all should resolve // Get best route since they all should resolve
let Some(pk) = rssd.get_best_route_set_key() else { let Some(pk) = rssd.get_best_route_set_key() else {
dead_ids.push(*rsid); dead_ids.push(rsid.clone());
continue; continue;
}; };
let Some(rsd) = rssd.get_route_by_key(&pk) else { let Some(rsd) = rssd.get_route_by_key(&pk) else {
dead_ids.push(*rsid); dead_ids.push(rsid.clone());
continue; continue;
}; };
// Go through best route and resolve noderefs // Go through best route and resolve noderefs
let mut hop_node_refs = Vec::with_capacity(rsd.hops.len()); let mut hop_node_refs = Vec::with_capacity(rsd.hops.len());
for h in &rsd.hops { for h in &rsd.hops {
let Ok(Some(nr)) = routing_table.lookup_node_ref(NodeId::new(rsd.crypto_kind, *h)) let Ok(Some(nr)) = routing_table.lookup_node_ref(h.clone()) else {
else { dead_ids.push(rsid.clone());
dead_ids.push(*rsid);
break; break;
}; };
hop_node_refs.push(nr); hop_node_refs.push(nr);
@ -62,16 +61,16 @@ impl RouteSpecStoreContent {
Ok(()) Ok(())
} }
pub fn add_detail(&mut self, id: BareRouteId, detail: RouteSetSpecDetail) { pub fn add_detail(&mut self, id: RouteId, detail: RouteSetSpecDetail) {
assert!(!self.details.contains_key(&id)); assert!(!self.details.contains_key(&id));
// also store in id by key table // also store in id by key table
for (pk, _) in detail.iter_route_set() { for (pk, _) in detail.iter_route_set() {
self.id_by_key.insert(*pk, id); self.id_by_key.insert(pk.clone(), id.clone());
} }
self.details.insert(id, detail); self.details.insert(id, detail);
} }
pub fn remove_detail(&mut self, id: &BareRouteId) -> Option<RouteSetSpecDetail> { pub fn remove_detail(&mut self, id: &RouteId) -> Option<RouteSetSpecDetail> {
let detail = self.details.remove(id)?; let detail = self.details.remove(id)?;
for (pk, _) in detail.iter_route_set() { for (pk, _) in detail.iter_route_set() {
let _ = self.id_by_key.remove(pk).unwrap(); let _ = self.id_by_key.remove(pk).unwrap();
@ -81,21 +80,19 @@ impl RouteSpecStoreContent {
pub fn get_detail_count(&self) -> usize { pub fn get_detail_count(&self) -> usize {
self.details.len() self.details.len()
} }
pub fn get_detail(&self, id: &BareRouteId) -> Option<&RouteSetSpecDetail> { pub fn get_detail(&self, id: &RouteId) -> Option<&RouteSetSpecDetail> {
self.details.get(id) self.details.get(id)
} }
pub fn get_detail_mut(&mut self, id: &BareRouteId) -> Option<&mut RouteSetSpecDetail> { pub fn get_detail_mut(&mut self, id: &RouteId) -> Option<&mut RouteSetSpecDetail> {
self.details.get_mut(id) self.details.get_mut(id)
} }
pub fn get_id_by_key(&self, key: &BarePublicKey) -> Option<BareRouteId> { pub fn get_id_by_key(&self, key: &BarePublicKey) -> Option<RouteId> {
self.id_by_key.get(key).cloned() self.id_by_key.get(key).cloned()
} }
// pub fn iter_ids(&self) -> std::collections::hash_map::Keys<BareRouteId, RouteSetSpecDetail> { // pub fn iter_ids(&self) -> std::collections::hash_map::Keys<RouteId, RouteSetSpecDetail> {
// self.details.keys() // self.details.keys()
// } // }
pub fn iter_details( pub fn iter_details(&self) -> std::collections::hash_map::Iter<RouteId, RouteSetSpecDetail> {
&self,
) -> std::collections::hash_map::Iter<BareRouteId, RouteSetSpecDetail> {
self.details.iter() self.details.iter()
} }

View file

@ -342,8 +342,8 @@ impl RoutingTableInner {
// Size the buckets (one per bit), one bucket set per crypto kind // Size the buckets (one per bit), one bucket set per crypto kind
self.buckets.clear(); self.buckets.clear();
for ck in VALID_CRYPTO_KINDS { for ck in VALID_CRYPTO_KINDS {
let mut ckbuckets = Vec::with_capacity(PUBLIC_KEY_LENGTH * 8); let mut ckbuckets = Vec::with_capacity(BUCKET_COUNT);
for _ in 0..PUBLIC_KEY_LENGTH * 8 { for _ in 0..BUCKET_COUNT {
let bucket = Bucket::new(self.registry(), ck); let bucket = Bucket::new(self.registry(), ck);
ckbuckets.push(bucket); ckbuckets.push(bucket);
} }
@ -666,7 +666,7 @@ impl RoutingTableInner {
let mut old_peer_infos = vec![]; let mut old_peer_infos = vec![];
for node_id in node_ids { for node_id in node_ids {
let ck = node_id.kind; let ck = node_id.kind();
let is_existing_node_id = existing_node_ids.contains(node_id); let is_existing_node_id = existing_node_ids.contains(node_id);
existing_node_ids.remove(ck); existing_node_ids.remove(ck);
@ -686,12 +686,12 @@ impl RoutingTableInner {
} }
// Add new node id to entry // Add new node id to entry
if let Some(old_node_id) = e.add_node_id(*node_id)? { if let Some(old_node_id) = e.add_node_id(node_id.clone())? {
// Remove any old node id for this crypto kind // Remove any old node id for this crypto kind
if VALID_CRYPTO_KINDS.contains(&ck) { if VALID_CRYPTO_KINDS.contains(&ck) {
let bucket_index = routing_table.calculate_bucket_index(&old_node_id); let bucket_index = routing_table.calculate_bucket_index(&old_node_id);
let bucket = self.get_bucket_mut(bucket_index); let bucket = self.get_bucket_mut(bucket_index);
bucket.remove_entry(&old_node_id.value); bucket.remove_entry(old_node_id.ref_value());
routing_table.kick_queue.lock().insert(bucket_index); routing_table.kick_queue.lock().insert(bucket_index);
} }
} }
@ -700,7 +700,7 @@ impl RoutingTableInner {
if VALID_CRYPTO_KINDS.contains(&ck) { if VALID_CRYPTO_KINDS.contains(&ck) {
let bucket_index = routing_table.calculate_bucket_index(node_id); let bucket_index = routing_table.calculate_bucket_index(node_id);
let bucket = self.get_bucket_mut(bucket_index); let bucket = self.get_bucket_mut(bucket_index);
bucket.add_existing_entry(node_id.value, entry.clone()); bucket.add_existing_entry(node_id.value(), entry.clone());
// Kick bucket // Kick bucket
routing_table.kick_queue.lock().insert(bucket_index); routing_table.kick_queue.lock().insert(bucket_index);
@ -709,11 +709,11 @@ impl RoutingTableInner {
// Remove from buckets if node id wasn't seen in new peer info list // Remove from buckets if node id wasn't seen in new peer info list
for node_id in existing_node_ids.iter() { for node_id in existing_node_ids.iter() {
let ck = node_id.kind; let ck = node_id.kind();
if VALID_CRYPTO_KINDS.contains(&ck) { if VALID_CRYPTO_KINDS.contains(&ck) {
let bucket_index = routing_table.calculate_bucket_index(node_id); let bucket_index = routing_table.calculate_bucket_index(node_id);
let bucket = self.get_bucket_mut(bucket_index); let bucket = self.get_bucket_mut(bucket_index);
bucket.remove_entry(&node_id.value); bucket.remove_entry(node_id.ref_value());
entry.with_mut_inner(|e| e.remove_node_id(ck)); entry.with_mut_inner(|e| e.remove_node_id(ck));
} }
} }
@ -763,15 +763,15 @@ impl RoutingTableInner {
let mut supported_node_ids = NodeIdGroup::new(); let mut supported_node_ids = NodeIdGroup::new();
for node_id in node_ids.iter() { for node_id in node_ids.iter() {
// Ignore node ids we don't support // Ignore node ids we don't support
if !VALID_CRYPTO_KINDS.contains(&node_id.kind) { if !VALID_CRYPTO_KINDS.contains(&node_id.kind()) {
continue; continue;
} }
supported_node_ids.add(*node_id); supported_node_ids.add(node_id.clone());
// Find the first in crypto sort order // Find the first in crypto sort order
let bucket_index = routing_table.calculate_bucket_index(node_id); let bucket_index = routing_table.calculate_bucket_index(node_id);
let bucket = self.get_bucket(bucket_index); let bucket = self.get_bucket(bucket_index);
if let Some(entry) = bucket.entry(&node_id.value) { if let Some(entry) = bucket.entry(node_id.ref_value()) {
// Best entry is the first one in sorted order that exists from the node id list // Best entry is the first one in sorted order that exists from the node id list
// Everything else that matches will be overwritten in the bucket and the // Everything else that matches will be overwritten in the bucket and the
// existing noderefs will eventually unref and drop the old unindexed bucketentry // existing noderefs will eventually unref and drop the old unindexed bucketentry
@ -806,10 +806,10 @@ impl RoutingTableInner {
} }
// If no entry exists yet, add the first entry to a bucket, possibly evicting a bucket member // If no entry exists yet, add the first entry to a bucket, possibly evicting a bucket member
let first_node_id = supported_node_ids[0]; let first_node_id = supported_node_ids[0].clone();
let bucket_entry = routing_table.calculate_bucket_index(&first_node_id); let bucket_entry = routing_table.calculate_bucket_index(&first_node_id);
let bucket = self.get_bucket_mut(bucket_entry); let bucket = self.get_bucket_mut(bucket_entry);
let new_entry = bucket.add_new_entry(first_node_id.value); let new_entry = bucket.add_new_entry(first_node_id.value());
self.all_entries.insert(new_entry.clone()); self.all_entries.insert(new_entry.clone());
routing_table.kick_queue.lock().insert(bucket_entry); routing_table.kick_queue.lock().insert(bucket_entry);
@ -832,9 +832,9 @@ impl RoutingTableInner {
/// Resolve an existing routing table entry using any crypto kind and return a reference to it /// Resolve an existing routing table entry using any crypto kind and return a reference to it
#[instrument(level = "trace", skip_all, err)] #[instrument(level = "trace", skip_all, err)]
pub fn lookup_any_node_ref(&self, node_id_key: BareNodeId) -> EyreResult<Option<NodeRef>> { pub fn lookup_bare_node_ref(&self, node_id_key: BareNodeId) -> EyreResult<Option<NodeRef>> {
for ck in VALID_CRYPTO_KINDS { for ck in VALID_CRYPTO_KINDS {
if let Some(nr) = self.lookup_node_ref(NodeId::new(ck, node_id_key))? { if let Some(nr) = self.lookup_node_ref(NodeId::new(ck, node_id_key.clone()))? {
return Ok(Some(nr)); return Ok(Some(nr));
} }
} }
@ -844,17 +844,17 @@ impl RoutingTableInner {
/// Resolve an existing routing table entry and return a reference to it /// Resolve an existing routing table entry and return a reference to it
#[instrument(level = "trace", skip_all, err)] #[instrument(level = "trace", skip_all, err)]
pub fn lookup_node_ref(&self, node_id: NodeId) -> EyreResult<Option<NodeRef>> { pub fn lookup_node_ref(&self, node_id: NodeId) -> EyreResult<Option<NodeRef>> {
if self.routing_table().matches_own_node_id(&[node_id]) { if self.routing_table().matches_own_node_id(&[node_id.clone()]) {
bail!("can't look up own node id in routing table"); bail!("can't look up own node id in routing table");
} }
if !VALID_CRYPTO_KINDS.contains(&node_id.kind) { if !VALID_CRYPTO_KINDS.contains(&node_id.kind()) {
bail!("can't look up node id with invalid crypto kind"); bail!("can't look up node id with invalid crypto kind");
} }
let bucket_index = self.routing_table().calculate_bucket_index(&node_id); let bucket_index = self.routing_table().calculate_bucket_index(&node_id);
let bucket = self.get_bucket(bucket_index); let bucket = self.get_bucket(bucket_index);
Ok(bucket Ok(bucket
.entry(&node_id.value) .entry(node_id.ref_value())
.map(|e| NodeRef::new(self.registry(), e))) .map(|e| NodeRef::new(self.registry(), e)))
} }
@ -881,17 +881,17 @@ impl RoutingTableInner {
where where
F: FnOnce(Arc<BucketEntry>) -> R, F: FnOnce(Arc<BucketEntry>) -> R,
{ {
if self.routing_table().matches_own_node_id(&[node_id]) { if self.routing_table().matches_own_node_id(&[node_id.clone()]) {
veilid_log!(self error "can't look up own node id in routing table"); veilid_log!(self error "can't look up own node id in routing table");
return None; return None;
} }
if !VALID_CRYPTO_KINDS.contains(&node_id.kind) { if !VALID_CRYPTO_KINDS.contains(&node_id.kind()) {
veilid_log!(self error "can't look up node id with invalid crypto kind"); veilid_log!(self error "can't look up node id with invalid crypto kind");
return None; return None;
} }
let bucket_entry = self.routing_table().calculate_bucket_index(&node_id); let bucket_entry = self.routing_table().calculate_bucket_index(&node_id);
let bucket = self.get_bucket(bucket_entry); let bucket = self.get_bucket(bucket_entry);
bucket.entry(&node_id.value).map(f) bucket.entry(node_id.ref_value()).map(f)
} }
/// Shortcut function to add a node to our routing table if it doesn't exist /// Shortcut function to add a node to our routing table if it doesn't exist
@ -1326,7 +1326,7 @@ impl RoutingTableInner {
pub fn find_preferred_closest_nodes<T, O>( pub fn find_preferred_closest_nodes<T, O>(
&self, &self,
node_count: usize, node_count: usize,
node_id: HashDigest, hash_coordinate: HashDigest,
mut filters: VecDeque<RoutingTableEntryFilter>, mut filters: VecDeque<RoutingTableEntryFilter>,
transform: T, transform: T,
) -> VeilidAPIResult<Vec<O>> ) -> VeilidAPIResult<Vec<O>>
@ -1337,7 +1337,7 @@ impl RoutingTableInner {
let routing_table = self.routing_table(); let routing_table = self.routing_table();
// Get the crypto kind // Get the crypto kind
let crypto_kind = node_id.kind; let crypto_kind = hash_coordinate.kind();
let crypto = self.crypto(); let crypto = self.crypto();
let Some(vcrypto) = crypto.get(crypto_kind) else { let Some(vcrypto) = crypto.get(crypto_kind) else {
apibail_generic!("invalid crypto kind"); apibail_generic!("invalid crypto kind");
@ -1400,8 +1400,14 @@ impl RoutingTableInner {
}; };
// distance is the next metric, closer nodes first // distance is the next metric, closer nodes first
let da = vcrypto.distance(&BareHashDigest::from(a_key.value), &node_id.value); let da = vcrypto.distance(
let db = vcrypto.distance(&BareHashDigest::from(b_key.value), &node_id.value); &BareHashDigest::from(a_key.value()),
hash_coordinate.ref_value(),
);
let db = vcrypto.distance(
&BareHashDigest::from(b_key.value()),
hash_coordinate.ref_value(),
);
da.cmp(&db) da.cmp(&db)
}; };
@ -1418,7 +1424,7 @@ impl RoutingTableInner {
closest_nodes: &[NodeRef], closest_nodes: &[NodeRef],
) -> Vec<NodeRef> { ) -> Vec<NodeRef> {
// Lock all noderefs // Lock all noderefs
let kind = node_id.kind; let kind = node_id.kind();
let mut closest_nodes_locked: Vec<LockedNodeRef> = closest_nodes let mut closest_nodes_locked: Vec<LockedNodeRef> = closest_nodes
.iter() .iter()
.filter_map(|nr| { .filter_map(|nr| {
@ -1593,9 +1599,9 @@ impl RoutingTableInner {
#[instrument(level = "trace", skip_all)] #[instrument(level = "trace", skip_all)]
pub fn make_closest_noderef_sort<'a>( pub fn make_closest_noderef_sort<'a>(
crypto: &'a Crypto, crypto: &'a Crypto,
node_id: HashDigest, hash_coordinate: HashDigest,
) -> impl Fn(&LockedNodeRef, &LockedNodeRef) -> core::cmp::Ordering + 'a { ) -> impl Fn(&LockedNodeRef, &LockedNodeRef) -> core::cmp::Ordering + 'a {
let kind = node_id.kind; let kind = hash_coordinate.kind();
// Get cryptoversion to check distance with // Get cryptoversion to check distance with
let vcrypto = crypto.get(kind).unwrap(); let vcrypto = crypto.get(kind).unwrap();
@ -1612,8 +1618,14 @@ pub fn make_closest_noderef_sort<'a>(
let b_key = b_entry.node_ids().get(kind).unwrap(); let b_key = b_entry.node_ids().get(kind).unwrap();
// distance is the next metric, closer nodes first // distance is the next metric, closer nodes first
let da = vcrypto.distance(&BareHashDigest::from(a_key.value), &node_id.value); let da = vcrypto.distance(
let db = vcrypto.distance(&BareHashDigest::from(b_key.value), &node_id.value); &BareHashDigest::from(a_key.value()),
hash_coordinate.ref_value(),
);
let db = vcrypto.distance(
&BareHashDigest::from(b_key.value()),
hash_coordinate.ref_value(),
);
da.cmp(&db) da.cmp(&db)
}) })
}) })
@ -1622,21 +1634,21 @@ pub fn make_closest_noderef_sort<'a>(
pub fn make_closest_node_id_sort( pub fn make_closest_node_id_sort(
crypto: &Crypto, crypto: &Crypto,
node_id: NodeId, hash_coordinate: HashDigest,
) -> impl Fn(&BareNodeId, &BareNodeId) -> core::cmp::Ordering + '_ { ) -> impl Fn(&BareNodeId, &BareNodeId) -> core::cmp::Ordering + '_ {
let kind = node_id.kind; let kind = hash_coordinate.kind();
// Get cryptoversion to check distance with // Get cryptoversion to check distance with
let vcrypto = crypto.get(kind).unwrap(); let vcrypto = crypto.get(kind).unwrap();
move |a: &BareNodeId, b: &BareNodeId| -> core::cmp::Ordering { move |a: &BareNodeId, b: &BareNodeId| -> core::cmp::Ordering {
// distance is the next metric, closer nodes first // distance is the next metric, closer nodes first
let da = vcrypto.distance( let da = vcrypto.distance(
&BareHashDigest::from(*a), &BareHashDigest::from(a.bytes()),
&BareHashDigest::from(node_id.value), hash_coordinate.ref_value(),
); );
let db = vcrypto.distance( let db = vcrypto.distance(
&BareHashDigest::from(*b), &BareHashDigest::from(b.bytes()),
&BareHashDigest::from(node_id.value), hash_coordinate.ref_value(),
); );
da.cmp(&db) da.cmp(&db)
} }

View file

@ -77,7 +77,7 @@ impl RoutingTable {
if self.matches_own_node_id(peer_node_ids) { if self.matches_own_node_id(peer_node_ids) {
veilid_log!(self debug "Ignoring own node in bootstrap response"); veilid_log!(self debug "Ignoring own node in bootstrap response");
} else { } else {
for nid in peer.node_ids().iter().copied() { for nid in peer.node_ids().iter().cloned() {
bootstrapped_peer_id_set.insert(nid); bootstrapped_peer_id_set.insert(nid);
} }
bootstrapped_peers.push(peer); bootstrapped_peers.push(peer);
@ -134,7 +134,7 @@ impl RoutingTable {
let mut rd_peer_ids = BTreeSet::new(); let mut rd_peer_ids = BTreeSet::new();
for peer in bootstrapped_peers.iter() { for peer in bootstrapped_peers.iter() {
if peer.routing_domain() == rd { if peer.routing_domain() == rd {
for nid in peer.node_ids().iter().copied() { for nid in peer.node_ids().iter().cloned() {
rd_peer_ids.insert(nid); rd_peer_ids.insert(nid);
} }
} }

View file

@ -30,7 +30,7 @@ impl RoutingTable {
let Some(buckets) = inner.buckets.get(&kind) else { let Some(buckets) = inner.buckets.get(&kind) else {
continue; continue;
}; };
let sort = make_closest_node_id_sort(&crypto, our_node_id); let sort = make_closest_node_id_sort(&crypto, our_node_id.into());
let mut closest_peers = BTreeSet::<BareNodeId>::new(); let mut closest_peers = BTreeSet::<BareNodeId>::new();
let mut closest_unreliable_count = 0usize; let mut closest_unreliable_count = 0usize;
@ -60,14 +60,14 @@ impl RoutingTable {
BucketEntryState::Unreliable => { BucketEntryState::Unreliable => {
// Add to closest unreliable nodes list // Add to closest unreliable nodes list
if closest_unreliable_count < KEEP_N_CLOSEST_UNRELIABLE_PEERS_COUNT { if closest_unreliable_count < KEEP_N_CLOSEST_UNRELIABLE_PEERS_COUNT {
closest_peers.insert(*key); closest_peers.insert(key.clone());
closest_unreliable_count += 1; closest_unreliable_count += 1;
} }
} }
BucketEntryState::Reliable => { BucketEntryState::Reliable => {
// Add to closest reliable nodes list // Add to closest reliable nodes list
if closest_reliable_count < KEEP_N_CLOSEST_RELIABLE_PEERS_COUNT { if closest_reliable_count < KEEP_N_CLOSEST_RELIABLE_PEERS_COUNT {
closest_peers.insert(*key); closest_peers.insert(key.clone());
closest_reliable_count += 1; closest_reliable_count += 1;
} }
} }

View file

@ -19,7 +19,7 @@ impl RoutingTable {
}) })
} }
/// Fastest routes sort /// Fastest routes sort
fn route_sort_latency_fn(a: &(BareRouteId, u64), b: &(BareRouteId, u64)) -> cmp::Ordering { fn route_sort_latency_fn(a: &(RouteId, u64), b: &(RouteId, u64)) -> cmp::Ordering {
let mut al = a.1; let mut al = a.1;
let mut bl = b.1; let mut bl = b.1;
// Treat zero latency as uncalculated // Treat zero latency as uncalculated
@ -46,14 +46,14 @@ impl RoutingTable {
/// ///
/// If a route doesn't 'need_testing', then we neither test nor drop it /// If a route doesn't 'need_testing', then we neither test nor drop it
#[instrument(level = "trace", skip(self))] #[instrument(level = "trace", skip(self))]
fn get_allocated_routes_to_test(&self, cur_ts: Timestamp) -> Vec<BareRouteId> { fn get_allocated_routes_to_test(&self, cur_ts: Timestamp) -> Vec<RouteId> {
let default_route_hop_count = self let default_route_hop_count = self
.config() .config()
.with(|c| c.network.rpc.default_route_hop_count as usize); .with(|c| c.network.rpc.default_route_hop_count as usize);
let mut must_test_routes = Vec::<BareRouteId>::new(); let mut must_test_routes = Vec::<RouteId>::new();
let mut unpublished_routes = Vec::<(BareRouteId, u64)>::new(); let mut unpublished_routes = Vec::<(RouteId, u64)>::new();
let mut expired_routes = Vec::<BareRouteId>::new(); let mut expired_routes = Vec::<RouteId>::new();
self.route_spec_store().list_allocated_routes(|k, v| { self.route_spec_store().list_allocated_routes(|k, v| {
let stats = v.get_stats(); let stats = v.get_stats();
// Ignore nodes that don't need testing // Ignore nodes that don't need testing
@ -63,15 +63,15 @@ impl RoutingTable {
// If this has been published, always test if we need it // If this has been published, always test if we need it
// Also if the route has never been tested, test it at least once // Also if the route has never been tested, test it at least once
if v.is_published() || stats.last_known_valid_ts.is_none() { if v.is_published() || stats.last_known_valid_ts.is_none() {
must_test_routes.push(*k); must_test_routes.push(k.clone());
} }
// If this is a default route hop length, include it in routes to keep alive // If this is a default route hop length, include it in routes to keep alive
else if v.hop_count() == default_route_hop_count { else if v.hop_count() == default_route_hop_count {
unpublished_routes.push((*k, stats.latency.average.as_u64())); unpublished_routes.push((k.clone(), stats.latency.average.as_u64()));
} }
// Else this is a route that hasnt been used recently enough and we can tear it down // Else this is a route that hasnt been used recently enough and we can tear it down
else { else {
expired_routes.push(*k); expired_routes.push(k.clone());
} }
Option::<()>::None Option::<()>::None
}); });
@ -85,13 +85,13 @@ impl RoutingTable {
background_safety_route_count, background_safety_route_count,
unpublished_routes.len(), unpublished_routes.len(),
)) { )) {
must_test_routes.push(unpublished_route.0); must_test_routes.push(unpublished_route.0.clone());
} }
// Kill off all but N unpublished routes rather than testing them // Kill off all but N unpublished routes rather than testing them
if unpublished_routes.len() > background_safety_route_count { if unpublished_routes.len() > background_safety_route_count {
for x in &unpublished_routes[background_safety_route_count..] { for x in &unpublished_routes[background_safety_route_count..] {
expired_routes.push(x.0); expired_routes.push(x.0.clone());
} }
} }
@ -110,7 +110,7 @@ impl RoutingTable {
async fn test_route_set( async fn test_route_set(
&self, &self,
stop_token: StopToken, stop_token: StopToken,
routes_needing_testing: Vec<BareRouteId>, routes_needing_testing: Vec<RouteId>,
) -> EyreResult<()> { ) -> EyreResult<()> {
if routes_needing_testing.is_empty() { if routes_needing_testing.is_empty() {
return Ok(()); return Ok(());
@ -119,7 +119,7 @@ impl RoutingTable {
#[derive(Default, Debug)] #[derive(Default, Debug)]
struct TestRouteContext { struct TestRouteContext {
dead_routes: Vec<BareRouteId>, dead_routes: Vec<RouteId>,
} }
let ctx = Arc::new(Mutex::new(TestRouteContext::default())); let ctx = Arc::new(Mutex::new(TestRouteContext::default()));
@ -129,7 +129,7 @@ impl RoutingTable {
let ctx = ctx.clone(); let ctx = ctx.clone();
unord.push( unord.push(
async move { async move {
let success = match self.route_spec_store().test_route(r).await { let success = match self.route_spec_store().test_route(r.clone()).await {
// Test had result // Test had result
Ok(Some(v)) => v, Ok(Some(v)) => v,
// Test could not be performed at this time // Test could not be performed at this time
@ -242,7 +242,7 @@ impl RoutingTable {
let remote_routes_needing_testing = self.route_spec_store().list_remote_routes(|k, v| { let remote_routes_needing_testing = self.route_spec_store().list_remote_routes(|k, v| {
let stats = v.get_stats(); let stats = v.get_stats();
if stats.needs_testing(cur_ts) { if stats.needs_testing(cur_ts) {
Some(*k) Some(k.clone())
} else { } else {
None None
} }

View file

@ -4,7 +4,7 @@ use crate::{routing_table::*, RegisteredComponents, VALID_CRYPTO_KINDS};
fn make_mock_typed_node_id(kind: CryptoKind, idx: u8) -> NodeId { fn make_mock_typed_node_id(kind: CryptoKind, idx: u8) -> NodeId {
NodeId::new( NodeId::new(
kind, kind,
BareNodeId::new([ BareNodeId::new(&[
idx, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, idx, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
]), ]),

View file

@ -63,7 +63,7 @@ impl SignedDirectNodeInfo {
let node_info_bytes = Self::make_signature_bytes(&node_info, timestamp)?; let node_info_bytes = Self::make_signature_bytes(&node_info, timestamp)?;
let typed_signatures = let typed_signatures =
crypto.generate_signatures(&node_info_bytes, &typed_key_pairs, |kp, s| { crypto.generate_signatures(&node_info_bytes, &typed_key_pairs, |kp, s| {
Signature::new(kp.kind, s) Signature::new(kp.kind(), s)
})?; })?;
Ok(Self { Ok(Self {
node_info, node_info,

View file

@ -93,7 +93,7 @@ impl SignedRelayedNodeInfo {
Self::make_signature_bytes(&node_info, &relay_ids, &relay_info, timestamp)?; Self::make_signature_bytes(&node_info, &relay_ids, &relay_info, timestamp)?;
let typed_signatures = let typed_signatures =
crypto.generate_signatures(&node_info_bytes, &typed_key_pairs, |kp, s| { crypto.generate_signatures(&node_info_bytes, &typed_key_pairs, |kp, s| {
Signature::new(kp.kind, s) Signature::new(kp.kind(), s)
})?; })?;
Ok(Self { Ok(Self {
node_info, node_info,
@ -121,8 +121,8 @@ impl SignedRelayedNodeInfo {
// Add relay ids to signature // Add relay ids to signature
for relay_id in relay_ids { for relay_id in relay_ids {
let mut rid_msg = ::capnp::message::Builder::new_default(); let mut rid_msg = ::capnp::message::Builder::new_default();
let mut rid_builder = rid_msg.init_root::<veilid_capnp::typed_key::Builder>(); let mut rid_builder = rid_msg.init_root::<veilid_capnp::node_id::Builder>();
encode_typed_node_id(relay_id, &mut rid_builder); encode_node_id(relay_id, &mut rid_builder);
sig_bytes.append(&mut builder_to_vec(rid_msg).map_err(VeilidAPIError::internal)?); sig_bytes.append(&mut builder_to_vec(rid_msg).map_err(VeilidAPIError::internal)?);
} }

View file

@ -0,0 +1,72 @@
use super::*;
use paste::paste;
// Utility Macros
macro_rules! define_typed_byte_data_coder {
($capnp_name: ident, $rust_name: ident) => {
paste! {
pub fn [< decode_ $capnp_name >](
reader: &veilid_capnp::$capnp_name::Reader,
) -> Result<$rust_name, RPCError> {
rpc_ignore_missing_property!(reader, value);
let value = reader.get_value()?;
let kind = reader.get_kind();
Ok($rust_name::new(
CryptoKind::from(kind.to_be_bytes()),
[< Bare $rust_name >]::new(value),
))
}
pub fn [< encode_ $capnp_name >](
$capnp_name: &$rust_name,
builder: &mut veilid_capnp::$capnp_name::Builder,
) {
builder.set_kind(u32::from_be_bytes($capnp_name.kind().0));
builder.set_value($capnp_name.ref_value());
}
}
};
}
macro_rules! define_untyped_byte_data_coder {
($capnp_name: ident, $rust_name: ident) => {
paste! {
pub fn [< decode_ $capnp_name >](
reader: &veilid_capnp::$capnp_name::Reader,
) -> Result<$rust_name, RPCError> {
rpc_ignore_missing_property!(reader, value);
let value = reader.get_value()?;
Ok(
[< $rust_name >]::new(value),
)
}
pub fn [< encode_ $capnp_name >](
$capnp_name: &$rust_name,
builder: &mut veilid_capnp::$capnp_name::Builder,
) {
builder.set_value($capnp_name);
}
}
};
}
// RecordKey
define_typed_byte_data_coder!(record_key, RecordKey);
// BlockId
#[cfg(feature = "unstable-blockstore")]
define_typed_byte_data_coder!(block_id, BlockId);
// NodeId
define_typed_byte_data_coder!(node_id, NodeId);
// PublicKey
define_typed_byte_data_coder!(public_key, PublicKey);
// RouteId
#[cfg(feature = "unstable-blockstore")]
define_typed_byte_data_coder!(route_id, RouteId);
// Signature
define_typed_byte_data_coder!(signature, Signature);
// Nonce
define_untyped_byte_data_coder!(nonce, BareNonce);

View file

@ -1,40 +0,0 @@
use super::*;
use core::convert::TryInto;
pub fn decode_key256(public_key: &veilid_capnp::key256::Reader) -> BarePublicKey {
let u0 = public_key.get_u0().to_be_bytes();
let u1 = public_key.get_u1().to_be_bytes();
let u2 = public_key.get_u2().to_be_bytes();
let u3 = public_key.get_u3().to_be_bytes();
let mut x: [u8; 32] = Default::default();
x[0..8].copy_from_slice(&u0);
x[8..16].copy_from_slice(&u1);
x[16..24].copy_from_slice(&u2);
x[24..32].copy_from_slice(&u3);
BarePublicKey::new(x)
}
pub fn encode_key256(key: &BarePublicKey, builder: &mut veilid_capnp::key256::Builder) {
builder.set_u0(u64::from_be_bytes(
key.bytes[0..8]
.try_into()
.expect("slice with incorrect length"),
));
builder.set_u1(u64::from_be_bytes(
key.bytes[8..16]
.try_into()
.expect("slice with incorrect length"),
));
builder.set_u2(u64::from_be_bytes(
key.bytes[16..24]
.try_into()
.expect("slice with incorrect length"),
));
builder.set_u3(u64::from_be_bytes(
key.bytes[24..32]
.try_into()
.expect("slice with incorrect length"),
));
}

View file

@ -1,13 +1,12 @@
mod address; mod address;
mod address_type_set; mod address_type_set;
mod byte_array_types;
mod dial_info; mod dial_info;
mod dial_info_class; mod dial_info_class;
mod dial_info_detail; mod dial_info_detail;
mod key256;
mod network_class; mod network_class;
mod node_info; mod node_info;
mod node_status; mod node_status;
mod nonce;
mod operations; mod operations;
mod peer_info; mod peer_info;
mod private_safety_route; mod private_safety_route;
@ -15,7 +14,6 @@ mod protocol_type_set;
mod sender_info; mod sender_info;
mod sequencing; mod sequencing;
mod signal_info; mod signal_info;
mod signature512;
mod signed_direct_node_info; mod signed_direct_node_info;
mod signed_node_info; mod signed_node_info;
mod signed_relayed_node_info; mod signed_relayed_node_info;
@ -24,19 +22,16 @@ mod signed_value_descriptor;
mod socket_address; mod socket_address;
#[cfg(feature = "unstable-tunnels")] #[cfg(feature = "unstable-tunnels")]
mod tunnel; mod tunnel;
mod typed_key;
mod typed_signature;
pub use address::*; pub use address::*;
pub use address_type_set::*; pub use address_type_set::*;
pub use byte_array_types::*;
pub use dial_info::*; pub use dial_info::*;
pub use dial_info_class::*; pub use dial_info_class::*;
pub use dial_info_detail::*; pub use dial_info_detail::*;
pub use key256::*;
pub use network_class::*; pub use network_class::*;
pub use node_info::*; pub use node_info::*;
pub use node_status::*; pub use node_status::*;
pub use nonce::*;
pub use operations::*; pub use operations::*;
pub use peer_info::*; pub use peer_info::*;
pub use private_safety_route::*; pub use private_safety_route::*;
@ -44,7 +39,6 @@ pub use protocol_type_set::*;
pub use sender_info::*; pub use sender_info::*;
pub use sequencing::*; pub use sequencing::*;
pub use signal_info::*; pub use signal_info::*;
pub use signature512::*;
pub use signed_direct_node_info::*; pub use signed_direct_node_info::*;
pub use signed_node_info::*; pub use signed_node_info::*;
pub use signed_relayed_node_info::*; pub use signed_relayed_node_info::*;
@ -53,8 +47,6 @@ pub use signed_value_descriptor::*;
pub use socket_address::*; pub use socket_address::*;
#[cfg(feature = "unstable-tunnels")] #[cfg(feature = "unstable-tunnels")]
pub use tunnel::*; pub use tunnel::*;
pub use typed_key::*;
pub use typed_signature::*;
use super::*; use super::*;

View file

@ -1,31 +0,0 @@
use super::*;
pub fn encode_nonce(nonce: &BareNonce, builder: &mut veilid_capnp::nonce24::Builder) {
builder.set_u0(u64::from_be_bytes(
nonce.bytes[0..8]
.try_into()
.expect("slice with incorrect length"),
));
builder.set_u1(u64::from_be_bytes(
nonce.bytes[8..16]
.try_into()
.expect("slice with incorrect length"),
));
builder.set_u2(u64::from_be_bytes(
nonce.bytes[16..24]
.try_into()
.expect("slice with incorrect length"),
));
}
pub fn decode_nonce(reader: &veilid_capnp::nonce24::Reader) -> BareNonce {
let u0 = reader.get_u0().to_be_bytes();
let u1 = reader.get_u1().to_be_bytes();
let u2 = reader.get_u2().to_be_bytes();
BareNonce::new([
u0[0], u0[1], u0[2], u0[3], u0[4], u0[5], u0[6], u0[7], // u0
u1[0], u1[1], u1[2], u1[3], u1[4], u1[5], u1[6], u1[7], // u1
u2[0], u2[1], u2[2], u2[3], u2[4], u2[5], u2[6], u2[7], // u2
])
}

View file

@ -36,7 +36,7 @@ impl RPCOperationFindNodeQ {
) -> Result<Self, RPCError> { ) -> Result<Self, RPCError> {
rpc_ignore_missing_property!(reader, node_id); rpc_ignore_missing_property!(reader, node_id);
let ni_reader = reader.get_node_id()?; let ni_reader = reader.get_node_id()?;
let node_id = decode_typed_node_id(&ni_reader)?; let node_id = decode_node_id(&ni_reader)?;
rpc_ignore_missing_property!(reader, capabilities); rpc_ignore_missing_property!(reader, capabilities);
let cap_reader = reader.get_capabilities()?; let cap_reader = reader.get_capabilities()?;
@ -60,7 +60,7 @@ impl RPCOperationFindNodeQ {
builder: &mut veilid_capnp::operation_find_node_q::Builder, builder: &mut veilid_capnp::operation_find_node_q::Builder,
) -> Result<(), RPCError> { ) -> Result<(), RPCError> {
let mut ni_builder = builder.reborrow().init_node_id(); let mut ni_builder = builder.reborrow().init_node_id();
encode_typed_node_id(&self.node_id, &mut ni_builder); encode_node_id(&self.node_id, &mut ni_builder);
let mut cap_builder = builder let mut cap_builder = builder
.reborrow() .reborrow()

View file

@ -58,7 +58,7 @@ impl RPCOperationGetValueQ {
) -> Result<Self, RPCError> { ) -> Result<Self, RPCError> {
rpc_ignore_missing_property!(reader, key); rpc_ignore_missing_property!(reader, key);
let k_reader = reader.get_key()?; let k_reader = reader.get_key()?;
let key = decode_typed_record_key(&k_reader)?; let key = decode_record_key(&k_reader)?;
let subkey = reader.get_subkey(); let subkey = reader.get_subkey();
let want_descriptor = reader.get_want_descriptor(); let want_descriptor = reader.get_want_descriptor();
Ok(Self { Ok(Self {
@ -72,7 +72,7 @@ impl RPCOperationGetValueQ {
builder: &mut veilid_capnp::operation_get_value_q::Builder, builder: &mut veilid_capnp::operation_get_value_q::Builder,
) -> Result<(), RPCError> { ) -> Result<(), RPCError> {
let mut k_builder = builder.reborrow().init_key(); let mut k_builder = builder.reborrow().init_key();
encode_typed_record_key(&self.key, &mut k_builder); encode_record_key(&self.key, &mut k_builder);
builder.set_subkey(self.subkey); builder.set_subkey(self.subkey);
builder.set_want_descriptor(self.want_descriptor); builder.set_want_descriptor(self.want_descriptor);
Ok(()) Ok(())
@ -150,7 +150,7 @@ impl RPCOperationGetValueA {
// And the signed value data // And the signed value data
if !value if !value
.validate(descriptor.owner(), get_value_context.subkey, &vcrypto) .validate(descriptor.ref_owner(), get_value_context.subkey, &vcrypto)
.map_err(RPCError::protocol)? .map_err(RPCError::protocol)?
{ {
return Err(RPCError::protocol("signed value data did not validate")); return Err(RPCError::protocol("signed value data did not validate"));

View file

@ -54,7 +54,7 @@ impl RPCOperationInspectValueQ {
) -> Result<Self, RPCError> { ) -> Result<Self, RPCError> {
rpc_ignore_missing_property!(reader, key); rpc_ignore_missing_property!(reader, key);
let k_reader = reader.get_key()?; let k_reader = reader.get_key()?;
let key = decode_typed_record_key(&k_reader)?; let key = decode_record_key(&k_reader)?;
rpc_ignore_missing_property!(reader, subkeys); rpc_ignore_missing_property!(reader, subkeys);
let sk_reader = reader.get_subkeys()?; let sk_reader = reader.get_subkeys()?;
@ -89,7 +89,7 @@ impl RPCOperationInspectValueQ {
builder: &mut veilid_capnp::operation_inspect_value_q::Builder, builder: &mut veilid_capnp::operation_inspect_value_q::Builder,
) -> Result<(), RPCError> { ) -> Result<(), RPCError> {
let mut k_builder = builder.reborrow().init_key(); let mut k_builder = builder.reborrow().init_key();
encode_typed_record_key(&self.key, &mut k_builder); encode_record_key(&self.key, &mut k_builder);
let mut sk_builder = builder.reborrow().init_subkeys( let mut sk_builder = builder.reborrow().init_subkeys(
self.subkeys self.subkeys

View file

@ -4,7 +4,7 @@ use super::*;
pub(in crate::rpc_processor) struct RoutedOperation { pub(in crate::rpc_processor) struct RoutedOperation {
routing_domain: RoutingDomain, routing_domain: RoutingDomain,
sequencing: Sequencing, sequencing: Sequencing,
signatures: Vec<BareSignature>, signatures: Vec<Signature>,
nonce: BareNonce, nonce: BareNonce,
data: Vec<u8>, data: Vec<u8>,
} }
@ -46,11 +46,11 @@ impl RoutedOperation {
pub fn sequencing(&self) -> Sequencing { pub fn sequencing(&self) -> Sequencing {
self.sequencing self.sequencing
} }
pub fn signatures(&self) -> &[BareSignature] { pub fn signatures(&self) -> &[Signature] {
&self.signatures &self.signatures
} }
pub fn add_signature(&mut self, signature: BareSignature) { pub fn add_signature(&mut self, signature: Signature) {
self.signatures.push(signature); self.signatures.push(signature);
} }
@ -71,22 +71,23 @@ impl RoutedOperation {
) -> Result<Self, RPCError> { ) -> Result<Self, RPCError> {
rpc_ignore_missing_property!(reader, signatures); rpc_ignore_missing_property!(reader, signatures);
let sigs_reader = reader.get_signatures()?; let sigs_reader = reader.get_signatures()?;
let mut signatures = Vec::<BareSignature>::with_capacity( let mut signatures = Vec::<Signature>::with_capacity(
sigs_reader sigs_reader
.len() .len()
.try_into() .try_into()
.map_err(RPCError::map_internal("too many signatures"))?, .map_err(RPCError::map_internal("too many signatures"))?,
); );
for s in sigs_reader.iter() { for s in sigs_reader.iter() {
// TODO: wants .ignore_ok() eventually let Some(sig) = decode_signature(&s).ignore_ok()? else {
let sig = decode_signature512(&s); continue;
};
signatures.push(sig); signatures.push(sig);
} }
let sequencing = decode_sequencing(reader.get_sequencing()?); let sequencing = decode_sequencing(reader.get_sequencing()?);
rpc_ignore_missing_property!(reader, nonce); rpc_ignore_missing_property!(reader, nonce);
let n_reader = reader.get_nonce()?; let n_reader = reader.get_nonce()?;
let nonce = decode_nonce(&n_reader); let nonce = decode_nonce(&n_reader)?;
rpc_ignore_missing_property!(reader, data); rpc_ignore_missing_property!(reader, data);
let data = reader.get_data()?; let data = reader.get_data()?;
@ -114,7 +115,7 @@ impl RoutedOperation {
); );
for (i, sig) in self.signatures.iter().enumerate() { for (i, sig) in self.signatures.iter().enumerate() {
let mut sig_builder = sigs_builder.reborrow().get(i as u32); let mut sig_builder = sigs_builder.reborrow().get(i as u32);
encode_signature512(sig, &mut sig_builder); encode_signature(sig, &mut sig_builder);
} }
let mut n_builder = builder.reborrow().init_nonce(); let mut n_builder = builder.reborrow().init_nonce();
encode_nonce(&self.nonce, &mut n_builder); encode_nonce(&self.nonce, &mut n_builder);

View file

@ -78,7 +78,7 @@ impl RPCOperationSetValueQ {
) -> Result<Self, RPCError> { ) -> Result<Self, RPCError> {
rpc_ignore_missing_property!(reader, key); rpc_ignore_missing_property!(reader, key);
let k_reader = reader.get_key()?; let k_reader = reader.get_key()?;
let key = decode_typed_record_key(&k_reader)?; let key = decode_record_key(&k_reader)?;
let subkey = reader.get_subkey(); let subkey = reader.get_subkey();
@ -105,7 +105,7 @@ impl RPCOperationSetValueQ {
builder: &mut veilid_capnp::operation_set_value_q::Builder, builder: &mut veilid_capnp::operation_set_value_q::Builder,
) -> Result<(), RPCError> { ) -> Result<(), RPCError> {
let mut k_builder = builder.reborrow().init_key(); let mut k_builder = builder.reborrow().init_key();
encode_typed_record_key(&self.key, &mut k_builder); encode_record_key(&self.key, &mut k_builder);
builder.set_subkey(self.subkey); builder.set_subkey(self.subkey);
let mut v_builder = builder.reborrow().init_value(); let mut v_builder = builder.reborrow().init_value();
encode_signed_value_data(&self.value, &mut v_builder)?; encode_signed_value_data(&self.value, &mut v_builder)?;
@ -164,7 +164,7 @@ impl RPCOperationSetValueA {
// And the signed value data // And the signed value data
if !value if !value
.validate( .validate(
set_value_context.descriptor.owner(), set_value_context.descriptor.ref_owner(),
set_value_context.subkey, set_value_context.subkey,
&vcrypto, &vcrypto,
) )

View file

@ -106,7 +106,7 @@ impl RPCOperationValueChanged {
) -> Result<Self, RPCError> { ) -> Result<Self, RPCError> {
rpc_ignore_missing_property!(reader, key); rpc_ignore_missing_property!(reader, key);
let k_reader = reader.get_key()?; let k_reader = reader.get_key()?;
let key = decode_typed_record_key(&k_reader)?; let key = decode_record_key(&k_reader)?;
rpc_ignore_missing_property!(reader, subkeys); rpc_ignore_missing_property!(reader, subkeys);
let sk_reader = reader.get_subkeys()?; let sk_reader = reader.get_subkeys()?;
@ -149,7 +149,7 @@ impl RPCOperationValueChanged {
builder: &mut veilid_capnp::operation_value_changed::Builder, builder: &mut veilid_capnp::operation_value_changed::Builder,
) -> Result<(), RPCError> { ) -> Result<(), RPCError> {
let mut k_builder = builder.reborrow().init_key(); let mut k_builder = builder.reborrow().init_key();
encode_typed_record_key(&self.key, &mut k_builder); encode_record_key(&self.key, &mut k_builder);
let mut sk_builder = builder.reborrow().init_subkeys( let mut sk_builder = builder.reborrow().init_subkeys(
self.subkeys self.subkeys

View file

@ -10,8 +10,8 @@ pub(in crate::rpc_processor) struct RPCOperationWatchValueQ {
expiration: u64, expiration: u64,
count: u32, count: u32,
watch_id: Option<u64>, watch_id: Option<u64>,
watcher: BarePublicKey, watcher: PublicKey,
signature: BareSignature, signature: Signature,
} }
impl RPCOperationWatchValueQ { impl RPCOperationWatchValueQ {
@ -21,7 +21,7 @@ impl RPCOperationWatchValueQ {
expiration: u64, expiration: u64,
count: u32, count: u32,
watch_id: Option<u64>, watch_id: Option<u64>,
watcher: BareKeyPair, watcher: KeyPair,
vcrypto: &CryptoSystemGuard<'_>, vcrypto: &CryptoSystemGuard<'_>,
) -> Result<Self, RPCError> { ) -> Result<Self, RPCError> {
if subkeys.ranges_len() > MAX_WATCH_VALUE_Q_SUBKEY_RANGES_LEN { if subkeys.ranges_len() > MAX_WATCH_VALUE_Q_SUBKEY_RANGES_LEN {
@ -34,9 +34,16 @@ impl RPCOperationWatchValueQ {
} }
let signature_data = Self::make_signature_data(&key, &subkeys, expiration, count, watch_id); let signature_data = Self::make_signature_data(&key, &subkeys, expiration, count, watch_id);
let signature = vcrypto let signature = Signature::new(
.sign(&watcher.key, &watcher.secret, &signature_data) vcrypto.kind(),
.map_err(RPCError::protocol)?; vcrypto
.sign(
watcher.ref_value().ref_key(),
watcher.ref_value().ref_secret(),
&signature_data,
)
.map_err(RPCError::protocol)?,
);
Ok(Self { Ok(Self {
key, key,
@ -44,7 +51,7 @@ impl RPCOperationWatchValueQ {
expiration, expiration,
count, count,
watch_id, watch_id,
watcher: watcher.key, watcher: PublicKey::new(watcher.kind(), watcher.ref_value().key()),
signature, signature,
}) })
} }
@ -60,9 +67,9 @@ impl RPCOperationWatchValueQ {
let subkeys_ranges_len = subkeys.ranges_len(); let subkeys_ranges_len = subkeys.ranges_len();
let mut sig_data = let mut sig_data =
Vec::with_capacity(PUBLIC_KEY_LENGTH + 4 + (subkeys_ranges_len * 8) + 8 + 8); Vec::with_capacity(key.ref_value().len() + 4 + (subkeys_ranges_len * 8) + 8 + 8);
sig_data.extend_from_slice(&key.kind.0); sig_data.extend_from_slice(&key.kind().0);
sig_data.extend_from_slice(&key.value.bytes); sig_data.extend_from_slice(key.ref_value());
for sk in subkeys.ranges() { for sk in subkeys.ranges() {
sig_data.extend_from_slice(&sk.start().to_le_bytes()); sig_data.extend_from_slice(&sk.start().to_le_bytes());
sig_data.extend_from_slice(&sk.end().to_le_bytes()); sig_data.extend_from_slice(&sk.end().to_le_bytes());
@ -77,7 +84,7 @@ impl RPCOperationWatchValueQ {
pub fn validate(&mut self, validate_context: &RPCValidateContext) -> Result<(), RPCError> { pub fn validate(&mut self, validate_context: &RPCValidateContext) -> Result<(), RPCError> {
let crypto = validate_context.crypto(); let crypto = validate_context.crypto();
let Some(vcrypto) = crypto.get(self.key.kind) else { let Some(vcrypto) = crypto.get(self.watcher.kind()) else {
return Err(RPCError::protocol("unsupported cryptosystem")); return Err(RPCError::protocol("unsupported cryptosystem"));
}; };
@ -89,7 +96,11 @@ impl RPCOperationWatchValueQ {
self.watch_id, self.watch_id,
); );
if !vcrypto if !vcrypto
.verify(&self.watcher, &sig_data, &self.signature) .verify(
self.watcher.ref_value(),
&sig_data,
self.signature.ref_value(),
)
.map_err(RPCError::protocol)? .map_err(RPCError::protocol)?
{ {
return Err(RPCError::protocol("failed to validate watcher signature")); return Err(RPCError::protocol("failed to validate watcher signature"));
@ -129,11 +140,11 @@ impl RPCOperationWatchValueQ {
} }
#[expect(dead_code)] #[expect(dead_code)]
pub fn watcher(&self) -> &BarePublicKey { pub fn watcher(&self) -> &PublicKey {
&self.watcher &self.watcher
} }
#[expect(dead_code)] #[expect(dead_code)]
pub fn signature(&self) -> &BareSignature { pub fn signature(&self) -> &Signature {
&self.signature &self.signature
} }
pub fn destructure( pub fn destructure(
@ -144,8 +155,8 @@ impl RPCOperationWatchValueQ {
u64, u64,
u32, u32,
Option<u64>, Option<u64>,
BarePublicKey, PublicKey,
BareSignature, Signature,
) { ) {
( (
self.key, self.key,
@ -164,7 +175,7 @@ impl RPCOperationWatchValueQ {
) -> Result<Self, RPCError> { ) -> Result<Self, RPCError> {
rpc_ignore_missing_property!(reader, key); rpc_ignore_missing_property!(reader, key);
let k_reader = reader.get_key()?; let k_reader = reader.get_key()?;
let key = decode_typed_record_key(&k_reader)?; let key = decode_record_key(&k_reader)?;
rpc_ignore_missing_property!(reader, subkeys); rpc_ignore_missing_property!(reader, subkeys);
let sk_reader = reader.get_subkeys()?; let sk_reader = reader.get_subkeys()?;
@ -195,11 +206,11 @@ impl RPCOperationWatchValueQ {
rpc_ignore_missing_property!(reader, watcher); rpc_ignore_missing_property!(reader, watcher);
let w_reader = reader.get_watcher()?; let w_reader = reader.get_watcher()?;
let watcher = decode_key256(&w_reader); let watcher = decode_public_key(&w_reader)?;
rpc_ignore_missing_property!(reader, signature); rpc_ignore_missing_property!(reader, signature);
let s_reader = reader.get_signature()?; let s_reader = reader.get_signature()?;
let signature = decode_signature512(&s_reader); let signature = decode_signature(&s_reader)?;
Ok(Self { Ok(Self {
key, key,
@ -217,7 +228,7 @@ impl RPCOperationWatchValueQ {
builder: &mut veilid_capnp::operation_watch_value_q::Builder, builder: &mut veilid_capnp::operation_watch_value_q::Builder,
) -> Result<(), RPCError> { ) -> Result<(), RPCError> {
let mut k_builder = builder.reborrow().init_key(); let mut k_builder = builder.reborrow().init_key();
encode_typed_record_key(&self.key, &mut k_builder); encode_record_key(&self.key, &mut k_builder);
let mut sk_builder = builder.reborrow().init_subkeys( let mut sk_builder = builder.reborrow().init_subkeys(
self.subkeys self.subkeys
@ -235,10 +246,10 @@ impl RPCOperationWatchValueQ {
builder.set_watch_id(self.watch_id.unwrap_or(0u64)); builder.set_watch_id(self.watch_id.unwrap_or(0u64));
let mut w_builder = builder.reborrow().init_watcher(); let mut w_builder = builder.reborrow().init_watcher();
encode_key256(&self.watcher, &mut w_builder); encode_public_key(&self.watcher, &mut w_builder);
let mut s_builder = builder.reborrow().init_signature(); let mut s_builder = builder.reborrow().init_signature();
encode_signature512(&self.signature, &mut s_builder); encode_signature(&self.signature, &mut s_builder);
Ok(()) Ok(())
} }

View file

@ -12,7 +12,7 @@ pub fn decode_peer_info(
let mut node_ids = NodeIdGroup::with_capacity(nids_reader.len() as usize); let mut node_ids = NodeIdGroup::with_capacity(nids_reader.len() as usize);
for nid_reader in nids_reader.iter() { for nid_reader in nids_reader.iter() {
let Some(nid) = decode_typed_node_id(&nid_reader).ignore_ok()? else { let Some(nid) = decode_node_id(&nid_reader).ignore_ok()? else {
continue; continue;
}; };
node_ids.add(nid); node_ids.add(nid);
@ -38,7 +38,7 @@ pub fn encode_peer_info(
.map_err(RPCError::map_invalid_format("out of bound error"))?, .map_err(RPCError::map_invalid_format("out of bound error"))?,
); );
for (i, nid) in peer_info.node_ids().iter().enumerate() { for (i, nid) in peer_info.node_ids().iter().enumerate() {
encode_typed_node_id( encode_node_id(
nid, nid,
&mut nids_builder.reborrow().get( &mut nids_builder.reborrow().get(
i.try_into() i.try_into()

View file

@ -6,7 +6,7 @@ pub fn decode_route_hop_data(
reader: &veilid_capnp::route_hop_data::Reader, reader: &veilid_capnp::route_hop_data::Reader,
) -> Result<RouteHopData, RPCError> { ) -> Result<RouteHopData, RPCError> {
rpc_ignore_missing_property!(reader, nonce); rpc_ignore_missing_property!(reader, nonce);
let nonce = decode_nonce(&reader.get_nonce()?); let nonce = decode_nonce(&reader.get_nonce()?)?;
rpc_ignore_missing_property!(reader, blob); rpc_ignore_missing_property!(reader, blob);
let blob = reader.get_blob()?.to_vec(); let blob = reader.get_blob()?.to_vec();
@ -45,7 +45,7 @@ pub fn decode_route_hop(
let node = match reader.get_node().which()? { let node = match reader.get_node().which()? {
veilid_capnp::route_hop::node::Which::NodeId(ni) => { veilid_capnp::route_hop::node::Which::NodeId(ni) => {
let ni_reader = ni?; let ni_reader = ni?;
RouteNode::BareNodeId(decode_key256(&ni_reader).into()) RouteNode::NodeId(decode_node_id(&ni_reader)?)
} }
veilid_capnp::route_hop::node::Which::PeerInfo(pi) => { veilid_capnp::route_hop::node::Which::PeerInfo(pi) => {
let pi_reader = pi?; let pi_reader = pi?;
@ -71,9 +71,9 @@ pub fn encode_route_hop(
) -> Result<(), RPCError> { ) -> Result<(), RPCError> {
let node_builder = builder.reborrow().init_node(); let node_builder = builder.reborrow().init_node();
match &route_hop.node { match &route_hop.node {
RouteNode::BareNodeId(ni) => { RouteNode::NodeId(ni) => {
let mut ni_builder = node_builder.init_node_id(); let mut ni_builder = node_builder.init_node_id();
encode_key256(&(*ni).into(), &mut ni_builder); encode_node_id(ni, &mut ni_builder);
} }
RouteNode::PeerInfo(pi) => { RouteNode::PeerInfo(pi) => {
let mut pi_builder = node_builder.init_peer_info(); let mut pi_builder = node_builder.init_peer_info();
@ -94,8 +94,7 @@ pub fn decode_private_route(
reader: &veilid_capnp::private_route::Reader, reader: &veilid_capnp::private_route::Reader,
) -> Result<PrivateRoute, RPCError> { ) -> Result<PrivateRoute, RPCError> {
rpc_ignore_missing_property!(reader, public_key); rpc_ignore_missing_property!(reader, public_key);
let public_key = decode_typed_public_key(&reader.get_public_key()?)?; let public_key = decode_public_key(&reader.get_public_key()?)?;
let hop_count = reader.get_hop_count();
let hops = match reader.get_hops().which()? { let hops = match reader.get_hops().which()? {
veilid_capnp::private_route::hops::Which::FirstHop(rh_reader) => { veilid_capnp::private_route::hops::Which::FirstHop(rh_reader) => {
@ -109,22 +108,17 @@ pub fn decode_private_route(
veilid_capnp::private_route::hops::Which::Empty(_) => PrivateRouteHops::Empty, veilid_capnp::private_route::hops::Which::Empty(_) => PrivateRouteHops::Empty,
}; };
Ok(PrivateRoute { Ok(PrivateRoute { public_key, hops })
public_key,
hop_count,
hops,
})
} }
pub fn encode_private_route( pub fn encode_private_route(
private_route: &PrivateRoute, private_route: &PrivateRoute,
builder: &mut veilid_capnp::private_route::Builder, builder: &mut veilid_capnp::private_route::Builder,
) -> Result<(), RPCError> { ) -> Result<(), RPCError> {
encode_typed_public_key( encode_public_key(
&private_route.public_key, &private_route.public_key,
&mut builder.reborrow().init_public_key(), &mut builder.reborrow().init_public_key(),
); );
builder.set_hop_count(private_route.hop_count);
let mut h_builder = builder.reborrow().init_hops(); let mut h_builder = builder.reborrow().init_hops();
match &private_route.hops { match &private_route.hops {
PrivateRouteHops::FirstHop(first_hop) => { PrivateRouteHops::FirstHop(first_hop) => {
@ -149,8 +143,7 @@ pub fn decode_safety_route(
reader: &veilid_capnp::safety_route::Reader, reader: &veilid_capnp::safety_route::Reader,
) -> Result<SafetyRoute, RPCError> { ) -> Result<SafetyRoute, RPCError> {
rpc_ignore_missing_property!(reader, public_key); rpc_ignore_missing_property!(reader, public_key);
let public_key = decode_typed_public_key(&reader.get_public_key()?)?; let public_key = decode_public_key(&reader.get_public_key()?)?;
let hop_count = reader.get_hop_count();
let hops = match reader.get_hops().which()? { let hops = match reader.get_hops().which()? {
veilid_capnp::safety_route::hops::Which::Data(rhd_reader) => { veilid_capnp::safety_route::hops::Which::Data(rhd_reader) => {
let rhd_reader = rhd_reader?; let rhd_reader = rhd_reader?;
@ -162,22 +155,17 @@ pub fn decode_safety_route(
} }
}; };
Ok(SafetyRoute { Ok(SafetyRoute { public_key, hops })
public_key,
hop_count,
hops,
})
} }
pub fn encode_safety_route( pub fn encode_safety_route(
safety_route: &SafetyRoute, safety_route: &SafetyRoute,
builder: &mut veilid_capnp::safety_route::Builder, builder: &mut veilid_capnp::safety_route::Builder,
) -> Result<(), RPCError> { ) -> Result<(), RPCError> {
encode_typed_public_key( encode_public_key(
&safety_route.public_key, &safety_route.public_key,
&mut builder.reborrow().init_public_key(), &mut builder.reborrow().init_public_key(),
); );
builder.set_hop_count(safety_route.hop_count);
let h_builder = builder.reborrow().init_hops(); let h_builder = builder.reborrow().init_hops();
match &safety_route.hops { match &safety_route.hops {
SafetyRouteHops::Data(rhd) => { SafetyRouteHops::Data(rhd) => {

View file

@ -1,52 +0,0 @@
use super::*;
pub fn encode_signature512(sig: &BareSignature, builder: &mut veilid_capnp::signature512::Builder) {
let sig = &sig.bytes;
builder.set_u0(u64::from_be_bytes(
sig[0..8].try_into().expect("slice with incorrect length"),
));
builder.set_u1(u64::from_be_bytes(
sig[8..16].try_into().expect("slice with incorrect length"),
));
builder.set_u2(u64::from_be_bytes(
sig[16..24].try_into().expect("slice with incorrect length"),
));
builder.set_u3(u64::from_be_bytes(
sig[24..32].try_into().expect("slice with incorrect length"),
));
builder.set_u4(u64::from_be_bytes(
sig[32..40].try_into().expect("slice with incorrect length"),
));
builder.set_u5(u64::from_be_bytes(
sig[40..48].try_into().expect("slice with incorrect length"),
));
builder.set_u6(u64::from_be_bytes(
sig[48..56].try_into().expect("slice with incorrect length"),
));
builder.set_u7(u64::from_be_bytes(
sig[56..64].try_into().expect("slice with incorrect length"),
));
}
pub fn decode_signature512(reader: &veilid_capnp::signature512::Reader) -> BareSignature {
let u0 = reader.get_u0().to_be_bytes();
let u1 = reader.get_u1().to_be_bytes();
let u2 = reader.get_u2().to_be_bytes();
let u3 = reader.get_u3().to_be_bytes();
let u4 = reader.get_u4().to_be_bytes();
let u5 = reader.get_u5().to_be_bytes();
let u6 = reader.get_u6().to_be_bytes();
let u7 = reader.get_u7().to_be_bytes();
BareSignature::new([
u0[0], u0[1], u0[2], u0[3], u0[4], u0[5], u0[6], u0[7], // u0
u1[0], u1[1], u1[2], u1[3], u1[4], u1[5], u1[6], u1[7], // u1
u2[0], u2[1], u2[2], u2[3], u2[4], u2[5], u2[6], u2[7], // u2
u3[0], u3[1], u3[2], u3[3], u3[4], u3[5], u3[6], u3[7], // u3
u4[0], u4[1], u4[2], u4[3], u4[4], u4[5], u4[6], u4[7], // u4
u5[0], u5[1], u5[2], u5[3], u5[4], u5[5], u5[6], u5[7], // u5
u6[0], u6[1], u6[2], u6[3], u6[4], u6[5], u6[6], u6[7], // u6
u7[0], u7[1], u7[2], u7[3], u7[4], u7[5], u7[6], u7[7], // u7
])
}

View file

@ -14,7 +14,7 @@ pub fn decode_signed_direct_node_info(
let sigs_len = rpc_ignore_max_len!(sigs_reader, MAX_CRYPTO_KINDS); let sigs_len = rpc_ignore_max_len!(sigs_reader, MAX_CRYPTO_KINDS);
let mut typed_signatures = Vec::with_capacity(sigs_len); let mut typed_signatures = Vec::with_capacity(sigs_len);
for sig_reader in sigs_reader { for sig_reader in sigs_reader {
let Some(typed_signature) = decode_typed_signature(&sig_reader).ignore_ok()? else { let Some(typed_signature) = decode_signature(&sig_reader).ignore_ok()? else {
continue; continue;
}; };
typed_signatures.push(typed_signature); typed_signatures.push(typed_signature);
@ -47,7 +47,7 @@ pub fn encode_signed_direct_node_info(
.map_err(RPCError::map_invalid_format("out of bound error"))?, .map_err(RPCError::map_invalid_format("out of bound error"))?,
); );
for (i, typed_signature) in signed_direct_node_info.signatures().iter().enumerate() { for (i, typed_signature) in signed_direct_node_info.signatures().iter().enumerate() {
encode_typed_signature( encode_signature(
typed_signature, typed_signature,
&mut sigs_builder.reborrow().get( &mut sigs_builder.reborrow().get(
i.try_into() i.try_into()

View file

@ -12,7 +12,7 @@ pub fn decode_signed_relayed_node_info(
let rid_count = rpc_ignore_max_len!(rids_reader, MAX_CRYPTO_KINDS); let rid_count = rpc_ignore_max_len!(rids_reader, MAX_CRYPTO_KINDS);
let mut relay_ids = NodeIdGroup::with_capacity(rid_count); let mut relay_ids = NodeIdGroup::with_capacity(rid_count);
for rid_reader in rids_reader { for rid_reader in rids_reader {
let Some(relay_id) = decode_typed_node_id(&rid_reader).ignore_ok()? else { let Some(relay_id) = decode_node_id(&rid_reader).ignore_ok()? else {
continue; continue;
}; };
relay_ids.add(relay_id); relay_ids.add(relay_id);
@ -31,7 +31,7 @@ pub fn decode_signed_relayed_node_info(
let sig_count = rpc_ignore_max_len!(sigs_reader, MAX_CRYPTO_KINDS); let sig_count = rpc_ignore_max_len!(sigs_reader, MAX_CRYPTO_KINDS);
let mut typed_signatures = Vec::with_capacity(sig_count); let mut typed_signatures = Vec::with_capacity(sig_count);
for sig_reader in sigs_reader { for sig_reader in sigs_reader {
let Some(typed_signature) = decode_typed_signature(&sig_reader).ignore_ok()? else { let Some(typed_signature) = decode_signature(&sig_reader).ignore_ok()? else {
continue; continue;
}; };
typed_signatures.push(typed_signature); typed_signatures.push(typed_signature);
@ -61,7 +61,7 @@ pub fn encode_signed_relayed_node_info(
.map_err(RPCError::map_invalid_format("out of bound error"))?, .map_err(RPCError::map_invalid_format("out of bound error"))?,
); );
for (i, typed_key) in signed_relayed_node_info.relay_ids().iter().enumerate() { for (i, typed_key) in signed_relayed_node_info.relay_ids().iter().enumerate() {
encode_typed_node_id( encode_node_id(
typed_key, typed_key,
&mut rids_builder.reborrow().get( &mut rids_builder.reborrow().get(
i.try_into() i.try_into()
@ -85,7 +85,7 @@ pub fn encode_signed_relayed_node_info(
.map_err(RPCError::map_invalid_format("out of bound error"))?, .map_err(RPCError::map_invalid_format("out of bound error"))?,
); );
for (i, typed_signature) in signed_relayed_node_info.signatures().iter().enumerate() { for (i, typed_signature) in signed_relayed_node_info.signatures().iter().enumerate() {
encode_typed_signature( encode_signature(
typed_signature, typed_signature,
&mut sigs_builder.reborrow().get( &mut sigs_builder.reborrow().get(
i.try_into() i.try_into()

View file

@ -9,10 +9,10 @@ pub fn decode_signed_value_data(
let data = reader.get_data()?.to_vec(); let data = reader.get_data()?.to_vec();
rpc_ignore_missing_property!(reader, writer); rpc_ignore_missing_property!(reader, writer);
let wr = reader.get_writer()?; let wr = reader.get_writer()?;
let writer = decode_key256(&wr); let writer = decode_public_key(&wr)?;
rpc_ignore_missing_property!(reader, signature); rpc_ignore_missing_property!(reader, signature);
let sr = reader.get_signature()?; let sr = reader.get_signature()?;
let signature = decode_signature512(&sr); let signature = decode_signature(&sr)?;
Ok(SignedValueData::new( Ok(SignedValueData::new(
ValueData::new_with_seq(seq, data, writer).map_err(RPCError::protocol)?, ValueData::new_with_seq(seq, data, writer).map_err(RPCError::protocol)?,
@ -27,8 +27,8 @@ pub fn encode_signed_value_data(
builder.set_seq(signed_value_data.value_data().seq()); builder.set_seq(signed_value_data.value_data().seq());
builder.set_data(signed_value_data.value_data().data()); builder.set_data(signed_value_data.value_data().data());
let mut wb = builder.reborrow().init_writer(); let mut wb = builder.reborrow().init_writer();
encode_key256(signed_value_data.value_data().writer(), &mut wb); encode_public_key(signed_value_data.value_data().ref_writer(), &mut wb);
let mut sb = builder.reborrow().init_signature(); let mut sb = builder.reborrow().init_signature();
encode_signature512(signed_value_data.signature(), &mut sb); encode_signature(signed_value_data.signature(), &mut sb);
Ok(()) Ok(())
} }

View file

@ -6,12 +6,12 @@ pub fn decode_signed_value_descriptor(
) -> Result<SignedValueDescriptor, RPCError> { ) -> Result<SignedValueDescriptor, RPCError> {
rpc_ignore_missing_property!(reader, owner); rpc_ignore_missing_property!(reader, owner);
let or = reader.get_owner()?; let or = reader.get_owner()?;
let owner = decode_key256(&or); let owner = decode_public_key(&or)?;
rpc_ignore_missing_property!(reader, schema_data); rpc_ignore_missing_property!(reader, schema_data);
let schema_data = reader.get_schema_data()?.to_vec(); let schema_data = reader.get_schema_data()?.to_vec();
rpc_ignore_missing_property!(reader, signature); rpc_ignore_missing_property!(reader, signature);
let sr = reader.get_signature()?; let sr = reader.get_signature()?;
let signature = decode_signature512(&sr); let signature = decode_signature(&sr)?;
Ok(SignedValueDescriptor::new(owner, schema_data, signature)) Ok(SignedValueDescriptor::new(owner, schema_data, signature))
} }
@ -20,9 +20,9 @@ pub fn encode_signed_value_descriptor(
builder: &mut veilid_capnp::signed_value_descriptor::Builder, builder: &mut veilid_capnp::signed_value_descriptor::Builder,
) -> Result<(), RPCError> { ) -> Result<(), RPCError> {
let mut ob = builder.reborrow().init_owner(); let mut ob = builder.reborrow().init_owner();
encode_key256(signed_value_descriptor.owner(), &mut ob); encode_public_key(signed_value_descriptor.ref_owner(), &mut ob);
builder.set_schema_data(signed_value_descriptor.schema_data()); builder.set_schema_data(signed_value_descriptor.schema_data());
let mut sb = builder.reborrow().init_signature(); let mut sb = builder.reborrow().init_signature();
encode_signature512(signed_value_descriptor.signature(), &mut sb); encode_signature(signed_value_descriptor.ref_signature(), &mut sb);
Ok(()) Ok(())
} }

View file

@ -1,62 +0,0 @@
use super::*;
pub fn decode_typed_public_key(
reader: &veilid_capnp::typed_key::Reader,
) -> Result<PublicKey, RPCError> {
rpc_ignore_missing_property!(reader, key);
let key_reader = reader.get_key()?;
let kind = reader.get_kind();
Ok(PublicKey::new(
CryptoKind::from(kind.to_be_bytes()),
decode_key256(&key_reader),
))
}
pub fn encode_typed_public_key(
typed_key: &PublicKey,
builder: &mut veilid_capnp::typed_key::Builder,
) {
builder.set_kind(u32::from_be_bytes(typed_key.kind.0));
let mut key_builder = builder.reborrow().init_key();
encode_key256(&typed_key.value, &mut key_builder);
}
pub fn decode_typed_node_id(reader: &veilid_capnp::typed_key::Reader) -> Result<NodeId, RPCError> {
rpc_ignore_missing_property!(reader, key);
let key_reader = reader.get_key()?;
let kind = reader.get_kind();
Ok(NodeId::new(
CryptoKind::from(kind.to_be_bytes()),
BareNodeId::new(decode_key256(&key_reader).bytes),
))
}
pub fn encode_typed_node_id(typed_key: &NodeId, builder: &mut veilid_capnp::typed_key::Builder) {
builder.set_kind(u32::from_be_bytes(typed_key.kind.0));
let mut key_builder = builder.reborrow().init_key();
encode_key256(&BarePublicKey::new(typed_key.value.bytes), &mut key_builder);
}
pub fn decode_typed_record_key(
reader: &veilid_capnp::typed_key::Reader,
) -> Result<RecordKey, RPCError> {
rpc_ignore_missing_property!(reader, key);
let key_reader = reader.get_key()?;
let kind = reader.get_kind();
Ok(RecordKey::new(
CryptoKind::from(kind.to_be_bytes()),
BareRecordKey::new(decode_key256(&key_reader).bytes),
))
}
pub fn encode_typed_record_key(
typed_key: &RecordKey,
builder: &mut veilid_capnp::typed_key::Builder,
) {
builder.set_kind(u32::from_be_bytes(typed_key.kind.0));
let mut key_builder = builder.reborrow().init_key();
encode_key256(&BarePublicKey::new(typed_key.value.bytes), &mut key_builder);
}

View file

@ -1,23 +0,0 @@
use super::*;
pub fn decode_typed_signature(
reader: &veilid_capnp::typed_signature::Reader,
) -> Result<Signature, RPCError> {
rpc_ignore_missing_property!(reader, signature);
let sig_reader = reader.get_signature()?;
let kind = reader.get_kind();
Ok(Signature::new(
CryptoKind::from(kind.to_be_bytes()),
decode_signature512(&sig_reader),
))
}
pub fn encode_typed_signature(
typed_signature: &Signature,
builder: &mut veilid_capnp::typed_signature::Builder,
) {
builder.set_kind(u32::from_be_bytes(typed_signature.kind.0));
let mut sig_builder = builder.reborrow().init_signature();
encode_signature512(&typed_signature.value, &mut sig_builder);
}

View file

@ -130,18 +130,20 @@ impl Destination {
Destination::Direct { Destination::Direct {
node, node,
safety_selection: _, safety_selection: _,
} => Ok(Target::BareNodeId( } => {
node.best_node_id() Ok(Target::NodeId(node.best_node_id().ok_or_else(|| {
.ok_or_else(|| RPCError::protocol("no supported node id"))?, RPCError::protocol("no supported node id")
)), })?))
}
Destination::Relay { Destination::Relay {
relay: _, relay: _,
node, node,
safety_selection: _, safety_selection: _,
} => Ok(Target::BareNodeId( } => {
node.best_node_id() Ok(Target::NodeId(node.best_node_id().ok_or_else(|| {
.ok_or_else(|| RPCError::protocol("no supported node id"))?, RPCError::protocol("no supported node id")
)), })?))
}
Destination::PrivateRoute { Destination::PrivateRoute {
private_route, private_route,
safety_selection: _, safety_selection: _,
@ -152,7 +154,7 @@ impl Destination {
.add_remote_private_route(private_route.clone()) .add_remote_private_route(private_route.clone())
.map_err(RPCError::protocol)?; .map_err(RPCError::protocol)?;
Ok(Target::PrivateRoute(route_id)) Ok(Target::RouteId(route_id))
} }
} }
} }
@ -289,9 +291,9 @@ impl RPCProcessor {
safety_selection: SafetySelection, safety_selection: SafetySelection,
) -> Result<rpc_processor::Destination, RPCError> { ) -> Result<rpc_processor::Destination, RPCError> {
match target { match target {
Target::BareNodeId(node_id) => { Target::NodeId(node_id) => {
// Resolve node // Resolve node
let nr = match self.resolve_node(node_id, safety_selection).await? { let nr = match self.resolve_node(node_id, safety_selection.clone()).await? {
Some(nr) => nr, Some(nr) => nr,
None => { None => {
return Err(RPCError::network("could not resolve node id")); return Err(RPCError::network("could not resolve node id"));
@ -305,7 +307,7 @@ impl RPCProcessor {
safety_selection, safety_selection,
}) })
} }
Target::PrivateRoute(rsid) => { Target::RouteId(rsid) => {
// Get remote private route // Get remote private route
let Some(private_route) = self let Some(private_route) = self
.routing_table() .routing_table()
@ -345,7 +347,7 @@ impl RPCProcessor {
let crypto_kind = target let crypto_kind = target
.best_node_id() .best_node_id()
.ok_or_else(|| RPCError::protocol("no supported node id"))? .ok_or_else(|| RPCError::protocol("no supported node id"))?
.kind; .kind();
let pr_key = network_result_try!(rss let pr_key = network_result_try!(rss
.get_private_route_for_safety_spec( .get_private_route_for_safety_spec(
crypto_kind, crypto_kind,
@ -376,7 +378,7 @@ impl RPCProcessor {
let crypto_kind = target let crypto_kind = target
.best_node_id() .best_node_id()
.ok_or_else(|| RPCError::protocol("no supported node id"))? .ok_or_else(|| RPCError::protocol("no supported node id"))?
.kind; .kind();
let mut avoid_nodes = relay.node_ids(); let mut avoid_nodes = relay.node_ids();
avoid_nodes.add_all(&target.node_ids()); avoid_nodes.add_all(&target.node_ids());
@ -402,7 +404,7 @@ impl RPCProcessor {
)); ));
}; };
let crypto_kind = private_route.public_key.kind; let crypto_kind = private_route.public_key.kind();
match safety_selection { match safety_selection {
SafetySelection::Unsafe(_) => { SafetySelection::Unsafe(_) => {
@ -418,10 +420,10 @@ impl RPCProcessor {
// Determine if we can use optimized nodeinfo // Determine if we can use optimized nodeinfo
let route_node = if rss.has_remote_private_route_seen_our_node_info( let route_node = if rss.has_remote_private_route_seen_our_node_info(
&private_route.public_key.value, private_route.public_key.ref_value(),
&published_peer_info, &published_peer_info,
) { ) {
RouteNode::BareNodeId(routing_table.node_id(crypto_kind).value) RouteNode::NodeId(routing_table.node_id(crypto_kind))
} else { } else {
RouteNode::PeerInfo(published_peer_info) RouteNode::PeerInfo(published_peer_info)
}; };
@ -438,12 +440,12 @@ impl RPCProcessor {
// Check for loopback test // Check for loopback test
let opt_private_route_id = let opt_private_route_id =
rss.get_route_id_for_key(&private_route.public_key.value); rss.get_route_id_for_key(private_route.public_key.ref_value());
let pr_key = if opt_private_route_id.is_some() let pr_key = if opt_private_route_id.is_some()
&& safety_spec.preferred_route == opt_private_route_id && safety_spec.preferred_route == opt_private_route_id
{ {
// Private route is also safety route during loopback test // Private route is also safety route during loopback test
private_route.public_key.value private_route.public_key.value()
} else { } else {
// Get the private route to respond to that matches the safety route spec we sent the request with // Get the private route to respond to that matches the safety route spec we sent the request with
network_result_try!(rss network_result_try!(rss
@ -519,7 +521,7 @@ impl RPCProcessor {
// If this was received over our private route, it's okay to respond to a private route via our safety route // If this was received over our private route, it's okay to respond to a private route via our safety route
NetworkResult::value(Destination::private_route( NetworkResult::value(Destination::private_route(
pr.clone(), pr.clone(),
SafetySelection::Safe(detail.safety_spec), SafetySelection::Safe(detail.safety_spec.clone()),
)) ))
} }
} }

View file

@ -400,7 +400,7 @@ impl<'a> FanoutCall<'a> {
self.routing_table self.routing_table
.find_preferred_closest_nodes( .find_preferred_closest_nodes(
self.node_count, self.node_count,
self.hash_coordinate, self.hash_coordinate.clone(),
filters, filters,
transform, transform,
) )
@ -415,7 +415,7 @@ impl<'a> FanoutCall<'a> {
pub async fn run(&self, init_fanout_queue: Vec<NodeRef>) -> Result<FanoutResult, RPCError> { pub async fn run(&self, init_fanout_queue: Vec<NodeRef>) -> Result<FanoutResult, RPCError> {
// Create context for this run // Create context for this run
let crypto = self.routing_table.crypto(); let crypto = self.routing_table.crypto();
let Some(vcrypto) = crypto.get(self.hash_coordinate.kind) else { let Some(vcrypto) = crypto.get(self.hash_coordinate.kind()) else {
return Err(RPCError::internal( return Err(RPCError::internal(
"should not try this on crypto we don't support", "should not try this on crypto we don't support",
)); ));
@ -425,12 +425,12 @@ impl<'a> FanoutCall<'a> {
b_key: &CryptoTyped<BareNodeId>| b_key: &CryptoTyped<BareNodeId>|
-> core::cmp::Ordering { -> core::cmp::Ordering {
let da = vcrypto.distance( let da = vcrypto.distance(
&BareHashDigest::from(a_key.value), &BareHashDigest::from(a_key.value()),
&self.hash_coordinate.value, self.hash_coordinate.ref_value(),
); );
let db = vcrypto.distance( let db = vcrypto.distance(
&BareHashDigest::from(b_key.value), &BareHashDigest::from(b_key.value()),
&self.hash_coordinate.value, self.hash_coordinate.ref_value(),
); );
da.cmp(&db) da.cmp(&db)
}, },
@ -438,7 +438,7 @@ impl<'a> FanoutCall<'a> {
let context = Arc::new(Mutex::new(FanoutContext { let context = Arc::new(Mutex::new(FanoutContext {
fanout_queue: FanoutQueue::new( fanout_queue: FanoutQueue::new(
self.routing_table.registry(), self.routing_table.registry(),
self.hash_coordinate.kind, self.hash_coordinate.kind(),
node_sort, node_sort,
self.consensus_count, self.consensus_count,
), ),

View file

@ -123,7 +123,7 @@ impl<'a> FanoutQueue<'a> {
} }
// Add the new node // Add the new node
self.nodes.insert( self.nodes.insert(
key, key.clone(),
FanoutNode { FanoutNode {
node_ref: node_ref.clone(), node_ref: node_ref.clone(),
status: FanoutNodeStatus::Queued, status: FanoutNodeStatus::Queued,

View file

@ -74,9 +74,9 @@ impl MessageHeader {
} }
pub fn direct_sender_node_id(&self) -> NodeId { pub fn direct_sender_node_id(&self) -> NodeId {
match &self.detail { match &self.detail {
RPCMessageHeaderDetail::Direct(d) => d.envelope.get_sender_typed_id(), RPCMessageHeaderDetail::Direct(d) => d.envelope.get_sender_id(),
RPCMessageHeaderDetail::SafetyRouted(s) => s.direct.envelope.get_sender_typed_id(), RPCMessageHeaderDetail::SafetyRouted(s) => s.direct.envelope.get_sender_id(),
RPCMessageHeaderDetail::PrivateRouted(p) => p.direct.envelope.get_sender_typed_id(), RPCMessageHeaderDetail::PrivateRouted(p) => p.direct.envelope.get_sender_id(),
} }
} }
} }

View file

@ -41,8 +41,8 @@ mod rpc_start_tunnel;
pub(crate) use answer::*; pub(crate) use answer::*;
pub(crate) use coders::{ pub(crate) use coders::{
builder_to_vec, decode_private_route, encode_node_info, encode_private_route, encode_route_hop, builder_to_vec, decode_private_route, encode_node_id, encode_node_info, encode_private_route,
encode_signed_direct_node_info, encode_typed_node_id, RPCDecodeContext, encode_route_hop, encode_signed_direct_node_info, RPCDecodeContext,
MAX_INSPECT_VALUE_A_SEQS_LEN, MAX_INSPECT_VALUE_A_SEQS_LEN,
}; };
pub(crate) use destination::*; pub(crate) use destination::*;
@ -146,7 +146,6 @@ pub(crate) struct RPCProcessor {
timeout_us: TimestampDuration, timeout_us: TimestampDuration,
queue_size: u32, queue_size: u32,
concurrency: u32, concurrency: u32,
max_route_hop_count: usize,
waiting_rpc_table: OperationWaiter<Message, Option<QuestionContext>>, waiting_rpc_table: OperationWaiter<Message, Option<QuestionContext>>,
waiting_app_call_table: OperationWaiter<Vec<u8>, ()>, waiting_app_call_table: OperationWaiter<Vec<u8>, ()>,
startup_context: RPCProcessorStartupContext, startup_context: RPCProcessorStartupContext,
@ -172,7 +171,7 @@ impl RPCProcessor {
startup_context: RPCProcessorStartupContext, startup_context: RPCProcessorStartupContext,
) -> Self { ) -> Self {
// make local copy of node id for easy access // make local copy of node id for easy access
let (concurrency, queue_size, max_route_hop_count, timeout_us) = { let (concurrency, queue_size, timeout_us) = {
let config = registry.config(); let config = registry.config();
let c = config.get(); let c = config.get();
@ -180,7 +179,6 @@ impl RPCProcessor {
let mut concurrency = c.network.rpc.concurrency; let mut concurrency = c.network.rpc.concurrency;
let queue_size = c.network.rpc.queue_size; let queue_size = c.network.rpc.queue_size;
let timeout_us = TimestampDuration::new(ms_to_us(c.network.rpc.timeout_ms)); let timeout_us = TimestampDuration::new(ms_to_us(c.network.rpc.timeout_ms));
let max_route_hop_count = c.network.rpc.max_route_hop_count as usize;
if concurrency == 0 { if concurrency == 0 {
concurrency = get_concurrency(); concurrency = get_concurrency();
if concurrency == 0 { if concurrency == 0 {
@ -190,7 +188,7 @@ impl RPCProcessor {
// Default RPC concurrency is the number of CPUs * 16 rpc workers per core, as a single worker takes about 1% CPU when relaying and 16% is reasonable for baseline plus relay // Default RPC concurrency is the number of CPUs * 16 rpc workers per core, as a single worker takes about 1% CPU when relaying and 16% is reasonable for baseline plus relay
concurrency *= RPC_WORKERS_PER_CORE; concurrency *= RPC_WORKERS_PER_CORE;
} }
(concurrency, queue_size, max_route_hop_count, timeout_us) (concurrency, queue_size, timeout_us)
}; };
Self { Self {
@ -199,7 +197,6 @@ impl RPCProcessor {
timeout_us, timeout_us,
queue_size, queue_size,
concurrency, concurrency,
max_route_hop_count,
waiting_rpc_table: OperationWaiter::new(), waiting_rpc_table: OperationWaiter::new(),
waiting_app_call_table: OperationWaiter::new(), waiting_app_call_table: OperationWaiter::new(),
startup_context, startup_context,
@ -374,7 +371,7 @@ impl RPCProcessor {
let routing_domain = RoutingDomain::PublicInternet; let routing_domain = RoutingDomain::PublicInternet;
// Ignore own node // Ignore own node
if routing_table.matches_own_node_id(&[node_id]) { if routing_table.matches_own_node_id(&[node_id.clone()]) {
return TimeoutOr::Value(Err(RPCError::network("can't search for own node id"))); return TimeoutOr::Value(Err(RPCError::network("can't search for own node id")));
} }
@ -382,14 +379,17 @@ impl RPCProcessor {
let result = Arc::new(Mutex::new(Option::<NodeRef>::None)); let result = Arc::new(Mutex::new(Option::<NodeRef>::None));
let registry = self.registry(); let registry = self.registry();
let node_id2 = node_id.clone();
let call_routine = Arc::new(move |next_node: NodeRef| { let call_routine = Arc::new(move |next_node: NodeRef| {
let registry = registry.clone(); let registry = registry.clone();
let node_id = node_id2.clone();
let safety_selection = safety_selection.clone();
Box::pin(async move { Box::pin(async move {
let this = registry.rpc_processor(); let this = registry.rpc_processor();
match this match this
.rpc_call_find_node( .rpc_call_find_node(
Destination::direct(next_node.routing_domain_filtered(routing_domain)) Destination::direct(next_node.routing_domain_filtered(routing_domain))
.with_safety(safety_selection), .with_safety(safety_selection.clone()),
node_id, node_id,
vec![], vec![],
) )
@ -416,8 +416,9 @@ impl RPCProcessor {
// Routine to call to check if we're done at each step // Routine to call to check if we're done at each step
let result2 = result.clone(); let result2 = result.clone();
let node_id2 = node_id.clone();
let check_done = Arc::new(move |_: &FanoutResult| -> bool { let check_done = Arc::new(move |_: &FanoutResult| -> bool {
let Ok(Some(nr)) = routing_table.lookup_node_ref(node_id) else { let Ok(Some(nr)) = routing_table.lookup_node_ref(node_id2.clone()) else {
return false; return false;
}; };
@ -483,7 +484,7 @@ impl RPCProcessor {
// First see if we have the node in our routing table already // First see if we have the node in our routing table already
let mut existing_nr = None; let mut existing_nr = None;
if let Some(nr) = routing_table if let Some(nr) = routing_table
.lookup_node_ref(node_id) .lookup_node_ref(node_id.clone())
.map_err(RPCError::internal)? .map_err(RPCError::internal)?
{ {
existing_nr = Some(nr.clone()); existing_nr = Some(nr.clone());
@ -575,7 +576,7 @@ impl RPCProcessor {
let node_id = self let node_id = self
.routing_table() .routing_table()
.node_id(sr.direct.envelope.get_crypto_kind()); .node_id(sr.direct.envelope.get_crypto_kind());
if node_id.value != reply_private_route.into() { if node_id.value() != reply_private_route.into() {
return Err(RPCError::protocol( return Err(RPCError::protocol(
"should have received reply from safety route to a stub", "should have received reply from safety route to a stub",
)); ));
@ -611,8 +612,7 @@ impl RPCProcessor {
// Get useful private route properties // Get useful private route properties
let pr_is_stub = remote_private_route.is_stub(); let pr_is_stub = remote_private_route.is_stub();
let pr_hop_count = remote_private_route.hop_count; let pr_pubkey = remote_private_route.public_key.value();
let pr_pubkey = remote_private_route.public_key.value;
let crypto_kind = remote_private_route.crypto_kind(); let crypto_kind = remote_private_route.crypto_kind();
let Some(vcrypto) = crypto.get(crypto_kind) else { let Some(vcrypto) = crypto.get(crypto_kind) else {
return Err(RPCError::internal( return Err(RPCError::internal(
@ -621,11 +621,12 @@ impl RPCProcessor {
}; };
// Compile the safety route with the private route // Compile the safety route with the private route
let sequencing = safety_selection.get_sequencing();
let compiled_route: CompiledRoute = network_result_try!(rss let compiled_route: CompiledRoute = network_result_try!(rss
.compile_safety_route(safety_selection, remote_private_route) .compile_safety_route(safety_selection, remote_private_route)
.to_rpc_network_result()?); .to_rpc_network_result()?);
let sr_is_stub = compiled_route.safety_route.is_stub(); let sr_is_stub = compiled_route.safety_route.is_stub();
let sr_pubkey = compiled_route.safety_route.public_key.value; let sr_pubkey = compiled_route.safety_route.public_key.value();
// Encrypt routed operation // Encrypt routed operation
// Xmsg + ENC(Xmsg, DH(PKapr, SKbsr)) // Xmsg + ENC(Xmsg, DH(PKapr, SKbsr))
@ -638,15 +639,9 @@ impl RPCProcessor {
.map_err(RPCError::map_internal("encryption failed"))?; .map_err(RPCError::map_internal("encryption failed"))?;
// Make the routed operation // Make the routed operation
let operation = RoutedOperation::new( let operation = RoutedOperation::new(routing_domain, sequencing, nonce, enc_msg_data);
routing_domain,
safety_selection.get_sequencing(),
nonce,
enc_msg_data,
);
// Prepare route operation // Prepare route operation
let sr_hop_count = compiled_route.safety_route.hop_count;
let route_operation = RPCOperationRoute::new(compiled_route.safety_route, operation); let route_operation = RPCOperationRoute::new(compiled_route.safety_route, operation);
let ssni_route = let ssni_route =
self.get_sender_peer_info(&Destination::direct(compiled_route.first_hop.clone())); self.get_sender_peer_info(&Destination::direct(compiled_route.first_hop.clone()));
@ -661,14 +656,10 @@ impl RPCProcessor {
operation.encode(&mut route_operation)?; operation.encode(&mut route_operation)?;
let out_message = builder_to_vec(route_msg)?; let out_message = builder_to_vec(route_msg)?;
// Get the first hop this is going to
let out_hop_count = (1 + sr_hop_count + pr_hop_count) as usize;
let out = RenderedOperation { let out = RenderedOperation {
message: out_message, message: out_message,
destination_node_ref: compiled_route.first_hop.unfiltered(), destination_node_ref: compiled_route.first_hop.unfiltered(),
node_ref: compiled_route.first_hop, node_ref: compiled_route.first_hop,
hop_count: out_hop_count,
safety_route: if sr_is_stub { None } else { Some(sr_pubkey) }, safety_route: if sr_is_stub { None } else { Some(sr_pubkey) },
remote_private_route: if pr_is_stub { None } else { Some(pr_pubkey) }, remote_private_route: if pr_is_stub { None } else { Some(pr_pubkey) },
reply_private_route, reply_private_route,
@ -701,7 +692,7 @@ impl RPCProcessor {
let reply_private_route = match operation.kind() { let reply_private_route = match operation.kind() {
RPCOperationKind::Question(q) => match q.respond_to() { RPCOperationKind::Question(q) => match q.respond_to() {
RespondTo::Sender => None, RespondTo::Sender => None,
RespondTo::PrivateRoute(pr) => Some(pr.public_key.value), RespondTo::PrivateRoute(pr) => Some(pr.public_key.value()),
}, },
RPCOperationKind::Statement(_) | RPCOperationKind::Answer(_) => None, RPCOperationKind::Statement(_) | RPCOperationKind::Answer(_) => None,
}; };
@ -710,12 +701,12 @@ impl RPCProcessor {
match dest { match dest {
Destination::Direct { Destination::Direct {
node: ref node_ref, node: ref node_ref,
safety_selection, ref safety_selection,
} }
| Destination::Relay { | Destination::Relay {
relay: ref node_ref, relay: ref node_ref,
node: _, node: _,
safety_selection, ref safety_selection,
} => { } => {
// Send to a node without a private route // Send to a node without a private route
// -------------------------------------- // --------------------------------------
@ -737,8 +728,8 @@ impl RPCProcessor {
SafetySelection::Unsafe(sequencing) => { SafetySelection::Unsafe(sequencing) => {
// Apply safety selection sequencing requirement if it is more strict than the node_ref's sequencing requirement // Apply safety selection sequencing requirement if it is more strict than the node_ref's sequencing requirement
let mut node_ref = node_ref.clone(); let mut node_ref = node_ref.clone();
if sequencing > node_ref.sequencing() { if *sequencing > node_ref.sequencing() {
node_ref.set_sequencing(sequencing) node_ref.set_sequencing(*sequencing)
} }
// Reply private route should be None here, even for questions // Reply private route should be None here, even for questions
@ -750,7 +741,6 @@ impl RPCProcessor {
message, message,
destination_node_ref, destination_node_ref,
node_ref, node_ref,
hop_count: 1,
safety_route: None, safety_route: None,
remote_private_route: None, remote_private_route: None,
reply_private_route: None, reply_private_route: None,
@ -786,7 +776,7 @@ impl RPCProcessor {
// Wrap with safety route // Wrap with safety route
out = self.wrap_with_route( out = self.wrap_with_route(
routing_domain, routing_domain,
safety_selection, safety_selection.clone(),
private_route, private_route,
reply_private_route, reply_private_route,
message, message,
@ -1142,15 +1132,24 @@ impl RPCProcessor {
message, message,
destination_node_ref, destination_node_ref,
node_ref, node_ref,
hop_count,
safety_route, safety_route,
remote_private_route, remote_private_route,
reply_private_route, reply_private_route,
} = network_result_try!(self.render_operation(dest.clone(), &operation)?); } = network_result_try!(self.render_operation(dest.clone(), &operation)?);
// Calculate answer timeout // Calculate answer timeout
// Timeout is number of hops times the timeout per hop //
let timeout_us = self.timeout_us * (hop_count as u64); // Maximum timeout is number of hops times the timeout per hop, but the hop
// count is not known for routes.
//
// Practical timeout for routed operations is twice the node-to-node maximum timeout
// or performance suffers. If there are too many timeouts on a route, the route
// should fail to test, and a newer and hopefully faster route will be allocated.
let timeout_us = if safety_route.is_some() || remote_private_route.is_some() {
self.timeout_us * 2u64
} else {
self.timeout_us
};
// Set up op id eventual // Set up op id eventual
let handle = self.waiting_rpc_table.add_op_waiter(op_id, context); let handle = self.waiting_rpc_table.add_op_waiter(op_id, context);
@ -1174,8 +1173,8 @@ impl RPCProcessor {
RPCKind::Question, RPCKind::Question,
send_ts, send_ts,
node_ref.unfiltered(), node_ref.unfiltered(),
safety_route, safety_route.clone(),
remote_private_route, remote_private_route.clone(),
); );
RPCError::network(e) RPCError::network(e)
})?; })?;
@ -1195,8 +1194,8 @@ impl RPCProcessor {
send_ts, send_ts,
bytes, bytes,
node_ref.unfiltered(), node_ref.unfiltered(),
safety_route, safety_route.clone(),
remote_private_route, remote_private_route.clone(),
send_data_result.is_ordered(), send_data_result.is_ordered(),
); );
@ -1241,7 +1240,6 @@ impl RPCProcessor {
message, message,
destination_node_ref, destination_node_ref,
node_ref, node_ref,
hop_count: _,
safety_route, safety_route,
remote_private_route, remote_private_route,
reply_private_route: _, reply_private_route: _,
@ -1266,8 +1264,8 @@ impl RPCProcessor {
RPCKind::Statement, RPCKind::Statement,
send_ts, send_ts,
node_ref.unfiltered(), node_ref.unfiltered(),
safety_route, safety_route.clone(),
remote_private_route, remote_private_route.clone(),
); );
RPCError::network(e) RPCError::network(e)
})?; })?;
@ -1276,7 +1274,7 @@ impl RPCProcessor {
let send_ts = Timestamp::now(); let send_ts = Timestamp::now();
let send_data_result = network_result_value_or_log!(self res => [ format!(": node_ref={}, destination_node_ref={}, message.len={}", node_ref, destination_node_ref, message_len) ] { let send_data_result = network_result_value_or_log!(self res => [ format!(": node_ref={}, destination_node_ref={}, message.len={}", node_ref, destination_node_ref, message_len) ] {
// If we couldn't send we're still cleaning up // If we couldn't send we're still cleaning up
self.record_send_failure(RPCKind::Statement, send_ts, node_ref.unfiltered(), safety_route, remote_private_route); self.record_send_failure(RPCKind::Statement, send_ts, node_ref.unfiltered(), safety_route.clone(), remote_private_route.clone());
network_result_raise!(res); network_result_raise!(res);
} }
); );
@ -1315,7 +1313,6 @@ impl RPCProcessor {
message, message,
destination_node_ref, destination_node_ref,
node_ref, node_ref,
hop_count: _,
safety_route, safety_route,
remote_private_route, remote_private_route,
reply_private_route: _, reply_private_route: _,
@ -1340,8 +1337,8 @@ impl RPCProcessor {
RPCKind::Answer, RPCKind::Answer,
send_ts, send_ts,
node_ref.unfiltered(), node_ref.unfiltered(),
safety_route, safety_route.clone(),
remote_private_route, remote_private_route.clone(),
); );
RPCError::network(e) RPCError::network(e)
})?; })?;
@ -1350,7 +1347,7 @@ impl RPCProcessor {
let send_ts = Timestamp::now(); let send_ts = Timestamp::now();
let send_data_result = network_result_value_or_log!(self res => [ format!(": node_ref={}, destination_node_ref={}, message.len={}", node_ref, destination_node_ref, message_len) ] { let send_data_result = network_result_value_or_log!(self res => [ format!(": node_ref={}, destination_node_ref={}, message.len={}", node_ref, destination_node_ref, message_len) ] {
// If we couldn't send we're still cleaning up // If we couldn't send we're still cleaning up
self.record_send_failure(RPCKind::Answer, send_ts, node_ref.unfiltered(), safety_route, remote_private_route); self.record_send_failure(RPCKind::Answer, send_ts, node_ref.unfiltered(), safety_route.clone(), remote_private_route.clone());
network_result_raise!(res); network_result_raise!(res);
} }
); );
@ -1427,7 +1424,7 @@ impl RPCProcessor {
let msg = match &encoded_msg.header.detail { let msg = match &encoded_msg.header.detail {
RPCMessageHeaderDetail::Direct(detail) => { RPCMessageHeaderDetail::Direct(detail) => {
// Get sender node id // Get sender node id
let sender_node_id = detail.envelope.get_sender_typed_id(); let sender_node_id = detail.envelope.get_sender_id();
// Decode and validate the RPC operation // Decode and validate the RPC operation
let decode_res = self.decode_rpc_operation(&encoded_msg); let decode_res = self.decode_rpc_operation(&encoded_msg);
@ -1464,7 +1461,7 @@ impl RPCProcessor {
// Get the sender noderef, incorporating sender's peer info // Get the sender noderef, incorporating sender's peer info
let sender_peer_info = operation.sender_peer_info(); let sender_peer_info = operation.sender_peer_info();
let mut opt_sender_nr: Option<NodeRef> = network_result_try!(self let mut opt_sender_nr: Option<NodeRef> = network_result_try!(self
.process_sender_peer_info(routing_domain, sender_node_id, &sender_peer_info)? => { .process_sender_peer_info(routing_domain, sender_node_id.clone(), &sender_peer_info)? => {
veilid_log!(self debug target:"network_result", "Sender PeerInfo: {:?}", sender_peer_info); veilid_log!(self debug target:"network_result", "Sender PeerInfo: {:?}", sender_peer_info);
veilid_log!(self debug target:"network_result", "From Operation: {:?}", operation.kind()); veilid_log!(self debug target:"network_result", "From Operation: {:?}", operation.kind());
veilid_log!(self debug target:"network_result", "With Detail: {:?}", detail); veilid_log!(self debug target:"network_result", "With Detail: {:?}", detail);

View file

@ -8,8 +8,6 @@ pub struct RenderedOperation {
pub destination_node_ref: NodeRef, pub destination_node_ref: NodeRef,
/// Node to send envelope to (may not be destination node in case of relay) /// Node to send envelope to (may not be destination node in case of relay)
pub node_ref: FilteredNodeRef, pub node_ref: FilteredNodeRef,
/// Total safety + private route hop count + 1 hop for the initial send
pub hop_count: usize,
/// The safety route used to send the message /// The safety route used to send the message
pub safety_route: Option<BarePublicKey>, pub safety_route: Option<BarePublicKey>,
/// The private route used to send the message /// The private route used to send the message
@ -24,7 +22,6 @@ impl fmt::Debug for RenderedOperation {
.field("message(len)", &self.message.len()) .field("message(len)", &self.message.len())
.field("destination_node_ref", &self.destination_node_ref) .field("destination_node_ref", &self.destination_node_ref)
.field("node_ref", &self.node_ref) .field("node_ref", &self.node_ref)
.field("hop_count", &self.hop_count)
.field("safety_route", &self.safety_route) .field("safety_route", &self.safety_route)
.field("remote_private_route", &self.remote_private_route) .field("remote_private_route", &self.remote_private_route)
.field("reply_private_route", &self.reply_private_route) .field("reply_private_route", &self.reply_private_route)

View file

@ -29,7 +29,7 @@ impl RPCProcessor {
let waitable_reply = network_result_try!(self.question(dest, question, None).await?); let waitable_reply = network_result_try!(self.question(dest, question, None).await?);
// Keep the reply private route that was used to return with the answer // Keep the reply private route that was used to return with the answer
let reply_private_route = waitable_reply.context.reply_private_route; let reply_private_route = waitable_reply.context.reply_private_route.clone();
// Wait for reply // Wait for reply
let (msg, latency) = match self.wait_for_reply(waitable_reply, debug_string).await? { let (msg, latency) = match self.wait_for_reply(waitable_reply, debug_string).await? {
@ -84,7 +84,7 @@ impl RPCProcessor {
// Get the private route this came over // Get the private route this came over
let opt_pr_pubkey = match &msg.header.detail { let opt_pr_pubkey = match &msg.header.detail {
RPCMessageHeaderDetail::Direct(_) | RPCMessageHeaderDetail::SafetyRouted(_) => None, RPCMessageHeaderDetail::Direct(_) | RPCMessageHeaderDetail::SafetyRouted(_) => None,
RPCMessageHeaderDetail::PrivateRouted(pr) => Some(pr.private_route), RPCMessageHeaderDetail::PrivateRouted(pr) => Some(pr.private_route.clone()),
}; };
let route_id = if let Some(pr_pubkey) = opt_pr_pubkey { let route_id = if let Some(pr_pubkey) = opt_pr_pubkey {
let rss = routing_table.route_spec_store(); let rss = routing_table.route_spec_store();

View file

@ -47,7 +47,7 @@ impl RPCProcessor {
// Get the private route this came over // Get the private route this came over
let opt_pr_pubkey = match &msg.header.detail { let opt_pr_pubkey = match &msg.header.detail {
RPCMessageHeaderDetail::Direct(_) | RPCMessageHeaderDetail::SafetyRouted(_) => None, RPCMessageHeaderDetail::Direct(_) | RPCMessageHeaderDetail::SafetyRouted(_) => None,
RPCMessageHeaderDetail::PrivateRouted(pr) => Some(pr.private_route), RPCMessageHeaderDetail::PrivateRouted(pr) => Some(pr.private_route.clone()),
}; };
let route_id = if let Some(pr_pubkey) = opt_pr_pubkey { let route_id = if let Some(pr_pubkey) = opt_pr_pubkey {
let rss = routing_table.route_spec_store(); let rss = routing_table.route_spec_store();

View file

@ -36,7 +36,7 @@ impl RPCProcessor {
} }
let find_node_q_detail = RPCQuestionDetail::FindNodeQ(Box::new( let find_node_q_detail = RPCQuestionDetail::FindNodeQ(Box::new(
RPCOperationFindNodeQ::new(node_id, capabilities.clone()), RPCOperationFindNodeQ::new(node_id.clone(), capabilities.clone()),
)); ));
let find_node_q = RPCQuestion::new( let find_node_q = RPCQuestion::new(
network_result_try!(self.get_destination_respond_to(&dest)?), network_result_try!(self.get_destination_respond_to(&dest)?),
@ -49,7 +49,7 @@ impl RPCProcessor {
let waitable_reply = network_result_try!(self.question(dest, find_node_q, None).await?); let waitable_reply = network_result_try!(self.question(dest, find_node_q, None).await?);
// Keep the reply private route that was used to return with the answer // Keep the reply private route that was used to return with the answer
let reply_private_route = waitable_reply.context.reply_private_route; let reply_private_route = waitable_reply.context.reply_private_route.clone();
// Wait for reply // Wait for reply
let (msg, latency) = match self.wait_for_reply(waitable_reply, debug_string).await? { let (msg, latency) = match self.wait_for_reply(waitable_reply, debug_string).await? {
@ -120,7 +120,7 @@ impl RPCProcessor {
let closest_nodes = network_result_try!(routing_table.find_preferred_closest_peers( let closest_nodes = network_result_try!(routing_table.find_preferred_closest_peers(
routing_domain, routing_domain,
node_id, &node_id.clone().into(),
&capabilities &capabilities
)); ));

View file

@ -28,7 +28,7 @@ impl RPCProcessor {
pub async fn rpc_call_get_value( pub async fn rpc_call_get_value(
&self, &self,
dest: Destination, dest: Destination,
key: RecordKey, record_key: RecordKey,
subkey: ValueSubkey, subkey: ValueSubkey,
last_descriptor: Option<SignedValueDescriptor>, last_descriptor: Option<SignedValueDescriptor>,
) -> RPCNetworkResult<Answer<GetValueAnswer>> { ) -> RPCNetworkResult<Answer<GetValueAnswer>> {
@ -48,16 +48,16 @@ impl RPCProcessor {
// Get the target node id // Get the target node id
let crypto = self.crypto(); let crypto = self.crypto();
let Some(vcrypto) = crypto.get(key.kind) else { let Some(vcrypto) = crypto.get(record_key.kind()) else {
return Err(RPCError::internal("unsupported cryptosystem")); return Err(RPCError::internal("unsupported cryptosystem"));
}; };
let Some(target_node_id) = target_node_ids.get(key.kind) else { let Some(target_node_id) = target_node_ids.get(record_key.kind()) else {
return Err(RPCError::internal("No node id for crypto kind")); return Err(RPCError::internal("No node id for crypto kind"));
}; };
let debug_string = format!( let debug_string = format!(
"OUT ==> GetValueQ({} #{}{}) => {}", "OUT ==> GetValueQ({} #{}{}) => {}",
key, record_key,
subkey, subkey,
if last_descriptor.is_some() { if last_descriptor.is_some() {
" +lastdesc" " +lastdesc"
@ -68,7 +68,8 @@ impl RPCProcessor {
); );
// Send the getvalue question // Send the getvalue question
let get_value_q = RPCOperationGetValueQ::new(key, subkey, last_descriptor.is_none()); let get_value_q =
RPCOperationGetValueQ::new(record_key.clone(), subkey, last_descriptor.is_none());
let question = RPCQuestion::new( let question = RPCQuestion::new(
network_result_try!(self.get_destination_respond_to(&dest)?), network_result_try!(self.get_destination_respond_to(&dest)?),
RPCQuestionDetail::GetValueQ(Box::new(get_value_q)), RPCQuestionDetail::GetValueQ(Box::new(get_value_q)),
@ -88,7 +89,7 @@ impl RPCProcessor {
); );
// Keep the reply private route that was used to return with the answer // Keep the reply private route that was used to return with the answer
let reply_private_route = waitable_reply.context.reply_private_route; let reply_private_route = waitable_reply.context.reply_private_route.clone();
// Wait for reply // Wait for reply
let (msg, latency) = match self.wait_for_reply(waitable_reply, debug_string).await? { let (msg, latency) = match self.wait_for_reply(waitable_reply, debug_string).await? {
@ -122,7 +123,7 @@ impl RPCProcessor {
let debug_string_answer = format!( let debug_string_answer = format!(
"OUT <== GetValueA({} #{}{}{} peers={}) <= {}", "OUT <== GetValueA({} #{}{}{} peers={}) <= {}",
key, record_key,
subkey, subkey,
debug_string_value, debug_string_value,
if descriptor.is_some() { " +desc" } else { "" }, if descriptor.is_some() { " +desc" } else { "" },
@ -134,7 +135,7 @@ impl RPCProcessor {
let peer_ids: Vec<String> = peers let peer_ids: Vec<String> = peers
.iter() .iter()
.filter_map(|p| p.node_ids().get(key.kind).map(|k| k.to_string())) .filter_map(|p| p.node_ids().get(record_key.kind()).map(|k| k.to_string()))
.collect(); .collect();
veilid_log!(self debug target: "dht", "Peers: {:#?}", peer_ids); veilid_log!(self debug target: "dht", "Peers: {:#?}", peer_ids);
} }
@ -142,8 +143,8 @@ impl RPCProcessor {
// Validate peers returned are, in fact, closer to the key than the node we sent this to // Validate peers returned are, in fact, closer to the key than the node we sent this to
let valid = match RoutingTable::verify_peers_closer( let valid = match RoutingTable::verify_peers_closer(
&vcrypto, &vcrypto,
target_node_id.into(), &target_node_id.clone().into(),
key.into(), &record_key.clone().into(),
&peers, &peers,
) { ) {
Ok(v) => v, Ok(v) => v,
@ -219,17 +220,20 @@ impl RPCProcessor {
}; };
// Destructure // Destructure
let (key, subkey, want_descriptor) = get_value_q.destructure(); let (record_key, subkey, want_descriptor) = get_value_q.destructure();
// Get the nodes that we know about that are closer to the the key than our own node // Get the nodes that we know about that are closer to the the key than our own node
let closer_to_key_peers = network_result_try!( let closer_to_key_peers = network_result_try!(routing_table
routing_table.find_preferred_peers_closer_to_key(routing_domain, key, vec![CAP_DHT]) .find_preferred_peers_closer_to_key(
); routing_domain,
&record_key.clone().into(),
vec![CAP_DHT]
));
if debug_target_enabled!("dht") { if debug_target_enabled!("dht") {
let debug_string = format!( let debug_string = format!(
"IN <=== GetValueQ({} #{}{}) <== {}", "IN <=== GetValueQ({} #{}{}) <== {}",
key, record_key,
subkey, subkey,
if want_descriptor { " +wantdesc" } else { "" }, if want_descriptor { " +wantdesc" } else { "" },
msg.header.direct_sender_node_id() msg.header.direct_sender_node_id()
@ -252,7 +256,7 @@ impl RPCProcessor {
// See if we have this record ourselves // See if we have this record ourselves
let storage_manager = self.storage_manager(); let storage_manager = self.storage_manager();
let get_result = network_result_try!(storage_manager let get_result = network_result_try!(storage_manager
.inbound_get_value(key, subkey, want_descriptor) .inbound_get_value(record_key.clone(), subkey, want_descriptor)
.await .await
.map_err(RPCError::internal)?); .map_err(RPCError::internal)?);
(get_result.opt_value, get_result.opt_descriptor) (get_result.opt_value, get_result.opt_descriptor)
@ -273,7 +277,7 @@ impl RPCProcessor {
let debug_string_answer = format!( let debug_string_answer = format!(
"IN ===> GetValueA({} #{}{}{} peers={}) ==> {}", "IN ===> GetValueA({} #{}{}{} peers={}) ==> {}",
key, record_key,
subkey, subkey,
debug_string_value, debug_string_value,
if get_result_descriptor.is_some() { if get_result_descriptor.is_some() {

View file

@ -30,7 +30,7 @@ impl RPCProcessor {
pub async fn rpc_call_inspect_value( pub async fn rpc_call_inspect_value(
&self, &self,
dest: Destination, dest: Destination,
key: RecordKey, record_key: RecordKey,
subkeys: ValueSubkeyRangeSet, subkeys: ValueSubkeyRangeSet,
last_descriptor: Option<SignedValueDescriptor>, last_descriptor: Option<SignedValueDescriptor>,
) -> RPCNetworkResult<Answer<InspectValueAnswer>> { ) -> RPCNetworkResult<Answer<InspectValueAnswer>> {
@ -50,16 +50,16 @@ impl RPCProcessor {
// Get the target node id // Get the target node id
let crypto = self.crypto(); let crypto = self.crypto();
let Some(vcrypto) = crypto.get(key.kind) else { let Some(vcrypto) = crypto.get(record_key.kind()) else {
return Err(RPCError::internal("unsupported cryptosystem")); return Err(RPCError::internal("unsupported cryptosystem"));
}; };
let Some(target_node_id) = target_node_ids.get(key.kind) else { let Some(target_node_id) = target_node_ids.get(record_key.kind()) else {
return Err(RPCError::internal("No node id for crypto kind")); return Err(RPCError::internal("No node id for crypto kind"));
}; };
let debug_string = format!( let debug_string = format!(
"OUT ==> InspectValueQ({} #{}{}) => {}", "OUT ==> InspectValueQ({} #{}{}) => {}",
key, record_key,
&subkeys, &subkeys,
if last_descriptor.is_some() { if last_descriptor.is_some() {
" +lastdesc" " +lastdesc"
@ -70,8 +70,11 @@ impl RPCProcessor {
); );
// Send the inspectvalue question // Send the inspectvalue question
let inspect_value_q = let inspect_value_q = RPCOperationInspectValueQ::new(
RPCOperationInspectValueQ::new(key, subkeys.clone(), last_descriptor.is_none())?; record_key.clone(),
subkeys.clone(),
last_descriptor.is_none(),
)?;
let question = RPCQuestion::new( let question = RPCQuestion::new(
network_result_try!(self.get_destination_respond_to(&dest)?), network_result_try!(self.get_destination_respond_to(&dest)?),
RPCQuestionDetail::InspectValueQ(Box::new(inspect_value_q)), RPCQuestionDetail::InspectValueQ(Box::new(inspect_value_q)),
@ -91,7 +94,7 @@ impl RPCProcessor {
); );
// Keep the reply private route that was used to return with the answer // Keep the reply private route that was used to return with the answer
let reply_private_route = waitable_reply.context.reply_private_route; let reply_private_route = waitable_reply.context.reply_private_route.clone();
// Wait for reply // Wait for reply
let (msg, latency) = match self.wait_for_reply(waitable_reply, debug_string).await? { let (msg, latency) = match self.wait_for_reply(waitable_reply, debug_string).await? {
@ -118,7 +121,7 @@ impl RPCProcessor {
if debug_target_enabled!("dht") { if debug_target_enabled!("dht") {
let debug_string_answer = format!( let debug_string_answer = format!(
"OUT <== InspectValueA({} {} peers={}) <= {} seqs:\n{}", "OUT <== InspectValueA({} {} peers={}) <= {} seqs:\n{}",
key, record_key,
if descriptor.is_some() { " +desc" } else { "" }, if descriptor.is_some() { " +desc" } else { "" },
peers.len(), peers.len(),
dest, dest,
@ -129,7 +132,7 @@ impl RPCProcessor {
let peer_ids: Vec<String> = peers let peer_ids: Vec<String> = peers
.iter() .iter()
.filter_map(|p| p.node_ids().get(key.kind).map(|k| k.to_string())) .filter_map(|p| p.node_ids().get(record_key.kind()).map(|k| k.to_string()))
.collect(); .collect();
veilid_log!(self debug target: "dht", "Peers: {:#?}", peer_ids); veilid_log!(self debug target: "dht", "Peers: {:#?}", peer_ids);
} }
@ -137,8 +140,8 @@ impl RPCProcessor {
// Validate peers returned are, in fact, closer to the key than the node we sent this to // Validate peers returned are, in fact, closer to the key than the node we sent this to
let valid = match RoutingTable::verify_peers_closer( let valid = match RoutingTable::verify_peers_closer(
&vcrypto, &vcrypto,
target_node_id.into(), &target_node_id.clone().into(),
key.into(), &record_key.clone().into(),
&peers, &peers,
) { ) {
Ok(v) => v, Ok(v) => v,
@ -205,17 +208,20 @@ impl RPCProcessor {
}; };
// Destructure // Destructure
let (key, subkeys, want_descriptor) = inspect_value_q.destructure(); let (record_key, subkeys, want_descriptor) = inspect_value_q.destructure();
// Get the nodes that we know about that are closer to the the key than our own node // Get the nodes that we know about that are closer to the the key than our own node
let closer_to_key_peers = network_result_try!( let closer_to_key_peers = network_result_try!(routing_table
routing_table.find_preferred_peers_closer_to_key(routing_domain, key, vec![CAP_DHT]) .find_preferred_peers_closer_to_key(
); routing_domain,
&record_key.clone().into(),
vec![CAP_DHT]
));
if debug_target_enabled!("dht") { if debug_target_enabled!("dht") {
let debug_string = format!( let debug_string = format!(
"IN <=== InspectValueQ({} {}{}) <== {}", "IN <=== InspectValueQ({} {}{}) <== {}",
key, record_key,
subkeys, subkeys,
if want_descriptor { " +wantdesc" } else { "" }, if want_descriptor { " +wantdesc" } else { "" },
msg.header.direct_sender_node_id() msg.header.direct_sender_node_id()
@ -239,7 +245,7 @@ impl RPCProcessor {
// See if we have this record ourselves // See if we have this record ourselves
let storage_manager = self.storage_manager(); let storage_manager = self.storage_manager();
let inspect_result = network_result_try!(storage_manager let inspect_result = network_result_try!(storage_manager
.inbound_inspect_value(key, subkeys, want_descriptor) .inbound_inspect_value(record_key.clone(), subkeys, want_descriptor)
.await .await
.map_err(RPCError::internal)?); .map_err(RPCError::internal)?);
( (
@ -255,7 +261,7 @@ impl RPCProcessor {
if debug_target_enabled!("dht") { if debug_target_enabled!("dht") {
let debug_string_answer = format!( let debug_string_answer = format!(
"IN ===> InspectValueA({} {:?}{} peers={}) ==> {}", "IN ===> InspectValueA({} {:?}{} peers={}) ==> {}",
key, record_key,
inspect_result_seqs, inspect_result_seqs,
if inspect_result_descriptor.is_some() { if inspect_result_descriptor.is_some() {
" +desc" " +desc"

View file

@ -10,32 +10,12 @@ impl RPCProcessor {
route_hop: RouteHop, route_hop: RouteHop,
safety_route: SafetyRoute, safety_route: SafetyRoute,
) -> RPCNetworkResult<()> { ) -> RPCNetworkResult<()> {
// Make sure hop count makes sense
if safety_route.hop_count as usize > self.max_route_hop_count {
return Ok(NetworkResult::invalid_message(
"Safety route hop count too high to process",
));
}
if safety_route.hop_count == 0 {
return Ok(NetworkResult::invalid_message(
"Safety route hop count should not be zero if there are more hops",
));
}
if route_hop.next_hop.is_none() {
return Ok(NetworkResult::invalid_message(
"Safety route hop must have next hop",
));
}
// Get next hop node ref // Get next hop node ref
let routing_table = self.routing_table(); let routing_table = self.routing_table();
let Some(next_hop_nr) = route_hop let Some(next_hop_nr) = route_hop.node.node_ref(&routing_table) else {
.node
.node_ref(&routing_table, safety_route.public_key.kind)
else {
return Ok(NetworkResult::invalid_message(format!( return Ok(NetworkResult::invalid_message(format!(
"could not get route node hop ref: {}", "could not get route node hop ref: {}",
route_hop.node.describe(safety_route.public_key.kind) route_hop.node.describe()
))); )));
}; };
@ -46,7 +26,6 @@ impl RPCProcessor {
let next_hop_route = RPCOperationRoute::new( let next_hop_route = RPCOperationRoute::new(
SafetyRoute { SafetyRoute {
public_key: safety_route.public_key, public_key: safety_route.public_key,
hop_count: safety_route.hop_count - 1,
hops: SafetyRouteHops::Data(route_hop.next_hop.unwrap()), hops: SafetyRouteHops::Data(route_hop.next_hop.unwrap()),
}, },
routed_operation, routed_operation,
@ -67,21 +46,12 @@ impl RPCProcessor {
safety_route_public_key: PublicKey, safety_route_public_key: PublicKey,
next_private_route: PrivateRoute, next_private_route: PrivateRoute,
) -> RPCNetworkResult<()> { ) -> RPCNetworkResult<()> {
// Make sure hop count makes sense
if next_private_route.hop_count as usize > self.max_route_hop_count {
return Ok(NetworkResult::invalid_message(
"Private route hop count too high to process",
));
}
// Get next hop node ref // Get next hop node ref
let routing_table = self.routing_table(); let routing_table = self.routing_table();
let Some(next_hop_nr) = let Some(next_hop_nr) = next_route_node.node_ref(&routing_table) else {
next_route_node.node_ref(&routing_table, safety_route_public_key.kind)
else {
return Ok(NetworkResult::invalid_message(format!( return Ok(NetworkResult::invalid_message(format!(
"could not get route node hop ref: {}", "could not get route node hop ref: {}",
next_route_node.describe(safety_route_public_key.kind) next_route_node.describe()
))); )));
}; };
@ -92,7 +62,6 @@ impl RPCProcessor {
let next_hop_route = RPCOperationRoute::new( let next_hop_route = RPCOperationRoute::new(
SafetyRoute { SafetyRoute {
public_key: safety_route_public_key, public_key: safety_route_public_key,
hop_count: 0,
hops: SafetyRouteHops::Private(next_private_route), hops: SafetyRouteHops::Private(next_private_route),
}, },
routed_operation, routed_operation,
@ -122,8 +91,8 @@ impl RPCProcessor {
// xxx: punish nodes that send messages that fail to decrypt eventually? How to do this for safety routes? // xxx: punish nodes that send messages that fail to decrypt eventually? How to do this for safety routes?
let node_id_secret = self let node_id_secret = self
.routing_table() .routing_table()
.node_id_secret_key(remote_sr_pubkey.kind); .node_id_secret_key(remote_sr_pubkey.kind());
let Ok(dh_secret) = vcrypto.cached_dh(&remote_sr_pubkey.value, &node_id_secret) else { let Ok(dh_secret) = vcrypto.cached_dh(remote_sr_pubkey.ref_value(), &node_id_secret) else {
return Ok(NetworkResult::invalid_message( return Ok(NetworkResult::invalid_message(
"dh failed for remote safety route for safety routed operation", "dh failed for remote safety route for safety routed operation",
)); ));
@ -146,7 +115,7 @@ impl RPCProcessor {
// Pass message to RPC system // Pass message to RPC system
self.enqueue_safety_routed_message( self.enqueue_safety_routed_message(
detail, detail,
remote_sr_pubkey.value, remote_sr_pubkey.value(),
routed_operation.sequencing(), routed_operation.sequencing(),
body, body,
) )
@ -166,7 +135,7 @@ impl RPCProcessor {
pr_pubkey: PublicKey, pr_pubkey: PublicKey,
) -> RPCNetworkResult<()> { ) -> RPCNetworkResult<()> {
// Get sender id of the peer with the crypto kind of the route // Get sender id of the peer with the crypto kind of the route
let Some(sender_id) = detail.sender_noderef.node_ids().get(pr_pubkey.kind) else { let Some(sender_id) = detail.sender_noderef.node_ids().get(pr_pubkey.kind()) else {
return Ok(NetworkResult::invalid_message( return Ok(NetworkResult::invalid_message(
"route node doesnt have a required crypto kind for routed operation", "route node doesnt have a required crypto kind for routed operation",
)); ));
@ -176,16 +145,16 @@ impl RPCProcessor {
// Ensure the route is validated, and construct a return safetyspec that matches the inbound preferences // Ensure the route is validated, and construct a return safetyspec that matches the inbound preferences
let routing_table = self.routing_table(); let routing_table = self.routing_table();
let rss = routing_table.route_spec_store(); let rss = routing_table.route_spec_store();
let preferred_route = rss.get_route_id_for_key(&pr_pubkey.value); let preferred_route = rss.get_route_id_for_key(pr_pubkey.ref_value());
let Some((secret_key, safety_spec)) = rss.with_signature_validated_route( let Some((secret_key, safety_spec)) = rss.with_signature_validated_route(
&pr_pubkey, &pr_pubkey,
routed_operation.signatures(), routed_operation.signatures(),
routed_operation.data(), routed_operation.data(),
sender_id.value, &sender_id,
|rssd, rsd| { |rssd, rsd| {
( (
rsd.secret_key, rsd.secret_key.clone(),
SafetySpec { SafetySpec {
preferred_route, preferred_route,
hop_count: rssd.hop_count(), hop_count: rssd.hop_count(),
@ -202,7 +171,7 @@ impl RPCProcessor {
// Now that things are valid, decrypt the routed operation with DEC(nonce, DH(the SR's public key, the PR's (or node's) secret) // Now that things are valid, decrypt the routed operation with DEC(nonce, DH(the SR's public key, the PR's (or node's) secret)
// xxx: punish nodes that send messages that fail to decrypt eventually. How to do this for private routes? // xxx: punish nodes that send messages that fail to decrypt eventually. How to do this for private routes?
let Ok(dh_secret) = vcrypto.cached_dh(&remote_sr_pubkey.value, &secret_key) else { let Ok(dh_secret) = vcrypto.cached_dh(remote_sr_pubkey.ref_value(), &secret_key) else {
return Ok(NetworkResult::invalid_message( return Ok(NetworkResult::invalid_message(
"dh failed for remote safety route for private routed operation", "dh failed for remote safety route for private routed operation",
)); ));
@ -221,8 +190,8 @@ impl RPCProcessor {
// Pass message to RPC system // Pass message to RPC system
self.enqueue_private_routed_message( self.enqueue_private_routed_message(
detail, detail,
remote_sr_pubkey.value, remote_sr_pubkey.value(),
pr_pubkey.value, pr_pubkey.value(),
safety_spec, safety_spec,
body, body,
) )
@ -242,7 +211,11 @@ impl RPCProcessor {
) -> RPCNetworkResult<()> { ) -> RPCNetworkResult<()> {
// If the private route public key is our node id, then this was sent via safety route to our node directly // If the private route public key is our node id, then this was sent via safety route to our node directly
// so there will be no signatures to validate // so there will be no signatures to validate
if self.routing_table().node_ids().contains(&pr_pubkey.into()) { if self
.routing_table()
.node_ids()
.contains(&pr_pubkey.clone().into())
{
// The private route was a stub // The private route was a stub
self.process_safety_routed_operation( self.process_safety_routed_operation(
detail, detail,
@ -291,13 +264,6 @@ impl RPCProcessor {
&mut routed_operation &mut routed_operation
)?); )?);
// Ensure hop count > 0
if private_route.hop_count == 0 {
return Ok(NetworkResult::invalid_message(
"route should not be at the end",
));
}
// Make next PrivateRoute and pass it on // Make next PrivateRoute and pass it on
return self return self
.process_route_private_route_hop( .process_route_private_route_hop(
@ -306,7 +272,6 @@ impl RPCProcessor {
sr_pubkey, sr_pubkey,
PrivateRoute { PrivateRoute {
public_key: private_route.public_key, public_key: private_route.public_key,
hop_count: private_route.hop_count - 1,
hops: route_hop hops: route_hop
.next_hop .next_hop
.map(PrivateRouteHops::Data) .map(PrivateRouteHops::Data)
@ -336,7 +301,7 @@ impl RPCProcessor {
) -> RPCNetworkResult<RouteHop> { ) -> RPCNetworkResult<RouteHop> {
// Get crypto kind // Get crypto kind
let crypto = self.crypto(); let crypto = self.crypto();
let crypto_kind = pr_pubkey.kind; let crypto_kind = pr_pubkey.kind();
let Some(vcrypto) = crypto.get(crypto_kind) else { let Some(vcrypto) = crypto.get(crypto_kind) else {
return Ok(NetworkResult::invalid_message( return Ok(NetworkResult::invalid_message(
"private route hop data crypto is not supported", "private route hop data crypto is not supported",
@ -346,7 +311,7 @@ impl RPCProcessor {
// Decrypt the blob with DEC(nonce, DH(the PR's public key, this hop's secret) // Decrypt the blob with DEC(nonce, DH(the PR's public key, this hop's secret)
let node_id_secret = self.routing_table().node_id_secret_key(crypto_kind); let node_id_secret = self.routing_table().node_id_secret_key(crypto_kind);
let dh_secret = vcrypto let dh_secret = vcrypto
.cached_dh(&pr_pubkey.value, &node_id_secret) .cached_dh(pr_pubkey.ref_value(), &node_id_secret)
.map_err(RPCError::protocol)?; .map_err(RPCError::protocol)?;
let dec_blob_data = match vcrypto.decrypt_aead( let dec_blob_data = match vcrypto.decrypt_aead(
&route_hop_data.blob, &route_hop_data.blob,
@ -381,13 +346,16 @@ impl RPCProcessor {
if route_hop.next_hop.is_some() { if route_hop.next_hop.is_some() {
let node_id = self.routing_table().node_id(crypto_kind); let node_id = self.routing_table().node_id(crypto_kind);
let node_id_secret = self.routing_table().node_id_secret_key(crypto_kind); let node_id_secret = self.routing_table().node_id_secret_key(crypto_kind);
let sig = vcrypto let sig = Signature::new(
.sign( vcrypto.kind(),
&node_id.value.into(), vcrypto
&node_id_secret, .sign(
routed_operation.data(), &node_id.value().into(),
) &node_id_secret,
.map_err(RPCError::internal)?; routed_operation.data(),
)
.map_err(RPCError::internal)?,
);
routed_operation.add_signature(sig); routed_operation.add_signature(sig);
} }
@ -452,7 +420,7 @@ impl RPCProcessor {
// Decrypt the blob with DEC(nonce, DH(the SR's public key, this hop's secret) // Decrypt the blob with DEC(nonce, DH(the SR's public key, this hop's secret)
let node_id_secret = self.routing_table().node_id_secret_key(crypto_kind); let node_id_secret = self.routing_table().node_id_secret_key(crypto_kind);
let Ok(dh_secret) = let Ok(dh_secret) =
vcrypto.cached_dh(&safety_route.public_key.value, &node_id_secret) vcrypto.cached_dh(safety_route.public_key.ref_value(), &node_id_secret)
else { else {
return Ok(NetworkResult::invalid_message( return Ok(NetworkResult::invalid_message(
"dh failed for safety route hop", "dh failed for safety route hop",
@ -583,13 +551,6 @@ impl RPCProcessor {
&mut routed_operation &mut routed_operation
)?); )?);
// Ensure hop count > 0
if private_route.hop_count == 0 {
return Ok(NetworkResult::invalid_message(
"route should not be at the end",
));
}
// Make next PrivateRoute and pass it on // Make next PrivateRoute and pass it on
network_result_try!( network_result_try!(
self.process_route_private_route_hop( self.process_route_private_route_hop(
@ -598,7 +559,6 @@ impl RPCProcessor {
safety_route.public_key, safety_route.public_key,
PrivateRoute { PrivateRoute {
public_key: private_route.public_key, public_key: private_route.public_key,
hop_count: private_route.hop_count - 1,
hops: route_hop hops: route_hop
.next_hop .next_hop
.map(PrivateRouteHops::Data) .map(PrivateRouteHops::Data)
@ -609,18 +569,6 @@ impl RPCProcessor {
); );
} }
PrivateRouteHops::Empty => { PrivateRouteHops::Empty => {
// Ensure hop count == 0
if private_route.hop_count != 0 {
return Ok(NetworkResult::invalid_message(
"route should be at the end",
));
}
if safety_route.hop_count != 0 {
return Ok(NetworkResult::invalid_message(
"Safety hop count should be zero if switched to private route",
));
}
// No hops left, time to process the routed operation // No hops left, time to process the routed operation
network_result_try!(self.process_routed_operation( network_result_try!(self.process_routed_operation(
detail, detail,

View file

@ -30,7 +30,7 @@ impl RPCProcessor {
pub async fn rpc_call_set_value( pub async fn rpc_call_set_value(
&self, &self,
dest: Destination, dest: Destination,
key: RecordKey, record_key: RecordKey,
subkey: ValueSubkey, subkey: ValueSubkey,
value: SignedValueData, value: SignedValueData,
descriptor: SignedValueDescriptor, descriptor: SignedValueDescriptor,
@ -52,16 +52,16 @@ impl RPCProcessor {
// Get the target node id // Get the target node id
let crypto = self.crypto(); let crypto = self.crypto();
let Some(vcrypto) = crypto.get(key.kind) else { let Some(vcrypto) = crypto.get(record_key.kind()) else {
return Err(RPCError::internal("unsupported cryptosystem")); return Err(RPCError::internal("unsupported cryptosystem"));
}; };
let Some(target_node_id) = target_node_ids.get(key.kind) else { let Some(target_node_id) = target_node_ids.get(record_key.kind()) else {
return Err(RPCError::internal("No node id for crypto kind")); return Err(RPCError::internal("No node id for crypto kind"));
}; };
let debug_string = format!( let debug_string = format!(
"OUT ==> SetValueQ({} #{} len={} seq={} writer={}{}) => {}", "OUT ==> SetValueQ({} #{} len={} seq={} writer={}{}) => {}",
key, record_key,
subkey, subkey,
value.value_data().data().len(), value.value_data().data().len(),
value.value_data().seq(), value.value_data().seq(),
@ -72,7 +72,7 @@ impl RPCProcessor {
// Send the setvalue question // Send the setvalue question
let set_value_q = RPCOperationSetValueQ::new( let set_value_q = RPCOperationSetValueQ::new(
key, record_key.clone(),
subkey, subkey,
value, value,
if send_descriptor { if send_descriptor {
@ -101,7 +101,7 @@ impl RPCProcessor {
); );
// Keep the reply private route that was used to return with the answer // Keep the reply private route that was used to return with the answer
let reply_private_route = waitable_reply.context.reply_private_route; let reply_private_route = waitable_reply.context.reply_private_route.clone();
// Wait for reply // Wait for reply
let (msg, latency) = match self.wait_for_reply(waitable_reply, debug_string).await? { let (msg, latency) = match self.wait_for_reply(waitable_reply, debug_string).await? {
@ -136,7 +136,7 @@ impl RPCProcessor {
let debug_string_answer = format!( let debug_string_answer = format!(
"OUT <== SetValueA({} #{}{}{} peers={}) <= {}", "OUT <== SetValueA({} #{}{}{} peers={}) <= {}",
key, record_key,
subkey, subkey,
if set { " +set" } else { "" }, if set { " +set" } else { "" },
debug_string_value, debug_string_value,
@ -148,7 +148,7 @@ impl RPCProcessor {
let peer_ids: Vec<String> = peers let peer_ids: Vec<String> = peers
.iter() .iter()
.filter_map(|p| p.node_ids().get(key.kind).map(|k| k.to_string())) .filter_map(|p| p.node_ids().get(record_key.kind()).map(|k| k.to_string()))
.collect(); .collect();
veilid_log!(self debug target: "dht", "Peers: {:#?}", peer_ids); veilid_log!(self debug target: "dht", "Peers: {:#?}", peer_ids);
} }
@ -156,8 +156,8 @@ impl RPCProcessor {
// Validate peers returned are, in fact, closer to the key than the node we sent this to // Validate peers returned are, in fact, closer to the key than the node we sent this to
let valid = match RoutingTable::verify_peers_closer( let valid = match RoutingTable::verify_peers_closer(
&vcrypto, &vcrypto,
target_node_id.into(), &target_node_id.clone().into(),
key.into(), &record_key.clone().into(),
&peers, &peers,
) { ) {
Ok(v) => v, Ok(v) => v,
@ -231,20 +231,23 @@ impl RPCProcessor {
}; };
// Destructure // Destructure
let (key, subkey, value, descriptor) = set_value_q.destructure(); let (record_key, subkey, value, descriptor) = set_value_q.destructure();
// Get target for ValueChanged notifications // Get target for ValueChanged notifications
let dest = network_result_try!(self.get_respond_to_destination(&msg)); let dest = network_result_try!(self.get_respond_to_destination(&msg));
let target = dest.get_target(&routing_table)?; let target = dest.get_target(&routing_table)?;
// Get the nodes that we know about that are closer to the the key than our own node // Get the nodes that we know about that are closer to the the key than our own node
let closer_to_key_peers = network_result_try!( let closer_to_key_peers = network_result_try!(routing_table
routing_table.find_preferred_peers_closer_to_key(routing_domain, key, vec![CAP_DHT]) .find_preferred_peers_closer_to_key(
); routing_domain,
&record_key.clone().into(),
vec![CAP_DHT]
));
let debug_string = format!( let debug_string = format!(
"IN <=== SetValueQ({} #{} len={} seq={} writer={}{}) <== {}", "IN <=== SetValueQ({} #{} len={} seq={} writer={}{}) <== {}",
key, record_key,
subkey, subkey,
value.value_data().data().len(), value.value_data().data().len(),
value.value_data().seq(), value.value_data().seq(),
@ -270,7 +273,7 @@ impl RPCProcessor {
let storage_manager = self.storage_manager(); let storage_manager = self.storage_manager();
let new_value = network_result_try!(storage_manager let new_value = network_result_try!(storage_manager
.inbound_set_value( .inbound_set_value(
key, record_key.clone(),
subkey, subkey,
Arc::new(value), Arc::new(value),
descriptor.map(Arc::new), descriptor.map(Arc::new),
@ -297,7 +300,7 @@ impl RPCProcessor {
let debug_string_answer = format!( let debug_string_answer = format!(
"IN ===> SetValueA({} #{}{}{} peers={}) ==> {}", "IN ===> SetValueA({} #{}{}{} peers={}) ==> {}",
key, record_key,
subkey, subkey,
if set { " +set" } else { "" }, if set { " +set" } else { "" },
debug_string_value, debug_string_value,

View file

@ -78,7 +78,7 @@ impl RPCProcessor {
let send_data_method = waitable_reply.context.send_data_result.clone(); let send_data_method = waitable_reply.context.send_data_result.clone();
// Keep the reply private route that was used to return with the answer // Keep the reply private route that was used to return with the answer
let reply_private_route = waitable_reply.context.reply_private_route; let reply_private_route = waitable_reply.context.reply_private_route.clone();
// Wait for reply // Wait for reply
let (msg, latency) = match self.wait_for_reply(waitable_reply, debug_string).await? { let (msg, latency) = match self.wait_for_reply(waitable_reply, debug_string).await? {

View file

@ -131,7 +131,7 @@ impl RPCProcessor {
// We filter on the -outgoing- protocol capability status not the node's dial info // We filter on the -outgoing- protocol capability status not the node's dial info
// Use the address type though, to ensure we reach an ipv6 capable node if this is // Use the address type though, to ensure we reach an ipv6 capable node if this is
// an ipv6 address // an ipv6 address
let sender_node_id = detail.envelope.get_sender_typed_id(); let sender_node_id = detail.envelope.get_sender_id();
let routing_domain = detail.routing_domain; let routing_domain = detail.routing_domain;
let node_count = self let node_count = self
.config() .config()

View file

@ -56,7 +56,7 @@ impl RPCProcessor {
// Try it as the node if, and the storage manager will reject the // Try it as the node if, and the storage manager will reject the
// value change if it doesn't match the active watch's node id // value change if it doesn't match the active watch's node id
let inbound_node_id = match &msg.header.detail { let inbound_node_id = match &msg.header.detail {
RPCMessageHeaderDetail::Direct(d) => d.envelope.get_sender_typed_id(), RPCMessageHeaderDetail::Direct(d) => d.envelope.get_sender_id(),
RPCMessageHeaderDetail::SafetyRouted(_) => { RPCMessageHeaderDetail::SafetyRouted(_) => {
return Ok(NetworkResult::invalid_message( return Ok(NetworkResult::invalid_message(
"not processing value change over safety route", "not processing value change over safety route",
@ -64,7 +64,7 @@ impl RPCProcessor {
} }
RPCMessageHeaderDetail::PrivateRouted(p) => NodeId::new( RPCMessageHeaderDetail::PrivateRouted(p) => NodeId::new(
p.direct.envelope.get_crypto_kind(), p.direct.envelope.get_crypto_kind(),
p.remote_safety_route.into(), p.remote_safety_route.clone().into(),
), ),
}; };

View file

@ -27,11 +27,11 @@ impl RPCProcessor {
pub async fn rpc_call_watch_value( pub async fn rpc_call_watch_value(
&self, &self,
dest: Destination, dest: Destination,
key: RecordKey, record_key: RecordKey,
subkeys: ValueSubkeyRangeSet, subkeys: ValueSubkeyRangeSet,
expiration: Timestamp, expiration: Timestamp,
count: u32, count: u32,
watcher: BareKeyPair, watcher: KeyPair,
watch_id: Option<u64>, watch_id: Option<u64>,
) -> RPCNetworkResult<Answer<WatchValueAnswer>> { ) -> RPCNetworkResult<Answer<WatchValueAnswer>> {
let _guard = self let _guard = self
@ -50,10 +50,10 @@ impl RPCProcessor {
// Get the target node id // Get the target node id
let crypto = self.crypto(); let crypto = self.crypto();
let Some(vcrypto) = crypto.get(key.kind) else { let Some(vcrypto) = crypto.get(record_key.kind()) else {
return Err(RPCError::internal("unsupported cryptosystem")); return Err(RPCError::internal("unsupported cryptosystem"));
}; };
let Some(target_node_id) = target_node_ids.get(key.kind) else { let Some(target_node_id) = target_node_ids.get(record_key.kind()) else {
return Err(RPCError::internal("No node id for crypto kind")); return Err(RPCError::internal("No node id for crypto kind"));
}; };
@ -64,17 +64,17 @@ impl RPCProcessor {
} else { } else {
"".to_owned() "".to_owned()
}, },
key, record_key,
subkeys, subkeys,
expiration, expiration,
count, count,
dest, dest,
watcher.key watcher
); );
// Send the watchvalue question // Send the watchvalue question
let watch_value_q = RPCOperationWatchValueQ::new( let watch_value_q = RPCOperationWatchValueQ::new(
key, record_key.clone(),
subkeys.clone(), subkeys.clone(),
expiration.as_u64(), expiration.as_u64(),
count, count,
@ -93,7 +93,7 @@ impl RPCProcessor {
network_result_try!(self.question(dest.clone(), question, None).await?); network_result_try!(self.question(dest.clone(), question, None).await?);
// Keep the reply private route that was used to return with the answer // Keep the reply private route that was used to return with the answer
let reply_private_route = waitable_reply.context.reply_private_route; let reply_private_route = waitable_reply.context.reply_private_route.clone();
// Wait for reply // Wait for reply
let (msg, latency) = match self.wait_for_reply(waitable_reply, debug_string).await? { let (msg, latency) = match self.wait_for_reply(waitable_reply, debug_string).await? {
@ -117,7 +117,7 @@ impl RPCProcessor {
"OUT <== WatchValueA({}id={} {} #{:?}@{} peers={}) <= {}", "OUT <== WatchValueA({}id={} {} #{:?}@{} peers={}) <= {}",
if accepted { "+accept " } else { "" }, if accepted { "+accept " } else { "" },
watch_id, watch_id,
key, record_key,
subkeys, subkeys,
expiration, expiration,
peers.len(), peers.len(),
@ -128,7 +128,7 @@ impl RPCProcessor {
let peer_ids: Vec<String> = peers let peer_ids: Vec<String> = peers
.iter() .iter()
.filter_map(|p| p.node_ids().get(key.kind).map(|k| k.to_string())) .filter_map(|p| p.node_ids().get(record_key.kind()).map(|k| k.to_string()))
.collect(); .collect();
veilid_log!(self debug target: "dht", "Peers: {:#?}", peer_ids); veilid_log!(self debug target: "dht", "Peers: {:#?}", peer_ids);
} }
@ -155,8 +155,8 @@ impl RPCProcessor {
// Validate peers returned are, in fact, closer to the key than the node we sent this to // Validate peers returned are, in fact, closer to the key than the node we sent this to
let valid = match RoutingTable::verify_peers_closer( let valid = match RoutingTable::verify_peers_closer(
&vcrypto, &vcrypto,
target_node_id.into(), &target_node_id.clone().into(),
key.into(), &record_key.clone().into(),
&peers, &peers,
) { ) {
Ok(v) => v, Ok(v) => v,
@ -233,9 +233,16 @@ impl RPCProcessor {
}; };
// Destructure // Destructure
let (key, subkeys, expiration, count, watch_id, watcher, _signature) = let (record_key, subkeys, expiration, count, watch_id, watcher, _signature) =
watch_value_q.destructure(); watch_value_q.destructure();
// Extract member id for watcher
let Ok(watcher_member_id) = self.storage_manager().generate_member_id(&watcher) else {
return Ok(NetworkResult::invalid_message(
"could not generate member id for watcher public key",
));
};
// Get target for ValueChanged notifications // Get target for ValueChanged notifications
let dest = network_result_try!(self.get_respond_to_destination(&msg)); let dest = network_result_try!(self.get_respond_to_destination(&msg));
let target = dest.get_target(&routing_table)?; let target = dest.get_target(&routing_table)?;
@ -248,12 +255,12 @@ impl RPCProcessor {
} else { } else {
"".to_owned() "".to_owned()
}, },
key, record_key,
subkeys, subkeys,
expiration, expiration,
count, count,
msg.header.direct_sender_node_id(), msg.header.direct_sender_node_id(),
watcher watcher_member_id
); );
veilid_log!(self debug target: "dht", "{}", debug_string); veilid_log!(self debug target: "dht", "{}", debug_string);
@ -261,7 +268,11 @@ impl RPCProcessor {
// Get the nodes that we know about that are closer to the the key than our own node // Get the nodes that we know about that are closer to the the key than our own node
let closer_to_key_peers = network_result_try!(routing_table let closer_to_key_peers = network_result_try!(routing_table
.find_preferred_peers_closer_to_key(routing_domain, key, vec![CAP_DHT, CAP_DHT_WATCH])); .find_preferred_peers_closer_to_key(
routing_domain,
&record_key.clone().into(),
vec![CAP_DHT, CAP_DHT_WATCH]
));
// See if we would have accepted this as a set, same set_value_count for watches // See if we would have accepted this as a set, same set_value_count for watches
let set_value_count = self let set_value_count = self
@ -279,14 +290,14 @@ impl RPCProcessor {
subkeys: subkeys.clone(), subkeys: subkeys.clone(),
expiration: Timestamp::new(expiration), expiration: Timestamp::new(expiration),
count, count,
watcher, watcher_member_id,
target, target,
}; };
// See if we have this record ourselves, if so, accept the watch // See if we have this record ourselves, if so, accept the watch
let storage_manager = self.storage_manager(); let storage_manager = self.storage_manager();
let watch_result = network_result_try!(storage_manager let watch_result = network_result_try!(storage_manager
.inbound_watch_value(key, params, watch_id) .inbound_watch_value(record_key.clone(), params, watch_id)
.await .await
.map_err(RPCError::internal)?); .map_err(RPCError::internal)?);
@ -308,7 +319,7 @@ impl RPCProcessor {
"IN ===> WatchValueA({}id={} {} #{} expiration={} peers={}) ==> {}", "IN ===> WatchValueA({}id={} {} #{} expiration={} peers={}) ==> {}",
if ret_accepted { "+accept " } else { "" }, if ret_accepted { "+accept " } else { "" },
ret_watch_id, ret_watch_id,
key, record_key,
subkeys, subkeys,
ret_expiration, ret_expiration,
closer_to_key_peers.len(), closer_to_key_peers.len(),

View file

@ -34,7 +34,10 @@ impl StorageManager {
record_key: RecordKey, record_key: RecordKey,
subkey: ValueSubkey, subkey: ValueSubkey,
) -> Option<ActiveSubkeyWriteGuard> { ) -> Option<ActiveSubkeyWriteGuard> {
let asw = inner.active_subkey_writes.entry(record_key).or_default(); let asw = inner
.active_subkey_writes
.entry(record_key.clone())
.or_default();
if asw.contains(subkey) { if asw.contains(subkey) {
veilid_log!(self debug "already writing to this subkey: {}:{}", record_key, subkey); veilid_log!(self debug "already writing to this subkey: {}:{}", record_key, subkey);
None None

View file

@ -41,7 +41,7 @@ impl StorageManager {
let mut out = "[\n".to_owned(); let mut out = "[\n".to_owned();
for (k, v) in &inner.offline_subkey_writes { for (k, v) in &inner.offline_subkey_writes {
let record_info = local_record_store let record_info = local_record_store
.peek_record(*k, |r| format!("{} nodes", r.detail().nodes.len())) .peek_record(k, |r| format!("{} nodes", r.detail().nodes.len()))
.unwrap_or("Not found".to_owned()); .unwrap_or("Not found".to_owned());
out += &format!(" {}:{:?}, {}\n", k, v, record_info); out += &format!(" {}:{:?}, {}\n", k, v, record_info);
@ -108,7 +108,7 @@ impl StorageManager {
let Some(local_record_store) = &inner.local_record_store else { let Some(local_record_store) = &inner.local_record_store else {
return "not initialized".to_owned(); return "not initialized".to_owned();
}; };
let local_debug = local_record_store.debug_record_info(record_key); let local_debug = local_record_store.debug_record_info(record_key.clone());
let opened_debug = if let Some(o) = inner.opened_records.get(&record_key) { let opened_debug = if let Some(o) = inner.opened_records.get(&record_key) {
format!("Opened Record: {:#?}\n", o) format!("Opened Record: {:#?}\n", o)

View file

@ -47,7 +47,7 @@ impl StorageManager {
// Get the nodes we know are caching this value to seed the fanout // Get the nodes we know are caching this value to seed the fanout
let init_fanout_queue = { let init_fanout_queue = {
self.get_value_nodes(record_key) self.get_value_nodes(record_key.clone())
.await? .await?
.unwrap_or_default() .unwrap_or_default()
.into_iter() .into_iter()
@ -81,11 +81,15 @@ impl StorageManager {
let call_routine = { let call_routine = {
let context = context.clone(); let context = context.clone();
let registry = self.registry(); let registry = self.registry();
let record_key = record_key.clone();
let safety_selection = safety_selection.clone();
Arc::new( Arc::new(
move |next_node: NodeRef| -> PinBoxFutureStatic<FanoutCallResult> { move |next_node: NodeRef| -> PinBoxFutureStatic<FanoutCallResult> {
let context = context.clone(); let context = context.clone();
let registry = registry.clone(); let registry = registry.clone();
let record_key = record_key.clone();
let last_descriptor = last_get_result.opt_descriptor.clone(); let last_descriptor = last_get_result.opt_descriptor.clone();
let safety_selection = safety_selection.clone();
Box::pin(async move { Box::pin(async move {
let rpc_processor = registry.rpc_processor(); let rpc_processor = registry.rpc_processor();
let gva = match let gva = match
@ -93,7 +97,7 @@ impl StorageManager {
.rpc_call_get_value( .rpc_call_get_value(
Destination::direct(next_node.routing_domain_filtered(routing_domain)) Destination::direct(next_node.routing_domain_filtered(routing_domain))
.with_safety(safety_selection), .with_safety(safety_selection),
record_key, record_key.clone(),
subkey, subkey,
last_descriptor.map(|x| (*x).clone()), last_descriptor.map(|x| (*x).clone()),
) )
@ -145,8 +149,8 @@ impl StorageManager {
}; };
// Validate with schema // Validate with schema
if schema.check_subkey_value_data( if registry.storage_manager().check_subkey_value_data(schema,
descriptor.owner(), descriptor.ref_owner(),
subkey, subkey,
value.value_data(), value.value_data(),
).is_err() { ).is_err() {
@ -255,7 +259,7 @@ impl StorageManager {
let routing_table = registry.routing_table(); let routing_table = registry.routing_table();
let fanout_call = FanoutCall::new( let fanout_call = FanoutCall::new(
&routing_table, &routing_table,
record_key.into(), record_key.clone().into(),
key_count, key_count,
fanout, fanout,
consensus_count, consensus_count,
@ -316,6 +320,7 @@ impl StorageManager {
Box::new( Box::new(
move |result: VeilidAPIResult<get_value::OutboundGetValueResult>| -> PinBoxFutureStatic<bool> { move |result: VeilidAPIResult<get_value::OutboundGetValueResult>| -> PinBoxFutureStatic<bool> {
let registry=registry.clone(); let registry=registry.clone();
let key = key.clone();
Box::pin(async move { Box::pin(async move {
let this = registry.storage_manager(); let this = registry.storage_manager();
let result = match result { let result = match result {
@ -326,7 +331,7 @@ impl StorageManager {
} }
}; };
let is_incomplete = result.fanout_result.kind.is_incomplete(); let is_incomplete = result.fanout_result.kind.is_incomplete();
let value_data = match this.process_outbound_get_value_result(key, subkey, Some(last_seq), result).await { let value_data = match this.process_outbound_get_value_result(key.clone(), subkey, Some(last_seq), result).await {
Ok(Some(v)) => v, Ok(Some(v)) => v,
Ok(None) => { Ok(None) => {
return is_incomplete; return is_incomplete;
@ -344,7 +349,7 @@ impl StorageManager {
// if the sequence number changed since our first partial update // if the sequence number changed since our first partial update
// Send with a max count as this is not attached to any watch // Send with a max count as this is not attached to any watch
if last_seq != value_data.seq() { if last_seq != value_data.seq() {
this.update_callback_value_change(key,ValueSubkeyRangeSet::single(subkey), u32::MAX, Some(value_data)); this.update_callback_value_change(key.clone(),ValueSubkeyRangeSet::single(subkey), u32::MAX, Some(value_data));
} }
// Return done // Return done
@ -371,7 +376,7 @@ impl StorageManager {
// Get cryptosystem // Get cryptosystem
let crypto = self.crypto(); let crypto = self.crypto();
let Some(vcrypto) = crypto.get(record_key.kind) else { let Some(vcrypto) = crypto.get(record_key.kind()) else {
apibail_generic!("unsupported cryptosystem"); apibail_generic!("unsupported cryptosystem");
}; };
@ -381,7 +386,7 @@ impl StorageManager {
Self::process_fanout_results_inner( Self::process_fanout_results_inner(
&mut inner, &mut inner,
&vcrypto, &vcrypto,
record_key, record_key.clone(),
core::iter::once((ValueSubkeyRangeSet::single(subkey), result.fanout_result)), core::iter::once((ValueSubkeyRangeSet::single(subkey), result.fanout_result)),
false, false,
self.config() self.config()
@ -416,7 +421,7 @@ impl StorageManager {
let (_is_local, last_get_result) = { let (_is_local, last_get_result) = {
// See if the subkey we are getting has a last known local value // See if the subkey we are getting has a last known local value
let mut last_get_result = self let mut last_get_result = self
.handle_get_local_value_inner(&mut inner, key, subkey, true) .handle_get_local_value_inner(&mut inner, key.clone(), subkey, true)
.await?; .await?;
// If this is local, it must have a descriptor already // If this is local, it must have a descriptor already
if last_get_result.opt_descriptor.is_some() { if last_get_result.opt_descriptor.is_some() {

View file

@ -88,7 +88,7 @@ impl StorageManager {
// Get the nodes we know are caching this value to seed the fanout // Get the nodes we know are caching this value to seed the fanout
let init_fanout_queue = { let init_fanout_queue = {
self.get_value_nodes(record_key) self.get_value_nodes(record_key.clone())
.await? .await?
.unwrap_or_default() .unwrap_or_default()
.into_iter() .into_iter()
@ -125,12 +125,16 @@ impl StorageManager {
let call_routine = { let call_routine = {
let context = context.clone(); let context = context.clone();
let registry = self.registry(); let registry = self.registry();
let record_key = record_key.clone();
let safety_selection = safety_selection.clone();
Arc::new( Arc::new(
move |next_node: NodeRef| -> PinBoxFutureStatic<FanoutCallResult> { move |next_node: NodeRef| -> PinBoxFutureStatic<FanoutCallResult> {
let context = context.clone(); let context = context.clone();
let registry = registry.clone(); let registry = registry.clone();
let opt_descriptor = local_inspect_result.opt_descriptor(); let opt_descriptor = local_inspect_result.opt_descriptor();
let subkeys = subkeys.clone(); let subkeys = subkeys.clone();
let record_key = record_key.clone();
let safety_selection = safety_selection.clone();
Box::pin(async move { Box::pin(async move {
let rpc_processor = registry.rpc_processor(); let rpc_processor = registry.rpc_processor();
@ -138,7 +142,7 @@ impl StorageManager {
rpc_processor rpc_processor
.rpc_call_inspect_value( .rpc_call_inspect_value(
Destination::direct(next_node.routing_domain_filtered(routing_domain)).with_safety(safety_selection), Destination::direct(next_node.routing_domain_filtered(routing_domain)).with_safety(safety_selection),
record_key, record_key.clone(),
subkeys.clone(), subkeys.clone(),
opt_descriptor.map(|x| (*x).clone()), opt_descriptor.map(|x| (*x).clone()),
) )
@ -368,7 +372,12 @@ impl StorageManager {
let (_is_local, inspect_result) = { let (_is_local, inspect_result) = {
// See if the subkey we are getting has a last known local value // See if the subkey we are getting has a last known local value
let mut local_inspect_result = self let mut local_inspect_result = self
.handle_inspect_local_value_inner(&mut inner, record_key, subkeys.clone(), true) .handle_inspect_local_value_inner(
&mut inner,
record_key.clone(),
subkeys.clone(),
true,
)
.await?; .await?;
// If this is local, it must have a descriptor already // If this is local, it must have a descriptor already
if local_inspect_result.opt_descriptor().is_some() { if local_inspect_result.opt_descriptor().is_some() {

View file

@ -6,6 +6,7 @@ mod offline_subkey_writes;
mod outbound_watch_manager; mod outbound_watch_manager;
mod record_store; mod record_store;
mod rehydrate; mod rehydrate;
mod schema;
mod set_value; mod set_value;
mod tasks; mod tasks;
mod types; mod types;
@ -28,6 +29,8 @@ pub use types::*;
impl_veilid_log_facility!("stor"); impl_veilid_log_facility!("stor");
/// Fixed length of MemberId (DHT Schema member id) in bytes
pub const MEMBER_ID_LENGTH: usize = 32;
/// The maximum size of a single subkey /// The maximum size of a single subkey
pub(crate) const MAX_SUBKEY_SIZE: usize = ValueData::MAX_LEN; pub(crate) const MAX_SUBKEY_SIZE: usize = ValueData::MAX_LEN;
/// The maximum total size of all subkeys of a record /// The maximum total size of all subkeys of a record
@ -488,7 +491,7 @@ impl StorageManager {
Destination::direct( Destination::direct(
node_ref.routing_domain_filtered(RoutingDomain::PublicInternet), node_ref.routing_domain_filtered(RoutingDomain::PublicInternet),
) )
.with_safety(current.params().safety_selection), .with_safety(current.params().safety_selection.clone()),
) )
} }
} }
@ -501,13 +504,12 @@ impl StorageManager {
#[instrument(level = "trace", target = "stor", skip_all)] #[instrument(level = "trace", target = "stor", skip_all)]
pub fn get_record_key( pub fn get_record_key(
&self, &self,
kind: CryptoKind,
schema: DHTSchema, schema: DHTSchema,
owner_key: &BarePublicKey, owner_key: &PublicKey,
) -> VeilidAPIResult<RecordKey> { ) -> VeilidAPIResult<RecordKey> {
// Get cryptosystem // Get cryptosystem
let crypto = self.crypto(); let crypto = self.crypto();
let Some(vcrypto) = crypto.get(kind) else { let Some(vcrypto) = crypto.get(owner_key.kind()) else {
apibail_generic!("unsupported cryptosystem"); apibail_generic!("unsupported cryptosystem");
}; };
@ -515,7 +517,24 @@ impl StorageManager {
schema.validate()?; schema.validate()?;
let schema_data = schema.compile(); let schema_data = schema.compile();
Ok(Self::get_key(&vcrypto, owner_key, &schema_data)) Ok(Self::make_record_key(
&vcrypto,
owner_key.ref_value(),
&schema_data,
))
}
fn make_record_key(
vcrypto: &CryptoSystemGuard<'_>,
owner_key: &BarePublicKey,
schema_data: &[u8],
) -> RecordKey {
let mut hash_data = Vec::<u8>::with_capacity(owner_key.len() + 4 + schema_data.len());
hash_data.extend_from_slice(&vcrypto.kind().0);
hash_data.extend_from_slice(owner_key);
hash_data.extend_from_slice(schema_data);
let hash = vcrypto.generate_hash(&hash_data);
RecordKey::new(vcrypto.kind(), BareRecordKey::from(hash))
} }
/// Create a local record from scratch with a new owner key, open it, and return the opened descriptor /// Create a local record from scratch with a new owner key, open it, and return the opened descriptor
@ -523,7 +542,7 @@ impl StorageManager {
&self, &self,
kind: CryptoKind, kind: CryptoKind,
schema: DHTSchema, schema: DHTSchema,
owner: Option<BareKeyPair>, owner: Option<KeyPair>,
safety_selection: SafetySelection, safety_selection: SafetySelection,
) -> VeilidAPIResult<DHTRecordDescriptor> { ) -> VeilidAPIResult<DHTRecordDescriptor> {
let Ok(_guard) = self.startup_lock.enter() else { let Ok(_guard) = self.startup_lock.enter() else {
@ -538,7 +557,13 @@ impl StorageManager {
// Create a new owned local record from scratch // Create a new owned local record from scratch
let (key, owner) = self let (key, owner) = self
.create_new_owned_local_record_inner(&mut inner, kind, schema, owner, safety_selection) .create_new_owned_local_record_inner(
&mut inner,
kind,
schema,
owner,
safety_selection.clone(),
)
.await?; .await?;
// Now that the record is made we should always succeed to open the existing record // Now that the record is made we should always succeed to open the existing record
@ -553,7 +578,7 @@ impl StorageManager {
pub async fn open_record( pub async fn open_record(
&self, &self,
record_key: RecordKey, record_key: RecordKey,
writer: Option<BareKeyPair>, writer: Option<KeyPair>,
safety_selection: SafetySelection, safety_selection: SafetySelection,
) -> VeilidAPIResult<DHTRecordDescriptor> { ) -> VeilidAPIResult<DHTRecordDescriptor> {
let Ok(_guard) = self.startup_lock.enter() else { let Ok(_guard) = self.startup_lock.enter() else {
@ -564,7 +589,12 @@ impl StorageManager {
// See if we have a local record already or not // See if we have a local record already or not
if let Some(res) = self if let Some(res) = self
.open_existing_record_inner(&mut inner, record_key, writer, safety_selection) .open_existing_record_inner(
&mut inner,
record_key.clone(),
writer.clone(),
safety_selection.clone(),
)
.await? .await?
{ {
drop(inner); drop(inner);
@ -593,9 +623,9 @@ impl StorageManager {
// Use the safety selection we opened the record with // Use the safety selection we opened the record with
let result = self let result = self
.outbound_inspect_value( .outbound_inspect_value(
record_key, record_key.clone(),
ValueSubkeyRangeSet::single(0), ValueSubkeyRangeSet::single(0),
safety_selection, safety_selection.clone(),
InspectResult::default(), InspectResult::default(),
false, false,
) )
@ -613,7 +643,12 @@ impl StorageManager {
let mut inner = self.inner.lock().await; let mut inner = self.inner.lock().await;
if let Some(res) = self if let Some(res) = self
.open_existing_record_inner(&mut inner, record_key, writer, safety_selection) .open_existing_record_inner(
&mut inner,
record_key.clone(),
writer.clone(),
safety_selection.clone(),
)
.await? .await?
{ {
// Don't bother to rehydrate in this edge case // Don't bother to rehydrate in this edge case
@ -655,7 +690,7 @@ impl StorageManager {
// Attempt to close the record, returning the opened record if it wasn't already closed // Attempt to close the record, returning the opened record if it wasn't already closed
let mut inner = self.inner.lock().await; let mut inner = self.inner.lock().await;
let keys = inner.opened_records.keys().copied().collect::<Vec<_>>(); let keys = inner.opened_records.keys().cloned().collect::<Vec<_>>();
for key in keys { for key in keys {
Self::close_record_inner(&mut inner, key)?; Self::close_record_inner(&mut inner, key)?;
} }
@ -672,7 +707,7 @@ impl StorageManager {
// Ensure the record is closed // Ensure the record is closed
let mut inner = self.inner.lock().await; let mut inner = self.inner.lock().await;
Self::close_record_inner(&mut inner, record_key)?; Self::close_record_inner(&mut inner, record_key.clone())?;
// Get record from the local store // Get record from the local store
let Some(local_record_store) = inner.local_record_store.as_mut() else { let Some(local_record_store) = inner.local_record_store.as_mut() else {
@ -705,7 +740,7 @@ impl StorageManager {
// See if the requested subkey is our local record store // See if the requested subkey is our local record store
let last_get_result = self let last_get_result = self
.handle_get_local_value_inner(&mut inner, record_key, subkey, true) .handle_get_local_value_inner(&mut inner, record_key.clone(), subkey, true)
.await?; .await?;
// Return the existing value if we have one unless we are forcing a refresh // Return the existing value if we have one unless we are forcing a refresh
@ -734,7 +769,12 @@ impl StorageManager {
.as_ref() .as_ref()
.map(|v| v.value_data().seq()); .map(|v| v.value_data().seq());
let res_rx = self let res_rx = self
.outbound_get_value(record_key, subkey, safety_selection, last_get_result) .outbound_get_value(
record_key.clone(),
subkey,
safety_selection,
last_get_result,
)
.await?; .await?;
// Wait for the first result // Wait for the first result
@ -746,7 +786,7 @@ impl StorageManager {
// Process the returned result // Process the returned result
let out = self let out = self
.process_outbound_get_value_result(record_key, subkey, opt_last_seq, result) .process_outbound_get_value_result(record_key.clone(), subkey, opt_last_seq, result)
.await?; .await?;
if let Some(out) = &out { if let Some(out) = &out {
@ -754,7 +794,7 @@ impl StorageManager {
if partial { if partial {
self.process_deferred_outbound_get_value_result( self.process_deferred_outbound_get_value_result(
res_rx, res_rx,
record_key, record_key.clone(),
subkey, subkey,
out.seq(), out.seq(),
); );
@ -781,7 +821,7 @@ impl StorageManager {
// Get cryptosystem // Get cryptosystem
let crypto = self.crypto(); let crypto = self.crypto();
let Some(vcrypto) = crypto.get(record_key.kind) else { let Some(vcrypto) = crypto.get(record_key.kind()) else {
apibail_generic!("unsupported cryptosystem"); apibail_generic!("unsupported cryptosystem");
}; };
@ -796,7 +836,10 @@ impl StorageManager {
}; };
// Use the specified writer, or if not specified, the default writer when the record was opened // Use the specified writer, or if not specified, the default writer when the record was opened
let opt_writer = options.as_ref().and_then(|o| o.writer).or(opt_writer); let opt_writer = options
.as_ref()
.and_then(|o| o.writer.clone())
.or(opt_writer);
let allow_offline = options let allow_offline = options
.unwrap_or_default() .unwrap_or_default()
.allow_offline .allow_offline
@ -809,7 +852,7 @@ impl StorageManager {
// See if the subkey we are modifying has a last known local value // See if the subkey we are modifying has a last known local value
let last_get_result = self let last_get_result = self
.handle_get_local_value_inner(&mut inner, record_key, subkey, true) .handle_get_local_value_inner(&mut inner, record_key.clone(), subkey, true)
.await?; .await?;
// Get the descriptor and schema for the key // Get the descriptor and schema for the key
@ -821,20 +864,22 @@ impl StorageManager {
// Make new subkey data // Make new subkey data
let value_data = if let Some(last_signed_value_data) = last_get_result.opt_value { let value_data = if let Some(last_signed_value_data) = last_get_result.opt_value {
if last_signed_value_data.value_data().data() == data if last_signed_value_data.value_data().data() == data
&& last_signed_value_data.value_data().writer() == &writer.key && last_signed_value_data.value_data().ref_writer() == &writer.key()
{ {
// Data and writer is the same, nothing is changing, // Data and writer is the same, nothing is changing,
// just return that we set it, but no network activity needs to happen // just return that we set it, but no network activity needs to happen
return Ok(None); return Ok(None);
} }
let seq = last_signed_value_data.value_data().seq(); let seq = last_signed_value_data.value_data().seq();
ValueData::new_with_seq(seq + 1, data, writer.key)? ValueData::new_with_seq(seq + 1, data, writer.key())?
} else { } else {
ValueData::new(data, writer.key)? ValueData::new(data, writer.key())?
}; };
// Validate with schema // Validate with schema
if let Err(e) = schema.check_subkey_value_data(descriptor.owner(), subkey, &value_data) { if let Err(e) =
self.check_subkey_value_data(&schema, descriptor.ref_owner(), subkey, &value_data)
{
veilid_log!(self debug "schema validation error: {}", e); veilid_log!(self debug "schema validation error: {}", e);
// Validation failed, ignore this value // Validation failed, ignore this value
apibail_generic!(format!( apibail_generic!(format!(
@ -846,10 +891,10 @@ impl StorageManager {
// Sign the new value data with the writer // Sign the new value data with the writer
let signed_value_data = Arc::new(SignedValueData::make_signature( let signed_value_data = Arc::new(SignedValueData::make_signature(
value_data, value_data,
descriptor.owner(), &descriptor.owner(),
subkey, subkey,
&vcrypto, &vcrypto,
writer.secret, &writer.bare_secret(),
)?); )?);
// Check if we are offline // Check if we are offline
@ -872,7 +917,7 @@ impl StorageManager {
// Note that we are writing this subkey in the foreground // Note that we are writing this subkey in the foreground
// If it appears we are already doing this, then put it to the background/offline queue // If it appears we are already doing this, then put it to the background/offline queue
let opt_guard = self.mark_active_subkey_write_inner(&mut inner, record_key, subkey); let opt_guard = self.mark_active_subkey_write_inner(&mut inner, record_key.clone(), subkey);
if opt_guard.is_none() { if opt_guard.is_none() {
if allow_offline == AllowOffline(false) { if allow_offline == AllowOffline(false) {
apibail_try_again!("offline, try again later"); apibail_try_again!("offline, try again later");
@ -898,9 +943,9 @@ impl StorageManager {
// Use the safety selection we opened the record with // Use the safety selection we opened the record with
let res_rx = match self let res_rx = match self
.outbound_set_value( .outbound_set_value(
record_key, record_key.clone(),
subkey, subkey,
safety_selection, safety_selection.clone(),
signed_value_data.clone(), signed_value_data.clone(),
descriptor, descriptor,
) )
@ -917,7 +962,7 @@ impl StorageManager {
if allow_offline == AllowOffline(true) { if allow_offline == AllowOffline(true) {
self.add_offline_subkey_write_inner( self.add_offline_subkey_write_inner(
&mut inner, &mut inner,
record_key, record_key.clone(),
subkey, subkey,
safety_selection, safety_selection,
signed_value_data.clone(), signed_value_data.clone(),
@ -990,10 +1035,10 @@ impl StorageManager {
// Process the returned result // Process the returned result
let out = self let out = self
.process_outbound_set_value_result( .process_outbound_set_value_result(
record_key, record_key.clone(),
subkey, subkey,
signed_value_data.value_data().clone(), signed_value_data.value_data().clone(),
safety_selection, safety_selection.clone(),
result, result,
) )
.await?; .await?;
@ -1038,10 +1083,10 @@ impl StorageManager {
let opt_value_data = self let opt_value_data = self
.process_outbound_set_value_result( .process_outbound_set_value_result(
record_key, record_key.clone(),
subkey, subkey,
signed_value_data.value_data().clone(), signed_value_data.value_data().clone(),
safety_selection, safety_selection.clone(),
result, result,
) )
.await?; .await?;
@ -1080,14 +1125,14 @@ impl StorageManager {
expiration: Timestamp, expiration: Timestamp,
count: u32, count: u32,
) -> VeilidAPIResult<bool> { ) -> VeilidAPIResult<bool> {
let key = watch_lock.tag(); let record_key = watch_lock.tag();
// Obtain the inner state lock // Obtain the inner state lock
let mut inner = self.inner.lock().await; let mut inner = self.inner.lock().await;
// Get the safety selection and the writer we opened this record // Get the safety selection and the writer we opened this record
let (safety_selection, opt_watcher) = { let (safety_selection, opt_watcher) = {
let Some(opened_record) = inner.opened_records.get(&key) else { let Some(opened_record) = inner.opened_records.get(&record_key) else {
// Record must be opened already to change watch // Record must be opened already to change watch
apibail_generic!("record not open"); apibail_generic!("record not open");
}; };
@ -1106,7 +1151,7 @@ impl StorageManager {
// Get the schema so we can truncate the watch to the number of subkeys // Get the schema so we can truncate the watch to the number of subkeys
let schema = if let Some(lrs) = inner.local_record_store.as_ref() { let schema = if let Some(lrs) = inner.local_record_store.as_ref() {
let Some(schema) = lrs.peek_record(key, |r| r.schema()) else { let Some(schema) = lrs.peek_record(&record_key, |r| r.schema()) else {
apibail_generic!("no local record found"); apibail_generic!("no local record found");
}; };
schema schema
@ -1148,7 +1193,7 @@ impl StorageManager {
let active = desired_params.is_some(); let active = desired_params.is_some();
inner inner
.outbound_watch_manager .outbound_watch_manager
.set_desired_watch(key, desired_params); .set_desired_watch(record_key, desired_params);
// Drop the lock for network access // Drop the lock for network access
drop(inner); drop(inner);
@ -1168,7 +1213,10 @@ impl StorageManager {
// Obtain the watch change lock // Obtain the watch change lock
// (may need to wait for background operations to complete on the watch) // (may need to wait for background operations to complete on the watch)
let watch_lock = self.outbound_watch_lock_table.lock_tag(record_key).await; let watch_lock = self
.outbound_watch_lock_table
.lock_tag(record_key.clone())
.await;
// Calculate change to existing watch // Calculate change to existing watch
let (subkeys, count, expiration_ts) = { let (subkeys, count, expiration_ts) = {
@ -1247,7 +1295,7 @@ impl StorageManager {
// Get cryptosystem // Get cryptosystem
let crypto = self.crypto(); let crypto = self.crypto();
let Some(vcrypto) = crypto.get(record_key.kind) else { let Some(vcrypto) = crypto.get(record_key.kind()) else {
apibail_generic!("unsupported cryptosystem"); apibail_generic!("unsupported cryptosystem");
}; };
@ -1261,7 +1309,7 @@ impl StorageManager {
// See if the requested record is our local record store // See if the requested record is our local record store
let mut local_inspect_result = self let mut local_inspect_result = self
.handle_inspect_local_value_inner(&mut inner, record_key, subkeys.clone(), true) .handle_inspect_local_value_inner(&mut inner, record_key.clone(), subkeys.clone(), true)
.await?; .await?;
// Get the offline subkeys for this record still only returning the ones we're inspecting // Get the offline subkeys for this record still only returning the ones we're inspecting
@ -1319,7 +1367,7 @@ impl StorageManager {
// Get the inspect record report from the network // Get the inspect record report from the network
let result = self let result = self
.outbound_inspect_value( .outbound_inspect_value(
record_key, record_key.clone(),
subkeys, subkeys,
safety_selection, safety_selection,
if matches!(scope, DHTReportScope::SyncGet | DHTReportScope::SyncSet) { if matches!(scope, DHTReportScope::SyncGet | DHTReportScope::SyncSet) {
@ -1343,7 +1391,7 @@ impl StorageManager {
Self::process_fanout_results_inner( Self::process_fanout_results_inner(
&mut inner, &mut inner,
&vcrypto, &vcrypto,
record_key, record_key.clone(),
results_iter, results_iter,
false, false,
self.config() self.config()
@ -1378,14 +1426,14 @@ impl StorageManager {
let dest = rpc_processor let dest = rpc_processor
.resolve_target_to_destination( .resolve_target_to_destination(
vc.target, vc.target.clone(),
SafetySelection::Unsafe(Sequencing::PreferOrdered), SafetySelection::Unsafe(Sequencing::PreferOrdered),
) )
.await .await
.map_err(VeilidAPIError::from)?; .map_err(VeilidAPIError::from)?;
network_result_value_or_log!(self rpc_processor network_result_value_or_log!(self rpc_processor
.rpc_call_value_changed(dest, vc.record_key, vc.subkeys.clone(), vc.count, vc.watch_id, vc.value.map(|v| (*v).clone()) ) .rpc_call_value_changed(dest, vc.record_key.clone(), vc.subkeys.clone(), vc.count, vc.watch_id, vc.value.map(|v| (*v).clone()) )
.await .await
.map_err(VeilidAPIError::from)? => [format!(": dest={:?} vc={:?}", dest, vc)] {}); .map_err(VeilidAPIError::from)? => [format!(": dest={:?} vc={:?}", dest, vc)] {});
@ -1464,9 +1512,9 @@ impl StorageManager {
inner: &mut StorageManagerInner, inner: &mut StorageManagerInner,
kind: CryptoKind, kind: CryptoKind,
schema: DHTSchema, schema: DHTSchema,
owner: Option<BareKeyPair>, owner: Option<KeyPair>,
safety_selection: SafetySelection, safety_selection: SafetySelection,
) -> VeilidAPIResult<(RecordKey, BareKeyPair)> { ) -> VeilidAPIResult<(RecordKey, KeyPair)> {
// Get cryptosystem // Get cryptosystem
let crypto = self.crypto(); let crypto = self.crypto();
let Some(vcrypto) = crypto.get(kind) else { let Some(vcrypto) = crypto.get(kind) else {
@ -1483,11 +1531,12 @@ impl StorageManager {
let config = self.config(); let config = self.config();
let cfg = config.get(); let cfg = config.get();
if let Some(node_id) = cfg.network.routing_table.node_id.get(kind) { if let Some(node_id) = cfg.network.routing_table.node_id.get(kind) {
if schema.is_member(&node_id.value.into()) { let node_member_id = BareMemberId::new(node_id.ref_value());
if schema.is_member(&node_member_id) {
apibail_invalid_argument!( apibail_invalid_argument!(
"node id can not be schema member", "node id can not be schema member",
"schema", "schema",
node_id.value node_id.value()
); );
} }
} }
@ -1497,17 +1546,24 @@ impl StorageManager {
let schema_data = schema.compile(); let schema_data = schema.compile();
// New values require a new owner key if not given // New values require a new owner key if not given
let owner = owner.unwrap_or_else(|| vcrypto.generate_keypair()); let owner = if let Some(owner) = owner {
if owner.kind() != vcrypto.kind() {
apibail_invalid_argument!("owner is wrong crypto kind", "owner", owner);
}
owner
} else {
KeyPair::new(vcrypto.kind(), vcrypto.generate_keypair())
};
// Calculate dht key // Calculate dht key
let dht_key = Self::get_key(&vcrypto, &owner.key, &schema_data); let record_key = Self::make_record_key(&vcrypto, owner.ref_value().ref_key(), &schema_data);
// Make a signed value descriptor for this dht value // Make a signed value descriptor for this dht value
let signed_value_descriptor = Arc::new(SignedValueDescriptor::make_signature( let signed_value_descriptor = Arc::new(SignedValueDescriptor::make_signature(
owner.key, owner.key(),
schema_data, schema_data,
&vcrypto, &vcrypto,
owner.secret, owner.bare_secret(),
)?); )?);
// Add new local value record // Add new local value record
@ -1516,9 +1572,11 @@ impl StorageManager {
let record = let record =
Record::<LocalRecordDetail>::new(cur_ts, signed_value_descriptor, local_record_detail)?; Record::<LocalRecordDetail>::new(cur_ts, signed_value_descriptor, local_record_detail)?;
local_record_store.new_record(dht_key, record).await?; local_record_store
.new_record(record_key.clone(), record)
.await?;
Ok((dht_key, owner)) Ok((record_key, owner))
} }
#[instrument(level = "trace", target = "stor", skip_all, err)] #[instrument(level = "trace", target = "stor", skip_all, err)]
@ -1527,7 +1585,7 @@ impl StorageManager {
inner: &mut StorageManagerInner, inner: &mut StorageManagerInner,
record_key: RecordKey, record_key: RecordKey,
safety_selection: SafetySelection, safety_selection: SafetySelection,
) -> VeilidAPIResult<Option<(BarePublicKey, DHTSchema)>> { ) -> VeilidAPIResult<Option<(PublicKey, DHTSchema)>> {
// Get local record store // Get local record store
let Some(local_record_store) = inner.local_record_store.as_mut() else { let Some(local_record_store) = inner.local_record_store.as_mut() else {
apibail_not_initialized!(); apibail_not_initialized!();
@ -1542,7 +1600,7 @@ impl StorageManager {
// Return record details // Return record details
r.clone() r.clone()
}; };
let Some(remote_record) = remote_record_store.with_record(record_key, rcb) else { let Some(remote_record) = remote_record_store.with_record(&record_key, rcb) else {
// No local or remote record found, return None // No local or remote record found, return None
return Ok(None); return Ok(None);
}; };
@ -1555,13 +1613,13 @@ impl StorageManager {
LocalRecordDetail::new(safety_selection), LocalRecordDetail::new(safety_selection),
)?; )?;
local_record_store local_record_store
.new_record(record_key, local_record) .new_record(record_key.clone(), local_record)
.await?; .await?;
// Move copy subkey data from remote to local store // Move copy subkey data from remote to local store
for subkey in remote_record.stored_subkeys().iter() { for subkey in remote_record.stored_subkeys().iter() {
let Some(get_result) = remote_record_store let Some(get_result) = remote_record_store
.get_subkey(record_key, subkey, false) .get_subkey(record_key.clone(), subkey, false)
.await? .await?
else { else {
// Subkey was missing // Subkey was missing
@ -1575,7 +1633,7 @@ impl StorageManager {
}; };
local_record_store local_record_store
.set_subkey( .set_subkey(
record_key, record_key.clone(),
subkey, subkey,
subkey_data, subkey_data,
InboundWatchUpdateMode::NoUpdate, InboundWatchUpdateMode::NoUpdate,
@ -1585,15 +1643,17 @@ impl StorageManager {
// Move watches // Move watches
local_record_store.move_watches( local_record_store.move_watches(
record_key, record_key.clone(),
remote_record_store.move_watches(record_key, None), remote_record_store.move_watches(record_key.clone(), None),
); );
// Delete remote record from store // Delete remote record from store
remote_record_store.delete_record(record_key).await?; remote_record_store
.delete_record(record_key.clone())
.await?;
// Return record information as transferred to local record // Return record information as transferred to local record
Ok(Some((*remote_record.owner(), remote_record.schema()))) Ok(Some((remote_record.owner(), remote_record.schema())))
} }
#[instrument(level = "trace", target = "stor", skip_all, err)] #[instrument(level = "trace", target = "stor", skip_all, err)]
@ -1601,7 +1661,7 @@ impl StorageManager {
&self, &self,
inner: &mut StorageManagerInner, inner: &mut StorageManagerInner,
record_key: RecordKey, record_key: RecordKey,
writer: Option<BareKeyPair>, writer: Option<KeyPair>,
safety_selection: SafetySelection, safety_selection: SafetySelection,
) -> VeilidAPIResult<Option<DHTRecordDescriptor>> { ) -> VeilidAPIResult<Option<DHTRecordDescriptor>> {
// Get local record store // Get local record store
@ -1614,18 +1674,22 @@ impl StorageManager {
// Process local record // Process local record
// Keep the safety selection we opened the record with // Keep the safety selection we opened the record with
r.detail_mut().safety_selection = safety_selection; r.detail_mut().safety_selection = safety_selection.clone();
// Return record details // Return record details
(*r.owner(), r.schema()) (r.owner(), r.schema())
}; };
let (owner, schema) = match local_record_store.with_record_mut(record_key, cb) { let (owner, schema) = match local_record_store.with_record_mut(&record_key, cb) {
Some(v) => v, Some(v) => v,
None => { None => {
// If we don't have a local record yet, check to see if we have a remote record // If we don't have a local record yet, check to see if we have a remote record
// if so, migrate it to a local record // if so, migrate it to a local record
let Some(v) = self let Some(v) = self
.move_remote_record_to_local_inner(&mut *inner, record_key, safety_selection) .move_remote_record_to_local_inner(
&mut *inner,
record_key.clone(),
safety_selection.clone(),
)
.await? .await?
else { else {
// No remote record either // No remote record either
@ -1638,9 +1702,9 @@ impl StorageManager {
// If the writer we chose is also the owner, we have the owner secret // If the writer we chose is also the owner, we have the owner secret
// Otherwise this is just another subkey writer // Otherwise this is just another subkey writer
let owner_secret = if let Some(writer) = writer { let owner_secret = if let Some(writer) = writer.clone() {
if writer.key == owner { if writer.key() == owner {
Some(writer.secret) Some(writer.bare_secret())
} else { } else {
None None
} }
@ -1651,12 +1715,12 @@ impl StorageManager {
// Write open record // Write open record
inner inner
.opened_records .opened_records
.entry(record_key) .entry(record_key.clone())
.and_modify(|e| { .and_modify(|e| {
e.set_writer(writer); e.set_writer(writer.clone());
e.set_safety_selection(safety_selection); e.set_safety_selection(safety_selection.clone());
}) })
.or_insert_with(|| OpenedRecord::new(writer, safety_selection)); .or_insert_with(|| OpenedRecord::new(writer.clone(), safety_selection.clone()));
// Make DHT Record Descriptor to return // Make DHT Record Descriptor to return
let descriptor = DHTRecordDescriptor::new(record_key, owner, owner_secret, schema); let descriptor = DHTRecordDescriptor::new(record_key, owner, owner_secret, schema);
@ -1668,7 +1732,7 @@ impl StorageManager {
&self, &self,
inner: &mut StorageManagerInner, inner: &mut StorageManagerInner,
record_key: RecordKey, record_key: RecordKey,
writer: Option<BareKeyPair>, writer: Option<KeyPair>,
inspect_result: InspectResult, inspect_result: InspectResult,
safety_selection: SafetySelection, safety_selection: SafetySelection,
) -> VeilidAPIResult<DHTRecordDescriptor> { ) -> VeilidAPIResult<DHTRecordDescriptor> {
@ -1683,13 +1747,13 @@ impl StorageManager {
apibail_generic!("no descriptor"); apibail_generic!("no descriptor");
}; };
// Get owner // Get owner
let owner = *signed_value_descriptor.owner(); let owner = signed_value_descriptor.owner();
// If the writer we chose is also the owner, we have the owner secret // If the writer we chose is also the owner, we have the owner secret
// Otherwise this is just another subkey writer // Otherwise this is just another subkey writer
let owner_secret = if let Some(writer) = writer { let owner_secret = if let Some(writer) = &writer {
if writer.key == owner { if writer.key() == owner {
Some(writer.secret) Some(writer.bare_secret())
} else { } else {
None None
} }
@ -1707,14 +1771,17 @@ impl StorageManager {
let record = Record::<LocalRecordDetail>::new( let record = Record::<LocalRecordDetail>::new(
Timestamp::now(), Timestamp::now(),
signed_value_descriptor, signed_value_descriptor,
LocalRecordDetail::new(safety_selection), LocalRecordDetail::new(safety_selection.clone()),
)?; )?;
local_record_store.new_record(record_key, record).await?; local_record_store
.new_record(record_key.clone(), record)
.await?;
// Write open record // Write open record
inner inner.opened_records.insert(
.opened_records record_key.clone(),
.insert(record_key, OpenedRecord::new(writer, safety_selection)); OpenedRecord::new(writer, safety_selection),
);
// Make DHT Record Descriptor to return // Make DHT Record Descriptor to return
let descriptor = DHTRecordDescriptor::new(record_key, owner, owner_secret, schema); let descriptor = DHTRecordDescriptor::new(record_key, owner, owner_secret, schema);
@ -1735,14 +1802,14 @@ impl StorageManager {
// Get routing table to see if we still know about these nodes // Get routing table to see if we still know about these nodes
let routing_table = self.routing_table(); let routing_table = self.routing_table();
let opt_value_nodes = local_record_store.peek_record(record_key, |r| { let opt_value_nodes = local_record_store.peek_record(&record_key, |r| {
let d = r.detail(); let d = r.detail();
d.nodes d.nodes
.keys() .keys()
.copied() .cloned()
.filter_map(|x| { .filter_map(|x| {
routing_table routing_table
.lookup_node_ref(NodeId::new(record_key.kind, x)) .lookup_node_ref(NodeId::new(record_key.kind(), x))
.ok() .ok()
.flatten() .flatten()
}) })
@ -1765,14 +1832,14 @@ impl StorageManager {
let local_record_store = inner.local_record_store.as_mut().unwrap(); let local_record_store = inner.local_record_store.as_mut().unwrap();
let cur_ts = Timestamp::now(); let cur_ts = Timestamp::now();
local_record_store.with_record_mut(record_key, |r| { local_record_store.with_record_mut(&record_key, |r| {
let d = r.detail_mut(); let d = r.detail_mut();
for (subkeys, fanout_result) in subkey_results_iter { for (subkeys, fanout_result) in subkey_results_iter {
for node_id in fanout_result for node_id in fanout_result
.value_nodes .value_nodes
.iter() .iter()
.filter_map(|x| x.node_ids().get(record_key.kind).map(|k| k.value)) .filter_map(|x| x.node_ids().get(record_key.kind()).map(|k| k.value()))
{ {
let pnd = d.nodes.entry(node_id).or_default(); let pnd = d.nodes.entry(node_id).or_default();
if is_set || pnd.last_set == Timestamp::default() { if is_set || pnd.last_set == Timestamp::default() {
@ -1787,7 +1854,7 @@ impl StorageManager {
let mut nodes_ts = d let mut nodes_ts = d
.nodes .nodes
.iter() .iter()
.map(|kv| (*kv.0, kv.1.last_seen)) .map(|kv| (kv.0.clone(), kv.1.last_seen))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
nodes_ts.sort_by(|a, b| { nodes_ts.sort_by(|a, b| {
// Timestamp is first metric // Timestamp is first metric
@ -1797,12 +1864,12 @@ impl StorageManager {
} }
// Distance is the next metric, closer nodes first // Distance is the next metric, closer nodes first
let da = vcrypto.distance( let da = vcrypto.distance(
&BareHashDigest::from(a.0), &BareHashDigest::from(a.0.clone()),
&BareHashDigest::from(record_key.value), &BareHashDigest::from(record_key.value()),
); );
let db = vcrypto.distance( let db = vcrypto.distance(
&BareHashDigest::from(b.0), &BareHashDigest::from(b.0.clone()),
&BareHashDigest::from(record_key.value), &BareHashDigest::from(record_key.value()),
); );
da.cmp(&db) da.cmp(&db)
}); });
@ -1820,7 +1887,10 @@ impl StorageManager {
let Some(local_record_store) = inner.local_record_store.as_mut() else { let Some(local_record_store) = inner.local_record_store.as_mut() else {
apibail_not_initialized!(); apibail_not_initialized!();
}; };
if local_record_store.peek_record(record_key, |_| {}).is_none() { if local_record_store
.peek_record(&record_key, |_| {})
.is_none()
{
apibail_key_not_found!(record_key); apibail_key_not_found!(record_key);
} }
@ -1846,7 +1916,7 @@ impl StorageManager {
// See if the value is in the offline subkey writes first, // See if the value is in the offline subkey writes first,
// since it may not have been committed yet to the local record store // since it may not have been committed yet to the local record store
if let Some(get_result) = if let Some(get_result) =
self.get_offline_subkey_writes_subkey(inner, record_key, subkey, want_descriptor)? self.get_offline_subkey_writes_subkey(inner, &record_key, subkey, want_descriptor)?
{ {
return Ok(get_result); return Ok(get_result);
} }
@ -1880,7 +1950,7 @@ impl StorageManager {
// See if this new data supercedes any offline subkey writes // See if this new data supercedes any offline subkey writes
self.remove_old_offline_subkey_writes_inner( self.remove_old_offline_subkey_writes_inner(
inner, inner,
record_key, record_key.clone(),
subkey, subkey,
signed_value_data.clone(), signed_value_data.clone(),
); );
@ -1967,7 +2037,7 @@ impl StorageManager {
// See if we have a remote record already or not // See if we have a remote record already or not
if remote_record_store if remote_record_store
.with_record(record_key, |_| {}) .with_record(&record_key, |_| {})
.is_none() .is_none()
{ {
// record didn't exist, make it // record didn't exist, make it
@ -1978,7 +2048,9 @@ impl StorageManager {
signed_value_descriptor, signed_value_descriptor,
remote_record_detail, remote_record_detail,
)?; )?;
remote_record_store.new_record(record_key, record).await? remote_record_store
.new_record(record_key.clone(), record)
.await?
}; };
// Write subkey to remote store // Write subkey to remote store
@ -2018,19 +2090,6 @@ impl StorageManager {
) )
} }
fn get_key(
vcrypto: &CryptoSystemGuard<'_>,
owner_key: &BarePublicKey,
schema_data: &[u8],
) -> RecordKey {
let mut hash_data = Vec::<u8>::with_capacity(PUBLIC_KEY_LENGTH + 4 + schema_data.len());
hash_data.extend_from_slice(&vcrypto.kind().0);
hash_data.extend_from_slice(&owner_key.bytes);
hash_data.extend_from_slice(schema_data);
let hash = vcrypto.generate_hash(&hash_data);
RecordKey::new(vcrypto.kind(), BareRecordKey::from(hash))
}
#[instrument(level = "trace", target = "stor", skip_all)] #[instrument(level = "trace", target = "stor", skip_all)]
fn process_deferred_results<T: Send + 'static>( fn process_deferred_results<T: Send + 'static>(
&self, &self,

View file

@ -49,14 +49,14 @@ impl StorageManager {
pub(super) fn get_offline_subkey_writes_subkey( pub(super) fn get_offline_subkey_writes_subkey(
&self, &self,
inner: &mut StorageManagerInner, inner: &mut StorageManagerInner,
record_key: RecordKey, record_key: &RecordKey,
subkey: ValueSubkey, subkey: ValueSubkey,
want_descriptor: bool, want_descriptor: bool,
) -> VeilidAPIResult<Option<GetResult>> { ) -> VeilidAPIResult<Option<GetResult>> {
let Some(local_record_store) = inner.local_record_store.as_mut() else { let Some(local_record_store) = inner.local_record_store.as_mut() else {
apibail_not_initialized!(); apibail_not_initialized!();
}; };
let Some(osw) = inner.offline_subkey_writes.get(&record_key) else { let Some(osw) = inner.offline_subkey_writes.get(record_key) else {
return Ok(None); return Ok(None);
}; };
let Some(signed_value_data) = osw.subkey_value_data.get(&subkey).cloned() else { let Some(signed_value_data) = osw.subkey_value_data.get(&subkey).cloned() else {
@ -93,7 +93,7 @@ impl StorageManager {
signed_value_data: Arc<SignedValueData>, signed_value_data: Arc<SignedValueData>,
) { ) {
// Get the offline subkey write record // Get the offline subkey write record
match inner.offline_subkey_writes.entry(record_key) { match inner.offline_subkey_writes.entry(record_key.clone()) {
hashlink::linked_hash_map::Entry::Occupied(mut o) => { hashlink::linked_hash_map::Entry::Occupied(mut o) => {
let finished = { let finished = {
let osw = o.get_mut(); let osw = o.get_mut();
@ -154,7 +154,7 @@ impl StorageManager {
); );
// Get the offline subkey write record // Get the offline subkey write record
match inner.offline_subkey_writes.entry(record_key) { match inner.offline_subkey_writes.entry(record_key.clone()) {
hashlink::linked_hash_map::Entry::Occupied(mut o) => { hashlink::linked_hash_map::Entry::Occupied(mut o) => {
let finished = { let finished = {
let osw = o.get_mut(); let osw = o.get_mut();

View file

@ -32,7 +32,7 @@ impl fmt::Display for OutboundWatchManager {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut out = format!("outbound_watches({}): [\n", self.outbound_watches.len()); let mut out = format!("outbound_watches({}): [\n", self.outbound_watches.len());
{ {
let mut keys = self.outbound_watches.keys().copied().collect::<Vec<_>>(); let mut keys = self.outbound_watches.keys().cloned().collect::<Vec<_>>();
keys.sort(); keys.sort();
for k in keys { for k in keys {
@ -43,7 +43,7 @@ impl fmt::Display for OutboundWatchManager {
out += "]\n"; out += "]\n";
out += &format!("per_node_states({}): [\n", self.per_node_states.len()); out += &format!("per_node_states({}): [\n", self.per_node_states.len());
{ {
let mut keys = self.per_node_states.keys().copied().collect::<Vec<_>>(); let mut keys = self.per_node_states.keys().cloned().collect::<Vec<_>>();
keys.sort(); keys.sort();
for k in keys { for k in keys {
@ -60,7 +60,7 @@ impl fmt::Display for OutboundWatchManager {
let mut keys = self let mut keys = self
.needs_change_inspection .needs_change_inspection
.keys() .keys()
.copied() .cloned()
.collect::<Vec<_>>(); .collect::<Vec<_>>();
keys.sort(); keys.sort();
@ -92,7 +92,7 @@ impl OutboundWatchManager {
pub fn prepare(&mut self, routing_table: VeilidComponentGuard<'_, RoutingTable>) { pub fn prepare(&mut self, routing_table: VeilidComponentGuard<'_, RoutingTable>) {
for (pnk, pns) in &mut self.per_node_states { for (pnk, pns) in &mut self.per_node_states {
pns.watch_node_ref = match routing_table.lookup_node_ref(pnk.node_id) { pns.watch_node_ref = match routing_table.lookup_node_ref(pnk.node_id.clone()) {
Ok(v) => v, Ok(v) => v,
Err(e) => { Err(e) => {
veilid_log!(routing_table debug "Error looking up outbound watch node ref: {}", e); veilid_log!(routing_table debug "Error looking up outbound watch node ref: {}", e);
@ -103,7 +103,7 @@ impl OutboundWatchManager {
self.per_node_states self.per_node_states
.retain(|_, v| v.watch_node_ref.is_some()); .retain(|_, v| v.watch_node_ref.is_some());
let keys = self.per_node_states.keys().copied().collect::<HashSet<_>>(); let keys = self.per_node_states.keys().cloned().collect::<HashSet<_>>();
for v in self.outbound_watches.values_mut() { for v in self.outbound_watches.values_mut() {
if let Some(state) = v.state_mut() { if let Some(state) = v.state_mut() {
@ -133,7 +133,7 @@ impl OutboundWatchManager {
// Watch does not exist, add one if that's what is desired // Watch does not exist, add one if that's what is desired
if let Some(desired) = desired_watch { if let Some(desired) = desired_watch {
self.outbound_watches self.outbound_watches
.insert(record_key, OutboundWatch::new(record_key, desired)); .insert(record_key.clone(), OutboundWatch::new(record_key, desired));
} }
} }
} }
@ -163,7 +163,7 @@ impl OutboundWatchManager {
for (pnk, pns) in &self.per_node_states { for (pnk, pns) in &self.per_node_states {
if pns.count == 0 { if pns.count == 0 {
// If per-node watch is done, add to finished list // If per-node watch is done, add to finished list
finished_pnks.insert(*pnk); finished_pnks.insert(pnk.clone());
} else if !pns } else if !pns
.watch_node_ref .watch_node_ref
.as_ref() .as_ref()
@ -172,10 +172,10 @@ impl OutboundWatchManager {
.is_alive() .is_alive()
{ {
// If node is unreachable add to dead list // If node is unreachable add to dead list
dead_pnks.insert(*pnk); dead_pnks.insert(pnk.clone());
} else if cur_ts >= pns.expiration_ts { } else if cur_ts >= pns.expiration_ts {
// If per-node watch has expired add to expired list // If per-node watch has expired add to expired list
expired_pnks.insert(*pnk); expired_pnks.insert(pnk.clone());
} }
} }

View file

@ -13,7 +13,7 @@ pub struct OutboundWatchParameters {
/// Subkeys requested for this watch /// Subkeys requested for this watch
pub subkeys: ValueSubkeyRangeSet, pub subkeys: ValueSubkeyRangeSet,
/// What key to use to perform the watch /// What key to use to perform the watch
pub opt_watcher: Option<BareKeyPair>, pub opt_watcher: Option<KeyPair>,
/// What safety selection to use on the network /// What safety selection to use on the network
pub safety_selection: SafetySelection, pub safety_selection: SafetySelection,
} }

View file

@ -163,7 +163,13 @@ impl OutboundWatchState {
self.value_changed_routes = self self.value_changed_routes = self
.nodes .nodes
.iter() .iter()
.filter_map(|x| per_node_state.get(x).unwrap().opt_value_changed_route) .filter_map(|x| {
per_node_state
.get(x)
.cloned()
.unwrap()
.opt_value_changed_route
})
.collect(); .collect();
res res

View file

@ -2,7 +2,7 @@ use super::*;
impl_veilid_log_facility!("stor"); impl_veilid_log_facility!("stor");
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub(in crate::storage_manager) struct PerNodeKey { pub(in crate::storage_manager) struct PerNodeKey {
/// Watched record key /// Watched record key
pub record_key: RecordKey, pub record_key: RecordKey,
@ -36,7 +36,7 @@ pub(in crate::storage_manager) struct PerNodeState {
/// SafetySelection used to contact the node /// SafetySelection used to contact the node
pub safety_selection: SafetySelection, pub safety_selection: SafetySelection,
/// What key was used to perform the watch /// What key was used to perform the watch
pub opt_watcher: Option<BareKeyPair>, pub opt_watcher: Option<KeyPair>,
/// The expiration of a successful watch /// The expiration of a successful watch
pub expiration_ts: Timestamp, pub expiration_ts: Timestamp,
/// How many value change notifications are left /// How many value change notifications are left

View file

@ -10,7 +10,7 @@ pub struct InboundWatchParameters {
/// How many updates are left before forced expiration /// How many updates are left before forced expiration
pub count: u32, pub count: u32,
/// The watching schema member key, or an anonymous key /// The watching schema member key, or an anonymous key
pub watcher: BarePublicKey, pub watcher_member_id: MemberId,
/// The place where updates are sent /// The place where updates are sent
pub target: Target, pub target: Target,
} }

View file

@ -1,63 +1,48 @@
use super::*; use super::*;
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct RecordTableKey { pub struct RecordTableKey {
pub key: RecordKey, pub record_key: RecordKey,
} }
impl RecordTableKey { impl RecordTableKey {
pub fn bytes(&self) -> [u8; HASH_DIGEST_LENGTH + 4] { pub fn bytes(&self) -> Vec<u8> {
let mut bytes = [0u8; HASH_DIGEST_LENGTH + 4]; Vec::from(self.record_key.clone())
bytes[0..4].copy_from_slice(&self.key.kind.0);
bytes[4..HASH_DIGEST_LENGTH + 4].copy_from_slice(&self.key.value.bytes);
bytes
} }
} }
impl TryFrom<&[u8]> for RecordTableKey { impl TryFrom<&[u8]> for RecordTableKey {
type Error = EyreReport; type Error = EyreReport;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> { fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
if bytes.len() != HASH_DIGEST_LENGTH + 4 { let key = RecordKey::try_from(bytes)?;
bail!("invalid bytes length"); Ok(RecordTableKey { record_key: key })
}
let kind = CryptoKind::try_from(&bytes[0..4]).wrap_err("invalid kind")?;
let value =
BareRecordKey::try_from(&bytes[4..HASH_DIGEST_LENGTH + 4]).wrap_err("invalid value")?;
let key = RecordKey::new(kind, value);
Ok(RecordTableKey { key })
} }
} }
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct SubkeyTableKey { pub struct SubkeyTableKey {
pub key: RecordKey, pub record_key: RecordKey,
pub subkey: ValueSubkey, pub subkey: ValueSubkey,
} }
impl SubkeyTableKey { impl SubkeyTableKey {
pub fn bytes(&self) -> [u8; HASH_DIGEST_LENGTH + 4 + 4] { pub fn bytes(&self) -> Vec<u8> {
let mut bytes = [0u8; HASH_DIGEST_LENGTH + 4 + 4]; let mut bytes = Vec::<_>::from(self.record_key.clone());
bytes[0..4].copy_from_slice(&self.key.kind.0); bytes.extend_from_slice(&self.subkey.to_le_bytes());
bytes[4..HASH_DIGEST_LENGTH + 4].copy_from_slice(&self.key.value.bytes);
bytes[HASH_DIGEST_LENGTH + 4..HASH_DIGEST_LENGTH + 4 + 4]
.copy_from_slice(&self.subkey.to_le_bytes());
bytes bytes
} }
} }
impl TryFrom<&[u8]> for SubkeyTableKey { impl TryFrom<&[u8]> for SubkeyTableKey {
type Error = EyreReport; type Error = EyreReport;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> { fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
if bytes.len() != HASH_DIGEST_LENGTH + 4 { let key = RecordKey::try_from(&bytes[0..bytes.len() - 4])?;
bail!("invalid bytes length");
}
let kind = CryptoKind::try_from(&bytes[0..4]).wrap_err("invalid kind")?;
let value =
BareRecordKey::try_from(&bytes[4..HASH_DIGEST_LENGTH + 4]).wrap_err("invalid value")?;
let subkey = ValueSubkey::from_le_bytes( let subkey = ValueSubkey::from_le_bytes(
bytes[HASH_DIGEST_LENGTH + 4..HASH_DIGEST_LENGTH + 4 + 4] bytes[(bytes.len() - 4)..]
.try_into() .try_into()
.wrap_err("invalid subkey")?, .wrap_err("invalid subkey")?,
); );
let key = RecordKey::new(kind, value); Ok(SubkeyTableKey {
Ok(SubkeyTableKey { key, subkey }) record_key: key,
subkey,
})
} }
} }

View file

@ -284,14 +284,17 @@ where
} }
// add to index and ensure we deduplicate in the case of an error // add to index and ensure we deduplicate in the case of an error
if let Some(v) = self.record_index.insert_with_callback(ri.0, ri.1, |k, v| { if let Some(v) = self
// If the configuration change, we only want to keep the 'limits.max_records' records .record_index
dead_records.push(DeadRecord { .insert_with_callback(ri.0.clone(), ri.1, |k, v| {
key: k, // If the configuration change, we only want to keep the 'limits.max_records' records
record: v, dead_records.push(DeadRecord {
in_total_storage: true, key: k,
}); record: v,
}) { in_total_storage: true,
});
})
{
// This shouldn't happen, but deduplicate anyway // This shouldn't happen, but deduplicate anyway
veilid_log!(self warn "duplicate record in table: {:?}", ri.0); veilid_log!(self warn "duplicate record in table: {:?}", ri.0);
dead_records.push(DeadRecord { dead_records.push(DeadRecord {
@ -412,7 +415,7 @@ where
for sk in stored_subkeys.iter() { for sk in stored_subkeys.iter() {
// From table // From table
let stk = SubkeyTableKey { let stk = SubkeyTableKey {
key: dr.key.key, record_key: dr.key.record_key.clone(),
subkey: sk, subkey: sk,
}; };
let stkb = stk.bytes(); let stkb = stk.bytes();
@ -469,8 +472,12 @@ where
} }
#[instrument(level = "trace", target = "stor", skip_all, err)] #[instrument(level = "trace", target = "stor", skip_all, err)]
pub async fn new_record(&mut self, key: RecordKey, record: Record<D>) -> VeilidAPIResult<()> { pub async fn new_record(
let rtk = RecordTableKey { key }; &mut self,
record_key: RecordKey,
record: Record<D>,
) -> VeilidAPIResult<()> {
let rtk = RecordTableKey { record_key };
if self.record_index.contains_key(&rtk) { if self.record_index.contains_key(&rtk) {
apibail_internal!("record already exists"); apibail_internal!("record already exists");
} }
@ -495,9 +502,12 @@ where
// Save to record index // Save to record index
let mut dead_records = Vec::new(); let mut dead_records = Vec::new();
if let Some(v) = self.record_index.insert_with_callback(rtk, record, |k, v| { if let Some(v) = self
dead_records.push((k, v)); .record_index
}) { .insert_with_callback(rtk.clone(), record, |k, v| {
dead_records.push((k, v));
})
{
// Shouldn't happen but log it // Shouldn't happen but log it
veilid_log!(self warn "new duplicate record in table: {:?}", rtk); veilid_log!(self warn "new duplicate record in table: {:?}", rtk);
self.add_dead_record(rtk, v); self.add_dead_record(rtk, v);
@ -510,13 +520,13 @@ where
} }
#[instrument(level = "trace", target = "stor", skip_all, err)] #[instrument(level = "trace", target = "stor", skip_all, err)]
pub async fn delete_record(&mut self, key: RecordKey) -> VeilidAPIResult<()> { pub async fn delete_record(&mut self, record_key: RecordKey) -> VeilidAPIResult<()> {
// Get the record table key // Get the record table key
let rtk = RecordTableKey { key }; let rtk = RecordTableKey { record_key };
// Remove record from the index // Remove record from the index
let Some(record) = self.record_index.remove(&rtk) else { let Some(record) = self.record_index.remove(&rtk) else {
apibail_key_not_found!(key); apibail_key_not_found!(rtk.record_key.clone());
}; };
// Remove watches // Remove watches
@ -526,7 +536,7 @@ where
self.changed_watched_values.remove(&rtk); self.changed_watched_values.remove(&rtk);
// Invalidate inspect cache for this key // Invalidate inspect cache for this key
self.inspect_cache.invalidate(&rtk.key); self.inspect_cache.invalidate(&rtk.record_key);
// Remove from table store immediately // Remove from table store immediately
self.add_dead_record(rtk, record); self.add_dead_record(rtk, record);
@ -536,19 +546,23 @@ where
} }
#[instrument(level = "trace", target = "stor", skip_all)] #[instrument(level = "trace", target = "stor", skip_all)]
pub(super) fn contains_record(&mut self, key: RecordKey) -> bool { pub(super) fn contains_record(&mut self, record_key: &RecordKey) -> bool {
let rtk = RecordTableKey { key }; let rtk = RecordTableKey {
record_key: record_key.clone(),
};
self.record_index.contains_key(&rtk) self.record_index.contains_key(&rtk)
} }
#[instrument(level = "trace", target = "stor", skip_all)] #[instrument(level = "trace", target = "stor", skip_all)]
pub(super) fn with_record<R, F>(&mut self, key: RecordKey, f: F) -> Option<R> pub(super) fn with_record<R, F>(&mut self, record_key: &RecordKey, f: F) -> Option<R>
where where
F: FnOnce(&Record<D>) -> R, F: FnOnce(&Record<D>) -> R,
{ {
// Get record from index // Get record from index
let mut out = None; let mut out = None;
let rtk = RecordTableKey { key }; let rtk = RecordTableKey {
record_key: record_key.clone(),
};
if let Some(record) = self.record_index.get_mut(&rtk) { if let Some(record) = self.record_index.get_mut(&rtk) {
// Callback // Callback
out = Some(f(record)); out = Some(f(record));
@ -566,13 +580,15 @@ where
} }
#[instrument(level = "trace", target = "stor", skip_all)] #[instrument(level = "trace", target = "stor", skip_all)]
pub(super) fn peek_record<R, F>(&self, key: RecordKey, f: F) -> Option<R> pub(super) fn peek_record<R, F>(&self, record_key: &RecordKey, f: F) -> Option<R>
where where
F: FnOnce(&Record<D>) -> R, F: FnOnce(&Record<D>) -> R,
{ {
// Get record from index // Get record from index
let mut out = None; let mut out = None;
let rtk = RecordTableKey { key }; let rtk = RecordTableKey {
record_key: record_key.clone(),
};
if let Some(record) = self.record_index.peek(&rtk) { if let Some(record) = self.record_index.peek(&rtk) {
// Callback // Callback
out = Some(f(record)); out = Some(f(record));
@ -581,13 +597,15 @@ where
} }
#[instrument(level = "trace", target = "stor", skip_all)] #[instrument(level = "trace", target = "stor", skip_all)]
pub(super) fn with_record_mut<R, F>(&mut self, key: RecordKey, f: F) -> Option<R> pub(super) fn with_record_mut<R, F>(&mut self, record_key: &RecordKey, f: F) -> Option<R>
where where
F: FnOnce(&mut Record<D>) -> R, F: FnOnce(&mut Record<D>) -> R,
{ {
// Get record from index // Get record from index
let mut out = None; let mut out = None;
let rtk = RecordTableKey { key }; let rtk = RecordTableKey {
record_key: record_key.clone(),
};
if let Some(record) = self.record_index.get_mut(&rtk) { if let Some(record) = self.record_index.get_mut(&rtk) {
// Callback // Callback
out = Some(f(record)); out = Some(f(record));
@ -607,22 +625,24 @@ where
#[instrument(level = "trace", target = "stor", skip_all, err)] #[instrument(level = "trace", target = "stor", skip_all, err)]
pub async fn get_subkey( pub async fn get_subkey(
&mut self, &mut self,
key: RecordKey, record_key: RecordKey,
subkey: ValueSubkey, subkey: ValueSubkey,
want_descriptor: bool, want_descriptor: bool,
) -> VeilidAPIResult<Option<GetResult>> { ) -> VeilidAPIResult<Option<GetResult>> {
// Get record from index // Get record from index
let Some((subkey_count, has_subkey, opt_descriptor)) = self.with_record(key, |record| { let Some((subkey_count, has_subkey, opt_descriptor)) =
( self.with_record(&record_key, |record| {
record.subkey_count(), (
record.stored_subkeys().contains(subkey), record.subkey_count(),
if want_descriptor { record.stored_subkeys().contains(subkey),
Some(record.descriptor().clone()) if want_descriptor {
} else { Some(record.descriptor().clone())
None } else {
}, None
) },
}) else { )
})
else {
// Record not available // Record not available
return Ok(None); return Ok(None);
}; };
@ -642,7 +662,7 @@ where
} }
// If subkey exists in subkey cache, use that // If subkey exists in subkey cache, use that
let stk = SubkeyTableKey { key, subkey }; let stk = SubkeyTableKey { record_key, subkey };
if let Some(record_data) = self.subkey_cache.get(&stk) { if let Some(record_data) = self.subkey_cache.get(&stk) {
let out = record_data.signed_value_data().clone(); let out = record_data.signed_value_data().clone();
@ -675,22 +695,24 @@ where
#[instrument(level = "trace", target = "stor", skip_all, err)] #[instrument(level = "trace", target = "stor", skip_all, err)]
pub async fn peek_subkey( pub async fn peek_subkey(
&self, &self,
key: RecordKey, record_key: RecordKey,
subkey: ValueSubkey, subkey: ValueSubkey,
want_descriptor: bool, want_descriptor: bool,
) -> VeilidAPIResult<Option<GetResult>> { ) -> VeilidAPIResult<Option<GetResult>> {
// record from index // record from index
let Some((subkey_count, has_subkey, opt_descriptor)) = self.peek_record(key, |record| { let Some((subkey_count, has_subkey, opt_descriptor)) =
( self.peek_record(&record_key, |record| {
record.subkey_count(), (
record.stored_subkeys().contains(subkey), record.subkey_count(),
if want_descriptor { record.stored_subkeys().contains(subkey),
Some(record.descriptor().clone()) if want_descriptor {
} else { Some(record.descriptor().clone())
None } else {
}, None
) },
}) else { )
})
else {
// Record not available // Record not available
return Ok(None); return Ok(None);
}; };
@ -710,7 +732,7 @@ where
} }
// If subkey exists in subkey cache, use that // If subkey exists in subkey cache, use that
let stk = SubkeyTableKey { key, subkey }; let stk = SubkeyTableKey { record_key, subkey };
if let Some(record_data) = self.subkey_cache.peek(&stk) { if let Some(record_data) = self.subkey_cache.peek(&stk) {
let out = record_data.signed_value_data().clone(); let out = record_data.signed_value_data().clone();
@ -740,7 +762,7 @@ where
#[instrument(level = "trace", target = "stor", skip_all)] #[instrument(level = "trace", target = "stor", skip_all)]
async fn update_watched_value( async fn update_watched_value(
&mut self, &mut self,
key: RecordKey, record_key: RecordKey,
subkey: ValueSubkey, subkey: ValueSubkey,
watch_update_mode: InboundWatchUpdateMode, watch_update_mode: InboundWatchUpdateMode,
) { ) {
@ -753,7 +775,7 @@ where
return; return;
} }
let rtk = RecordTableKey { key }; let rtk = RecordTableKey { record_key };
let Some(wr) = self.watched_records.get_mut(&rtk) else { let Some(wr) = self.watched_records.get_mut(&rtk) else {
return; return;
}; };
@ -779,7 +801,7 @@ where
#[instrument(level = "trace", target = "stor", skip_all, err)] #[instrument(level = "trace", target = "stor", skip_all, err)]
pub async fn set_subkey( pub async fn set_subkey(
&mut self, &mut self,
key: RecordKey, record_key: RecordKey,
subkey: ValueSubkey, subkey: ValueSubkey,
signed_value_data: Arc<SignedValueData>, signed_value_data: Arc<SignedValueData>,
watch_update_mode: InboundWatchUpdateMode, watch_update_mode: InboundWatchUpdateMode,
@ -794,10 +816,12 @@ where
} }
// Get record subkey count and total size of all record subkey data exclusive of structures // Get record subkey count and total size of all record subkey data exclusive of structures
let Some((subkey_count, prior_record_data_size)) = self.with_record(key, |record| { let Some((subkey_count, prior_record_data_size)) = self
(record.subkey_count(), record.record_data_size()) .with_record(&record_key, |record| {
}) else { (record.subkey_count(), record.record_data_size())
apibail_invalid_argument!("no record at this key", "key", key); })
else {
apibail_invalid_argument!("no record at this key", "key", record_key);
}; };
// Check if the subkey is in range // Check if the subkey is in range
@ -809,7 +833,10 @@ where
let mut prior_subkey_size = 0usize; let mut prior_subkey_size = 0usize;
// If subkey exists in subkey cache, use that // If subkey exists in subkey cache, use that
let stk = SubkeyTableKey { key, subkey }; let stk = SubkeyTableKey {
record_key: record_key.clone(),
subkey,
};
let stk_bytes = stk.bytes(); let stk_bytes = stk.bytes();
if let Some(record_data) = self.subkey_cache.peek(&stk) { if let Some(record_data) = self.subkey_cache.peek(&stk) {
@ -855,7 +882,7 @@ where
// Write to inspect cache // Write to inspect cache
self.inspect_cache.replace_subkey_seq( self.inspect_cache.replace_subkey_seq(
&stk.key, &stk.record_key,
subkey, subkey,
subkey_record_data.signed_value_data().value_data().seq(), subkey_record_data.signed_value_data().value_data().seq(),
); );
@ -864,7 +891,7 @@ where
self.add_to_subkey_cache(stk, subkey_record_data); self.add_to_subkey_cache(stk, subkey_record_data);
// Update record // Update record
self.with_record_mut(key, |record| { self.with_record_mut(&record_key, |record| {
record.store_subkey(subkey); record.store_subkey(subkey);
record.set_record_data_size(new_record_data_size); record.set_record_data_size(new_record_data_size);
}) })
@ -874,7 +901,7 @@ where
self.total_storage_space.commit().unwrap(); self.total_storage_space.commit().unwrap();
// Send updates to // Send updates to
self.update_watched_value(key, subkey, watch_update_mode) self.update_watched_value(record_key, subkey, watch_update_mode)
.await; .await;
Ok(()) Ok(())
@ -883,12 +910,12 @@ where
#[instrument(level = "trace", target = "stor", skip_all, err)] #[instrument(level = "trace", target = "stor", skip_all, err)]
pub async fn inspect_record( pub async fn inspect_record(
&mut self, &mut self,
key: RecordKey, record_key: RecordKey,
subkeys: &ValueSubkeyRangeSet, subkeys: &ValueSubkeyRangeSet,
want_descriptor: bool, want_descriptor: bool,
) -> VeilidAPIResult<Option<InspectResult>> { ) -> VeilidAPIResult<Option<InspectResult>> {
// Get record from index // Get record from index
let Some((schema_subkeys, opt_descriptor)) = self.with_record(key, |record| { let Some((schema_subkeys, opt_descriptor)) = self.with_record(&record_key, |record| {
// Get number of subkeys from schema and ensure we are getting the // Get number of subkeys from schema and ensure we are getting the
// right number of sequence numbers betwen that and what we asked for // right number of sequence numbers betwen that and what we asked for
let schema_subkeys = record let schema_subkeys = record
@ -917,7 +944,7 @@ where
} }
// See if we have this inspection cached // See if we have this inspection cached
if let Some(icv) = self.inspect_cache.get(&key, &schema_subkeys) { if let Some(icv) = self.inspect_cache.get(&record_key, &schema_subkeys) {
return Ok(Some(InspectResult::new( return Ok(Some(InspectResult::new(
self, self,
subkeys.clone(), subkeys.clone(),
@ -932,7 +959,10 @@ where
#[allow(clippy::unnecessary_cast)] #[allow(clippy::unnecessary_cast)]
let mut seqs = Vec::with_capacity(schema_subkeys.len() as usize); let mut seqs = Vec::with_capacity(schema_subkeys.len() as usize);
for subkey in schema_subkeys.iter() { for subkey in schema_subkeys.iter() {
let stk = SubkeyTableKey { key, subkey }; let stk = SubkeyTableKey {
record_key: record_key.clone(),
subkey,
};
let opt_seq = if let Some(record_data) = self.subkey_cache.peek(&stk) { let opt_seq = if let Some(record_data) = self.subkey_cache.peek(&stk) {
Some(record_data.signed_value_data().value_data().seq()) Some(record_data.signed_value_data().value_data().seq())
} else { } else {
@ -949,7 +979,7 @@ where
// Save seqs cache // Save seqs cache
self.inspect_cache.put( self.inspect_cache.put(
key, record_key,
schema_subkeys.clone(), schema_subkeys.clone(),
InspectCacheL2Value { seqs: seqs.clone() }, InspectCacheL2Value { seqs: seqs.clone() },
); );
@ -967,7 +997,7 @@ where
#[instrument(level = "trace", target = "stor", skip_all, err)] #[instrument(level = "trace", target = "stor", skip_all, err)]
pub async fn _change_existing_watch( pub async fn _change_existing_watch(
&mut self, &mut self,
key: RecordKey, record_key: RecordKey,
params: InboundWatchParameters, params: InboundWatchParameters,
watch_id: u64, watch_id: u64,
) -> VeilidAPIResult<InboundWatchResult> { ) -> VeilidAPIResult<InboundWatchResult> {
@ -978,7 +1008,7 @@ where
apibail_internal!("zero expiration should have been resolved to max by now"); apibail_internal!("zero expiration should have been resolved to max by now");
} }
// Get the watch list for this record // Get the watch list for this record
let rtk = RecordTableKey { key }; let rtk = RecordTableKey { record_key };
let Some(watch_list) = self.watched_records.get_mut(&rtk) else { let Some(watch_list) = self.watched_records.get_mut(&rtk) else {
// No watches, nothing to change // No watches, nothing to change
return Ok(InboundWatchResult::Rejected); return Ok(InboundWatchResult::Rejected);
@ -988,7 +1018,7 @@ where
for w in &mut watch_list.watches { for w in &mut watch_list.watches {
// If the watch id doesn't match, then we're not updating // If the watch id doesn't match, then we're not updating
// Also do not allow the watcher key to change // Also do not allow the watcher key to change
if w.id == watch_id && w.params.watcher == params.watcher { if w.id == watch_id && w.params.watcher_member_id == params.watcher_member_id {
// Updating an existing watch // Updating an existing watch
w.params = params; w.params = params;
return Ok(InboundWatchResult::Changed { return Ok(InboundWatchResult::Changed {
@ -1004,12 +1034,14 @@ where
#[instrument(level = "trace", target = "stor", skip_all, err)] #[instrument(level = "trace", target = "stor", skip_all, err)]
pub async fn _create_new_watch( pub async fn _create_new_watch(
&mut self, &mut self,
key: RecordKey, record_key: RecordKey,
params: InboundWatchParameters, params: InboundWatchParameters,
member_check: Box<dyn Fn(BarePublicKey) -> bool + Send>, member_check: Box<dyn Fn(&MemberId) -> bool + Send>,
) -> VeilidAPIResult<InboundWatchResult> { ) -> VeilidAPIResult<InboundWatchResult> {
// Generate a record-unique watch id > 0 // Generate a record-unique watch id > 0
let rtk = RecordTableKey { key }; let rtk = RecordTableKey {
record_key: record_key.clone(),
};
let mut id = 0; let mut id = 0;
while id == 0 { while id == 0 {
id = get_random_u64(); id = get_random_u64();
@ -1036,19 +1068,18 @@ where
let mut watch_count = 0; let mut watch_count = 0;
let mut target_watch_count = 0; let mut target_watch_count = 0;
let is_member = member_check(params.watcher); let is_member = member_check(&params.watcher_member_id);
let rtk = RecordTableKey { key };
if let Some(watched_record) = self.watched_records.get_mut(&rtk) { if let Some(watched_record) = self.watched_records.get_mut(&rtk) {
// Total up the number of watches for this key // Total up the number of watches for this key
for w in &mut watched_record.watches { for w in &mut watched_record.watches {
// See if this watch should be counted toward any limits // See if this watch should be counted toward any limits
let count_watch = if is_member { let count_watch = if is_member {
// If the watcher is a member of the schema, then consider the total per-watcher key // If the watcher is a member of the schema, then consider the total per-watcher key
w.params.watcher == params.watcher w.params.watcher_member_id == params.watcher_member_id
} else { } else {
// If the watcher is not a member of the schema, the check if this watch is an anonymous watch and contributes to per-record key total // If the watcher is not a member of the schema, the check if this watch is an anonymous watch and contributes to per-record key total
!member_check(w.params.watcher) !member_check(&w.params.watcher_member_id)
}; };
// For any watch, if the target matches our also tally that separately // For any watch, if the target matches our also tally that separately
@ -1095,14 +1126,16 @@ where
#[instrument(level = "trace", target = "stor", skip_all, err)] #[instrument(level = "trace", target = "stor", skip_all, err)]
pub async fn watch_record( pub async fn watch_record(
&mut self, &mut self,
key: RecordKey, record_key: RecordKey,
mut params: InboundWatchParameters, mut params: InboundWatchParameters,
opt_watch_id: Option<u64>, opt_watch_id: Option<u64>,
) -> VeilidAPIResult<InboundWatchResult> { ) -> VeilidAPIResult<InboundWatchResult> {
// If count is zero then we're cancelling a watch completely // If count is zero then we're cancelling a watch completely
if params.count == 0 { if params.count == 0 {
if let Some(watch_id) = opt_watch_id { if let Some(watch_id) = opt_watch_id {
let cancelled = self.cancel_watch(key, watch_id, params.watcher).await?; let cancelled = self
.cancel_watch(record_key.clone(), watch_id, params.watcher_member_id)
.await?;
if cancelled { if cancelled {
return Ok(InboundWatchResult::Cancelled); return Ok(InboundWatchResult::Cancelled);
} }
@ -1122,7 +1155,9 @@ where
} else if params.expiration.as_u64() < min_ts { } else if params.expiration.as_u64() < min_ts {
// Don't add watches with too low of an expiration time // Don't add watches with too low of an expiration time
if let Some(watch_id) = opt_watch_id { if let Some(watch_id) = opt_watch_id {
let cancelled = self.cancel_watch(key, watch_id, params.watcher).await?; let cancelled = self
.cancel_watch(record_key, watch_id, params.watcher_member_id)
.await?;
if cancelled { if cancelled {
return Ok(InboundWatchResult::Cancelled); return Ok(InboundWatchResult::Cancelled);
} }
@ -1131,20 +1166,26 @@ where
} }
// Make a closure to check for member vs anonymous // Make a closure to check for member vs anonymous
let Some(member_check) = self.with_record(key, |record| { let Some((schema, owner)) = self.with_record(&record_key, |record| {
let schema = record.schema(); let schema = record.schema();
let owner = *record.owner(); let owner = record.owner();
Box::new(move |watcher| owner == watcher || schema.is_member(&watcher)) (schema, owner)
}) else { }) else {
// Record not found // Record not found
return Ok(InboundWatchResult::Rejected); return Ok(InboundWatchResult::Rejected);
}; };
let owner_member_id = self.storage_manager().generate_member_id(&owner)?;
let member_check = Box::new(move |watcher: &MemberId| {
owner_member_id == *watcher || schema.is_member(watcher.ref_value())
});
// Create or update depending on if a watch id is specified or not // Create or update depending on if a watch id is specified or not
if let Some(watch_id) = opt_watch_id { if let Some(watch_id) = opt_watch_id {
self._change_existing_watch(key, params, watch_id).await self._change_existing_watch(record_key, params, watch_id)
.await
} else { } else {
self._create_new_watch(key, params, member_check).await self._create_new_watch(record_key, params, member_check)
.await
} }
} }
@ -1153,22 +1194,22 @@ where
#[instrument(level = "trace", target = "stor", skip_all, err)] #[instrument(level = "trace", target = "stor", skip_all, err)]
async fn cancel_watch( async fn cancel_watch(
&mut self, &mut self,
key: RecordKey, record_key: RecordKey,
watch_id: u64, watch_id: u64,
watcher: BarePublicKey, watcher_member_id: MemberId,
) -> VeilidAPIResult<bool> { ) -> VeilidAPIResult<bool> {
if watch_id == 0 { if watch_id == 0 {
apibail_internal!("should not have let a zero watch id get here"); apibail_internal!("should not have let a zero watch id get here");
} }
// See if we are cancelling an existing watch // See if we are cancelling an existing watch
let rtk = RecordTableKey { key }; let rtk = RecordTableKey { record_key };
let mut is_empty = false; let mut is_empty = false;
let mut ret = false; let mut ret = false;
if let Some(watch_list) = self.watched_records.get_mut(&rtk) { if let Some(watch_list) = self.watched_records.get_mut(&rtk) {
let mut dead_watcher = None; let mut dead_watcher = None;
for (wn, w) in watch_list.watches.iter_mut().enumerate() { for (wn, w) in watch_list.watches.iter_mut().enumerate() {
// Must match the watch id and the watcher key to cancel // Must match the watch id and the watcher key to cancel
if w.id == watch_id && w.params.watcher == watcher { if w.id == watch_id && w.params.watcher_member_id == watcher_member_id {
// Canceling an existing watch // Canceling an existing watch
dead_watcher = Some(wn); dead_watcher = Some(wn);
ret = true; ret = true;
@ -1193,15 +1234,15 @@ where
#[instrument(level = "trace", target = "stor", skip_all)] #[instrument(level = "trace", target = "stor", skip_all)]
pub fn move_watches( pub fn move_watches(
&mut self, &mut self,
key: RecordKey, record_key: RecordKey,
in_watch: Option<(InboundWatchList, bool)>, in_watch: Option<(InboundWatchList, bool)>,
) -> Option<(InboundWatchList, bool)> { ) -> Option<(InboundWatchList, bool)> {
let rtk = RecordTableKey { key }; let rtk = RecordTableKey { record_key };
let out = self.watched_records.remove(&rtk); let out = self.watched_records.remove(&rtk);
if let Some(in_watch) = in_watch { if let Some(in_watch) = in_watch {
self.watched_records.insert(rtk, in_watch.0); self.watched_records.insert(rtk.clone(), in_watch.0);
if in_watch.1 { if in_watch.1 {
self.changed_watched_values.insert(rtk); self.changed_watched_values.insert(rtk.clone());
} }
} }
let is_watched = self.changed_watched_values.remove(&rtk); let is_watched = self.changed_watched_values.remove(&rtk);
@ -1263,8 +1304,8 @@ where
} }
evcis.push(EarlyValueChangedInfo { evcis.push(EarlyValueChangedInfo {
target: w.params.target, target: w.params.target.clone(),
key: rtk.key, key: rtk.record_key.clone(),
subkeys, subkeys,
count, count,
watch_id: w.id, watch_id: w.id,
@ -1276,6 +1317,7 @@ where
watch.watches.remove(dw); watch.watches.remove(dw);
if watch.watches.is_empty() { if watch.watches.is_empty() {
empty_watched_records.push(rtk); empty_watched_records.push(rtk);
break;
} }
} }
} }
@ -1290,7 +1332,7 @@ where
veilid_log!(self error "first subkey should exist for value change notification"); veilid_log!(self error "first subkey should exist for value change notification");
continue; continue;
}; };
let get_result = match self.get_subkey(evci.key, first_subkey, false).await { let get_result = match self.get_subkey(evci.key.clone(), first_subkey, false).await {
Ok(Some(skr)) => skr, Ok(Some(skr)) => skr,
Ok(None) => { Ok(None) => {
veilid_log!(self error "subkey should have data for value change notification"); veilid_log!(self error "subkey should have data for value change notification");
@ -1345,7 +1387,7 @@ where
for (rik, rec) in &self.record_index { for (rik, rec) in &self.record_index {
out += &format!( out += &format!(
" {} age={} len={} subkeys={}\n", " {} age={} len={} subkeys={}\n",
rik.key, rik.record_key,
display_duration(get_timestamp() - rec.last_touched().as_u64()), display_duration(get_timestamp() - rec.last_touched().as_u64()),
rec.record_data_size(), rec.record_data_size(),
rec.stored_subkeys(), rec.stored_subkeys(),
@ -1359,21 +1401,21 @@ where
out += &format!("Total Storage Space: {}\n", self.total_storage_space.get()); out += &format!("Total Storage Space: {}\n", self.total_storage_space.get());
out += &format!("Dead Records: {}\n", self.dead_records.len()); out += &format!("Dead Records: {}\n", self.dead_records.len());
for dr in &self.dead_records { for dr in &self.dead_records {
out += &format!(" {}\n", dr.key.key); out += &format!(" {}\n", dr.key.record_key);
} }
out += &format!("Changed Records: {}\n", self.changed_records.len()); out += &format!("Changed Records: {}\n", self.changed_records.len());
for cr in &self.changed_records { for cr in &self.changed_records {
out += &format!(" {}\n", cr.key); out += &format!(" {}\n", cr.record_key);
} }
out out
} }
pub fn debug_record_info(&self, key: RecordKey) -> String { pub fn debug_record_info(&self, record_key: RecordKey) -> String {
let record_info = self let record_info = self
.peek_record(key, |r| format!("{:#?}", r)) .peek_record(&record_key, |r| format!("{:#?}", r))
.unwrap_or("Not found".to_owned()); .unwrap_or("Not found".to_owned());
let watched_record = match self.watched_records.get(&RecordTableKey { key }) { let watched_record = match self.watched_records.get(&RecordTableKey { record_key }) {
Some(w) => { Some(w) => {
format!("Remote Watches: {:#?}", w) format!("Remote Watches: {:#?}", w)
} }
@ -1382,8 +1424,12 @@ where
format!("{}\n{}\n", record_info, watched_record) format!("{}\n{}\n", record_info, watched_record)
} }
pub async fn debug_record_subkey_info(&self, key: RecordKey, subkey: ValueSubkey) -> String { pub async fn debug_record_subkey_info(
match self.peek_subkey(key, subkey, true).await { &self,
record_key: RecordKey,
subkey: ValueSubkey,
) -> String {
match self.peek_subkey(record_key, subkey, true).await {
Ok(Some(v)) => { Ok(Some(v)) => {
format!("{:#?}", v) format!("{:#?}", v)
} }

View file

@ -7,29 +7,29 @@ pub(in crate::storage_manager) struct OpenedRecord {
/// The key pair used to perform writes to subkey on this opened record /// The key pair used to perform writes to subkey on this opened record
/// Without this, set_value() will fail regardless of which key or subkey is being written to /// Without this, set_value() will fail regardless of which key or subkey is being written to
/// as all writes are signed /// as all writes are signed
writer: Option<BareKeyPair>, writer: Option<KeyPair>,
/// The safety selection in current use /// The safety selection in current use
safety_selection: SafetySelection, safety_selection: SafetySelection,
} }
impl OpenedRecord { impl OpenedRecord {
pub fn new(writer: Option<BareKeyPair>, safety_selection: SafetySelection) -> Self { pub fn new(writer: Option<KeyPair>, safety_selection: SafetySelection) -> Self {
Self { Self {
writer, writer,
safety_selection, safety_selection,
} }
} }
pub fn writer(&self) -> Option<&BareKeyPair> { pub fn writer(&self) -> Option<&KeyPair> {
self.writer.as_ref() self.writer.as_ref()
} }
pub fn set_writer(&mut self, writer: Option<BareKeyPair>) { pub fn set_writer(&mut self, writer: Option<KeyPair>) {
self.writer = writer; self.writer = writer;
} }
pub fn safety_selection(&self) -> SafetySelection { pub fn safety_selection(&self) -> SafetySelection {
self.safety_selection self.safety_selection.clone()
} }
pub fn set_safety_selection(&mut self, safety_selection: SafetySelection) { pub fn set_safety_selection(&mut self, safety_selection: SafetySelection) {
self.safety_selection = safety_selection; self.safety_selection = safety_selection;

View file

@ -37,7 +37,7 @@ where
pub fn descriptor(&self) -> Arc<SignedValueDescriptor> { pub fn descriptor(&self) -> Arc<SignedValueDescriptor> {
self.descriptor.clone() self.descriptor.clone()
} }
pub fn owner(&self) -> &BarePublicKey { pub fn owner(&self) -> PublicKey {
self.descriptor.owner() self.descriptor.owner()
} }

Some files were not shown because too many files have changed in this diff Show more