diff --git a/core/MIMC52.cpp b/core/MIMC52.cpp index 4ddeaa6d0..7b97a3d93 100644 --- a/core/MIMC52.cpp +++ b/core/MIMC52.cpp @@ -42,9 +42,31 @@ const uint32_t ZT_MIMC52_PRIMES[1024] = {4294895267, 4294895477, 4294895513, 429 4294963313, 4294963349, 4294963427, 4294963547, 4294963559, 4294963721, 4294963799, 4294963817, 4294963901, 4294963919, 4294964021, 4294964279, 4294964297, 4294964363, 4294964387, 4294964411, 4294964567, 4294964603, 4294964687, 4294964777, 4294965041, 4294965071, 4294965119, 4294965221, 4294965251, 4294965287, 4294965413, 4294965569, 4294965647, 4294965671, 4294965689, 4294965779, 4294965839, 4294965893, 4294966091, 4294966109, 4294966127, 4294966157, 4294966187, 4294966199, 4294966211, 4294966403, 4294966457, 4294966499, 4294966541, 4294966637, 4294966661, 4294966739, 4294966823, 4294966883, 4294966901, 4294966961, 4294967027, 4294967087, 4294967099, 4294967123, 4294967153, 4294967249}; -// 52-bit mulmod using FPU hack to achieve better performance than the majority of CPU dividers. +#ifdef ZT_NO_IEEE_DOUBLE + +// Integer 64-bit modular multiply for systems without an IEEE FPU. This is +// much slower on systems that can use the FPU hack. +static uint64_t mulmod64(uint64_t a, uint64_t b, const uint64_t m) +{ + uint64_t res = 0; + while ((a)) { + if ((a << 63U)) + res = (res + b) % m; + a >>= 1U; + b = (b << 1U) % m; + } + return res; +} + +#define mulmod52(a, b, m, mf) mulmod64((a), (b), (m)) + +#else + +// 52-bit mulmod using FPU hack, which is very fast on most systems with IEEE 64-bit floats. #define mulmod52(a, b, m, mf) ( ( ( a * b ) - ( ((uint64_t)(((double)a * (double)b) / mf) - 1) * m ) ) % m ) +#endif + // Compute a^e%m (mf is m in floating point form to avoid repeated conversion) ZT_INLINE uint64_t modpow52(uint64_t a, uint64_t e, const uint64_t m, const double mf) { diff --git a/core/MIMC52.hpp b/core/MIMC52.hpp index 8dfd361e0..b715568e0 100644 --- a/core/MIMC52.hpp +++ b/core/MIMC52.hpp @@ -16,6 +16,24 @@ #include "Constants.hpp" +/* + * This is a verifiable delay function (or serial proof of work) based on + * the MIMC prime field hash construction. MIMC is very fast to execute in + * one direction and inherently a lot slower in another, allowing expensive + * work to be quickly verified. The 52-bit algorithm implemented here can + * run very fast on a variety of systems by taking advantage of the + * interesting double precision FPU modular multiplication hack described + * here: + * + * https://stackoverflow.com/a/50479693 + * + * 52 bits is not sufficient for high strength cryptographic applications + * like block chains, but is good enough to add a deterministic delay to + * identity generation. That's its only purpose here. This is used as the + * delay function for "type 1" identities to replace the ad-hoc memory hard + * hash used in "type 0." This is both simpler and faster to verify. + */ + namespace ZeroTier { namespace MIMC52 { diff --git a/rust-zerotier-core/src/certificate.rs b/rust-zerotier-core/src/certificate.rs index a87853d9d..05d5f9dde 100644 --- a/rust-zerotier-core/src/certificate.rs +++ b/rust-zerotier-core/src/certificate.rs @@ -663,7 +663,7 @@ impl Certificate { timestamp: c.timestamp, validity: c.validity, subject: CertificateSubject::new_from_capi(&c.subject), - issuer: if c.issuer.is_null() { None } else { Some(Identity::new_from_capi(c.issuer, false)) }, + issuer: if c.issuer.is_null() { None } else { Some(Identity::new_from_capi(c.issuer, false).clone()) }, issuer_name: CertificateName::new_from_capi(&c.issuerName), extended_attributes: Vec::from(std::slice::from_raw_parts(c.extendedAttributes, c.extendedAttributesSize as usize)), max_path_length: c.maxPathLength as u32, @@ -855,9 +855,6 @@ mod tests { let cert_signed_decoded = cert_signed_decoded.ok().unwrap(); assert!(cert_signed_decoded.signature.len() > 0); - let cert_signed_verified = cert_signed_decoded.verify(); - println!("{}", cert_signed_decoded.to_json().as_str()); - println!("{}", cert_signed_verified.to_string()); - assert!(cert_signed_verified == CertificateError::None); + assert!(cert_signed_decoded.verify() == CertificateError::None); } } diff --git a/rust-zerotier-core/src/identity.rs b/rust-zerotier-core/src/identity.rs index 7c63e927c..94fbbbf23 100644 --- a/rust-zerotier-core/src/identity.rs +++ b/rust-zerotier-core/src/identity.rs @@ -20,7 +20,7 @@ use num_traits::{FromPrimitive, ToPrimitive}; use crate::*; use crate::bindings::capi as ztcore; -#[derive(FromPrimitive,ToPrimitive)] +#[derive(FromPrimitive, ToPrimitive, PartialEq, Eq)] pub enum IdentityType { Curve25519 = ztcore::ZT_IdentityType_ZT_IDENTITY_TYPE_C25519 as isize, NistP384 = ztcore::ZT_IdentityType_ZT_IDENTITY_TYPE_P384 as isize, @@ -78,10 +78,11 @@ impl Identity { fn intl_to_string(&self, include_private: bool) -> String { let mut buf: MaybeUninit<[c_char; 4096]> = MaybeUninit::uninit(); unsafe { - if ztcore::ZT_Identity_toString(self.capi, (*buf.as_mut_ptr()).as_mut_ptr(), 4096, if include_private { 1 } else { 0 }).is_null() { + let bufptr = (*buf.as_mut_ptr()).as_mut_ptr(); + if ztcore::ZT_Identity_toString(self.capi, bufptr, 4096, if include_private { 1 } else { 0 }).is_null() { return String::from("(invalid)"); } - return cstr_to_string((*buf.as_ptr()).as_ptr(), 4096); + return cstr_to_string(bufptr, 4096); } }