refactor
This commit is contained in:
		| @@ -44,17 +44,29 @@ pub const SHARED_SECRET_LENGTH_ENCODED: usize = 43; | ||||
| /// Length of a route id in bytes | ||||
| #[allow(dead_code)] | ||||
| pub const ROUTE_ID_LENGTH: usize = 32; | ||||
| /// Length of a route id in bytes afer encoding to base64url | ||||
| #[allow(dead_code)] | ||||
| pub const ROUTE_ID_LENGTH_ENCODED: usize = 43; | ||||
|  | ||||
| ////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| pub trait Encodable { | ||||
| pub trait Encodable | ||||
| where | ||||
|     Self: Sized, | ||||
| { | ||||
|     fn encode(&self) -> String; | ||||
|     fn encoded_len() -> usize; | ||||
|     fn try_decode<S: AsRef<str>>(input: S) -> Result<Self, VeilidAPIError> { | ||||
|         let b = input.as_ref().as_bytes(); | ||||
|         Self::try_decode_bytes(b) | ||||
|     } | ||||
|     fn try_decode_bytes(b: &[u8]) -> Result<Self, VeilidAPIError>; | ||||
| } | ||||
|  | ||||
| ////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| macro_rules! byte_array_type { | ||||
|     ($name:ident, $size:expr) => { | ||||
|     ($name:ident, $size:expr, $encoded_size:expr) => { | ||||
|         #[derive( | ||||
|             Clone, | ||||
|             Copy, | ||||
| @@ -161,12 +173,16 @@ macro_rules! byte_array_type { | ||||
|                 } | ||||
|                 None | ||||
|             } | ||||
|         } | ||||
|  | ||||
|             pub fn try_decode<S: AsRef<str>>(input: S) -> Result<Self, VeilidAPIError> { | ||||
|                 let b = input.as_ref().as_bytes(); | ||||
|                 Self::try_decode_bytes(b) | ||||
|         impl Encodable for $name { | ||||
|             fn encode(&self) -> String { | ||||
|                 BASE64URL_NOPAD.encode(&self.bytes) | ||||
|             } | ||||
|             pub fn try_decode_bytes(b: &[u8]) -> Result<Self, VeilidAPIError> { | ||||
|             fn encoded_len() -> usize { | ||||
|                 $encoded_size | ||||
|             } | ||||
|             fn try_decode_bytes(b: &[u8]) -> Result<Self, VeilidAPIError> { | ||||
|                 let mut bytes = [0u8; $size]; | ||||
|                 let res = BASE64URL_NOPAD.decode_len(b.len()); | ||||
|                 match res { | ||||
| @@ -187,15 +203,8 @@ macro_rules! byte_array_type { | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         impl Encodable for $name { | ||||
|             fn encode(&self) -> String { | ||||
|                 BASE64URL_NOPAD.encode(&self.bytes) | ||||
|             } | ||||
|         } | ||||
|         impl fmt::Display for $name { | ||||
|             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|                 //write!(f, "{}", String::from(self)) | ||||
|                 write!(f, "{}", self.encode()) | ||||
|             } | ||||
|         } | ||||
| @@ -210,12 +219,6 @@ macro_rules! byte_array_type { | ||||
|  | ||||
|         impl From<&$name> for String { | ||||
|             fn from(value: &$name) -> Self { | ||||
|                 // let mut s = String::new(); | ||||
|                 // for n in 0..($size / 8) { | ||||
|                 //     let b: [u8; 8] = value.bytes[n * 8..(n + 1) * 8].try_into().unwrap(); | ||||
|                 //     s.push_str(hex::encode(b).as_str()); | ||||
|                 // } | ||||
|                 // s | ||||
|                 value.encode() | ||||
|             } | ||||
|         } | ||||
| @@ -238,17 +241,6 @@ macro_rules! byte_array_type { | ||||
|         impl TryFrom<&str> for $name { | ||||
|             type Error = VeilidAPIError; | ||||
|             fn try_from(value: &str) -> Result<Self, Self::Error> { | ||||
|                 // let mut out = $name::default(); | ||||
|                 // if value == "" { | ||||
|                 //     return Ok(out); | ||||
|                 // } | ||||
|                 // if value.len() != ($size * 2) { | ||||
|                 //     apibail_generic!(concat!(stringify!($name), " is incorrect length")); | ||||
|                 // } | ||||
|                 // match hex::decode_to_slice(value, &mut out.bytes) { | ||||
|                 //     Ok(_) => Ok(out), | ||||
|                 //     Err(err) => Err(VeilidAPIError::generic(err)), | ||||
|                 // } | ||||
|                 Self::try_decode(value) | ||||
|             } | ||||
|         } | ||||
| @@ -257,10 +249,18 @@ macro_rules! byte_array_type { | ||||
|  | ||||
| ///////////////////////////////////////// | ||||
|  | ||||
| byte_array_type!(PublicKey, PUBLIC_KEY_LENGTH); | ||||
| byte_array_type!(SecretKey, SECRET_KEY_LENGTH); | ||||
| byte_array_type!(Signature, SIGNATURE_LENGTH); | ||||
| byte_array_type!(PublicKeyDistance, PUBLIC_KEY_LENGTH); | ||||
| byte_array_type!(Nonce, NONCE_LENGTH); | ||||
| byte_array_type!(SharedSecret, SHARED_SECRET_LENGTH); | ||||
| byte_array_type!(RouteId, ROUTE_ID_LENGTH); | ||||
| byte_array_type!(PublicKey, PUBLIC_KEY_LENGTH, PUBLIC_KEY_LENGTH_ENCODED); | ||||
| byte_array_type!(SecretKey, SECRET_KEY_LENGTH, SECRET_KEY_LENGTH_ENCODED); | ||||
| byte_array_type!(Signature, SIGNATURE_LENGTH, SIGNATURE_LENGTH_ENCODED); | ||||
| byte_array_type!( | ||||
|     PublicKeyDistance, | ||||
|     PUBLIC_KEY_LENGTH, | ||||
|     PUBLIC_KEY_LENGTH_ENCODED | ||||
| ); | ||||
| byte_array_type!(Nonce, NONCE_LENGTH, NONCE_LENGTH_ENCODED); | ||||
| byte_array_type!( | ||||
|     SharedSecret, | ||||
|     SHARED_SECRET_LENGTH, | ||||
|     SHARED_SECRET_LENGTH_ENCODED | ||||
| ); | ||||
| byte_array_type!(RouteId, ROUTE_ID_LENGTH, ROUTE_ID_LENGTH_ENCODED); | ||||
|   | ||||
| @@ -229,7 +229,7 @@ impl Crypto { | ||||
|             for nid in node_ids { | ||||
|                 if nid.kind == sig.kind { | ||||
|                     if let Some(vcrypto) = self.get(sig.kind) { | ||||
|                         vcrypto.verify(&nid.key, data, &sig.signature)?; | ||||
|                         vcrypto.verify(&nid.value, data, &sig.value)?; | ||||
|                         out.push(nid.kind); | ||||
|                     } | ||||
|                 } | ||||
| @@ -253,7 +253,7 @@ impl Crypto { | ||||
|         let mut out = Vec::<R>::with_capacity(typed_key_pairs.len()); | ||||
|         for kp in typed_key_pairs { | ||||
|             if let Some(vcrypto) = self.get(kp.kind) { | ||||
|                 let sig = vcrypto.sign(&kp.key, &kp.secret, data)?; | ||||
|                 let sig = vcrypto.sign(&kp.value.key, &kp.value.secret, data)?; | ||||
|                 out.push(transform(kp, sig)) | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -1,548 +0,0 @@ | ||||
| use super::*; | ||||
|  | ||||
| use core::cmp::{Eq, Ord, PartialEq, PartialOrd}; | ||||
| use core::convert::TryInto; | ||||
| use core::fmt; | ||||
| use core::hash::Hash; | ||||
|  | ||||
| use rkyv::{Archive as RkyvArchive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize}; | ||||
|  | ||||
| /// Cryptography version fourcc code | ||||
| pub type CryptoKind = FourCC; | ||||
|  | ||||
| /// Sort best crypto kinds first | ||||
| /// Better crypto kinds are 'less', ordered toward the front of a list | ||||
| pub fn compare_crypto_kind(a: &CryptoKind, b: &CryptoKind) -> cmp::Ordering { | ||||
|     let a_idx = VALID_CRYPTO_KINDS.iter().position(|k| k == a); | ||||
|     let b_idx = VALID_CRYPTO_KINDS.iter().position(|k| k == b); | ||||
|     if let Some(a_idx) = a_idx { | ||||
|         if let Some(b_idx) = b_idx { | ||||
|             // Both are valid, prefer better crypto kind | ||||
|             a_idx.cmp(&b_idx) | ||||
|         } else { | ||||
|             // A is valid, B is not | ||||
|             cmp::Ordering::Less | ||||
|         } | ||||
|     } else if b_idx.is_some() { | ||||
|         // B is valid, A is not | ||||
|         cmp::Ordering::Greater | ||||
|     } else { | ||||
|         // Both are invalid, so use lex comparison | ||||
|         a.cmp(b) | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Intersection of crypto kind vectors | ||||
| pub fn common_crypto_kinds(a: &[CryptoKind], b: &[CryptoKind]) -> Vec<CryptoKind> { | ||||
|     let mut out = Vec::new(); | ||||
|     for ack in a { | ||||
|         if b.contains(ack) { | ||||
|             out.push(*ack); | ||||
|         } | ||||
|     } | ||||
|     out | ||||
| } | ||||
|  | ||||
| #[derive( | ||||
|     Clone, | ||||
|     Copy, | ||||
|     Debug, | ||||
|     Serialize, | ||||
|     Deserialize, | ||||
|     PartialOrd, | ||||
|     Ord, | ||||
|     PartialEq, | ||||
|     Eq, | ||||
|     Hash, | ||||
|     RkyvArchive, | ||||
|     RkyvSerialize, | ||||
|     RkyvDeserialize, | ||||
| )] | ||||
| #[archive_attr(repr(C), derive(CheckBytes, Hash, PartialEq, Eq))] | ||||
| pub struct KeyPair { | ||||
|     pub key: PublicKey, | ||||
|     pub secret: SecretKey, | ||||
| } | ||||
|  | ||||
| impl KeyPair { | ||||
|     pub fn new(key: PublicKey, secret: SecretKey) -> Self { | ||||
|         Self { key, secret } | ||||
|     } | ||||
| } | ||||
|  | ||||
| xxx make default template version here for secretkey | ||||
| and put Vec<TypedKey<SecretKey>> in settings | ||||
| #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, RkyvArchive, RkyvSerialize, RkyvDeserialize)] | ||||
| #[archive_attr(repr(C), derive(CheckBytes, Hash, PartialEq, Eq))] | ||||
| pub struct TypedKey { | ||||
|     pub kind: CryptoKind, | ||||
|     pub key: PublicKey, | ||||
| } | ||||
|  | ||||
| impl TypedKey { | ||||
|     pub fn new(kind: CryptoKind, key: PublicKey) -> Self { | ||||
|         Self { kind, key } | ||||
|     } | ||||
| } | ||||
| impl PartialOrd for TypedKey { | ||||
|     fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { | ||||
|         Some(self.cmp(other)) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Ord for TypedKey { | ||||
|     fn cmp(&self, other: &Self) -> cmp::Ordering { | ||||
|         let x = compare_crypto_kind(&self.kind, &other.kind); | ||||
|         if x != cmp::Ordering::Equal { | ||||
|             return x; | ||||
|         } | ||||
|         self.key.cmp(&other.key) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Display for TypedKey { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { | ||||
|         write!(f, "{}:{}", self.kind, self.key.encode()) | ||||
|     } | ||||
| } | ||||
| impl FromStr for TypedKey { | ||||
|     type Err = VeilidAPIError; | ||||
|     fn from_str(s: &str) -> Result<Self, Self::Err> { | ||||
|         let b = s.as_bytes(); | ||||
|         if b.len() != (5 + PUBLIC_KEY_LENGTH_ENCODED) || b[4..5] != b":"[..] { | ||||
|             apibail_parse_error!("invalid typed key", s); | ||||
|         } | ||||
|         let kind: CryptoKind = b[0..4].try_into().expect("should not fail to convert"); | ||||
|         let key = PublicKey::try_decode_bytes(&b[5..])?; | ||||
|         Ok(Self { kind, key }) | ||||
|     } | ||||
| } | ||||
| impl<'de> Deserialize<'de> for TypedKey { | ||||
|     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> | ||||
|     where | ||||
|         D: serde::Deserializer<'de>, | ||||
|     { | ||||
|         let s = <String as Deserialize>::deserialize(deserializer)?; | ||||
|         FromStr::from_str(&s).map_err(serde::de::Error::custom) | ||||
|     } | ||||
| } | ||||
| impl Serialize for TypedKey { | ||||
|     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | ||||
|     where | ||||
|         S: serde::Serializer, | ||||
|     { | ||||
|         serializer.collect_str(self) | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive( | ||||
|     Clone, | ||||
|     Debug, | ||||
|     Serialize, | ||||
|     Deserialize, | ||||
|     PartialOrd, | ||||
|     Ord, | ||||
|     PartialEq, | ||||
|     Eq, | ||||
|     Hash, | ||||
|     RkyvArchive, | ||||
|     RkyvSerialize, | ||||
|     RkyvDeserialize, | ||||
| )] | ||||
| #[archive_attr(repr(C), derive(CheckBytes, Hash, PartialEq, Eq))] | ||||
| #[serde(from = "Vec<TypedKey>", into = "Vec<TypedKey>")]  | ||||
| pub struct TypedKeySet { | ||||
|     items: Vec<TypedKey>, | ||||
| } | ||||
|  | ||||
| impl TypedKeySet { | ||||
|     pub fn new() -> Self { | ||||
|         Self { items: Vec::new() } | ||||
|     } | ||||
|     pub fn with_capacity(cap: usize) -> Self { | ||||
|         Self { | ||||
|             items: Vec::with_capacity(cap), | ||||
|         } | ||||
|     } | ||||
|     pub fn kinds(&self) -> Vec<CryptoKind> { | ||||
|         let mut out = Vec::new(); | ||||
|         for tk in &self.items { | ||||
|             out.push(tk.kind); | ||||
|         } | ||||
|         out.sort_by(compare_crypto_kind); | ||||
|         out | ||||
|     } | ||||
|     pub fn keys(&self) -> Vec<PublicKey> { | ||||
|         let mut out = Vec::new(); | ||||
|         for tk in &self.items { | ||||
|             out.push(tk.key); | ||||
|         } | ||||
|         out | ||||
|     } | ||||
|     pub fn get(&self, kind: CryptoKind) -> Option<TypedKey> { | ||||
|         self.items.iter().find(|x| x.kind == kind).copied() | ||||
|     } | ||||
|     pub fn add(&mut self, typed_key: TypedKey) { | ||||
|         for x in &mut self.items { | ||||
|             if x.kind == typed_key.kind { | ||||
|                 *x = typed_key; | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|         self.items.push(typed_key); | ||||
|         self.items.sort() | ||||
|     } | ||||
|     pub fn add_all(&mut self, typed_keys: &[TypedKey]) { | ||||
|         'outer: for typed_key in typed_keys { | ||||
|             for x in &mut self.items { | ||||
|                 if x.kind == typed_key.kind { | ||||
|                     *x = *typed_key; | ||||
|                     continue 'outer; | ||||
|                 } | ||||
|             } | ||||
|             self.items.push(*typed_key); | ||||
|         } | ||||
|         self.items.sort() | ||||
|     } | ||||
|     pub fn remove(&mut self, kind: CryptoKind) { | ||||
|         if let Some(idx) = self.items.iter().position(|x| x.kind == kind) { | ||||
|             self.items.remove(idx); | ||||
|         } | ||||
|     } | ||||
|     pub fn remove_all(&mut self, kinds: &[CryptoKind]) { | ||||
|         for k in kinds { | ||||
|             self.remove(*k); | ||||
|         } | ||||
|     } | ||||
|     /// Return preferred typed key of our supported crypto kinds | ||||
|     pub fn best(&self) -> Option<TypedKey> { | ||||
|         match self.items.first().copied() { | ||||
|             None => None, | ||||
|             Some(k) => { | ||||
|                 if !VALID_CRYPTO_KINDS.contains(&k.kind) { | ||||
|                     None | ||||
|                 } else { | ||||
|                     Some(k) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     pub fn len(&self) -> usize { | ||||
|         self.items.len() | ||||
|     } | ||||
|     pub fn iter(&self) -> core::slice::Iter<'_, TypedKey> { | ||||
|         self.items.iter() | ||||
|     } | ||||
|     pub fn contains(&self, typed_key: &TypedKey) -> bool { | ||||
|         self.items.contains(typed_key) | ||||
|     } | ||||
|     pub fn contains_any(&self, typed_keys: &[TypedKey]) -> bool { | ||||
|         for typed_key in typed_keys { | ||||
|             if self.items.contains(typed_key) { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         false | ||||
|     } | ||||
|     pub fn contains_key(&self, key: &PublicKey) -> bool { | ||||
|         for tk in &self.items { | ||||
|             if tk.key == *key { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         false | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl core::ops::Deref for TypedKeySet { | ||||
|     type Target = [TypedKey]; | ||||
|  | ||||
|     #[inline] | ||||
|     fn deref(&self) -> &[TypedKey] { | ||||
|         &self.items | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Display for TypedKeySet { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { | ||||
|         write!(f, "[")?; | ||||
|         let mut first = true; | ||||
|         for x in &self.items { | ||||
|             if !first { | ||||
|                 write!(f, ",")?; | ||||
|                 first = false; | ||||
|             } | ||||
|             write!(f, "{}", x)?; | ||||
|         } | ||||
|         write!(f, "]") | ||||
|     } | ||||
| } | ||||
| impl FromStr for TypedKeySet { | ||||
|     type Err = VeilidAPIError; | ||||
|     fn from_str(s: &str) -> Result<Self, Self::Err> { | ||||
|         let mut items = Vec::new(); | ||||
|         if s.len() < 2 { | ||||
|             apibail_parse_error!("invalid length", s); | ||||
|         } | ||||
|         if &s[0..1] != "[" || &s[(s.len() - 1)..] != "]" { | ||||
|             apibail_parse_error!("invalid format", s); | ||||
|         } | ||||
|         for x in s[1..s.len() - 1].split(",") { | ||||
|             let tk = TypedKey::from_str(x.trim())?; | ||||
|             items.push(tk); | ||||
|         } | ||||
|  | ||||
|         Ok(Self { items }) | ||||
|     } | ||||
| } | ||||
| impl From<TypedKey> for TypedKeySet { | ||||
|     fn from(x: TypedKey) -> Self { | ||||
|         let mut tks = TypedKeySet::with_capacity(1); | ||||
|         tks.add(x); | ||||
|         tks | ||||
|     } | ||||
| } | ||||
| impl From<Vec<TypedKey>> for TypedKeySet { | ||||
|     fn from(x: Vec<TypedKey>) -> Self { | ||||
|         let mut tks = TypedKeySet::with_capacity(x.len()); | ||||
|         tks.add_all(&x); | ||||
|         tks | ||||
|     } | ||||
| } | ||||
| impl Into<Vec<TypedKey>> for TypedKeySet { | ||||
|     fn into(self) -> Vec<TypedKey> { | ||||
|         self.items | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive( | ||||
|     Clone, | ||||
|     Copy, | ||||
|     Debug, | ||||
|     PartialEq, | ||||
|     Eq, | ||||
|     Hash, | ||||
|     Serialize, | ||||
|     Deserialize, | ||||
|     RkyvArchive, | ||||
|     RkyvSerialize, | ||||
|     RkyvDeserialize, | ||||
| )] | ||||
| #[archive_attr(repr(C), derive(CheckBytes, Hash, PartialEq, Eq))] | ||||
| pub struct TypedKeyPair { | ||||
|     pub kind: CryptoKind, | ||||
|     pub key: PublicKey, | ||||
|     pub secret: SecretKey, | ||||
| } | ||||
|  | ||||
| impl TypedKeyPair { | ||||
|     pub fn new(kind: CryptoKind, key: PublicKey, secret: SecretKey) -> Self { | ||||
|         Self { kind, key, secret } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl PartialOrd for TypedKeyPair { | ||||
|     fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { | ||||
|         Some(self.cmp(other)) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Ord for TypedKeyPair { | ||||
|     fn cmp(&self, other: &Self) -> cmp::Ordering { | ||||
|         let x = compare_crypto_kind(&self.kind, &other.kind); | ||||
|         if x != cmp::Ordering::Equal { | ||||
|             return x; | ||||
|         } | ||||
|         let x = self.key.cmp(&other.key); | ||||
|         if x != cmp::Ordering::Equal { | ||||
|             return x; | ||||
|         } | ||||
|         self.secret.cmp(&other.secret) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Display for TypedKeyPair { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { | ||||
|         write!( | ||||
|             f, | ||||
|             "{}:{}:{}", | ||||
|             self.kind, | ||||
|             self.key.encode(), | ||||
|             self.secret.encode() | ||||
|         ) | ||||
|     } | ||||
| } | ||||
| impl FromStr for TypedKeyPair { | ||||
|     type Err = VeilidAPIError; | ||||
|     fn from_str(s: &str) -> Result<Self, Self::Err> { | ||||
|         let b = s.as_bytes(); | ||||
|         if b.len() != (5 + PUBLIC_KEY_LENGTH_ENCODED + 1 + SECRET_KEY_LENGTH_ENCODED) | ||||
|             || b[4..5] != b":"[..] | ||||
|             || b[5 + PUBLIC_KEY_LENGTH_ENCODED..6 + PUBLIC_KEY_LENGTH_ENCODED] != b":"[..] | ||||
|         { | ||||
|             apibail_parse_error!("invalid typed key pair", s); | ||||
|         } | ||||
|         let kind: CryptoKind = b[0..4].try_into().expect("should not fail to convert"); | ||||
|         let key = PublicKey::try_decode_bytes(&b[5..5 + PUBLIC_KEY_LENGTH_ENCODED])?; | ||||
|         let secret = SecretKey::try_decode_bytes(&b[5 + PUBLIC_KEY_LENGTH_ENCODED + 1..])?; | ||||
|         Ok(Self { kind, key, secret }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive( | ||||
|     Clone, | ||||
|     Copy, | ||||
|     Debug, | ||||
|     PartialEq, | ||||
|     Eq, | ||||
|     Hash, | ||||
|     Serialize, | ||||
|     Deserialize, | ||||
|     RkyvArchive, | ||||
|     RkyvSerialize, | ||||
|     RkyvDeserialize, | ||||
| )] | ||||
| #[archive_attr(repr(C), derive(CheckBytes, Hash, PartialEq, Eq))] | ||||
| pub struct TypedSignature { | ||||
|     pub kind: CryptoKind, | ||||
|     pub signature: Signature, | ||||
| } | ||||
| impl TypedSignature { | ||||
|     pub fn new(kind: CryptoKind, signature: Signature) -> Self { | ||||
|         Self { kind, signature } | ||||
|     } | ||||
|     pub fn from_keyed(tks: &TypedKeySignature) -> Self { | ||||
|         Self { | ||||
|             kind: tks.kind, | ||||
|             signature: tks.signature, | ||||
|         } | ||||
|     } | ||||
|     pub fn from_pair_sig(tkp: &TypedKeyPair, sig: Signature) -> Self { | ||||
|         Self { | ||||
|             kind: tkp.kind, | ||||
|             signature: sig, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl PartialOrd for TypedSignature { | ||||
|     fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { | ||||
|         Some(self.cmp(other)) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Ord for TypedSignature { | ||||
|     fn cmp(&self, other: &Self) -> cmp::Ordering { | ||||
|         let x = compare_crypto_kind(&self.kind, &other.kind); | ||||
|         if x != cmp::Ordering::Equal { | ||||
|             return x; | ||||
|         } | ||||
|         self.signature.cmp(&other.signature) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Display for TypedSignature { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { | ||||
|         write!(f, "{}:{}", self.kind, self.signature.encode()) | ||||
|     } | ||||
| } | ||||
| impl FromStr for TypedSignature { | ||||
|     type Err = VeilidAPIError; | ||||
|     fn from_str(s: &str) -> Result<Self, Self::Err> { | ||||
|         let b = s.as_bytes(); | ||||
|         if b.len() != (5 + SIGNATURE_LENGTH_ENCODED) || b[4..5] != b":"[..] { | ||||
|             apibail_parse_error!("invalid typed signature", s); | ||||
|         } | ||||
|         let kind: CryptoKind = b[0..4].try_into()?; | ||||
|         let signature = Signature::try_decode_bytes(&b[5..])?; | ||||
|         Ok(Self { kind, signature }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive( | ||||
|     Clone, | ||||
|     Copy, | ||||
|     Debug, | ||||
|     PartialEq, | ||||
|     Eq, | ||||
|     Hash, | ||||
|     Serialize, | ||||
|     Deserialize, | ||||
|     RkyvArchive, | ||||
|     RkyvSerialize, | ||||
|     RkyvDeserialize, | ||||
| )] | ||||
| #[archive_attr(repr(C), derive(CheckBytes, Hash, PartialEq, Eq))] | ||||
| pub struct TypedKeySignature { | ||||
|     pub kind: CryptoKind, | ||||
|     pub key: PublicKey, | ||||
|     pub signature: Signature, | ||||
| } | ||||
|  | ||||
| impl TypedKeySignature { | ||||
|     pub fn new(kind: CryptoKind, key: PublicKey, signature: Signature) -> Self { | ||||
|         Self { | ||||
|             kind, | ||||
|             key, | ||||
|             signature, | ||||
|         } | ||||
|     } | ||||
|     pub fn as_typed_signature(&self) -> TypedSignature { | ||||
|         TypedSignature { | ||||
|             kind: self.kind, | ||||
|             signature: self.signature, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl PartialOrd for TypedKeySignature { | ||||
|     fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { | ||||
|         Some(self.cmp(other)) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Ord for TypedKeySignature { | ||||
|     fn cmp(&self, other: &Self) -> cmp::Ordering { | ||||
|         let x = compare_crypto_kind(&self.kind, &other.kind); | ||||
|         if x != cmp::Ordering::Equal { | ||||
|             return x; | ||||
|         } | ||||
|         let x = self.key.cmp(&other.key); | ||||
|         if x != cmp::Ordering::Equal { | ||||
|             return x; | ||||
|         } | ||||
|         self.signature.cmp(&other.signature) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Display for TypedKeySignature { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { | ||||
|         write!( | ||||
|             f, | ||||
|             "{}:{}:{}", | ||||
|             self.kind, | ||||
|             self.key.encode(), | ||||
|             self.signature.encode() | ||||
|         ) | ||||
|     } | ||||
| } | ||||
| impl FromStr for TypedKeySignature { | ||||
|     type Err = VeilidAPIError; | ||||
|     fn from_str(s: &str) -> Result<Self, Self::Err> { | ||||
|         let b = s.as_bytes(); | ||||
|         if b.len() != (5 + PUBLIC_KEY_LENGTH_ENCODED + 1 + SIGNATURE_LENGTH_ENCODED) | ||||
|             || b[4] != b':' | ||||
|             || b[5 + PUBLIC_KEY_LENGTH_ENCODED] != b':' | ||||
|         { | ||||
|             apibail_parse_error!("invalid typed key signature", s); | ||||
|         } | ||||
|         let kind: CryptoKind = b[0..4].try_into().expect("should not fail to convert"); | ||||
|         let key = PublicKey::try_decode_bytes(&b[5..5 + PUBLIC_KEY_LENGTH_ENCODED])?; | ||||
|         let signature = Signature::try_decode_bytes(&b[5 + PUBLIC_KEY_LENGTH_ENCODED + 1..])?; | ||||
|         Ok(Self { | ||||
|             kind, | ||||
|             key, | ||||
|             signature, | ||||
|         }) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										184
									
								
								veilid-core/src/crypto/types/crypto_typed.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								veilid-core/src/crypto/types/crypto_typed.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,184 @@ | ||||
| use super::*; | ||||
|  | ||||
| #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, RkyvArchive, RkyvSerialize, RkyvDeserialize)] | ||||
| #[archive_attr(repr(C), derive(CheckBytes, Hash, PartialEq, Eq))] | ||||
| pub struct CryptoTyped<K> | ||||
| where | ||||
|     K: Clone | ||||
|         + Copy | ||||
|         + fmt::Debug | ||||
|         + fmt::Display | ||||
|         + FromStr | ||||
|         + PartialEq | ||||
|         + Eq | ||||
|         + Ord | ||||
|         + PartialOrd | ||||
|         + Hash | ||||
|         + RkyvArchive | ||||
|         + Encodable, | ||||
|     <K as RkyvArchive>::Archived: Hash + PartialEq + Eq, | ||||
| { | ||||
|     pub kind: CryptoKind, | ||||
|     pub value: K, | ||||
| } | ||||
|  | ||||
| impl<K> CryptoTyped<K> | ||||
| where | ||||
|     K: Clone | ||||
|         + Copy | ||||
|         + fmt::Debug | ||||
|         + fmt::Display | ||||
|         + FromStr | ||||
|         + PartialEq | ||||
|         + Eq | ||||
|         + Ord | ||||
|         + PartialOrd | ||||
|         + Hash | ||||
|         + RkyvArchive | ||||
|         + Encodable, | ||||
|     <K as RkyvArchive>::Archived: Hash + PartialEq + Eq, | ||||
| { | ||||
|     pub fn new(kind: CryptoKind, value: K) -> Self { | ||||
|         Self { kind, value } | ||||
|     } | ||||
| } | ||||
| impl<K> PartialOrd for CryptoTyped<K> | ||||
| where | ||||
|     K: Clone | ||||
|         + Copy | ||||
|         + fmt::Debug | ||||
|         + fmt::Display | ||||
|         + FromStr | ||||
|         + PartialEq | ||||
|         + Eq | ||||
|         + Ord | ||||
|         + PartialOrd | ||||
|         + Hash | ||||
|         + RkyvArchive | ||||
|         + Encodable, | ||||
|     <K as RkyvArchive>::Archived: Hash + PartialEq + Eq, | ||||
| { | ||||
|     fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { | ||||
|         Some(self.cmp(other)) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<K> Ord for CryptoTyped<K> | ||||
| where | ||||
|     K: Clone | ||||
|         + Copy | ||||
|         + fmt::Debug | ||||
|         + fmt::Display | ||||
|         + FromStr | ||||
|         + PartialEq | ||||
|         + Eq | ||||
|         + Ord | ||||
|         + PartialOrd | ||||
|         + Hash | ||||
|         + RkyvArchive | ||||
|         + Encodable, | ||||
|     <K as RkyvArchive>::Archived: Hash + PartialEq + Eq, | ||||
| { | ||||
|     fn cmp(&self, other: &Self) -> cmp::Ordering { | ||||
|         let x = compare_crypto_kind(&self.kind, &other.kind); | ||||
|         if x != cmp::Ordering::Equal { | ||||
|             return x; | ||||
|         } | ||||
|         self.value.cmp(&other.value) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<K> fmt::Display for CryptoTyped<K> | ||||
| where | ||||
|     K: Clone | ||||
|         + Copy | ||||
|         + fmt::Debug | ||||
|         + fmt::Display | ||||
|         + FromStr | ||||
|         + PartialEq | ||||
|         + Eq | ||||
|         + Ord | ||||
|         + PartialOrd | ||||
|         + Hash | ||||
|         + RkyvArchive | ||||
|         + Encodable, | ||||
|     <K as RkyvArchive>::Archived: Hash + PartialEq + Eq, | ||||
| { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { | ||||
|         write!(f, "{}:{}", self.kind, self.value) | ||||
|     } | ||||
| } | ||||
| impl<K> FromStr for CryptoTyped<K> | ||||
| where | ||||
|     K: Clone | ||||
|         + Copy | ||||
|         + fmt::Debug | ||||
|         + fmt::Display | ||||
|         + FromStr | ||||
|         + PartialEq | ||||
|         + Eq | ||||
|         + Ord | ||||
|         + PartialOrd | ||||
|         + Hash | ||||
|         + RkyvArchive | ||||
|         + Encodable, | ||||
|     <K as RkyvArchive>::Archived: Hash + PartialEq + Eq, | ||||
| { | ||||
|     type Err = VeilidAPIError; | ||||
|     fn from_str(s: &str) -> Result<Self, Self::Err> { | ||||
|         let b = s.as_bytes(); | ||||
|         if b.len() != (5 + K::encoded_len()) || b[4..5] != b":"[..] { | ||||
|             apibail_parse_error!("invalid typed key", s); | ||||
|         } | ||||
|         let kind: CryptoKind = b[0..4].try_into().expect("should not fail to convert"); | ||||
|         let value = K::try_decode_bytes(&b[5..])?; | ||||
|         Ok(Self { kind, value }) | ||||
|     } | ||||
| } | ||||
| impl<'de, K> Deserialize<'de> for CryptoTyped<K> | ||||
| where | ||||
|     K: Clone | ||||
|         + Copy | ||||
|         + fmt::Debug | ||||
|         + fmt::Display | ||||
|         + FromStr | ||||
|         + PartialEq | ||||
|         + Eq | ||||
|         + Ord | ||||
|         + PartialOrd | ||||
|         + Hash | ||||
|         + RkyvArchive | ||||
|         + Encodable, | ||||
|     <K as RkyvArchive>::Archived: Hash + PartialEq + Eq, | ||||
| { | ||||
|     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> | ||||
|     where | ||||
|         D: serde::Deserializer<'de>, | ||||
|     { | ||||
|         let s = <String as Deserialize>::deserialize(deserializer)?; | ||||
|         FromStr::from_str(&s).map_err(serde::de::Error::custom) | ||||
|     } | ||||
| } | ||||
| impl<K> Serialize for CryptoTyped<K> | ||||
| where | ||||
|     K: Clone | ||||
|         + Copy | ||||
|         + fmt::Debug | ||||
|         + fmt::Display | ||||
|         + FromStr | ||||
|         + PartialEq | ||||
|         + Eq | ||||
|         + Ord | ||||
|         + PartialOrd | ||||
|         + Hash | ||||
|         + RkyvArchive | ||||
|         + Encodable, | ||||
|     <K as RkyvArchive>::Archived: Hash + PartialEq + Eq, | ||||
| { | ||||
|     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | ||||
|     where | ||||
|         S: serde::Serializer, | ||||
|     { | ||||
|         serializer.collect_str(self) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										303
									
								
								veilid-core/src/crypto/types/crypto_typed_set.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										303
									
								
								veilid-core/src/crypto/types/crypto_typed_set.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,303 @@ | ||||
| use super::*; | ||||
|  | ||||
| #[derive( | ||||
|     Clone, | ||||
|     Debug, | ||||
|     Serialize, | ||||
|     Deserialize, | ||||
|     PartialOrd, | ||||
|     Ord, | ||||
|     PartialEq, | ||||
|     Eq, | ||||
|     Hash, | ||||
|     RkyvArchive, | ||||
|     RkyvSerialize, | ||||
|     RkyvDeserialize, | ||||
|     Default, | ||||
| )] | ||||
| #[archive_attr(repr(C), derive(CheckBytes, Hash, PartialEq, Eq))] | ||||
| #[serde(from = "Vec<CryptoTyped<K>>", into = "Vec<CryptoTyped<K>>")] | ||||
| pub struct CryptoTypedSet<K = PublicKey> | ||||
| where | ||||
|     K: Clone | ||||
|         + Copy | ||||
|         + fmt::Debug | ||||
|         + fmt::Display | ||||
|         + FromStr | ||||
|         + PartialEq | ||||
|         + Eq | ||||
|         + PartialOrd | ||||
|         + Ord | ||||
|         + Hash | ||||
|         + RkyvArchive | ||||
|         + Encodable, | ||||
|     <K as RkyvArchive>::Archived: Hash + PartialEq + Eq, | ||||
|     <Vec<CryptoTyped<K>> as RkyvArchive>::Archived: Hash + PartialEq + Eq, | ||||
| { | ||||
|     items: Vec<CryptoTyped<K>>, | ||||
| } | ||||
|  | ||||
| impl<K> CryptoTypedSet<K> | ||||
| where | ||||
|     K: Clone | ||||
|         + Copy | ||||
|         + fmt::Debug | ||||
|         + fmt::Display | ||||
|         + FromStr | ||||
|         + PartialEq | ||||
|         + Eq | ||||
|         + PartialOrd | ||||
|         + Ord | ||||
|         + Hash | ||||
|         + RkyvArchive | ||||
|         + Encodable, | ||||
|     <K as RkyvArchive>::Archived: Hash + PartialEq + Eq, | ||||
| { | ||||
|     pub fn new() -> Self { | ||||
|         Self { items: Vec::new() } | ||||
|     } | ||||
|     pub fn with_capacity(cap: usize) -> Self { | ||||
|         Self { | ||||
|             items: Vec::with_capacity(cap), | ||||
|         } | ||||
|     } | ||||
|     pub fn kinds(&self) -> Vec<CryptoKind> { | ||||
|         let mut out = Vec::new(); | ||||
|         for tk in &self.items { | ||||
|             out.push(tk.kind); | ||||
|         } | ||||
|         out.sort_by(compare_crypto_kind); | ||||
|         out | ||||
|     } | ||||
|     pub fn keys(&self) -> Vec<K> { | ||||
|         let mut out = Vec::new(); | ||||
|         for tk in &self.items { | ||||
|             out.push(tk.value); | ||||
|         } | ||||
|         out | ||||
|     } | ||||
|     pub fn get(&self, kind: CryptoKind) -> Option<CryptoTyped<K>> { | ||||
|         self.items.iter().find(|x| x.kind == kind).copied() | ||||
|     } | ||||
|     pub fn add(&mut self, typed_key: CryptoTyped<K>) { | ||||
|         for x in &mut self.items { | ||||
|             if x.kind == typed_key.kind { | ||||
|                 *x = typed_key; | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|         self.items.push(typed_key); | ||||
|         self.items.sort() | ||||
|     } | ||||
|     pub fn add_all(&mut self, typed_keys: &[CryptoTyped<K>]) { | ||||
|         'outer: for typed_key in typed_keys { | ||||
|             for x in &mut self.items { | ||||
|                 if x.kind == typed_key.kind { | ||||
|                     *x = *typed_key; | ||||
|                     continue 'outer; | ||||
|                 } | ||||
|             } | ||||
|             self.items.push(*typed_key); | ||||
|         } | ||||
|         self.items.sort() | ||||
|     } | ||||
|     pub fn remove(&mut self, kind: CryptoKind) { | ||||
|         if let Some(idx) = self.items.iter().position(|x| x.kind == kind) { | ||||
|             self.items.remove(idx); | ||||
|         } | ||||
|     } | ||||
|     pub fn remove_all(&mut self, kinds: &[CryptoKind]) { | ||||
|         for k in kinds { | ||||
|             self.remove(*k); | ||||
|         } | ||||
|     } | ||||
|     /// Return preferred typed key of our supported crypto kinds | ||||
|     pub fn best(&self) -> Option<CryptoTyped<K>> { | ||||
|         match self.items.first().copied() { | ||||
|             None => None, | ||||
|             Some(k) => { | ||||
|                 if !VALID_CRYPTO_KINDS.contains(&k.kind) { | ||||
|                     None | ||||
|                 } else { | ||||
|                     Some(k) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     pub fn len(&self) -> usize { | ||||
|         self.items.len() | ||||
|     } | ||||
|     pub fn iter(&self) -> core::slice::Iter<'_, CryptoTyped<K>> { | ||||
|         self.items.iter() | ||||
|     } | ||||
|     pub fn contains(&self, typed_key: &CryptoTyped<K>) -> bool { | ||||
|         self.items.contains(typed_key) | ||||
|     } | ||||
|     pub fn contains_any(&self, typed_keys: &[CryptoTyped<K>]) -> bool { | ||||
|         for typed_key in typed_keys { | ||||
|             if self.items.contains(typed_key) { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         false | ||||
|     } | ||||
|     pub fn contains_key(&self, key: &K) -> bool { | ||||
|         for tk in &self.items { | ||||
|             if tk.value == *key { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         false | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<K> core::ops::Deref for CryptoTypedSet<K> | ||||
| where | ||||
|     K: Clone | ||||
|         + Copy | ||||
|         + fmt::Debug | ||||
|         + fmt::Display | ||||
|         + FromStr | ||||
|         + PartialEq | ||||
|         + Eq | ||||
|         + PartialOrd | ||||
|         + Ord | ||||
|         + Hash | ||||
|         + RkyvArchive | ||||
|         + Encodable, | ||||
|     <K as RkyvArchive>::Archived: Hash + PartialEq + Eq, | ||||
| { | ||||
|     type Target = [CryptoTyped<K>]; | ||||
|  | ||||
|     #[inline] | ||||
|     fn deref(&self) -> &[CryptoTyped<K>] { | ||||
|         &self.items | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<K> fmt::Display for CryptoTypedSet<K> | ||||
| where | ||||
|     K: Clone | ||||
|         + Copy | ||||
|         + fmt::Debug | ||||
|         + fmt::Display | ||||
|         + FromStr | ||||
|         + PartialEq | ||||
|         + Eq | ||||
|         + PartialOrd | ||||
|         + Ord | ||||
|         + Hash | ||||
|         + RkyvArchive | ||||
|         + Encodable, | ||||
|     <K as RkyvArchive>::Archived: Hash + PartialEq + Eq, | ||||
| { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { | ||||
|         write!(f, "[")?; | ||||
|         let mut first = true; | ||||
|         for x in &self.items { | ||||
|             if !first { | ||||
|                 write!(f, ",")?; | ||||
|                 first = false; | ||||
|             } | ||||
|             write!(f, "{}", x)?; | ||||
|         } | ||||
|         write!(f, "]") | ||||
|     } | ||||
| } | ||||
| impl<K> FromStr for CryptoTypedSet<K> | ||||
| where | ||||
|     K: Clone | ||||
|         + Copy | ||||
|         + fmt::Debug | ||||
|         + fmt::Display | ||||
|         + FromStr | ||||
|         + PartialEq | ||||
|         + Eq | ||||
|         + PartialOrd | ||||
|         + Ord | ||||
|         + Hash | ||||
|         + RkyvArchive | ||||
|         + Encodable, | ||||
|     <K as RkyvArchive>::Archived: Hash + PartialEq + Eq, | ||||
| { | ||||
|     type Err = VeilidAPIError; | ||||
|     fn from_str(s: &str) -> Result<Self, Self::Err> { | ||||
|         let mut items = Vec::new(); | ||||
|         if s.len() < 2 { | ||||
|             apibail_parse_error!("invalid length", s); | ||||
|         } | ||||
|         if &s[0..1] != "[" || &s[(s.len() - 1)..] != "]" { | ||||
|             apibail_parse_error!("invalid format", s); | ||||
|         } | ||||
|         for x in s[1..s.len() - 1].split(",") { | ||||
|             let tk = CryptoTyped::<K>::from_str(x.trim())?; | ||||
|             items.push(tk); | ||||
|         } | ||||
|  | ||||
|         Ok(Self { items }) | ||||
|     } | ||||
| } | ||||
| impl<K> From<CryptoTyped<K>> for CryptoTypedSet<K> | ||||
| where | ||||
|     K: Clone | ||||
|         + Copy | ||||
|         + fmt::Debug | ||||
|         + fmt::Display | ||||
|         + FromStr | ||||
|         + PartialEq | ||||
|         + Eq | ||||
|         + PartialOrd | ||||
|         + Ord | ||||
|         + Hash | ||||
|         + RkyvArchive | ||||
|         + Encodable, | ||||
|     <K as RkyvArchive>::Archived: Hash + PartialEq + Eq, | ||||
| { | ||||
|     fn from(x: CryptoTyped<K>) -> Self { | ||||
|         let mut tks = CryptoTypedSet::<K>::with_capacity(1); | ||||
|         tks.add(x); | ||||
|         tks | ||||
|     } | ||||
| } | ||||
| impl<K> From<Vec<CryptoTyped<K>>> for CryptoTypedSet<K> | ||||
| where | ||||
|     K: Clone | ||||
|         + Copy | ||||
|         + fmt::Debug | ||||
|         + fmt::Display | ||||
|         + FromStr | ||||
|         + PartialEq | ||||
|         + Eq | ||||
|         + PartialOrd | ||||
|         + Ord | ||||
|         + Hash | ||||
|         + RkyvArchive | ||||
|         + Encodable, | ||||
|     <K as RkyvArchive>::Archived: Hash + PartialEq + Eq, | ||||
| { | ||||
|     fn from(x: Vec<CryptoTyped<K>>) -> Self { | ||||
|         let mut tks = CryptoTypedSet::<K>::with_capacity(x.len()); | ||||
|         tks.add_all(&x); | ||||
|         tks | ||||
|     } | ||||
| } | ||||
| impl<K> Into<Vec<CryptoTyped<K>>> for CryptoTypedSet<K> | ||||
| where | ||||
|     K: Clone | ||||
|         + Copy | ||||
|         + fmt::Debug | ||||
|         + fmt::Display | ||||
|         + FromStr | ||||
|         + PartialEq | ||||
|         + Eq | ||||
|         + PartialOrd | ||||
|         + Ord | ||||
|         + Hash | ||||
|         + RkyvArchive | ||||
|         + Encodable, | ||||
|     <K as RkyvArchive>::Archived: Hash + PartialEq + Eq, | ||||
| { | ||||
|     fn into(self) -> Vec<CryptoTyped<K>> { | ||||
|         self.items | ||||
|     } | ||||
| } | ||||
							
								
								
									
										85
									
								
								veilid-core/src/crypto/types/keypair.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								veilid-core/src/crypto/types/keypair.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,85 @@ | ||||
| use super::*; | ||||
|  | ||||
| #[derive( | ||||
|     Clone, | ||||
|     Copy, | ||||
|     Serialize, | ||||
|     Deserialize, | ||||
|     PartialOrd, | ||||
|     Ord, | ||||
|     PartialEq, | ||||
|     Eq, | ||||
|     Hash, | ||||
|     RkyvArchive, | ||||
|     RkyvSerialize, | ||||
|     RkyvDeserialize, | ||||
| )] | ||||
| #[archive_attr(repr(C), derive(CheckBytes, Hash, PartialEq, Eq))] | ||||
| pub struct KeyPair { | ||||
|     pub key: PublicKey, | ||||
|     pub secret: SecretKey, | ||||
| } | ||||
|  | ||||
| impl KeyPair { | ||||
|     pub fn new(key: PublicKey, secret: SecretKey) -> Self { | ||||
|         Self { key, secret } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl Encodable for KeyPair { | ||||
|     fn encode(&self) -> String { | ||||
|         format!("{}:{}", self.key.encode(), self.secret.encode()) | ||||
|     } | ||||
|     fn encoded_len() -> usize { | ||||
|         PublicKey::encoded_len() + 1 + SecretKey::encoded_len() | ||||
|     } | ||||
|     fn try_decode_bytes(b: &[u8]) -> Result<Self, VeilidAPIError> { | ||||
|         if b.len() != Self::encoded_len() { | ||||
|             apibail_parse_error!("input has wrong encoded length", format!("len={}", b.len())); | ||||
|         } | ||||
|         let key = PublicKey::try_decode_bytes(&b[0..PublicKey::encoded_len()])?; | ||||
|         let secret = SecretKey::try_decode_bytes(&b[(PublicKey::encoded_len() + 1)..])?; | ||||
|         Ok(KeyPair { key, secret }) | ||||
|     } | ||||
| } | ||||
| impl fmt::Display for KeyPair { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         write!(f, "{}", self.encode()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Debug for KeyPair { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         write!(f, concat!(stringify!($name), "("))?; | ||||
|         write!(f, "{}", self.encode())?; | ||||
|         write!(f, ")") | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl From<&KeyPair> for String { | ||||
|     fn from(value: &KeyPair) -> Self { | ||||
|         value.encode() | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl FromStr for KeyPair { | ||||
|     type Err = VeilidAPIError; | ||||
|  | ||||
|     fn from_str(s: &str) -> Result<Self, Self::Err> { | ||||
|         KeyPair::try_from(s) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl TryFrom<String> for KeyPair { | ||||
|     type Error = VeilidAPIError; | ||||
|     fn try_from(value: String) -> Result<Self, Self::Error> { | ||||
|         KeyPair::try_from(value.as_str()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl TryFrom<&str> for KeyPair { | ||||
|     type Error = VeilidAPIError; | ||||
|     fn try_from(value: &str) -> Result<Self, Self::Error> { | ||||
|         Self::try_decode(value) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										59
									
								
								veilid-core/src/crypto/types/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								veilid-core/src/crypto/types/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | ||||
| use super::*; | ||||
|  | ||||
| use core::cmp::{Eq, Ord, PartialEq, PartialOrd}; | ||||
| use core::convert::TryInto; | ||||
| use core::fmt; | ||||
| use core::hash::Hash; | ||||
|  | ||||
| use rkyv::{Archive as RkyvArchive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize}; | ||||
|  | ||||
| /// Cryptography version fourcc code | ||||
| pub type CryptoKind = FourCC; | ||||
|  | ||||
| /// Sort best crypto kinds first | ||||
| /// Better crypto kinds are 'less', ordered toward the front of a list | ||||
| pub fn compare_crypto_kind(a: &CryptoKind, b: &CryptoKind) -> cmp::Ordering { | ||||
|     let a_idx = VALID_CRYPTO_KINDS.iter().position(|k| k == a); | ||||
|     let b_idx = VALID_CRYPTO_KINDS.iter().position(|k| k == b); | ||||
|     if let Some(a_idx) = a_idx { | ||||
|         if let Some(b_idx) = b_idx { | ||||
|             // Both are valid, prefer better crypto kind | ||||
|             a_idx.cmp(&b_idx) | ||||
|         } else { | ||||
|             // A is valid, B is not | ||||
|             cmp::Ordering::Less | ||||
|         } | ||||
|     } else if b_idx.is_some() { | ||||
|         // B is valid, A is not | ||||
|         cmp::Ordering::Greater | ||||
|     } else { | ||||
|         // Both are invalid, so use lex comparison | ||||
|         a.cmp(b) | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Intersection of crypto kind vectors | ||||
| pub fn common_crypto_kinds(a: &[CryptoKind], b: &[CryptoKind]) -> Vec<CryptoKind> { | ||||
|     let mut out = Vec::new(); | ||||
|     for ack in a { | ||||
|         if b.contains(ack) { | ||||
|             out.push(*ack); | ||||
|         } | ||||
|     } | ||||
|     out | ||||
| } | ||||
|  | ||||
| mod crypto_typed; | ||||
| mod crypto_typed_set; | ||||
| mod keypair; | ||||
|  | ||||
| pub use crypto_typed::*; | ||||
| pub use crypto_typed_set::*; | ||||
| pub use keypair::*; | ||||
|  | ||||
| pub type TypedKey = CryptoTyped<PublicKey>; | ||||
| pub type TypedSecret = CryptoTyped<SecretKey>; | ||||
| pub type TypedKeyPair = CryptoTyped<KeyPair>; | ||||
| pub type TypedSignature = CryptoTyped<Signature>; | ||||
| pub type TypedKeySet = CryptoTypedSet<PublicKey>; | ||||
| pub type TypedSecretSet = CryptoTypedSet<SecretKey>; | ||||
| @@ -32,7 +32,16 @@ fn ed25519_to_x25519_sk(key: &ed::SecretKey) -> Result<xd::StaticSecret, VeilidA | ||||
|     Ok(xd::StaticSecret::from(lowbytes)) | ||||
| } | ||||
|  | ||||
| /// V1 CryptoSystem | ||||
| pub fn vld0_generate_keypair() -> (PublicKey, SecretKey) { | ||||
|     let mut csprng = VeilidRng {}; | ||||
|     let keypair = ed::Keypair::generate(&mut csprng); | ||||
|     let dht_key = PublicKey::new(keypair.public.to_bytes()); | ||||
|     let dht_key_secret = SecretKey::new(keypair.secret.to_bytes()); | ||||
|  | ||||
|     (dht_key, dht_key_secret) | ||||
| } | ||||
|  | ||||
| /// V0 CryptoSystem | ||||
| #[derive(Clone)] | ||||
| pub struct CryptoSystemVLD0 { | ||||
|     crypto: Crypto, | ||||
| @@ -87,12 +96,7 @@ impl CryptoSystem for CryptoSystemVLD0 { | ||||
|         Ok(SharedSecret::new(sk_xd.diffie_hellman(&pk_xd).to_bytes())) | ||||
|     } | ||||
|     fn generate_keypair(&self) -> (PublicKey, SecretKey) { | ||||
|         let mut csprng = VeilidRng {}; | ||||
|         let keypair = ed::Keypair::generate(&mut csprng); | ||||
|         let dht_key = PublicKey::new(keypair.public.to_bytes()); | ||||
|         let dht_key_secret = SecretKey::new(keypair.secret.to_bytes()); | ||||
|  | ||||
|         (dht_key, dht_key_secret) | ||||
|         vld0_generate_keypair() | ||||
|     } | ||||
|     fn generate_hash(&self, data: &[u8]) -> PublicKey { | ||||
|         PublicKey::new(*blake3::hash(data).as_bytes()) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user