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