P384 work and cleaning up old code.

This commit is contained in:
Adam Ierymenko
2023-08-04 12:02:48 -04:00
parent 8b14cb917b
commit 02406aa45d
9 changed files with 798 additions and 1730 deletions
-328
View File
@@ -1,328 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* (c) ZeroTier, Inc.
* https://www.zerotier.com/
*/
use std::array::TryFromSliceError;
use std::fmt::Debug;
use std::hash::Hash;
use std::mem::{size_of, transmute};
use std::str::FromStr;
use serde::{Deserialize, Serialize};
use zerotier_utils::error::InvalidParameterError;
use zerotier_utils::hex::{self, HEX_CHARS};
use zerotier_utils::tofrombytes::ToFromBytes;
use zerotier_utils::{base24, memory};
/// A unique identifier for an identity on the ZeroTier VL1 network
#[repr(transparent)]
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Address(pub(crate) [u8; Self::SIZE]);
impl Address {
/// The size of a full address, 384 bits.
pub const SIZE: usize = 48;
/// The size of a short address.
pub const SHORT_SIZE: usize = 16;
/// The size of a legacy ZeroTier One short address.
pub const LEGACY_SHORT_SIZE: usize = 5;
/// Legacy ZeroTier One addresses may not begin with 0xff.
pub const LEGACY_RESERVED_PREFIX: u8 = 0xff;
#[inline(always)]
pub(crate) fn new_uninit() -> Self {
Self([0u8; Self::SIZE])
}
#[inline(always)]
pub fn from_short_bytes(b: &[u8]) -> Option<Self> {
if b.len() == Self::SHORT_SIZE {
let mut a = Address([0u8; Self::SIZE]);
a.0[..Self::SHORT_SIZE].copy_from_slice(b);
Some(a)
} else {
None
}
}
#[inline(always)]
pub fn as_bytes(&self) -> &[u8; Self::SIZE] {
&self.0
}
#[inline(always)]
pub fn as_short_bytes(&self) -> &[u8; Self::SHORT_SIZE] {
memory::array_range::<u8, { Self::SIZE }, 0, { Self::SHORT_SIZE }>(&self.0)
}
#[inline(always)]
pub fn as_legacy_short_bytes(&self) -> &[u8; Self::LEGACY_SHORT_SIZE] {
memory::array_range::<u8, { Self::SIZE }, 0, { Self::LEGACY_SHORT_SIZE }>(&self.0)
}
/// True if this is a full-length 384-bit address.
#[inline]
pub fn is_complete(&self) -> bool {
self.0[Self::SHORT_SIZE..].iter().any(|i| *i != 0)
}
/// True if this is a short (128-bit or legacy 40-bit) address.
#[inline]
pub fn is_short(&self) -> bool {
self.0[Self::SHORT_SIZE..].iter().all(|i| *i == 0)
}
/// Append a string representation of this address to a mutable string.
pub fn to_string_append(&self, s: &mut String) {
let mut i = 0;
while i < Self::SHORT_SIZE {
let ii = i + 4;
if i > 0 {
s.push('-');
}
base24::encode_4to7(&self.0[i..ii], s);
i = ii;
}
if self.is_complete() {
s.push('.');
while i < Self::SIZE {
let ii = i + 4;
if i > 16 {
s.push('-');
}
base24::encode_4to7(&self.0[i..ii], s);
i = ii;
}
}
}
/// Get the legacy 40-bit ZeroTier One address in the least significant 40 bits of a u64.
#[cfg(feature = "legacy_zt1")]
#[inline]
pub fn to_legacy_short_u64(&self) -> u64 {
u64::from_be_bytes(self.0[..8].try_into().unwrap()).wrapping_shr(24)
}
#[cfg(feature = "legacy_zt1")]
#[inline]
pub fn from_legacy_short_u64(i: u64) -> Self {
let mut a = Self([0u8; Self::SIZE]);
a.0[..Self::LEGACY_SHORT_SIZE].copy_from_slice(&i.to_be_bytes()[3..]);
a
}
#[cfg(feature = "legacy_zt1")]
#[inline(always)]
pub fn from_legacy_short_bytes(b: &[u8]) -> Option<Self> {
if b.len() == Self::LEGACY_SHORT_SIZE {
let mut a = Address([0u8; Self::SIZE]);
a.0[..Self::LEGACY_SHORT_SIZE].copy_from_slice(b);
Some(a)
} else {
None
}
}
/// Output a legacy short ZeroTier One address (first 5 bytes) in string form.
/// This is only meaningful if this address belongs to an Identity with the appropriate flag set.
#[cfg(feature = "legacy_zt1")]
pub fn to_legacy_short_string(&self) -> String {
let mut s = String::with_capacity(Self::LEGACY_SHORT_SIZE * 2);
for b in self.0[..Self::LEGACY_SHORT_SIZE].iter() {
let b = *b;
s.push(HEX_CHARS[b.wrapping_shr(4) as usize] as char);
s.push(HEX_CHARS[(b & 0xf) as usize] as char);
}
s
}
/// Parse a legacy 10-digit hex ZeroTier One address.
///
/// This must be used instead of from_str() to parse these short addresses. None is returned if
/// the provided address is not valid.
#[cfg(feature = "legacy_zt1")]
pub fn from_legacy_short_string(s: &str) -> Result<Address, InvalidParameterError> {
let i = hex::from_string_u64(s) & 0xffffffffff;
if i == 0 || s.len() != (Self::LEGACY_SHORT_SIZE * 2) {
return Err(InvalidParameterError("invalid legacy address"));
}
let i = i.to_be_bytes();
if i[3] == Self::LEGACY_RESERVED_PREFIX {
return Err(InvalidParameterError("invalid legacy address"));
}
let mut a = Address([0u8; Self::SIZE]);
a.0[..Self::LEGACY_SHORT_SIZE].copy_from_slice(&i[3..]);
Ok(a)
}
}
impl From<[u8; Address::SIZE]> for Address {
#[inline(always)]
fn from(value: [u8; Address::SIZE]) -> Self {
Self(value)
}
}
impl From<&[u8; Address::SIZE]> for &Address {
#[inline(always)]
fn from(value: &[u8; Address::SIZE]) -> Self {
assert_eq!(size_of::<[u8; Address::SIZE]>(), size_of::<Address>());
unsafe { transmute(value) }
}
}
impl From<Address> for [u8; Address::SIZE] {
#[inline(always)]
fn from(value: Address) -> Self {
value.0
}
}
impl From<&Address> for [u8; Address::SIZE] {
#[inline(always)]
fn from(value: &Address) -> Self {
value.0
}
}
impl TryFrom<&[u8]> for Address {
type Error = TryFromSliceError;
#[inline(always)]
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
value.try_into().map(|a| Self(a))
}
}
impl ToString for Address {
fn to_string(&self) -> String {
let mut s = String::with_capacity(96);
self.to_string_append(&mut s);
s
}
}
impl FromStr for Address {
type Err = InvalidParameterError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut a = Self([0u8; Self::SIZE]);
let mut i = 0;
for ss in s.split(&['-', '.']) {
if ss.len() == 7 {
for b in base24::decode_7to4(ss.as_bytes())? {
if i >= Self::SIZE {
return Err(InvalidParameterError("invalid address"));
}
a.0[i] = b;
i += 1;
}
} else {
return Err(InvalidParameterError("invalid address"));
}
}
return Ok(a);
}
}
impl Debug for Address {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.to_string().as_str())
}
}
impl ToFromBytes for Address {
#[inline(always)]
fn read_bytes<R: std::io::Read>(r: &mut R) -> std::io::Result<Self> {
let mut tmp = Address([0u8; Self::SIZE]);
r.read_exact(&mut tmp.0)?;
Ok(tmp)
}
#[inline(always)]
fn from_bytes(b: &[u8]) -> std::io::Result<Self> {
Ok(Self(
b.try_into()
.map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, "invalid address"))?,
))
}
#[inline(always)]
fn write_bytes<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
w.write_all(&self.0)
}
#[inline(always)]
fn to_bytes(&self) -> Vec<u8> {
self.0.to_vec()
}
}
impl Hash for Address {
#[inline(always)]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
state.write(&self.0[..8])
}
}
impl Serialize for Address {
#[inline]
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
if serializer.is_human_readable() {
self.to_string().serialize(serializer)
} else {
serializer.serialize_bytes(&self.0)
}
}
}
struct AddressDeserializeVisitor;
impl<'de> serde::de::Visitor<'de> for AddressDeserializeVisitor {
type Value = Address;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("ZeroTier address")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Address::from_str(v.trim()).map_err(|e| serde::de::Error::custom(e.to_string()))
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
v.try_into()
.map(|b| Address(b))
.map_err(|_| serde::de::Error::invalid_length(v.len(), &self))
}
}
impl<'de> Deserialize<'de> for Address {
#[inline]
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
if deserializer.is_human_readable() {
deserializer.deserialize_str(AddressDeserializeVisitor)
} else {
deserializer.deserialize_bytes(AddressDeserializeVisitor)
}
}
}
+55
View File
@@ -0,0 +1,55 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* (c) ZeroTier, Inc.
* https://www.zerotier.com/
*/
use zerotier_common_utils::error::InvalidParameterError;
/// All unambiguous letters, thus easy to type on the alphabetic keyboards on phones without extra shift taps.
/// The letters 'l' and 'u' are skipped.
const BASE24_ALPHABET: [u8; 24] = [
b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'm', b'n', b'o', b'p', b'q', b'r', b's', b't', b'v', b'w', b'x', b'y', b'z',
];
/// Reverse table for BASE24 alphabet, indexed relative to 'a' or 'A'.
const BASE24_ALPHABET_INV: [u8; 26] = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 255, 11, 12, 13, 14, 15, 16, 17, 18, 255, 19, 20, 21, 22, 23,
];
/// Encode 4 binary bytes into 7 base24 characters.
pub fn encode_4to7(b: &[u8], s: &mut String) {
let mut n = u32::from_be_bytes(b[..4].try_into().unwrap());
for _ in 0..6 {
let (d, r) = (n / 24, n % 24);
n = d;
s.push(BASE24_ALPHABET[r as usize] as char);
}
s.push(BASE24_ALPHABET[n as usize] as char);
}
pub fn decode_7to4(mut s: &[u8]) -> Result<[u8; 4], InvalidParameterError> {
let mut n = 0u32;
if s.len() > 7 {
s = &s[..7];
}
for c in s.iter().rev() {
let mut c = *c;
if c >= 97 && c <= 122 {
c -= 97;
} else if c >= 65 && c <= 90 {
c -= 65;
} else {
return Err(InvalidParameterError("invalid base24"));
}
let i = BASE24_ALPHABET_INV[c as usize];
if i == 255 {
return Err(InvalidParameterError("invalid base24"));
}
n *= 24;
n = n.wrapping_add(i as u32);
}
return Ok(n.to_be_bytes());
}
+42
View File
@@ -0,0 +1,42 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* (c) ZeroTier, Inc.
* https://www.zerotier.com/
*/
use zerotier_common_utils::error::InvalidParameterError;
pub fn encode_8to11(mut n: u64, s: &mut String) {
for _ in 0..11 {
let (d, r) = (n / 62, n % 62);
n = d;
let r = r as u8;
s.push(if r < 26 {
r + 97 // a..z
} else if r < 52 {
r + 39 // A..Z
} else {
r - 4 // 0..9
} as char);
}
}
pub fn decode_11to8(s: &[u8]) -> Result<u64, InvalidParameterError> {
let mut n = 0u64;
for c in s.iter().rev() {
let c = *c;
n *= 62;
n = n.wrapping_add(if c >= 97 && c <= 122 {
n - 97
} else if c >= 65 && c <= 90 {
n - 39
} else if c >= 48 && c <= 57 {
n + 4
} else {
return Err(InvalidParameterError("invalid base62"));
} as u64);
}
return Ok(n);
}
-647
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+10 -96
View File
@@ -9,6 +9,10 @@
use std::hash::Hash;
use std::str::FromStr;
use serde::de::DeserializeOwned;
use serde::Serialize;
use zerotier_common_utils::error::InvalidParameterError;
use zerotier_common_utils::tofrombytes::ToFromBytes;
/// A unique global identifier for a ZeroTier identity.
@@ -33,7 +37,7 @@ pub trait Identity: ToString + FromStr + ToFromBytes + Sync + Send + Clone + Par
}
/// Secret keys that correspond to a public Identity.
pub trait IdentitySecret: Sync + Send + Clone + PartialEq + Eq + Hash + PartialOrd + Ord + 'static {
pub trait IdentitySecret: Sync + Send + Clone + PartialEq + Eq + Serialize + DeserializeOwned + 'static {
type Public: Identity;
/// Type returned by sign(), should typically be [u8; Public::SIGNATURE_SIZE].
@@ -42,7 +46,7 @@ pub trait IdentitySecret: Sync + Send + Clone + PartialEq + Eq + Hash + PartialO
/// Generate a new identity.
/// This may in some cases be a time consuming operation.
fn generate() -> Self;
fn generate(timestamp: u64) -> Self;
/// Get the public portion of this secret identity.
fn public(&self) -> &Self::Public;
@@ -51,100 +55,10 @@ pub trait IdentitySecret: Sync + Send + Clone + PartialEq + Eq + Hash + PartialO
fn sign(&self, data: &[u8]) -> Self::Signature;
}
mod base24;
mod base62;
pub mod p384;
pub mod x25519;
//mod address;
//mod signature;
//pub mod identity;
//pub mod identitysecret;
//pub use address::Address;
//pub use identity::Identity;
//pub use identitysecret::IdentitySecret;
//pub use signature::Signature;
/*
#[cfg(test)]
mod tests {
use super::*;
use zerotier_utils::tofrombytes::ToFromBytes;
#[test]
fn identity_generate_sign_verify_serialize_deserialize() {
let id0 = IdentitySecret::generate_x25519();
let id1 = IdentitySecret::generate_x25519p384(1, None).unwrap();
let id2 = IdentitySecret::generate_p384(1);
let sig_data = "hello".as_bytes();
let sig_wrong_data = "goodbye".as_bytes();
let sig0 = id0.sign(sig_data);
let sig1 = id1.sign(sig_data);
let sig2 = id2.sign(sig_data);
/*
println!(
"identity: signature lengths: x25519 {}, x25519p384 {}, p384 {}, p384pqc {}",
sig0.len(),
sig1.len(),
sig2.len(),
sig3.len()
);
*/
assert!(id0.public.verify(sig0.as_ref(), sig_data));
assert!(id1.public.verify(sig1.as_ref(), sig_data));
assert!(id2.public.verify(sig2.as_ref(), sig_data));
assert!(!id0.public.verify(sig0.as_ref(), sig_wrong_data));
assert!(!id1.public.verify(sig1.as_ref(), sig_wrong_data));
assert!(!id2.public.verify(sig2.as_ref(), sig_wrong_data));
let id0_bytes = id0.to_bytes();
let id1_bytes = id1.to_bytes();
let id2_bytes = id2.to_bytes();
/*
println!(
"identity: serialized secret lengths: x25519 {}, x25519p384 {}, p384 {}, p384pqc {}",
id0_bytes.len(),
id1_bytes.len(),
id2_bytes.len(),
id3_bytes.len()
);
*/
let id0_de = IdentitySecret::from_bytes(id0_bytes.as_slice()).unwrap();
let id1_de = IdentitySecret::from_bytes(id1_bytes.as_slice()).unwrap();
let id2_de = IdentitySecret::from_bytes(id2_bytes.as_slice()).unwrap();
assert_eq!(id0_de.to_bytes(), id0.to_bytes());
assert_eq!(id1_de.to_bytes(), id1.to_bytes());
assert_eq!(id2_de.to_bytes(), id2.to_bytes());
let id0_bytes = id0.public.to_bytes();
let id1_bytes = id1.public.to_bytes();
let id2_bytes = id2.public.to_bytes();
/*
println!(
"identity: serialized public lengths: x25519 {}, x25519p384 {}, p384 {}, p384pqc {}",
id0_bytes.len(),
id1_bytes.len(),
id2_bytes.len(),
id3_bytes.len()
);
*/
let id0_de = Identity::from_bytes(id0_bytes.as_slice()).unwrap();
let id1_de = Identity::from_bytes(id1_bytes.as_slice()).unwrap();
let id2_de = Identity::from_bytes(id2_bytes.as_slice()).unwrap();
assert_eq!(id0_de.to_bytes(), id0.public.to_bytes());
assert_eq!(id1_de.to_bytes(), id1.public.to_bytes());
assert_eq!(id2_de.to_bytes(), id2.public.to_bytes());
}
}
*/
pub(crate) const ADDRESS_ERR: InvalidParameterError = InvalidParameterError("invalid address");
pub(crate) const IDENTITY_ERR: InvalidParameterError = InvalidParameterError("invalid identity");
+647
View File
File diff suppressed because it is too large Load Diff
-60
View File
@@ -1,60 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* (c) ZeroTier, Inc.
* https://www.zerotier.com/
*/
use zerotier_crypto::p384::P384_ECDSA_SIGNATURE_SIZE;
use zerotier_crypto::x25519::ED25519_SIGNATURE_SIZE;
use zerotier_utils::arrayvec::ArrayVec;
/// Buffer type large enough to store any possible signature combination.
/// This can be enlarged if necessary.
pub type Signature = ArrayVec<u8, 192>;
const SIGNATURE_FLAG_ECDSA_P384: u8 = 0x01;
const SIGNATURE_FLAG_EDDSA_ED25519: u8 = 0x02;
pub(crate) fn make_signature(ecdsa_p384: &[u8], eddsa_ed25519: &[u8]) -> Signature {
let mut s = Signature::new();
s.push(0);
let mut flags = 0;
if ecdsa_p384.len() == P384_ECDSA_SIGNATURE_SIZE {
flags |= SIGNATURE_FLAG_ECDSA_P384;
s.push_slice(ecdsa_p384);
}
if eddsa_ed25519.len() == ED25519_SIGNATURE_SIZE {
flags |= SIGNATURE_FLAG_EDDSA_ED25519;
s.push_slice(eddsa_ed25519);
}
s.as_mut()[0] = flags;
s
}
/// Returns which signatures are present: (p384, ed25519)
pub(crate) fn parse_signature(mut s: &[u8]) -> (Option<&[u8]>, Option<&[u8]>) {
let mut sigs = (None, None);
if !s.is_empty() {
let flags = s[0];
s = &s[1..];
if (flags & SIGNATURE_FLAG_ECDSA_P384) != 0 {
if s.len() >= P384_ECDSA_SIGNATURE_SIZE {
sigs.0 = Some(&s[..P384_ECDSA_SIGNATURE_SIZE]);
s = &s[P384_ECDSA_SIGNATURE_SIZE..];
}
}
if (flags & SIGNATURE_FLAG_EDDSA_ED25519) != 0 {
if s.len() >= ED25519_SIGNATURE_SIZE {
sigs.1 = Some(&s[..ED25519_SIGNATURE_SIZE]);
//s = &s[ED25519_SIGNATURE_SIZE..];
}
}
}
sigs
}
+44 -58
View File
@@ -14,8 +14,7 @@ use zerotier_crypto_glue::hash::SHA512;
use zerotier_crypto_glue::salsa::Salsa;
use zerotier_crypto_glue::x25519::*;
const ADDRESS_ERR: InvalidParameterError = InvalidParameterError("invalid address");
const IDENTITY_ERR: InvalidParameterError = InvalidParameterError("invalid identity");
use crate::{ADDRESS_ERR, IDENTITY_ERR};
/// Legacy 40-bit ZeroTier address.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -72,7 +71,7 @@ impl FromStr for Address {
if s.len() == 10 {
Self::try_from(hex::from_string_u64(s))
} else {
Err(InvalidParameterError("invalid address"))
Err(InvalidParameterError(ADDRESS_ERR.0))
}
}
}
@@ -85,7 +84,7 @@ impl ToFromBytes for Address {
if tmp.is_valid() {
Ok(tmp)
} else {
Err(std::io::Error::new(std::io::ErrorKind::Other, "invalid address"))
Err(std::io::Error::new(std::io::ErrorKind::Other, ADDRESS_ERR.0))
}
}
@@ -110,7 +109,7 @@ impl Serialize for Address {
if serializer.is_human_readable() {
self.to_string().serialize(serializer)
} else {
serializer.serialize_bytes(&self.0)
(self.0[0], self.0[1], self.0[2], self.0[3], self.0[4]).serialize(serializer)
}
}
}
@@ -123,7 +122,13 @@ impl<'de> Deserialize<'de> for Address {
if deserializer.is_human_readable() {
Address::from_str(<&str>::deserialize(deserializer)?).map_err(|_| serde::de::Error::custom(ADDRESS_ERR.0))
} else {
Address::from_bytes(<&[u8]>::deserialize(deserializer)?).map_err(|_| serde::de::Error::custom(ADDRESS_ERR.0))
let b = <(u8, u8, u8, u8, u8)>::deserialize(deserializer)?;
let a = Self([b.0, b.1, b.2, b.3, b.4]);
if a.is_valid() {
Ok(a)
} else {
Err(serde::de::Error::custom(ADDRESS_ERR.0))
}
}
}
}
@@ -142,12 +147,16 @@ pub struct Identity {
impl Identity {
fn locally_validate(&self) -> bool {
let mut legacy_address_hasher = SHA512::new();
legacy_address_hasher.update(&self.ecdh);
legacy_address_hasher.update(&self.eddsa);
let mut legacy_address_hash = legacy_address_hasher.finish();
legacy_address_derivation_work_function(&mut legacy_address_hash);
legacy_address_hash[0] < LEGACY_ADDRESS_POW_THRESHOLD && legacy_address_hash[59..64].eq(&self.address.0)
if self.address.is_valid() {
let mut legacy_address_hasher = SHA512::new();
legacy_address_hasher.update(&self.ecdh);
legacy_address_hasher.update(&self.eddsa);
let mut legacy_address_hash = legacy_address_hasher.finish();
legacy_address_derivation_work_function(&mut legacy_address_hash);
legacy_address_hash[0] < LEGACY_ADDRESS_POW_THRESHOLD && legacy_address_hash[59..64].eq(&self.address.0)
} else {
false
}
}
}
@@ -321,32 +330,11 @@ impl PartialEq for IdentitySecret {
impl Eq for IdentitySecret {}
impl PartialOrd for IdentitySecret {
#[inline(always)]
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.public.partial_cmp(&other.public)
}
}
impl Ord for IdentitySecret {
#[inline(always)]
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.public.cmp(&other.public)
}
}
impl Hash for IdentitySecret {
#[inline(always)]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.public.hash(state);
}
}
impl crate::IdentitySecret for IdentitySecret {
type Public = Identity;
type Signature = [u8; 96];
fn generate() -> Self {
fn generate(_timestamp: u64) -> Self {
let mut ecdh = X25519KeyPair::generate();
let eddsa = Ed25519KeyPair::generate();
let mut legacy_address_hasher = SHA512::new();
@@ -388,7 +376,7 @@ impl crate::IdentitySecret for IdentitySecret {
#[derive(Serialize, Deserialize)]
struct IdentitySecretSerialized {
a: Blob<5>,
a: Address,
p0: Blob<C25519_PUBLIC_KEY_SIZE>,
s0: Blob<C25519_SECRET_KEY_SIZE>,
p1: Blob<ED25519_PUBLIC_KEY_SIZE>,
@@ -401,7 +389,7 @@ impl Serialize for IdentitySecret {
S: Serializer,
{
IdentitySecretSerialized {
a: self.public.address.0.into(),
a: self.public.address,
p0: self.public.ecdh.into(),
s0: (*self.ecdh.secret_bytes().as_bytes()).into(),
p1: self.public.eddsa.into(),
@@ -417,26 +405,24 @@ impl<'de> Deserialize<'de> for IdentitySecret {
D: Deserializer<'de>,
{
let d = <IdentitySecretSerialized>::deserialize(deserializer)?;
let ecdh = X25519KeyPair::from_bytes(d.p0.as_bytes(), d.s0.as_bytes());
let eddsa = Ed25519KeyPair::from_bytes(d.p1.as_bytes(), d.s1.as_bytes());
if ecdh.is_none() || eddsa.is_none() {
return Err(serde::de::Error::custom(IDENTITY_ERR.0));
if let (Some(ecdh), Some(eddsa)) = (
X25519KeyPair::from_bytes(d.p0.as_bytes(), d.s0.as_bytes()),
Ed25519KeyPair::from_bytes(d.p1.as_bytes(), d.s1.as_bytes()),
) {
let id = Self {
public: Identity {
address: d.a,
ecdh: ecdh.public_bytes(),
eddsa: eddsa.public_bytes(),
},
ecdh,
eddsa,
};
if id.public.locally_validate() {
return Ok(id);
}
}
let ecdh = ecdh.unwrap();
let eddsa = eddsa.unwrap();
let id = Self {
public: Identity {
address: Address(d.a.into()),
ecdh: ecdh.public_bytes(),
eddsa: eddsa.public_bytes(),
},
ecdh,
eddsa,
};
if !id.public.address.is_valid() || !id.public.locally_validate() {
return Err(serde::de::Error::custom(IDENTITY_ERR.0));
}
return Ok(id);
return Err(serde::de::Error::custom(IDENTITY_ERR.0));
}
}
@@ -506,7 +492,7 @@ mod tests {
fn generate() {
let start = ms_monotonic();
for _ in 0..3 {
let secret = x25519::IdentitySecret::generate();
let secret = x25519::IdentitySecret::generate(0);
println!("S: {}", secret.to_string());
println!("P: {}", secret.public.to_string());
}
@@ -516,7 +502,7 @@ mod tests {
#[test]
fn tostring_fromstring() {
let secret = x25519::IdentitySecret::generate();
let secret = x25519::IdentitySecret::generate(0);
assert!(x25519::Address::from_str(secret.public.address.to_string().as_str())
.unwrap()
.eq(&secret.public.address));
@@ -526,7 +512,7 @@ mod tests {
#[test]
fn tobytes_frombytes() {
let secret = x25519::IdentitySecret::generate();
let secret = x25519::IdentitySecret::generate(0);
assert!(x25519::Address::from_bytes(secret.public.address.to_bytes().as_slice())
.unwrap()
.eq(&secret.public.address));