Rework how V1 identities work a bit to introduce a deterministic PoW (actually a VDF) function. This stuff was already developed, just not integrated yet, and this is the time to do it.

This commit is contained in:
Adam Ierymenko 2021-01-12 20:45:06 -05:00
parent 053452b4a0
commit d808d33f91
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
7 changed files with 285 additions and 113 deletions

View file

@ -33,6 +33,7 @@ set(core_headers
LZ4.hpp
MAC.hpp
Member.hpp
MIMC52.hpp
MulticastGroup.hpp
Mutex.hpp
Network.hpp
@ -80,6 +81,7 @@ set(core_src
Locator.cpp
LZ4.cpp
Member.cpp
MIMC52.cpp
Network.cpp
NetworkConfig.cpp
Node.cpp

View file

@ -18,6 +18,7 @@
#include "Poly1305.hpp"
#include "Utils.hpp"
#include "Endpoint.hpp"
#include "MIMC52.hpp"
#include <algorithm>
#include <memory>
@ -27,8 +28,6 @@ namespace ZeroTier {
namespace {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// This is the memory-intensive hash function used to compute v0 identities from v0 public keys.
#define ZT_V0_IDENTITY_GEN_MEMORY 2097152
@ -82,67 +81,25 @@ struct identityV0ProofOfWorkCriteria
char *genmem;
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define ZT_IDENTITY_V1_POW_MEMORY_SIZE 131072
struct p_CompareLittleEndian
void v1ChallengeFromPub(const uint8_t pub[ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE], uint64_t challenge[4])
{
#if __BYTE_ORDER == __BIG_ENDIAN
ZT_INLINE bool operator()(const uint64_t a,const uint64_t b) const noexcept
{ return Utils::swapBytes(a) < Utils::swapBytes(b); }
#else
ZT_INLINE bool operator()(const uint64_t a, const uint64_t b) const noexcept
{ return a < b; }
#endif
};
// This is a simpler memory-intensive frankenhash for V1 identity generation.
bool identityV1ProofOfWorkCriteria(const void *in, const unsigned int len, uint64_t *const w)
{
// Fill work buffer with pseudorandom bytes using a construction that should be
// relatively hostile to GPU acceleration. GPUs usually implement branching by
// executing all branches and then selecting the answer, which means this
// construction should require a GPU to do ~3X the work of a CPU per iteration.
SHA512(w, in, len);
for (unsigned int i = 8, j = 0; i < (ZT_IDENTITY_V1_POW_MEMORY_SIZE / 8);) {
uint64_t *const ww = w + i;
const uint64_t *const wp = w + j;
i += 8;
j += 8;
if ((wp[0] & 7U) == 0) {
SHA512(ww, wp, 64);
} else if ((wp[1] & 15U) == 0) {
ww[0] = Utils::hton(Utils::ntoh(wp[0]) % 4503599627370101ULL);
ww[1] = Utils::hton(Utils::ntoh(wp[1]) % 4503599627370161ULL);
ww[2] = Utils::hton(Utils::ntoh(wp[2]) % 4503599627370227ULL);
ww[3] = Utils::hton(Utils::ntoh(wp[3]) % 4503599627370287ULL);
ww[4] = Utils::hton(Utils::ntoh(wp[4]) % 4503599627370299ULL);
ww[5] = Utils::hton(Utils::ntoh(wp[5]) % 4503599627370323ULL);
ww[6] = Utils::hton(Utils::ntoh(wp[6]) % 4503599627370353ULL);
ww[7] = Utils::hton(Utils::ntoh(wp[7]) % 4503599627370449ULL);
SHA384(ww, wp, 128);
} else {
Salsa20(wp, wp + 4).crypt12(wp, ww, 64);
}
}
// Sort 64-bit integers (little-endian) into ascending order and compute a
// cryptographic checksum. Sorting makes the order of values dependent on all
// other values, making a speed competitive implementation that skips on the
// memory requirement extremely hard.
std::sort(w, w + (ZT_IDENTITY_V1_POW_MEMORY_SIZE / 8), p_CompareLittleEndian());
Poly1305::compute(w, w, ZT_IDENTITY_V1_POW_MEMORY_SIZE, w);
// PoW criteria passed if this is true. The value 1093 was chosen experimentally
// to yield a good average performance balancing fast setup with intentional
// identity collision resistance.
return (Utils::ntoh(w[0]) % 1000U) == 0;
// This builds a 256-bit challenge by XORing the two public keys together. This doesn't need to be
// a hash, just different for different public keys. Public keys are basically kind of hashes of
// private keys, so that's good enough. This is only used to seed a PRNG in MIMC52 for a proof of
// sequential work. It's not used for authentication beyond checking PoW.
Utils::copy< 32 >(challenge, pub + 7);
challenge[0] ^= Utils::loadMachineEndian< uint64_t >(pub + 40);
challenge[1] ^= Utils::loadMachineEndian< uint64_t >(pub + 48);
challenge[2] ^= Utils::loadMachineEndian< uint64_t >(pub + 56);
challenge[3] ^= Utils::loadMachineEndian< uint64_t >(pub + 64);
challenge[0] ^= Utils::loadMachineEndian< uint64_t >(pub + 72);
challenge[1] ^= Utils::loadMachineEndian< uint64_t >(pub + 80);
challenge[2] ^= Utils::loadMachineEndian< uint64_t >(pub + 88);
challenge[3] ^= Utils::loadMachineEndian< uint64_t >(pub + 96);
challenge[0] ^= Utils::loadMachineEndian< uint64_t >(pub + 104);
challenge[1] ^= Utils::loadMachineEndian< uint64_t >(pub + 112);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
} // anonymous namespace
const Identity Identity::NIL;
@ -170,38 +127,29 @@ bool Identity::generate(const Type t)
}
break;
case P384: {
//uint64_t w[ZT_IDENTITY_V1_POW_MEMORY_SIZE / 8];
uint64_t *const w = (uint64_t *)malloc(ZT_IDENTITY_V1_POW_MEMORY_SIZE);
if (!w)
return false;
try {
for (;;) {
// Loop until we pass the PoW criteria. The nonce is only 8 bits, so generate
// some new key material every time it wraps. The ECC384 generator is slightly
// faster so use that one.
m_pub[0] = 0; // zero nonce
C25519::generateCombined(m_pub + 1, m_priv + 1);
ECC384GenerateKey(m_pub + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, m_priv + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE);
for (;;) {
if (identityV1ProofOfWorkCriteria(m_pub, sizeof(m_pub), w))
break;
if (++m_pub[0] == 0)
ECC384GenerateKey(m_pub + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, m_priv + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE);
}
case P384:
for (;;) {
C25519::generateCombined(m_pub + 7, m_priv);
ECC384GenerateKey(m_pub + 7 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, m_priv + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE);
// If we passed PoW then check that the address is valid, otherwise loop
// back around and run the whole process again.
m_computeHash();
const Address addr(m_fp.hash);
if (!addr.isReserved()) {
m_fp.address = addr;
break;
}
uint64_t challenge[4];
v1ChallengeFromPub(m_pub, challenge);
const uint64_t proof = MIMC52::delay(reinterpret_cast<const uint8_t *>(challenge), ZT_IDENTITY_TYPE1_MIMC52_ROUNDS);
m_pub[0] = (uint8_t)(proof >> 48U);
m_pub[1] = (uint8_t)(proof >> 40U);
m_pub[2] = (uint8_t)(proof >> 32U);
m_pub[3] = (uint8_t)(proof >> 24U);
m_pub[4] = (uint8_t)(proof >> 16U);
m_pub[5] = (uint8_t)(proof >> 8U);
m_pub[6] = (uint8_t)proof;
m_computeHash();
const Address addr(m_fp.hash);
if (!addr.isReserved()) {
m_fp.address = addr;
break;
}
} catch ( ... ) {}
free(w);
}
}
break;
default:
@ -216,6 +164,7 @@ bool Identity::locallyValidate() const noexcept
try {
if ((m_fp) && ((!Address(m_fp.address).isReserved()))) {
switch (m_type) {
case C25519: {
uint8_t digest[64];
char *const genmem = (char *)malloc(ZT_V0_IDENTITY_GEN_MEMORY);
@ -225,16 +174,15 @@ bool Identity::locallyValidate() const noexcept
free(genmem);
return ((Address(digest + 59) == m_fp.address) && (digest[0] < 17));
}
case P384: {
if (Address(m_fp.hash) != m_fp.address)
return false;
uint64_t *const w = (uint64_t *)malloc(ZT_IDENTITY_V1_POW_MEMORY_SIZE);
if (!w)
return false;
const bool valid = identityV1ProofOfWorkCriteria(m_pub, sizeof(m_pub), w);
free(w);
return valid;
}
case P384:
if (Address(m_fp.hash) == m_fp.address) {
uint64_t challenge[4];
v1ChallengeFromPub(m_pub, challenge);
return MIMC52::verify(reinterpret_cast<const uint8_t *>(challenge), ZT_IDENTITY_TYPE1_MIMC52_ROUNDS, ((uint64_t)m_pub[0] << 48U) | ((uint64_t)m_pub[1] << 40U) | ((uint64_t)m_pub[2] << 32U) | ((uint64_t)m_pub[3] << 24U) | ((uint64_t)m_pub[4] << 16U) | ((uint64_t)m_pub[5] << 8U) | (uint64_t)m_pub[6]);
}
return false;
}
}
} catch (...) {}
@ -245,12 +193,15 @@ void Identity::hashWithPrivate(uint8_t h[ZT_FINGERPRINT_HASH_SIZE]) const
{
if (m_hasPrivate) {
switch (m_type) {
case C25519:
SHA384(h, m_pub, ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, m_priv, ZT_C25519_COMBINED_PRIVATE_KEY_SIZE);
return;
case P384:
SHA384(h, m_pub, sizeof(m_pub), m_priv, sizeof(m_priv));
return;
}
}
Utils::zero< ZT_FINGERPRINT_HASH_SIZE >(h);
@ -260,15 +211,16 @@ unsigned int Identity::sign(const void *data, unsigned int len, void *sig, unsig
{
if (m_hasPrivate) {
switch (m_type) {
case C25519:
if (siglen >= ZT_C25519_SIGNATURE_LEN) {
C25519::sign(m_priv, m_pub, data, len, sig);
return ZT_C25519_SIGNATURE_LEN;
}
break;
case P384:
if (siglen >= ZT_ECC384_SIGNATURE_SIZE) {
// SECURITY: signatures also include the public keys to further enforce their coupling.
static_assert(ZT_ECC384_SIGNATURE_HASH_SIZE == ZT_SHA384_DIGEST_SIZE, "weird!");
uint8_t h[ZT_ECC384_SIGNATURE_HASH_SIZE];
SHA384(h, data, len, m_pub, ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
@ -276,6 +228,7 @@ unsigned int Identity::sign(const void *data, unsigned int len, void *sig, unsig
return ZT_ECC384_SIGNATURE_SIZE;
}
break;
}
}
return 0;
@ -284,15 +237,18 @@ unsigned int Identity::sign(const void *data, unsigned int len, void *sig, unsig
bool Identity::verify(const void *data, unsigned int len, const void *sig, unsigned int siglen) const
{
switch (m_type) {
case C25519:
return C25519::verify(m_pub, data, len, sig, siglen);
case P384:
if (siglen == ZT_ECC384_SIGNATURE_SIZE) {
uint8_t h[ZT_ECC384_SIGNATURE_HASH_SIZE];
SHA384(h, data, len, m_pub, ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
return ECC384ECDSAVerify(m_pub + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, h, (const uint8_t *)sig);
return ECC384ECDSAVerify(m_pub + 7 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, h, (const uint8_t *)sig);
}
break;
}
return false;
}
@ -315,7 +271,7 @@ bool Identity::agree(const Identity &id, uint8_t key[ZT_SYMMETRIC_KEY_SIZE]) con
// or something. For those who don't trust P384 this means the privacy of
// your traffic is also protected by C25519.
C25519::agree(m_priv, id.m_pub, rawkey);
ECC384ECDH(id.m_pub + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, m_priv + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE, rawkey + ZT_C25519_ECDH_SHARED_SECRET_SIZE);
ECC384ECDH(id.m_pub + 7 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, m_priv + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE, rawkey + ZT_C25519_ECDH_SHARED_SECRET_SIZE);
SHA384(key, rawkey, ZT_C25519_ECDH_SHARED_SECRET_SIZE + ZT_ECC384_SHARED_SECRET_SIZE);
return true;
}
@ -516,15 +472,15 @@ int Identity::unmarshal(const uint8_t *data, const int len) noexcept
return -1;
privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE];
if (privlen == ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE) {
if (privlen == 0) {
m_hasPrivate = false;
return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1;
} else if (privlen == ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE) {
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE))
return -1;
m_hasPrivate = true;
Utils::copy< ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE >(&m_priv, data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1);
return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE;
} else if (privlen == 0) {
m_hasPrivate = false;
return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1;
}
break;
@ -539,9 +495,11 @@ void Identity::m_computeHash()
default:
m_fp.zero();
break;
case C25519:
SHA384(m_fp.hash, m_pub, ZT_C25519_COMBINED_PUBLIC_KEY_SIZE);
break;
case P384:
SHA384(m_fp.hash, m_pub, ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
break;

View file

@ -27,9 +27,10 @@
#define ZT_IDENTITY_STRING_BUFFER_LENGTH 1024
#define ZT_IDENTITY_C25519_PUBLIC_KEY_SIZE ZT_C25519_COMBINED_PUBLIC_KEY_SIZE
#define ZT_IDENTITY_C25519_PRIVATE_KEY_SIZE ZT_C25519_COMBINED_PRIVATE_KEY_SIZE
#define ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE (1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + ZT_ECC384_PUBLIC_KEY_SIZE)
#define ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE (7 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + ZT_ECC384_PUBLIC_KEY_SIZE)
#define ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE (ZT_C25519_COMBINED_PRIVATE_KEY_SIZE + ZT_ECC384_PRIVATE_KEY_SIZE)
#define ZT_IDENTITY_MARSHAL_SIZE_MAX (ZT_ADDRESS_LENGTH + 4 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE)
#define ZT_IDENTITY_TYPE1_MIMC52_ROUNDS 262144
namespace ZeroTier {

View file

@ -464,7 +464,9 @@ InetAddress InetAddress::makeIpv66plane(uint64_t nwid, uint64_t zeroTierAddress)
return r;
}
const int ZT_AF_INET = (int)AF_INET;
const int ZT_AF_INET6 = (int)AF_INET6;
extern "C" {
extern const int ZT_AF_INET = (int)AF_INET;
extern const int ZT_AF_INET6 = (int)AF_INET6;
}
} // namespace ZeroTier

127
core/MIMC52.cpp Normal file
View file

@ -0,0 +1,127 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
#include "Constants.hpp"
#include "AES.hpp"
#include "MIMC52.hpp"
namespace {
// The highest 1024 primes less than 2 ^ 52 (only the least significant 32 bits are needed)
const uint32_t ZT_MIMC52_PRIMES[1024] = {4294895267, 4294895477, 4294895513, 4294895519, 4294895543, 4294895567, 4294895657, 4294895711, 4294895777, 4294895861, 4294895909, 4294895921, 4294895969, 4294896011, 4294896149, 4294896227, 4294896401, 4294896473, 4294896527, 4294896563, 4294896653, 4294896731, 4294896863, 4294896899, 4294896983, 4294897037, 4294897103, 4294897331, 4294897349, 4294897451, 4294897571, 4294897661, 4294897703, 4294897757, 4294897793, 4294897811, 4294897817, 4294897829, 4294897877, 4294897919, 4294897991, 4294898027, 4294898129, 4294898153, 4294898231, 4294898273,
4294898279, 4294898291, 4294898363, 4294898369, 4294898417, 4294898423, 4294898453, 4294898489, 4294898573, 4294898579, 4294898639, 4294898693, 4294898747, 4294898759, 4294898867, 4294898879, 4294898909, 4294898921, 4294898933, 4294899011, 4294899041, 4294899047, 4294899203, 4294899221, 4294899227, 4294899287, 4294899341, 4294899431, 4294899509, 4294899533, 4294899539, 4294899551, 4294899629, 4294899791, 4294899809, 4294899971, 4294900001, 4294900007, 4294900013, 4294900307, 4294900331, 4294900427, 4294900469, 4294900481, 4294900541, 4294900583,
4294900781, 4294900853, 4294900931, 4294900991, 4294901033, 4294901087, 4294901159, 4294901267, 4294901393, 4294901411, 4294901489, 4294901657, 4294902011, 4294902071, 4294902101, 4294902107, 4294902353, 4294902377, 4294902599, 4294902647, 4294902743, 4294902869, 4294902977, 4294903067, 4294903103, 4294903259, 4294903289, 4294903397, 4294903421, 4294903493, 4294903577, 4294903631, 4294903637, 4294903733, 4294903799, 4294903823, 4294904003, 4294904033, 4294904081, 4294904129, 4294904279, 4294904297, 4294904303, 4294904333, 4294904351, 4294904381,
4294904453, 4294904519, 4294904561, 4294904639, 4294904657, 4294904747, 4294904807, 4294904843, 4294905089, 4294905149, 4294905293, 4294905299, 4294905311, 4294905443, 4294905479, 4294905539, 4294905623, 4294905641, 4294905671, 4294905707, 4294905887, 4294905977, 4294906091, 4294906103, 4294906139, 4294906157, 4294906223, 4294906259, 4294906487, 4294906493, 4294906523, 4294906547, 4294906553, 4294906571, 4294906577, 4294906589, 4294906703, 4294906733, 4294906763, 4294906841, 4294906859, 4294906937, 4294907057, 4294907063, 4294907141, 4294907231,
4294907249, 4294907261, 4294907267, 4294907387, 4294907417, 4294907567, 4294907603, 4294907699, 4294907789, 4294907849, 4294907873, 4294907879, 4294908023, 4294908071, 4294908119, 4294908209, 4294908227, 4294908329, 4294908491, 4294908503, 4294908569, 4294908653, 4294908713, 4294908719, 4294908791, 4294908839, 4294908869, 4294908989, 4294909031, 4294909067, 4294909109, 4294909253, 4294909529, 4294909589, 4294909643, 4294909739, 4294909799, 4294909811, 4294909853, 4294910003, 4294910039, 4294910189, 4294910201, 4294910219, 4294910273, 4294910333,
4294910369, 4294910393, 4294910471, 4294910549, 4294910651, 4294910669, 4294910681, 4294910711, 4294910753, 4294910801, 4294910981, 4294911053, 4294911143, 4294911227, 4294911239, 4294911359, 4294911383, 4294911407, 4294911521, 4294911551, 4294911611, 4294911641, 4294911689, 4294911719, 4294911869, 4294912109, 4294912133, 4294912151, 4294912187, 4294912223, 4294912331, 4294912439, 4294912607, 4294912703, 4294912859, 4294912871, 4294912907, 4294912961, 4294913003, 4294913111, 4294913309, 4294913333, 4294913357, 4294913399, 4294913411, 4294913459,
4294913501, 4294913531, 4294913591, 4294913609, 4294913663, 4294913783, 4294913819, 4294913903, 4294914137, 4294914413, 4294914473, 4294914497, 4294914527, 4294914551, 4294914593, 4294914611, 4294914659, 4294914671, 4294914743, 4294914863, 4294914917, 4294915061, 4294915103, 4294915139, 4294915217, 4294915223, 4294915253, 4294915283, 4294915373, 4294915433, 4294915607, 4294916069, 4294916213, 4294916267, 4294916303, 4294916393, 4294916441, 4294916477, 4294916507, 4294916573, 4294916633, 4294916687, 4294916783, 4294916837, 4294916897, 4294916921,
4294917029, 4294917047, 4294917101, 4294917203, 4294917287, 4294917299, 4294917389, 4294917437, 4294917527, 4294917557, 4294917611, 4294917617, 4294917689, 4294917821, 4294917857, 4294917917, 4294917941, 4294918169, 4294918187, 4294918307, 4294918409, 4294918433, 4294918481, 4294918703, 4294918709, 4294918733, 4294918799, 4294918871, 4294919009, 4294919249, 4294919279, 4294919291, 4294919363, 4294919381, 4294919441, 4294919447, 4294919549, 4294919579, 4294919633, 4294919657, 4294919669, 4294919693, 4294919711, 4294920029, 4294920059, 4294920089,
4294920197, 4294920239, 4294920257, 4294920263, 4294920269, 4294920341, 4294920353, 4294920407, 4294920503, 4294920599, 4294920647, 4294920743, 4294920803, 4294920809, 4294920881, 4294920899, 4294920983, 4294921043, 4294921139, 4294921151, 4294921181, 4294921229, 4294921289, 4294921331, 4294921343, 4294921391, 4294921469, 4294921709, 4294921721, 4294921823, 4294921847, 4294921889, 4294922057, 4294922171, 4294922201, 4294922237, 4294922309, 4294922399, 4294922447, 4294922507, 4294922513, 4294922549, 4294922609, 4294922663, 4294922861, 4294922933,
4294923101, 4294923191, 4294923209, 4294923221, 4294923251, 4294923263, 4294923359, 4294923371, 4294923377, 4294923461, 4294923521, 4294923953, 4294924001, 4294924091, 4294924121, 4294924319, 4294924397, 4294924571, 4294924583, 4294924751, 4294924817, 4294924823, 4294924847, 4294924877, 4294925003, 4294925027, 4294925117, 4294925237, 4294925243, 4294925297, 4294925369, 4294925627, 4294925639, 4294925729, 4294925747, 4294925873, 4294925891, 4294925933, 4294926047, 4294926059, 4294926209, 4294926221, 4294926233, 4294926257, 4294926329, 4294926371,
4294926401, 4294926413, 4294926437, 4294926563, 4294926569, 4294926917, 4294926923, 4294926947, 4294926971, 4294927067, 4294927073, 4294927151, 4294927349, 4294927367, 4294927403, 4294927481, 4294927523, 4294927553, 4294927589, 4294927649, 4294927673, 4294927727, 4294927739, 4294927763, 4294927889, 4294928183, 4294928207, 4294928249, 4294928327, 4294928351, 4294928399, 4294928483, 4294928489, 4294928543, 4294928597, 4294928951, 4294928963, 4294928981, 4294929017, 4294929059, 4294929161, 4294929197, 4294929233, 4294929269, 4294929311, 4294929323,
4294929341, 4294929383, 4294929401, 4294929497, 4294929509, 4294929581, 4294929707, 4294929743, 4294930043, 4294930121, 4294930193, 4294930223, 4294930349, 4294930403, 4294930571, 4294930613, 4294930721, 4294930751, 4294930877, 4294930931, 4294930961, 4294930967, 4294930973, 4294931021, 4294931051, 4294931057, 4294931063, 4294931219, 4294931273, 4294931339, 4294931423, 4294931441, 4294931453, 4294931567, 4294931639, 4294931717, 4294931897, 4294931969, 4294932023, 4294932053, 4294932239, 4294932299, 4294932443, 4294932671, 4294932677, 4294932731,
4294932743, 4294932767, 4294932773, 4294932779, 4294932881, 4294932899, 4294932929, 4294933067, 4294933277, 4294933307, 4294933343, 4294933451, 4294933523, 4294933763, 4294933793, 4294933829, 4294933847, 4294933871, 4294933997, 4294934033, 4294934111, 4294934207, 4294934243, 4294934267, 4294934279, 4294934291, 4294934327, 4294934363, 4294934423, 4294934489, 4294934561, 4294934867, 4294934921, 4294934969, 4294935137, 4294935239, 4294935299, 4294935431, 4294935539, 4294935629, 4294935701, 4294935791, 4294935797, 4294935803, 4294935959, 4294936001,
4294936007, 4294936037, 4294936079, 4294936127, 4294936163, 4294936247, 4294936307, 4294936331, 4294936409, 4294936451, 4294936601, 4294936607, 4294936619, 4294936667, 4294936709, 4294936733, 4294936751, 4294936763, 4294936829, 4294936937, 4294936997, 4294937027, 4294937051, 4294937093, 4294937177, 4294937213, 4294937291, 4294937381, 4294937417, 4294937429, 4294937681, 4294937693, 4294937753, 4294937771, 4294937813, 4294937837, 4294937891, 4294937969, 4294938071, 4294938101, 4294938323, 4294938371, 4294938401, 4294938467, 4294938473, 4294938521,
4294938599, 4294938731, 4294938779, 4294938833, 4294938899, 4294938977, 4294938983, 4294939067, 4294939127, 4294939223, 4294939277, 4294939331, 4294939337, 4294939391, 4294939457, 4294939559, 4294939673, 4294939691, 4294939901, 4294939991, 4294940087, 4294940093, 4294940189, 4294940213, 4294940417, 4294940657, 4294940699, 4294940753, 4294940801, 4294940873, 4294940951, 4294941047, 4294941143, 4294941161, 4294941227, 4294941281, 4294941377, 4294941509, 4294941551, 4294941701, 4294941731, 4294941767, 4294941911, 4294941923, 4294942043, 4294942139,
4294942313, 4294942343, 4294942373, 4294942427, 4294942529, 4294942601, 4294942649, 4294942673, 4294942679, 4294942733, 4294942769, 4294942811, 4294942961, 4294943129, 4294943141, 4294943219, 4294943369, 4294943423, 4294943471, 4294943651, 4294943687, 4294943717, 4294943729, 4294943747, 4294943759, 4294943813, 4294943819, 4294943891, 4294944077, 4294944191, 4294944233, 4294944239, 4294944353, 4294944389, 4294944581, 4294944623, 4294944629, 4294944659, 4294944821, 4294945031, 4294945157, 4294945211, 4294945229, 4294945301, 4294945337, 4294945343,
4294945511, 4294945547, 4294945667, 4294945709, 4294945757, 4294945841, 4294945991, 4294946033, 4294946099, 4294946153, 4294946477, 4294946687, 4294946747, 4294946957, 4294946993, 4294947023, 4294947131, 4294947167, 4294947287, 4294947311, 4294947413, 4294947581, 4294947599, 4294947671, 4294947851, 4294947959, 4294948067, 4294948073, 4294948193, 4294948259, 4294948421, 4294948451, 4294948613, 4294948673, 4294948883, 4294949027, 4294949057, 4294949069, 4294949519, 4294949531, 4294949603, 4294949609, 4294949627, 4294949693, 4294949729, 4294949741,
4294949807, 4294949921, 4294949939, 4294949981, 4294949993, 4294950083, 4294950173, 4294950197, 4294950251, 4294950287, 4294950317, 4294950323, 4294950329, 4294950581, 4294950593, 4294950617, 4294950629, 4294950713, 4294950929, 4294951151, 4294951163, 4294951169, 4294951379, 4294951583, 4294951613, 4294951853, 4294951907, 4294951913, 4294951937, 4294951961, 4294952063, 4294952183, 4294952393, 4294952543, 4294952549, 4294952597, 4294952627, 4294952687, 4294952723, 4294952729, 4294952789, 4294952819, 4294952873, 4294952891, 4294952903, 4294952969,
4294952999, 4294953023, 4294953107, 4294953173, 4294953281, 4294953341, 4294953431, 4294953599, 4294953689, 4294953719, 4294953827, 4294953887, 4294953977, 4294954073, 4294954079, 4294954157, 4294954217, 4294954283, 4294954607, 4294954667, 4294954859, 4294954901, 4294954973, 4294955081, 4294955237, 4294955273, 4294955327, 4294955441, 4294955507, 4294955591, 4294955789, 4294955831, 4294955837, 4294955927, 4294955963, 4294955969, 4294955987, 4294956041, 4294956047, 4294956197, 4294956323, 4294956359, 4294956551, 4294956593, 4294956623, 4294956629,
4294956641, 4294956719, 4294956761, 4294956767, 4294956797, 4294956821, 4294956833, 4294957037, 4294957079, 4294957103, 4294957181, 4294957349, 4294957379, 4294957433, 4294957463, 4294957511, 4294957577, 4294957727, 4294957859, 4294957877, 4294958039, 4294958153, 4294958309, 4294958417, 4294958441, 4294958693, 4294958717, 4294958753, 4294958903, 4294958909, 4294959017, 4294959071, 4294959107, 4294959161, 4294959257, 4294959299, 4294959329, 4294959431, 4294959593, 4294959599, 4294959659, 4294959893, 4294959917, 4294959983, 4294960001, 4294960031,
4294960061, 4294960079, 4294960097, 4294960271, 4294960283, 4294960349, 4294960367, 4294960421, 4294960529, 4294960541, 4294960583, 4294960613, 4294960673, 4294960691, 4294960697, 4294960787, 4294960919, 4294961003, 4294961039, 4294961153, 4294961159, 4294961171, 4294961321, 4294961411, 4294961471, 4294961507, 4294961537, 4294961669, 4294961717, 4294961741, 4294961873, 4294962059, 4294962137, 4294962167, 4294962263, 4294962281, 4294962311, 4294962341, 4294962413, 4294962521, 4294962563, 4294962761, 4294962893, 4294963103, 4294963163, 4294963223,
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.
#define mulmod52(a, b, m, mf) ( ( ( a * b ) - ( ((uint64_t)(((double)a * (double)b) / mf) - 1) * m ) ) % m )
// 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)
{
uint64_t res = 1ULL;
for (;;) {
if ((e << 63U)) {
res = mulmod52(res, a, m, mf);
}
if (likely((e >>= 1U) != 0)) {
a = mulmod52(a, a, m, mf);
} else {
break;
}
}
return res;
}
static const ZeroTier::AES s_mimc52AES("abcdefghijklmnopqrstuvwxyz012345");
// This fills k[] with pseudorandom bytes from the challenge.
// This doesn't have to be non-reversible or secure, just strongly random.
ZT_INLINE void fillK(uint64_t k[34], const uint8_t challenge[32])
{
s_mimc52AES.encrypt(challenge, k);
s_mimc52AES.encrypt(challenge + 16, k + 2);
k[2] ^= k[0];
k[3] ^= k[1];
for (unsigned int i = 2, j = 4; j < 34; i += 2, j += 2)
s_mimc52AES.encrypt(k + i, k + j);
#if __BYTE_ORDER == __BIG_ENDIAN
for (unsigned int i = 0; i < 34; ++i)
k[i] = Utils::swapBytes(k[i]);
#endif
}
} // anonymous namespace
namespace ZeroTier {
namespace MIMC52 {
uint64_t delay(const uint8_t challenge[32], const unsigned long rounds)
{
uint64_t k[34];
fillK(k, challenge);
const uint64_t p = 0x000fffff00000000ULL | (uint64_t)ZT_MIMC52_PRIMES[((unsigned long)k[32]) & 1023];
const uint64_t e = ((p * 2ULL) - 1ULL) / 3ULL;
const uint64_t m52 = 0xfffffffffffffULL;
const double pf = (double)p;
uint64_t x = k[33] % p;
for (unsigned long r = 0, kn = rounds; r < rounds; ++r) {
x = (x - k[--kn & 31]) & m52;
x = modpow52(x, e, p, pf);
}
return x;
}
bool verify(const uint8_t challenge[32], const unsigned long rounds, uint64_t proof)
{
uint64_t k[34];
fillK(k, challenge);
const uint64_t p = 0x000fffff00000000ULL | (uint64_t)ZT_MIMC52_PRIMES[((unsigned long)k[32]) & 1023];
const uint64_t m52 = 0xfffffffffffffULL;
const double pf = (double)p;
for (unsigned long r = 0; r < rounds; ++r) {
const uint64_t kk = k[r & 31];
proof = mulmod52(mulmod52(proof, proof, p, pf), proof, p, pf); // y = y ^ 3
proof = (proof + kk) & m52;
}
return ((proof % p) == (k[33] % p));
}
} // namespace MIMC52
} // namespace ZeroTier

44
core/MIMC52.hpp Normal file
View file

@ -0,0 +1,44 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2025-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
#ifndef ZT_MIMC52_HPP
#define ZT_MIMC52_HPP
#include "Constants.hpp"
namespace ZeroTier {
namespace MIMC52 {
/**
* Compute proof of execution for the delay function
*
* @param challenge 256-bit challenge input to randomize algorithm, making it a unique function
* @param rounds Number of rounds
* @return Proof of execution of delay function (only least significant 52 bits are meaningful)
*/
uint64_t delay(const uint8_t challenge[32], unsigned long rounds);
/**
* Verify a proof of execution
*
* @param challenge 256-bit challenge
* @param rounds Number of rounds
* @param proof Proof from delay()
* @return True if proof is valid
*/
bool verify(const uint8_t challenge[32], unsigned long rounds, uint64_t proof);
} // namespace MIMC52
} // namespcae ZeroTier
#endif

View file

@ -43,6 +43,7 @@
#include "Endpoint.hpp"
#include "Locator.hpp"
#include "Certificate.hpp"
#include "MIMC52.hpp"
#ifdef __UNIX_LIKE__
@ -67,7 +68,7 @@ static clock_serv_t _machGetRealtimeClock() noexcept
static clock_serv_t s_machRealtimeClock = _machGetRealtimeClock();
#endif
#endif // __APPLE__
using namespace ZeroTier;
@ -218,7 +219,7 @@ static const C25519TestVector C25519_TEST_VECTORS[ZT_NUM_C25519_TEST_VECTORS] =
};
#define IDENTITY_V0_KNOWN_GOOD_0 "8e4df28b72:0:ac3d46abe0c21f3cfe7a6c8d6a85cfcffcb82fbd55af6a4d6350657c68200843fa2e16f9418bbd9702cae365f2af5fb4c420908b803a681d4daef6114d78a2d7:bd8dd6e4ce7022d2f812797a80c6ee8ad180dc4ebf301dec8b06d1be08832bddd63a2f1cfa7b2c504474c75bdc8898ba476ef92e8e2d0509f8441985171ff16e"
#define IDENTITY_V1_KNOWN_GOOD_0 "cb8be88914:1:uhvyeplt7yjunjissek2ndvj6p6aj5jl7fhdgu64dnqld6h6daixc2ngqxm6pu62hxwheioy3jr46qyaxbmy536qvk5asltqqeyuqhhxakzkfyc3ejza52a4qpp6fabitfiuu6337zji47c4exrepurn6blovy5fgocmp7icwkrohqx354kk55a:xw62q5dniqpm4v7tmagukxlzgmegm3gbhx6izatu43vkvgvi6gejcvzlfg3d7ovqduzosawkq7agwx4qriqv56tr57cpdxzhrouuht7thiptbcvkh5yqrsturbw2eiudf4fijl4zhivtpiw4rbcxhkaobzhhapynhnahswppjlpmvnf4ncia"
#define IDENTITY_V1_KNOWN_GOOD_0 "26e83e3b8c:1:bwtgzeejkrkxeiuqyy35srdorynvz3nfrepqwiwedkm55bkhx77vaf6deknmikr2tgvymw3dxnifawo4m5pbfcqbnws6wzxlm7rgrad4xu52fcqg7ebwt4rhao6mjmrbn2bhdcevrlard5k7vropjrsuodoysvwbnjqef3q4fkrjgygddl4tatr5ztkjwt7f:a5vpcmommfyvjiqudkk7sjekscc4zyc3vqqdytkwlix5ahsxgz73ic3a62secgmyum65dok7b5aochdhdlinn3olyyswzy64ubx3pzbtryqsfmxpntxsvj7aqrd6kkrr3gobstl5yzln6bgqkihmhktbqt4vfwfqynkfjmncd4xqodogyxzq"
// --------------------------------------------------------------------------------------------------------------------
@ -440,7 +441,7 @@ extern "C" const char *ZTT_general()
}
#ifdef ZT_ARCH_X64
ZT_T_PRINTF("[general] X64 CPUID: aes=%d avx=%d avx2=%d avx512f=%d fsrm=%d rdrand=%d sha=%d vaes=%d vpclmulqdq=%d" ZT_EOL_S,
ZT_T_PRINTF("[general] X64 CPUID features: aes=%d avx=%d avx2=%d avx512f=%d fsrm=%d rdrand=%d sha=%d vaes=%d vpclmulqdq=%d" ZT_EOL_S,
Utils::CPUID.aes,
Utils::CPUID.avx,
Utils::CPUID.avx2,
@ -936,6 +937,27 @@ extern "C" const char *ZTT_general()
extern "C" const char *ZTT_crypto()
{
try {
{
ZT_T_PRINTF("[crypto] Testing MIMC52... ");
uint8_t challenge[32];
Utils::zero<32>(challenge);
uint64_t proof = MIMC52::delay(challenge, ZT_IDENTITY_TYPE1_MIMC52_ROUNDS);
if (!MIMC52::verify(challenge, ZT_IDENTITY_TYPE1_MIMC52_ROUNDS, proof)) {
ZT_T_PRINTF("FAILED (MIMC52 verify)" ZT_EOL_S);
return "MIMC52 failed (verify)";
}
if (proof != 0x0001bce730224699ULL) {
ZT_T_PRINTF("FAILED (MIMC52 proof not correct)" ZT_EOL_S);
return "MIMC52 failed (proof not correct)";
}
challenge[0] = 1;
if (MIMC52::verify(challenge, ZT_IDENTITY_TYPE1_MIMC52_ROUNDS, proof)) {
ZT_T_PRINTF("FAILED (MIMC52 verify known-bad)" ZT_EOL_S);
return "MIMC52 failed (verify known-bad)";
}
ZT_T_PRINTF("OK (%.16llx)" ZT_EOL_S, proof);
}
{
ZT_T_PRINTF("[crypto] Testing SHA384 and SHA512... ");
uint8_t h[64];
@ -1263,6 +1285,22 @@ extern "C" const char *ZTT_benchmarkCrypto()
Utils::zero< sizeof(tmp) >(tmp);
Utils::zero< sizeof(tag) >(tag);
{
Utils::getSecureRandom(tmp, 32);
ZT_T_PRINTF("[crypto] Benchmarking MIMC52 for %u rounds... ", ZT_IDENTITY_TYPE1_MIMC52_ROUNDS);
int64_t start = now();
uint64_t proof = MIMC52::delay(tmp, ZT_IDENTITY_TYPE1_MIMC52_ROUNDS);
int64_t t = now() - start;
ZT_T_PRINTF("%llu ms total, %.8f ms/round, verification: " , t, (double)t / (double)ZT_IDENTITY_TYPE1_MIMC52_ROUNDS);
start = now();
if (!MIMC52::verify(tmp, ZT_IDENTITY_TYPE1_MIMC52_ROUNDS, proof)) {
ZT_T_PRINTF("FAILED" ZT_EOL_S);
return "MIMC52 verify failed";
}
t = now() - start;
ZT_T_PRINTF("%llu ms, %.4f per second" ZT_EOL_S, t, 1000.0 / (double)t);
}
{
ZT_T_PRINTF("[crypto] Benchmarking SHA384... ");
int64_t start = now();