mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-03 19:13:43 +02:00
Identities, buffers, crypto, and more, all getting rustier.
This commit is contained in:
parent
df25f09e6b
commit
a88d89a854
8 changed files with 346 additions and 91 deletions
|
@ -2,6 +2,7 @@ use std::convert::TryInto;
|
|||
use std::io::Write;
|
||||
|
||||
use ed25519_dalek::Digest;
|
||||
use std::error::Error;
|
||||
|
||||
pub const C25519_PUBLIC_KEY_SIZE: usize = 32;
|
||||
pub const C25519_SECRET_KEY_SIZE: usize = 32;
|
||||
|
@ -64,21 +65,19 @@ impl Ed25519KeyPair {
|
|||
Ed25519KeyPair(ed25519_dalek::Keypair::generate(&mut rng))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn from_keys(public_key: &[u8], secret_key: &[u8]) -> Ed25519KeyPair {
|
||||
let mut tmp = [0_u8; 64];
|
||||
tmp[0..32].copy_from_slice(secret_key);
|
||||
tmp[32..64].copy_from_slice(public_key);
|
||||
Ed25519KeyPair(ed25519_dalek::Keypair::from_bytes(&tmp).unwrap())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn from_bytes(public_bytes: &[u8], secret_bytes: &[u8]) -> Option<Ed25519KeyPair> {
|
||||
if public_bytes.len() == ED25519_PUBLIC_KEY_SIZE && secret_bytes.len() == ED25519_SECRET_KEY_SIZE {
|
||||
let mut tmp = [0_u8; 64];
|
||||
tmp[0..32].copy_from_slice(public_bytes);
|
||||
tmp[32..64].copy_from_slice(secret_bytes);
|
||||
Some(Ed25519KeyPair(ed25519_dalek::Keypair::from_bytes(&tmp).unwrap()))
|
||||
let pk = ed25519_dalek::PublicKey::from_bytes(public_bytes);
|
||||
let sk = ed25519_dalek::SecretKey::from_bytes(secret_bytes);
|
||||
if pk.is_ok() && sk.is_ok() {
|
||||
Some(Ed25519KeyPair(ed25519_dalek::Keypair {
|
||||
public: pk.unwrap(),
|
||||
secret: sk.unwrap(),
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
@ -210,6 +210,15 @@ impl P521PublicKey {
|
|||
}
|
||||
}
|
||||
|
||||
impl PartialEq for P521PublicKey {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.public_key_bytes.eq(&other.public_key_bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for P521PublicKey {}
|
||||
|
||||
impl Clone for P521PublicKey {
|
||||
fn clone(&self) -> Self {
|
||||
P521PublicKey::from_bytes(&self.public_key_bytes).unwrap()
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
use std::error::Error;
|
||||
use std::fmt::{Display, Debug};
|
||||
|
||||
pub struct InvalidFormatError(pub(crate) &'static str);
|
||||
pub struct InvalidFormatError;
|
||||
|
||||
impl Display for InvalidFormatError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "UnmarshalError: {}", self.0)
|
||||
f.write_str("InvalidFormatError")
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for InvalidFormatError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "UnmarshalError: {}", self.0)
|
||||
f.write_str("InvalidFormatError")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ impl Address {
|
|||
if b.len() >= 5 {
|
||||
Ok(Address((b[0] as u64) << 32 | (b[1] as u64) << 24 | (b[2] as u64) << 16 | (b[3] as u64) << 8 | b[4] as u64))
|
||||
} else {
|
||||
Err(InvalidFormatError("invalid ZeroTier address"))
|
||||
Err(InvalidFormatError)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
use std::mem::size_of;
|
||||
use std::mem::{size_of, MaybeUninit};
|
||||
use std::marker::PhantomData;
|
||||
use std::io::Write;
|
||||
|
||||
const OVERFLOW_ERR_MSG: &'static str = "overflow";
|
||||
|
||||
/// Annotates a type as containing only primitive types like integers and arrays.
|
||||
/// This means it's safe to abuse with raw copy, raw zero, or "type punning."
|
||||
/// This is ONLY used for packed protocol header or segment objects.
|
||||
|
@ -35,6 +37,21 @@ impl<H: RawObject, const L: usize> Buffer<H, L> {
|
|||
Self::default()
|
||||
}
|
||||
|
||||
/// Create a buffer that contains a copy of a slice.
|
||||
/// If the slice is larger than the maximum size L of the buffer, only the first L bytes
|
||||
/// are copied and the rest is ignored.
|
||||
#[inline(always)]
|
||||
pub fn from_bytes_truncate(b: &[u8]) -> Self {
|
||||
let l = b.len().min(L);
|
||||
unsafe {
|
||||
let mut tmp = MaybeUninit::<Self>::uninit().assume_init();
|
||||
tmp.0 = l;
|
||||
tmp.1[0..l].copy_from_slice(b);
|
||||
tmp.1[l..L].fill(0);
|
||||
tmp
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a slice containing the entire buffer in raw form including the header.
|
||||
#[inline(always)]
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
|
@ -80,7 +97,7 @@ impl<H: RawObject, const L: usize> Buffer<H, L> {
|
|||
Ok(initializer(&mut *self.1.as_mut_ptr().cast::<u8>().offset(ptr as isize).cast::<T>()))
|
||||
}
|
||||
} else {
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "overflow"))
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, OVERFLOW_ERR_MSG))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,7 +114,7 @@ impl<H: RawObject, const L: usize> Buffer<H, L> {
|
|||
Ok(initializer(&mut *self.1.as_mut_ptr().cast::<u8>().offset(ptr as isize).cast::<[u8; N]>()))
|
||||
}
|
||||
} else {
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "overflow"))
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, OVERFLOW_ERR_MSG))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,7 +128,7 @@ impl<H: RawObject, const L: usize> Buffer<H, L> {
|
|||
self.0 = end;
|
||||
Ok(initializer(&mut self.1[ptr..end]))
|
||||
} else {
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "overflow"))
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, OVERFLOW_ERR_MSG))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,7 +143,7 @@ impl<H: RawObject, const L: usize> Buffer<H, L> {
|
|||
self.1[ptr..end].copy_from_slice(buf);
|
||||
Ok(())
|
||||
} else {
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "overflow"))
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, OVERFLOW_ERR_MSG))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,7 +158,7 @@ impl<H: RawObject, const L: usize> Buffer<H, L> {
|
|||
self.1[ptr..end].copy_from_slice(buf);
|
||||
Ok(())
|
||||
} else {
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "overflow"))
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, OVERFLOW_ERR_MSG))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,7 +171,7 @@ impl<H: RawObject, const L: usize> Buffer<H, L> {
|
|||
self.1[ptr] = i;
|
||||
Ok(())
|
||||
} else {
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "overflow"))
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, OVERFLOW_ERR_MSG))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,7 +185,7 @@ impl<H: RawObject, const L: usize> Buffer<H, L> {
|
|||
crate::util::integer_store_be_u16(i, &mut self.1[ptr..end]);
|
||||
Ok(())
|
||||
} else {
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "overflow"))
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, OVERFLOW_ERR_MSG))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -182,7 +199,7 @@ impl<H: RawObject, const L: usize> Buffer<H, L> {
|
|||
crate::util::integer_store_be_u32(i, &mut self.1[ptr..end]);
|
||||
Ok(())
|
||||
} else {
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "overflow"))
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, OVERFLOW_ERR_MSG))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,7 +213,7 @@ impl<H: RawObject, const L: usize> Buffer<H, L> {
|
|||
crate::util::integer_store_be_u64(i, &mut self.1[ptr..end]);
|
||||
Ok(())
|
||||
} else {
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "overflow"))
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, OVERFLOW_ERR_MSG))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -217,7 +234,7 @@ impl<H: RawObject, const L: usize> Buffer<H, L> {
|
|||
Ok(&*self.1.as_ptr().cast::<u8>().offset(ptr as isize).cast::<T>())
|
||||
}
|
||||
} else {
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "overflow"))
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, OVERFLOW_ERR_MSG))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -233,7 +250,7 @@ impl<H: RawObject, const L: usize> Buffer<H, L> {
|
|||
Ok(&*self.1.as_ptr().cast::<u8>().offset(ptr as isize).cast::<[u8; S]>())
|
||||
}
|
||||
} else {
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "overflow"))
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, OVERFLOW_ERR_MSG))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -246,7 +263,7 @@ impl<H: RawObject, const L: usize> Buffer<H, L> {
|
|||
*cursor = end;
|
||||
Ok(&self.1[ptr..end])
|
||||
} else {
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "overflow"))
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, OVERFLOW_ERR_MSG))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -258,7 +275,7 @@ impl<H: RawObject, const L: usize> Buffer<H, L> {
|
|||
*cursor = ptr + 1;
|
||||
Ok(self.1[ptr])
|
||||
} else {
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "overflow"))
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, OVERFLOW_ERR_MSG))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -271,7 +288,7 @@ impl<H: RawObject, const L: usize> Buffer<H, L> {
|
|||
*cursor = end;
|
||||
Ok(crate::util::integer_load_be_u16(&self.1[ptr..end]))
|
||||
} else {
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "overflow"))
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, OVERFLOW_ERR_MSG))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -284,7 +301,7 @@ impl<H: RawObject, const L: usize> Buffer<H, L> {
|
|||
*cursor = end;
|
||||
Ok(crate::util::integer_load_be_u32(&self.1[ptr..end]))
|
||||
} else {
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "overflow"))
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, OVERFLOW_ERR_MSG))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -297,7 +314,7 @@ impl<H: RawObject, const L: usize> Buffer<H, L> {
|
|||
*cursor = end;
|
||||
Ok(crate::util::integer_load_be_u64(&self.1[ptr..end]))
|
||||
} else {
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "overflow"))
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, OVERFLOW_ERR_MSG))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -312,7 +329,7 @@ impl<H: RawObject, const L: usize> Write for Buffer<H, L> {
|
|||
self.1[ptr..end].copy_from_slice(buf);
|
||||
Ok(buf.len())
|
||||
} else {
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "overflow"))
|
||||
std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, OVERFLOW_ERR_MSG))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use std::alloc::{Layout, dealloc, alloc};
|
||||
use std::ptr::{slice_from_raw_parts_mut, slice_from_raw_parts};
|
||||
use std::io::Write;
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::vl1::Address;
|
||||
use crate::vl1::buffer::{Buffer, RawObject, NoHeader};
|
||||
|
@ -9,9 +10,14 @@ use crate::crypto::p521::{P521KeyPair, P521PublicKey, P521_ECDSA_SIGNATURE_SIZE,
|
|||
use crate::crypto::hash::{SHA384, SHA512, SHA512_HASH_SIZE};
|
||||
use crate::crypto::balloon;
|
||||
use crate::crypto::salsa::Salsa;
|
||||
use crate::error::InvalidFormatError;
|
||||
use std::convert::TryInto;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
// Memory parameter for V0 address derivation work function.
|
||||
const V0_IDENTITY_GEN_MEMORY: usize = 2097152;
|
||||
|
||||
// Balloon hash parameters for V1 address derivation work function.
|
||||
const V1_BALLOON_SPACE_COST: usize = 16384;
|
||||
const V1_BALLOON_TIME_COST: usize = 3;
|
||||
const V1_BALLOON_DELTA: usize = 3;
|
||||
|
@ -85,8 +91,8 @@ impl Identity {
|
|||
let c25519 = C25519KeyPair::generate();
|
||||
let c25519_pub_bytes = c25519.public_bytes();
|
||||
|
||||
sha.update(&ed25519_pub_bytes);
|
||||
sha.update(&c25519_pub_bytes);
|
||||
sha.update(&ed25519_pub_bytes);
|
||||
let mut digest = sha.finish();
|
||||
|
||||
v0_frankenhash(&mut digest, genmem_ptr);
|
||||
|
@ -165,17 +171,41 @@ impl Identity {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get this identity's 40-bit address.
|
||||
#[inline(always)]
|
||||
pub fn address(&self) -> Address {
|
||||
self.address
|
||||
}
|
||||
|
||||
/// Compute a SHA384 hash of this identity's keys, including private keys if present.
|
||||
pub fn hash_all_keys(&self) -> [u8; 48] {
|
||||
let mut sha = SHA384::new();
|
||||
sha.update(&self.c25519);
|
||||
sha.update(&self.ed25519);
|
||||
self.v1.as_ref().map(|p521| {
|
||||
sha.update((*p521).0.public_key_bytes());
|
||||
sha.update((*p521).1.public_key_bytes());
|
||||
});
|
||||
self.secrets.as_ref().map(|secrets| {
|
||||
sha.update(&secrets.c25519.secret_bytes());
|
||||
sha.update(&secrets.ed25519.secret_bytes());
|
||||
secrets.v1.as_ref().map(|p521_secrets| {
|
||||
sha.update((*p521_secrets).0.secret_key_bytes());
|
||||
sha.update((*p521_secrets).1.secret_key_bytes());
|
||||
});
|
||||
});
|
||||
sha.finish()
|
||||
}
|
||||
|
||||
/// Locally validate this identity.
|
||||
/// This can take a few milliseconds, especially on slower systems. V0 identities are slower
|
||||
/// to fully validate than V1 identities.
|
||||
pub fn locally_validate(&self) -> bool {
|
||||
if self.v1.is_some() {
|
||||
if self.address.is_valid() {
|
||||
if self.address.is_valid() {
|
||||
if self.v1.is_none() {
|
||||
let genmem_layout = Layout::from_size_align(V0_IDENTITY_GEN_MEMORY, 8).unwrap();
|
||||
let genmem_ptr = unsafe { alloc(genmem_layout) };
|
||||
if genmem_ptr.is_null() {
|
||||
false
|
||||
} else {
|
||||
if !genmem_ptr.is_null() {
|
||||
let mut sha = SHA512::new();
|
||||
sha.update(&self.c25519);
|
||||
sha.update(&self.ed25519);
|
||||
|
@ -183,12 +213,10 @@ impl Identity {
|
|||
v0_frankenhash(&mut digest, genmem_ptr);
|
||||
unsafe { dealloc(genmem_ptr, genmem_layout) };
|
||||
(digest[0] < 17) && Address::from_bytes(&digest[59..64]).unwrap().eq(&self.address)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
if self.address.is_valid() {
|
||||
let p521 = self.v1.as_ref().unwrap();
|
||||
let mut signing_buf = [0_u8; C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE];
|
||||
signing_buf[0..C25519_PUBLIC_KEY_SIZE].copy_from_slice(&self.c25519);
|
||||
|
@ -201,9 +229,9 @@ impl Identity {
|
|||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -263,23 +291,9 @@ impl Identity {
|
|||
self.secrets.is_some()
|
||||
}
|
||||
|
||||
/// Get this identity in string format, including its secret keys.
|
||||
pub fn to_secret_string(&self) -> String {
|
||||
self.secrets.as_ref().map_or_else(|| {
|
||||
self.to_string()
|
||||
}, |secrets| {
|
||||
secrets.v1.as_ref().map_or_else(|| {
|
||||
format!("{}:{}{}", self.to_string(), crate::util::hex::to_string(&secrets.c25519.secret_bytes()), crate::util::hex::to_string(&secrets.ed25519.secret_bytes()))
|
||||
}, |p521_secret| {
|
||||
let mut secret_key_blob: Vec<u8> = Vec::new();
|
||||
secret_key_blob.reserve(C25519_SECRET_KEY_SIZE + ED25519_SECRET_KEY_SIZE + P521_SECRET_KEY_SIZE + P521_SECRET_KEY_SIZE);
|
||||
let _ = secret_key_blob.write_all(&secrets.c25519.secret_bytes());
|
||||
let _ = secret_key_blob.write_all(&secrets.ed25519.secret_bytes());
|
||||
let _ = secret_key_blob.write_all(p521_secret.0.secret_key_bytes());
|
||||
let _ = secret_key_blob.write_all(p521_secret.1.secret_key_bytes());
|
||||
format!("{}:{}", self.to_string(), base64::encode_config(secret_key_blob.as_slice(), base64::URL_SAFE_NO_PAD))
|
||||
})
|
||||
})
|
||||
/// Erase secrets from this identity object, if present.
|
||||
pub fn forget_secrets(&mut self) {
|
||||
let _ = self.secrets.take();
|
||||
}
|
||||
|
||||
/// Append this in binary format to a buffer.
|
||||
|
@ -308,11 +322,9 @@ impl Identity {
|
|||
buf.append_u8(0)?; // 0 secret bytes if not adding any
|
||||
}
|
||||
} else {
|
||||
buf.append_and_init_bytes_fixed(|b: &mut [u8; 1 + C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE]| {
|
||||
b[0] = 0; // type 0
|
||||
b[1..(1 + C25519_PUBLIC_KEY_SIZE)].copy_from_slice(&self.c25519);
|
||||
b[(1 + C25519_PUBLIC_KEY_SIZE)..(1 + C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE)].copy_from_slice(&self.ed25519);
|
||||
})?;
|
||||
buf.append_u8(0)?; // type 0
|
||||
buf.append_bytes_fixed(&self.c25519)?;
|
||||
buf.append_bytes_fixed(&self.ed25519)?;
|
||||
if include_private && self.secrets.is_some() {
|
||||
let secrets = self.secrets.as_ref().unwrap();
|
||||
buf.append_u8((C25519_SECRET_KEY_SIZE + ED25519_SECRET_KEY_SIZE) as u8)?;
|
||||
|
@ -400,11 +412,38 @@ impl Identity {
|
|||
}
|
||||
|
||||
/// Get this identity in byte array format.
|
||||
pub fn marshal_to_vec(&self, include_private: bool) -> Vec<u8> {
|
||||
pub fn marshal_to_bytes(&self, include_private: bool) -> Vec<u8> {
|
||||
let mut buf: Buffer<NoHeader, 2048> = Buffer::new();
|
||||
self.marshal(&mut buf, include_private).expect("overflow");
|
||||
buf.as_bytes().to_vec()
|
||||
}
|
||||
|
||||
/// Unmarshal an identity from a byte slice.
|
||||
/// On success the identity and the number of bytes actually read from the slice are
|
||||
/// returned.
|
||||
pub fn unmarshal_from_bytes(bytes: &[u8]) -> std::io::Result<(Identity, usize)> {
|
||||
let buf = Buffer::<NoHeader, 2048>::from_bytes_truncate(bytes);
|
||||
let mut cursor: usize = 0;
|
||||
let id = Self::unmarshal(&buf, &mut cursor)?;
|
||||
Ok((id, cursor))
|
||||
}
|
||||
|
||||
/// Get this identity in string format, including its secret keys.
|
||||
pub fn to_secret_string(&self) -> String {
|
||||
self.secrets.as_ref().map_or_else(|| self.to_string(), |secrets| {
|
||||
secrets.v1.as_ref().map_or_else(|| {
|
||||
format!("{}:{}{}", self.to_string(), crate::util::hex::to_string(&secrets.c25519.secret_bytes()), crate::util::hex::to_string(&secrets.ed25519.secret_bytes()))
|
||||
}, |p521_secret| {
|
||||
let mut secret_key_blob: Vec<u8> = Vec::new();
|
||||
secret_key_blob.reserve(C25519_SECRET_KEY_SIZE + ED25519_SECRET_KEY_SIZE + P521_SECRET_KEY_SIZE + P521_SECRET_KEY_SIZE);
|
||||
let _ = secret_key_blob.write_all(&secrets.c25519.secret_bytes());
|
||||
let _ = secret_key_blob.write_all(&secrets.ed25519.secret_bytes());
|
||||
let _ = secret_key_blob.write_all(p521_secret.0.secret_key_bytes());
|
||||
let _ = secret_key_blob.write_all(p521_secret.1.secret_key_bytes());
|
||||
format!("{}:{}", self.to_string(), base64::encode_config(secret_key_blob.as_slice(), base64::URL_SAFE_NO_PAD))
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for Identity {
|
||||
|
@ -425,26 +464,219 @@ impl ToString for Identity {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[allow(unused_imports)]
|
||||
use crate::vl1::Identity;
|
||||
#[allow(unused_imports)]
|
||||
use crate::vl1::identity::Type;
|
||||
impl FromStr for Identity {
|
||||
type Err = InvalidFormatError;
|
||||
|
||||
#[test]
|
||||
fn p521() {
|
||||
/*
|
||||
let mut ms = 0.0;
|
||||
let mut id: Option<Identity> = None;
|
||||
for _ in 0..64 {
|
||||
let start = std::time::SystemTime::now();
|
||||
id.replace(Identity::generate(Type::P521));
|
||||
let duration = std::time::SystemTime::now().duration_since(start).unwrap();
|
||||
ms += duration.as_nanos() as f64 / 1000000.0;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let fields_v: Vec<&str> = s.split(':').collect();
|
||||
let fields = fields_v.as_slice();
|
||||
if fields.len() == 3 || fields.len() == 4 {
|
||||
let addr = Address::from_str(fields[0])?;
|
||||
if fields[1] == "0" {
|
||||
let public_keys = crate::util::hex::from_string(fields[2]);
|
||||
if public_keys.len() == (C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE) {
|
||||
let mut secrets: Option<IdentitySecrets> = None;
|
||||
if fields.len() == 4 {
|
||||
let secret_keys = crate::util::hex::from_string(fields[3]);
|
||||
if secret_keys.len() == (C25519_SECRET_KEY_SIZE + ED25519_SECRET_KEY_SIZE) {
|
||||
let c25519_secret = C25519KeyPair::from_bytes(&public_keys.as_slice()[0..32], &secret_keys.as_slice()[0..32]);
|
||||
let ed25519_secret = Ed25519KeyPair::from_bytes(&public_keys.as_slice()[32..64], &secret_keys.as_slice()[32..64]);
|
||||
if c25519_secret.is_some() && ed25519_secret.is_some() {
|
||||
secrets = Some(IdentitySecrets {
|
||||
c25519: c25519_secret.unwrap(),
|
||||
ed25519: ed25519_secret.unwrap(),
|
||||
v1: None,
|
||||
});
|
||||
} else {
|
||||
return Err(InvalidFormatError);
|
||||
}
|
||||
} else {
|
||||
return Err(InvalidFormatError);
|
||||
}
|
||||
}
|
||||
return Ok(Identity {
|
||||
address: addr,
|
||||
c25519: public_keys.as_slice()[0..32].try_into().unwrap(),
|
||||
ed25519: public_keys.as_slice()[32..64].try_into().unwrap(),
|
||||
v1: None,
|
||||
secrets,
|
||||
});
|
||||
}
|
||||
} else if fields[1] == "1" {
|
||||
let public_keys_and_sig = base64::decode_config(fields[2], base64::URL_SAFE_NO_PAD);
|
||||
if public_keys_and_sig.is_ok() {
|
||||
let public_keys_and_sig = public_keys_and_sig.unwrap();
|
||||
if public_keys_and_sig.len() == (C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_ECDSA_SIGNATURE_SIZE + SHA512_HASH_SIZE) {
|
||||
let p521_ecdh_public = P521PublicKey::from_bytes(&public_keys_and_sig.as_slice()[(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE)..(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE)]);
|
||||
let p521_ecdsa_public = P521PublicKey::from_bytes(&public_keys_and_sig.as_slice()[(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE)..(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE)]);
|
||||
if p521_ecdh_public.is_some() && p521_ecdsa_public.is_some() {
|
||||
let p521_ecdh_public = p521_ecdh_public.unwrap();
|
||||
let p521_ecdsa_public = p521_ecdsa_public.unwrap();
|
||||
let mut secrets: Option<IdentitySecrets> = None;
|
||||
if fields.len() == 4 {
|
||||
let secret_keys = base64::decode_config(fields[3], base64::URL_SAFE_NO_PAD);
|
||||
if secret_keys.is_ok() {
|
||||
let secret_keys = secret_keys.unwrap();
|
||||
if secret_keys.len() == (C25519_SECRET_KEY_SIZE + ED25519_SECRET_KEY_SIZE + P521_SECRET_KEY_SIZE + P521_SECRET_KEY_SIZE) {
|
||||
let p521_ecdh_secret = P521KeyPair::from_bytes(p521_ecdh_public.public_key_bytes(), &secret_keys.as_slice()[(C25519_SECRET_KEY_SIZE + ED25519_SECRET_KEY_SIZE)..(C25519_SECRET_KEY_SIZE + ED25519_SECRET_KEY_SIZE + P521_SECRET_KEY_SIZE)]);
|
||||
let p521_ecdsa_secret = P521KeyPair::from_bytes(p521_ecdsa_public.public_key_bytes(), &secret_keys.as_slice()[(C25519_SECRET_KEY_SIZE + ED25519_SECRET_KEY_SIZE + P521_SECRET_KEY_SIZE)..(C25519_SECRET_KEY_SIZE + ED25519_SECRET_KEY_SIZE + P521_SECRET_KEY_SIZE + P521_SECRET_KEY_SIZE)]);
|
||||
if p521_ecdh_secret.is_some() && p521_ecdsa_secret.is_some() {
|
||||
secrets = Some(IdentitySecrets {
|
||||
c25519: C25519KeyPair::from_bytes(&public_keys_and_sig.as_slice()[0..32], &secret_keys.as_slice()[0..32]).unwrap(),
|
||||
ed25519: Ed25519KeyPair::from_bytes(&public_keys_and_sig.as_slice()[32..64], &secret_keys.as_slice()[32..64]).unwrap(),
|
||||
v1: Some((p521_ecdh_secret.unwrap(), p521_ecdsa_secret.unwrap())),
|
||||
});
|
||||
} else {
|
||||
return Err(InvalidFormatError);
|
||||
}
|
||||
} else {
|
||||
return Err(InvalidFormatError);
|
||||
}
|
||||
} else {
|
||||
return Err(InvalidFormatError);
|
||||
}
|
||||
}
|
||||
return Ok(Identity {
|
||||
address: addr,
|
||||
c25519: public_keys_and_sig.as_slice()[0..32].try_into().unwrap(),
|
||||
ed25519: public_keys_and_sig.as_slice()[32..64].try_into().unwrap(),
|
||||
v1: Some((
|
||||
p521_ecdh_public,
|
||||
p521_ecdsa_public,
|
||||
public_keys_and_sig.as_slice()[(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE)..(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_ECDSA_SIGNATURE_SIZE)].try_into().unwrap(),
|
||||
public_keys_and_sig.as_slice()[(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_ECDSA_SIGNATURE_SIZE)..(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_ECDSA_SIGNATURE_SIZE + SHA512_HASH_SIZE)].try_into().unwrap()
|
||||
)),
|
||||
secrets,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(InvalidFormatError)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Identity {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.address.eq(&other.address) &&
|
||||
self.c25519.eq(&other.c25519) &&
|
||||
self.ed25519.eq(&other.ed25519) &&
|
||||
self.v1.as_ref().map_or_else(|| other.v1.is_none(), |v1| other.v1.as_ref().map_or(false, |other_v1| (*v1).0.eq(&(*other_v1).0) && (*v1).1.eq(&(*other_v1).1)))
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Identity {}
|
||||
|
||||
impl PartialOrd for Identity {
|
||||
#[inline(always)]
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Identity {
|
||||
#[inline(always)]
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
let c = self.address.cmp(&other.address);
|
||||
if c.is_eq() {
|
||||
self.c25519.cmp(&other.c25519)
|
||||
} else {
|
||||
c
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::str::FromStr;
|
||||
use crate::vl1::identity::{Identity, Type};
|
||||
|
||||
#[test]
|
||||
fn type0() {
|
||||
let id = Identity::generate(Type::C25519);
|
||||
//println!("V0: {}", id.to_string());
|
||||
if !id.locally_validate() {
|
||||
panic!("new V0 identity validation failed");
|
||||
}
|
||||
let sig = id.sign(&[1_u8]).unwrap();
|
||||
//println!("sig: {}", crate::util::hex::to_string(sig.as_slice()));
|
||||
if !id.verify(&[1_u8], sig.as_slice()) {
|
||||
panic!("valid signature verification failed");
|
||||
}
|
||||
if id.verify(&[0_u8], sig.as_slice()) {
|
||||
panic!("invalid signature verification succeeded");
|
||||
}
|
||||
for good_id in [
|
||||
"7f3a8e50db:0:936b698c68f51508e9184f7510323a01da0e5778158244c83520614822e2352855ff4d82443823b866cdb553d02d8fa5da833fbee62472e666a60605b76194b9:0d46684e30d561c859bf7d530d2de0452605d8cf392db4beb2768ceda55e63673f11d84a9f31ce7504f0e3ce5dc9ab7ecf9662e555846d130422916482be5fbb",
|
||||
"f529e17b64:0:56676b36b94212cc479825cbf685527a097287950cf9642ae336d57bf17fdd6e4c96ac65e2cf9f757151bbb65e63abbd90b655df0934394906176cc07e81ff64:99e5f483dedf4b26b72524cfe1385e5b44d1eb9c8435316a551c6b4674ab484f6d72c2fdbb3d5b1f01ff1c092fc05d97734d6410c21acf8640cd1fa8e03a110a",
|
||||
"cbdb6f47e9:0:ec7f3ffd9c139b31eb6f5903f4a2d069ec77c51fea228ab80d679dd0ce79fe12f531046634f1f94c51ce806910de3ad73df1940fe466bb65d247b3e492d75183:26e7c8473514205186704d5cf9ee3f82a6f45dc719b91f54e7f31f982071003100a86689de8abd82817f607e192d0e84cc344defe3bb3795f2bdcfcbff41c8cb",
|
||||
"8bd225d6a9:0:08e7fc755ee0aa2e10bf37c0b8dd6f33b3164de04cf3f716584ee44df1fe9506ce1f3f2874c6d1450fc8fab339a95092ec7e628cddd26af93c4392e6564d9ee7:431bb44d22734d925538cbcdc7c2a80c0f71968041949f76ccb6f690f01b6cf45976071c86fcf2ddda2d463c8cfe6444b36c8ee0d057d665350acdcb86dff06f"
|
||||
] {
|
||||
let id = Identity::from_str(good_id).unwrap();
|
||||
if !id.locally_validate() {
|
||||
panic!("known-good V0 identity failed local validation");
|
||||
}
|
||||
let id_bytes = id.marshal_to_bytes(true);
|
||||
let id2 = Identity::unmarshal_from_bytes(id_bytes.as_slice()).unwrap().0;
|
||||
if !id.eq(&id2) {
|
||||
panic!("identity V0 marshal/unmarshal failed");
|
||||
}
|
||||
}
|
||||
for bad_id in [
|
||||
"7f3b8e50db:0:936b698c68f51508e9184f7510323a01da0e5778158244c83520614822e2352855ff4d82443823b866cdb553d02d8fa5da833fbee62472e666a60605b76194b9:0d46684e30d561c859bf7d530d2de0452605d8cf392db4beb2768ceda55e63673f11d84a9f31ce7504f0e3ce5dc9ab7ecf9662e555846d130422916482be5fbb",
|
||||
"f529e17b64:0:56676b36b94212cc479825cbf685527a097287951cf9642ae336d57bf17fdd6e4c96ac65e2cf9f757151bbb65e63abbd90b655df0934394906176cc07e81ff64:99e5f483dedf4b26b72524cfe1385e5b44d1eb9c8435316a551c6b4674ab484f6d72c2fdbb3d5b1f01ff1c092fc05d97734d6410c21acf8640cd1fa8e03a110a",
|
||||
"cbdb6f47e9:0:ec7f3ffd9c139b31eb6f5903f4a2d069ec77c51fea228ab80d679dd0ce79fe12f531046634f1f94c51ce806910de3ad73df1940fe466cb65d247b3e492d75183:26e7c8473514205186704d5cf9ee3f82a6f45dc719b91f54e7f31f982071003100a86689de8abd82817f607e192d0e84cc344defe3bb3795f2bdcfcbff41c8cb",
|
||||
"8bd225d6a9:0:98e7fc755ee0aa2e10bf37c0b8dd6f33b3164de04cf3f716584ee44df1fe9506ce1f3f2874c6d1450fc8fab339a95092ec7e628cddd26af93c4392e6564d9ee7:431bb44d22734d925538cbcdc7c2a80c0f71968041949f76ccb6f690f01b6cf45976071c86fcf2ddda2d463c8cfe6444b36c8ee0d057d665350acdcb86dff06f"
|
||||
] {
|
||||
let id = Identity::from_str(bad_id).unwrap();
|
||||
if id.locally_validate() {
|
||||
panic!("known-bad V0 identity validated");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn type1() {
|
||||
let id = Identity::generate(Type::P521);
|
||||
//println!("V1: {}", id.to_string());
|
||||
if !id.locally_validate() {
|
||||
panic!("new V1 identity validation failed");
|
||||
}
|
||||
let sig = id.sign(&[1_u8]).unwrap();
|
||||
//println!("sig: {}", crate::util::hex::to_string(sig.as_slice()));
|
||||
if !id.verify(&[1_u8], sig.as_slice()) {
|
||||
panic!("valid signature verification failed");
|
||||
}
|
||||
if id.verify(&[0_u8], sig.as_slice()) {
|
||||
panic!("invalid signature verification succeeded");
|
||||
}
|
||||
for good_id in [
|
||||
"9c6095d8e3:1:ZhjuMgE1EP6rfmCW5bV3WbnSNq1EthIEIpvSU_-wCxdBdzzBvc2Hz5ZHXTNie5mxAtxqzvwO6oDhd1zyLfd7xgDSbSpiBO9gGoHjFeJN_MAoH8NJuHOLvfgLO4lb4ld8s9muhx8qVn7ZFgMki0sYJfYNYoTqfwN5lVmRSiSN8zzlHQDCQmSMLwQDaKvYwtIsqvPLgDKeWX7brJrW5hF8PpVapnuP8uJr4efXer5s5_fIlCaI2K-KwjbQ0IfsQrcgC-8JRgGog7KDgEaNjiqS74bFSdpemhYEEK9xWhi7SGFDAEVHJ58LoTsJc6yJ9ISThOQQJ_6DkWDr5vY77GBqmNZI0bPuLQA8H5NgdpAed4yVVE3Q0vYjkklC8zmjfdA05W7kV5dvbOi45qh8I7li2JI47CB1FZ-3B672onKCdoaPSiQzi4GAfwGy71MStTYyiADUKGog9nKAMpmg4EOgDfU6gXCvK9VYlTRY7FIvYVv1TQfNe4EwBnLYG0XRcpl6MQwgeFUvyTQ57ACKfwVdVlVdBwXaglfYk2sFu7E63VrMi1Lh-tyPhZgs4D1GIIONt6Z8UY0IMGwfhr1uZu_2M_evxC7w-4Av6V9T5AbNCg2qjNvab6iZFPQxE8gsT0cnacq6SoT1jdP9kl-6TXqg_f095c0Lbds7xaKd9A0k4HJPAhX87pMynGCV2OM",
|
||||
"23061c9924:1:Wic-UHeYc9-ri2PMLMxoaXpq3Vl7erG79ZD69HvEVjmtQ8Dtbj-kW6LY2fwANEy4EGl1Oq1z6SLI5SbowRaPJQCboc6YqOA6ZQZXPn4sulnLNoEWhclA1Fk5HMEKG1tptJ3D321CNJzb-McaIErA2l33iQLOgLWpcJSuCIapAl_tCgCH03OtJkexLZyfjhlzarWd8NOmzt6z963UMnNo3H3w9StyiNMDvCCUs2j_rP0QOLPH2mlUfw7Z1FbpezBxKmmxxQFq6zgVyDKyXPXLaLfYHJ4wj2uTBaQ_5qZGT3TQMy9ApTE-ywl9K6aM4uMXelO_dqhaoSOb4jWYRLnzrSXBcxtSlgD9xTI2rTTdiYaW8udvFtc_1sB0DwGfXx2E2W8cX2PYdhYxco5tUssuKVyRNuYr3FfnAWvhNKfooNNnuaJaFh6gZwDH1opFWlIz9AfgxeDAJ7F4Bt80O-H0Fxa4OEqyWX944FG5KiIFRP9lHlrkTa2E2cGH8lsa130fhCFreI4WU0qJFwEPHo_H39ukEzrkQhQtHWxsVg7ypokrSfD57vstxU6TCNyAA-6dPTpFZJ0gr848cj5pHPdWs0RaiohaDMYS8V4ZCALwEGoDptswgZsJauyU-GRKteKCEJ6GYBHFLDldlQtA99R70Em2RhlaW2Ic4_MFK8_-Z4ZEP4CsIgCWIwYcmSQ",
|
||||
"dcc7eb3f14:1:rw1eHn1xivAX8zs2yrJLjYWM35rvPEkWGN1ln63BMwL9mVMmjN1kxv_bY3LDwzhVgc6pyL7OsXkhHQDQ2m4q5AGFv1yZLy5LghaA37WX5ayCG2MeD01C243kjwfwE4VOm7576dPtghGXX8EGhtfspHyW8enAJHL9CnBAM8ACLYwakgChp8EzynwsnnsQlW6MTQdxFSZjq0OLmBLDWvCuhcABWdT1iPP9s9ngFah1xTaEiHALsS3M0HC1-vvbmwKzT6-sWwCPqF-XEtaIMNhTzZ0d1BluXj1KJvH6K5vD8o2fvyzHelezA8br7HFdT06DE9_Gh2xaJoaFlUfOdtajEhOiwirI5wBREUjd0q96EgxLKgGDKFrYYoXAs6MbXlc11jYs9RuMu90kAH4KNIsmETPGp5Qk8U3-2I_7lw8xFx3fb70PblNoJAD1yisM70AnpwZSaTr5bWsfV7JiglCOy1F1qFm7U5X8dseZ0d0oLGX4byLDl7lnNgM3KMQd4IY3dljZevUXc58M_wH0b7VecirJr_DRhAacHkJcsnKfqOfDM8yn8ot9N2K5rlLxHKWwSK1p7EO2kwdlBLuR_DzGTJSm2jj8vmk-J6jxcQCYvHvSJTx1j0Uk9w4HIseiw2tSnww9B3dEnlesvoxb2xWLMVvNXSjDuHqqh80gAbg0Ts14bbqZXk__3MfrPxQ",
|
||||
"cf0399c634:1:aSVlK4GVn9KTqf62Qx1LZpkxQL86xc7LapOyC6sbR1eTN1SKO3IJ742sfFufDa133rAUNXDVC2zNA0gRlen2SgCTCC18xqyhtsry-LLwOVSER5TSrlSL7EfDJ4Q9VFIPsj1Vo3UXrPGXur1k1K3XRStEQFdBuy0lW0Kw2fgyWVnTzwASCpOKg3Fgbv8z7XiUlPsPK1ZVbIyXVX4KFkyxnOrnSWALUHlifXRWrGAjZQhqSaU_vMrEVYSJYkFy7pLJKCQeWwFKZIZFure-5YP630qwxeY9pyrez7TalGfZFTCFPXv6BgWhQ1CfkPtJPY_1-amzRJn2IvYm3ci5OiwAcdMhSgl1VgC6dqcnz7HtuovppFTJ5FOxUYhD4YemZ376UZT7VrvKBho-mwBY2V0ZVtO_hgYg3yJbeX6wjv9HXnXsrvl5uuY04ACtZAtczPvkY0Roh2T18OdhVqytZD3QNGiirVb7GE0_SexQ2lcF0aWEsr6bS3iGhZFch1G8SlV4tag2ia-mMcD4HgFOyzlOwK5Paet4i1LfXuVG9vz-mjFoaND0here6s74NlOvizJvamwiid0k-kp4rYbsot0wGRYpNE0NtooBmp64VAFSUgGKr0OX3TRWTdiNFqBf28m8Cba-WjLSirLYZDMo83PWOHMzViHS6IIXo5mqFWJSXds9cx9gYeU3zwOZxjQ"
|
||||
] {
|
||||
let id = Identity::from_str(good_id).unwrap();
|
||||
if !id.locally_validate() {
|
||||
panic!("known-good V1 identity failed local validation");
|
||||
}
|
||||
let id_bytes = id.marshal_to_bytes(true);
|
||||
let id2 = Identity::unmarshal_from_bytes(id_bytes.as_slice()).unwrap().0;
|
||||
if !id.eq(&id2) {
|
||||
panic!("identity V1 marshal/unmarshal failed");
|
||||
}
|
||||
}
|
||||
for bad_id in [
|
||||
"9c6005d8e3:1:ZhjuMgE1EP6rfmCW5bV3WbnSNq1EthIEIpvSU_-wCxdBdzzBvc2Hz5ZHXTNie5mxAtxqzvwO6oDhd1zyLfd7xgDSbSpiBO9gGoHjFeJN_MAoH8NJuHOLvfgLO4lb4ld8s9muhx8qVn7ZFgMki0sYJfYNYoTqfwN5lVmRSiSN8zzlHQDCQmSMLwQDaKvYwtIsqvPLgDKeWX7brJrW5hF8PpVapnuP8uJr4efXer5s5_fIlCaI2K-KwjbQ0IfsQrcgC-8JRgGog7KDgEaNjiqS74bFSdpemhYEEK9xWhi7SGFDAEVHJ58LoTsJc6yJ9ISThOQQJ_6DkWDr5vY77GBqmNZI0bPuLQA8H5NgdpAed4yVVE3Q0vYjkklC8zmjfdA05W7kV5dvbOi45qh8I7li2JI47CB1FZ-3B672onKCdoaPSiQzi4GAfwGy71MStTYyiADUKGog9nKAMpmg4EOgDfU6gXCvK9VYlTRY7FIvYVv1TQfNe4EwBnLYG0XRcpl6MQwgeFUvyTQ57ACKfwVdVlVdBwXaglfYk2sFu7E63VrMi1Lh-tyPhZgs4D1GIIONt6Z8UY0IMGwfhr1uZu_2M_evxC7w-4Av6V9T5AbNCg2qjNvab6iZFPQxE8gsT0cnacq6SoT1jdP9kl-6TXqg_f095c0Lbds7xaKd9A0k4HJPAhX87pMynGCV2OM",
|
||||
"23061c9934:1:Wic-UHeYc9-ri2PMLMxoaXpq3Vl7erG79ZD69HvEVjmtQ8Dtbj-kW6LY2fwANEy4EGl1Oq1z6SLI5SbowRaPJQCboc6YqOA6ZQZXPn4sulnLNoEWhclA1Fk5HMEKG1tptJ3D321CNJzb-McaIErA2l33iQLOgLWpcJSuCIapAl_tCgCH03OtJkexLZyfjhlzarWd8NOmzt6z963UMnNo3H3w9StyiNMDvCCUs2j_rP0QOLPH2mlUfw7Z1FbpezBxKmmxxQFq6zgVyDKyXPXLaLfYHJ4wj2uTBaQ_5qZGT3TQMy9ApTE-ywl9K6aM4uMXelO_dqhaoSOb4jWYRLnzrSXBcxtSlgD9xTI2rTTdiYaW8udvFtc_1sB0DwGfXx2E2W8cX2PYdhYxco5tUssuKVyRNuYr3FfnAWvhNKfooNNnuaJaFh6gZwDH1opFWlIz9AfgxeDAJ7F4Bt80O-H0Fxa4OEqyWX944FG5KiIFRP9lHlrkTa2E2cGH8lsa130fhCFreI4WU0qJFwEPHo_H39ukEzrkQhQtHWxsVg7ypokrSfD57vstxU6TCNyAA-6dPTpFZJ0gr848cj5pHPdWs0RaiohaDMYS8V4ZCALwEGoDptswgZsJauyU-GRKteKCEJ6GYBHFLDldlQtA99R70Em2RhlaW2Ic4_MFK8_-Z4ZEP4CsIgCWIwYcmSQ",
|
||||
"dcc7eb3f14:1:rw1eHn1xivAX8zs1yrJLjYWM35rvPEkWGN1ln63BMwL9mVMmjN1kxv_bY3LDwzhVgc6pyL7OsXkhHQDQ2m4q5AGFv1yZLy5LghaA37WX5ayCG2MeD01C243kjwfwE4VOm7576dPtghGXX8EGhtfspHyW8enAJHL9CnBAM8ACLYwakgChp8EzynwsnnsQlW6MTQdxFSZjq0OLmBLDWvCuhcABWdT1iPP9s9ngFah1xTaEiHALsS3M0HC1-vvbmwKzT6-sWwCPqF-XEtaIMNhTzZ0d1BluXj1KJvH6K5vD8o2fvyzHelezA8br7HFdT06DE9_Gh2xaJoaFlUfOdtajEhOiwirI5wBREUjd0q96EgxLKgGDKFrYYoXAs6MbXlc11jYs9RuMu90kAH4KNIsmETPGp5Qk8U3-2I_7lw8xFx3fb70PblNoJAD1yisM70AnpwZSaTr5bWsfV7JiglCOy1F1qFm7U5X8dseZ0d0oLGX4byLDl7lnNgM3KMQd4IY3dljZevUXc58M_wH0b7VecirJr_DRhAacHkJcsnKfqOfDM8yn8ot9N2K5rlLxHKWwSK1p7EO2kwdlBLuR_DzGTJSm2jj8vmk-J6jxcQCYvHvSJTx1j0Uk9w4HIseiw2tSnww9B3dEnlesvoxb2xWLMVvNXSjDuHqqh80gAbg0Ts14bbqZXk__3MfrPxQ",
|
||||
"cf0399c634:1:aSVlK4GVn9KTqf62Qx1LZpkxQL86xc7LapOyC5sbR1eTN1SKO3IJ742sfFufDa133rAUNXDVC2zNA0gRlen2SgCTCC18xqyhtsry-LLwOVSER5TSrlSL7EfDJ4Q9VFIPsj1Vo3UXrPGXur1k1K3XRStEQFdBuy0lW0Kw2fgyWVnTzwASCpOKg3Fgbv8z7XiUlPsPK1ZVbIyXVX4KFkyxnOrnSWALUHlifXRWrGAjZQhqSaU_vMrEVYSJYkFy7pLJKCQeWwFKZIZFure-5YP630qwxeY9pyrez7TalGfZFTCFPXv6BgWhQ1CfkPtJPY_1-amzRJn2IvYm3ci5OiwAcdMhSgl1VgC6dqcnz7HtuovppFTJ5FOxUYhD4YemZ376UZT7VrvKBho-mwBY2V0ZVtO_hgYg3yJbeX6wjv9HXnXsrvl5uuY04ACtZAtczPvkY0Roh2T18OdhVqytZD3QNGiirVb7GE0_SexQ2lcF0aWEsr6bS3iGhZFch1G8SlV4tag2ia-mMcD4HgFOyzlOwK5Paet4i1LfXuVG9vz-mjFoaND0here6s74NlOvizJvamwiid0k-kp4rYbsot0wGRYpNE0NtooBmp64VAFSUgGKr0OX3TRWTdiNFqBf28m8Cba-WjLSirLYZDMo83PWOHMzViHS6IIXo5mqFWJSXds9cx9gYeU3zwOZxjQ"
|
||||
] {
|
||||
let id = Identity::from_str(bad_id).unwrap();
|
||||
if id.locally_validate() {
|
||||
panic!("known-bad V1 identity validated");
|
||||
}
|
||||
}
|
||||
ms /= 64.0;
|
||||
println!("{}ms {}", ms, id.unwrap().to_secret_string());
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,4 @@ pub mod node;
|
|||
pub mod identity;
|
||||
|
||||
mod address;
|
||||
|
||||
pub use address::Address;
|
||||
pub use identity::Identity;
|
||||
|
|
|
@ -13,7 +13,7 @@ impl MAC {
|
|||
if b.len() >= 6 {
|
||||
Ok(MAC((b[0] as u64) << 40 | (b[1] as u64) << 32 | (b[2] as u64) << 24 | (b[3] as u64) << 16 as u64 | (b[4] as u64) << 8 | b[5] as u64))
|
||||
} else {
|
||||
Err(InvalidFormatError("invalid MAC address"))
|
||||
Err(InvalidFormatError)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue