mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-06 12:33:44 +02:00
Some work on delay function... which is delaying us... but need to get it right because its hard as hell to change later.
This commit is contained in:
parent
5463c70aaf
commit
a20aebaaf8
4 changed files with 187 additions and 60 deletions
|
@ -41,6 +41,7 @@ set(core_headers
|
||||||
SelfAwareness.hpp
|
SelfAwareness.hpp
|
||||||
SHA512.hpp
|
SHA512.hpp
|
||||||
SharedPtr.hpp
|
SharedPtr.hpp
|
||||||
|
Speck128.hpp
|
||||||
Tag.hpp
|
Tag.hpp
|
||||||
Topology.hpp
|
Topology.hpp
|
||||||
Trace.hpp
|
Trace.hpp
|
||||||
|
|
|
@ -14,6 +14,9 @@
|
||||||
#include "MIMC52.hpp"
|
#include "MIMC52.hpp"
|
||||||
#include "SHA512.hpp"
|
#include "SHA512.hpp"
|
||||||
#include "Utils.hpp"
|
#include "Utils.hpp"
|
||||||
|
#include "Speck128.hpp"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
// This gets defined on any architecture whose FPU is not capable of doing the mulmod52() FPU trick.
|
// This gets defined on any architecture whose FPU is not capable of doing the mulmod52() FPU trick.
|
||||||
//#define ZT_MIMC52_NO_FPU
|
//#define ZT_MIMC52_NO_FPU
|
||||||
|
@ -96,67 +99,31 @@ ZT_INLINE uint64_t modpow52(uint64_t a,uint64_t e,const uint64_t p) noexcept
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// See: https://en.wikipedia.org/wiki/Speck_(cipher)
|
|
||||||
#define SPECK_ROR(x,r) ((x >> r) | (x << (64U - r)))
|
|
||||||
#define SPECK_ROL(x,r) ((x << r) | (x >> (64U - r)))
|
|
||||||
#define SPECK_R(x,y,k) (x = SPECK_ROR(x,8U), x += y, x ^= k, y = SPECK_ROL(y,3U), y ^= x)
|
|
||||||
|
|
||||||
ZT_INLINE void mimc52Init(uint64_t k[128],const void *const salt,const unsigned int saltSize,uint64_t &p,uint64_t &x) noexcept
|
|
||||||
{
|
|
||||||
uint64_t hash[6];
|
|
||||||
SHA384(hash,salt,saltSize);
|
|
||||||
|
|
||||||
// Choose a prime and a delay starting point / verification end point.
|
|
||||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
|
||||||
p = s_mimc52Primes[hash[0] & 511U];
|
|
||||||
x = hash[1] % p;
|
|
||||||
#else
|
|
||||||
p = s_mimc52Primes[Utils::swapBytes(hash[0]) & 511U];
|
|
||||||
x = Utils::swapBytes(hash[1]) % p;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Use the Speck128 round function as a fast PRNG to generate MIMC round constants. Speck128 initial inputs are
|
|
||||||
// from the last 256 bits of the salt hash. MIMC round constants could be static, but generating them from the
|
|
||||||
// salt may improve the overall randomness and non-reversibility of the delay function.
|
|
||||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
|
||||||
uint64_t ka = hash[2],kb = hash[3];
|
|
||||||
#else
|
|
||||||
uint64_t ka = Utils::swapBytes(hash[2]),kb = Utils::swapBytes(hash[3]);
|
|
||||||
#endif
|
|
||||||
uint64_t sy = hash[4],sx = hash[5];
|
|
||||||
for(unsigned long i=0;i<128;i+=2) {
|
|
||||||
ka += i;
|
|
||||||
kb += i;
|
|
||||||
SPECK_R(sx,sy,kb);
|
|
||||||
SPECK_R(ka,kb,0U);
|
|
||||||
SPECK_R(sx,sy,kb);
|
|
||||||
SPECK_R(ka,kb,1U);
|
|
||||||
SPECK_R(sx,sy,kb);
|
|
||||||
SPECK_R(ka,kb,2U);
|
|
||||||
SPECK_R(sx,sy,kb);
|
|
||||||
SPECK_R(ka,kb,3U);
|
|
||||||
SPECK_R(sx,sy,kb);
|
|
||||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
|
||||||
k[i] = sy;
|
|
||||||
k[i+1] = sx;
|
|
||||||
#else
|
|
||||||
k[i] = Utils::swapBytes(sy);
|
|
||||||
k[i+1] = Utils::swapBytes(sx);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
uint64_t mimc52Delay(const void *const salt,const unsigned int saltSize,const unsigned long rounds)
|
uint64_t mimc52Delay(const void *const salt,const unsigned int saltSize,const unsigned long rounds)
|
||||||
{
|
{
|
||||||
uint64_t k[128],x,p;
|
uint64_t hash[6];
|
||||||
mimc52Init(k,salt,saltSize,p,x);
|
SHA384(hash,salt,saltSize);
|
||||||
|
|
||||||
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
uint64_t p = s_mimc52Primes[hash[0] & 511U];
|
||||||
|
uint64_t x = hash[1] % p;
|
||||||
|
#else
|
||||||
|
uint64_t p = s_mimc52Primes[Utils::swapBytes(hash[0]) & 511U];
|
||||||
|
uint64_t x = Utils::swapBytes(hash[1]) % p;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Speck128<8> roundConstantGenerator(hash + 2);
|
||||||
const uint64_t e = ((p * 2) - 1) / 3;
|
const uint64_t e = ((p * 2) - 1) / 3;
|
||||||
const uint64_t m52 = 0xfffffffffffffULL;
|
const uint64_t m52 = 0xfffffffffffffULL;
|
||||||
for(unsigned long r=0,kn=rounds;r<rounds;++r) {
|
const uint64_t rmin1 = rounds - 1;
|
||||||
x = (x - k[--kn & 127U]) & m52;
|
const uint64_t sxx = hash[4];
|
||||||
|
#pragma unroll 16
|
||||||
|
for(unsigned long r=0;r<rounds;++r) {
|
||||||
|
uint64_t sx = sxx,sy = rmin1 - r;
|
||||||
|
roundConstantGenerator.encryptXY(sx,sy);
|
||||||
|
x = (x - sy) & m52;
|
||||||
x = modpow52(x,e,p);
|
x = modpow52(x,e,p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,18 +132,29 @@ uint64_t mimc52Delay(const void *const salt,const unsigned int saltSize,const un
|
||||||
|
|
||||||
bool mimc52Verify(const void *const salt,const unsigned int saltSize,unsigned long rounds,const uint64_t proof)
|
bool mimc52Verify(const void *const salt,const unsigned int saltSize,unsigned long rounds,const uint64_t proof)
|
||||||
{
|
{
|
||||||
uint64_t k[128],x,p;
|
uint64_t hash[6];
|
||||||
mimc52Init(k,salt,saltSize,p,x);
|
SHA384(hash,salt,saltSize);
|
||||||
|
|
||||||
// Note: x64_cubemod() seems slower even here on all tested cores.
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
uint64_t p = s_mimc52Primes[hash[0] & 511U];
|
||||||
|
uint64_t x = hash[1] % p;
|
||||||
|
#else
|
||||||
|
uint64_t p = s_mimc52Primes[Utils::swapBytes(hash[0]) & 511U];
|
||||||
|
uint64_t x = Utils::swapBytes(hash[1]) % p;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Speck128<8> roundConstantGenerator(hash + 2);
|
||||||
const uint64_t m52 = 0xfffffffffffffULL;
|
const uint64_t m52 = 0xfffffffffffffULL;
|
||||||
uint64_t y = proof & m52;
|
uint64_t y = proof & m52;
|
||||||
|
const uint64_t sxx = hash[4];
|
||||||
#if !defined(ZT_MIMC52_NO_FPU)
|
#if !defined(ZT_MIMC52_NO_FPU)
|
||||||
double ii,of,pp = (double)p;
|
double ii,of,pp = (double)p;
|
||||||
uint64_t oi,one = 1;
|
uint64_t oi,one = 1;
|
||||||
#endif
|
#endif
|
||||||
|
#pragma unroll 16
|
||||||
for(unsigned long r=0;r<rounds;++r) {
|
for(unsigned long r=0;r<rounds;++r) {
|
||||||
|
uint64_t sx = sxx,sy = r;
|
||||||
|
roundConstantGenerator.encryptXY(sx,sy);
|
||||||
#ifdef ZT_MIMC52_NO_FPU
|
#ifdef ZT_MIMC52_NO_FPU
|
||||||
#ifdef x64_cubemod
|
#ifdef x64_cubemod
|
||||||
x64_cubemod(y,p);
|
x64_cubemod(y,p);
|
||||||
|
@ -196,7 +174,7 @@ bool mimc52Verify(const void *const salt,const unsigned int saltSize,unsigned lo
|
||||||
y -= ((uint64_t)ii - one) * p;
|
y -= ((uint64_t)ii - one) * p;
|
||||||
y %= p;
|
y %= p;
|
||||||
#endif
|
#endif
|
||||||
y = (y + k[r & 127U]) & m52;
|
y = (y + sy) & m52;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (y % p) == x;
|
return (y % p) == x;
|
||||||
|
|
148
node/Speck128.hpp
Normal file
148
node/Speck128.hpp
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
/*
|
||||||
|
* 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: 2024-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_SPECK128_HPP
|
||||||
|
#define ZT_SPECK128_HPP
|
||||||
|
|
||||||
|
#include "Constants.hpp"
|
||||||
|
#include "Utils.hpp"
|
||||||
|
|
||||||
|
namespace ZeroTier {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tiny and simple 128-bit ARX block cipher
|
||||||
|
*
|
||||||
|
* Speck does not specify a mandatory endian-ness. This implementation is
|
||||||
|
* little-endian for higher performance on the majority of platforms.
|
||||||
|
*
|
||||||
|
* @tparam R Number of rounds (default: 32)
|
||||||
|
*/
|
||||||
|
template<int R = 32>
|
||||||
|
class Speck128
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Create an uninitialized instance, init() must be called to set up.
|
||||||
|
*/
|
||||||
|
ZT_INLINE Speck128() noexcept {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize Speck from a 128-bit key
|
||||||
|
*
|
||||||
|
* @param k 128-bit / 16 byte key
|
||||||
|
*/
|
||||||
|
ZT_INLINE Speck128(const void *k) noexcept { this->init(k); }
|
||||||
|
|
||||||
|
ZT_INLINE ~Speck128() { Utils::burn(_k,sizeof(_k)); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize Speck from a 128-bit key
|
||||||
|
*
|
||||||
|
* @param k 128-bit / 16 byte key
|
||||||
|
*/
|
||||||
|
ZT_INLINE void init(const void *k) noexcept
|
||||||
|
{
|
||||||
|
uint64_t x = Utils::loadLittleEndian<uint64_t>(k);
|
||||||
|
uint64_t y = Utils::loadLittleEndian<uint64_t>(reinterpret_cast<const uint8_t *>(k) + 8);
|
||||||
|
_k[0] = x;
|
||||||
|
for(uint64_t i=0;i<(R-1);++i) {
|
||||||
|
x = x >> 8U | x << 56U;
|
||||||
|
x += y;
|
||||||
|
x ^= i;
|
||||||
|
y = y << 3U | y >> 61U;
|
||||||
|
y ^= x;
|
||||||
|
_k[i + 1] = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypt a 128-bit block as two 64-bit words
|
||||||
|
*
|
||||||
|
* These should be in host byte order. If read or written to/from data
|
||||||
|
* they should be stored in little-endian byte order.
|
||||||
|
*
|
||||||
|
* @param x Least significant 64 bits
|
||||||
|
* @param y Most significant 64 bits
|
||||||
|
*/
|
||||||
|
ZT_INLINE void encryptXY(uint64_t &x,uint64_t &y) const noexcept
|
||||||
|
{
|
||||||
|
#pragma unroll
|
||||||
|
for (int i=0;i<R;++i) {
|
||||||
|
const uint64_t kk = _k[i];
|
||||||
|
x = x >> 8U | x << 56U;
|
||||||
|
x += y;
|
||||||
|
x ^= kk;
|
||||||
|
y = y << 3U | y >> 61U;
|
||||||
|
y ^= x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypt a 128-bit block as two 64-bit words
|
||||||
|
*
|
||||||
|
* These should be in host byte order. If read or written to/from data
|
||||||
|
* they should be stored in little-endian byte order.
|
||||||
|
*
|
||||||
|
* @param x Least significant 64 bits
|
||||||
|
* @param y Most significant 64 bits
|
||||||
|
*/
|
||||||
|
ZT_INLINE void decryptXY(uint64_t &x,uint64_t &y) const noexcept
|
||||||
|
{
|
||||||
|
#pragma unroll
|
||||||
|
for (int i=(R-1);i>=0;--i) {
|
||||||
|
const uint64_t kk = _k[i];
|
||||||
|
y ^= x;
|
||||||
|
y = y >> 3U | y << 61U;
|
||||||
|
x ^= kk;
|
||||||
|
x -= y;
|
||||||
|
x = x << 8U | x >> 56U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypt a block
|
||||||
|
*
|
||||||
|
* @param in 128-bit / 16 byte input
|
||||||
|
* @param out 128-bit / 16 byte output
|
||||||
|
*/
|
||||||
|
ZT_INLINE void encrypt(const void *const in,void *const out) const noexcept
|
||||||
|
{
|
||||||
|
uint64_t x = Utils::loadLittleEndian<uint64_t>(in);
|
||||||
|
uint64_t y = Utils::loadLittleEndian<uint64_t>(reinterpret_cast<const uint8_t *>(in) + 8);
|
||||||
|
encryptXY(x,y);
|
||||||
|
Utils::storeLittleEndian<uint64_t>(out,x);
|
||||||
|
Utils::storeLittleEndian<uint64_t>(reinterpret_cast<uint8_t *>(out) + 8,y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypt a block
|
||||||
|
*
|
||||||
|
* @param in 128-bit / 16 byte input
|
||||||
|
* @param out 128-bit / 16 byte output
|
||||||
|
*/
|
||||||
|
ZT_INLINE void decrypt(const void *const in,void *const out) const noexcept
|
||||||
|
{
|
||||||
|
uint64_t x = Utils::loadLittleEndian<uint64_t>(in);
|
||||||
|
uint64_t y = Utils::loadLittleEndian<uint64_t>(reinterpret_cast<const uint8_t *>(in) + 8);
|
||||||
|
decryptXY(x,y);
|
||||||
|
Utils::storeLittleEndian<uint64_t>(out,x);
|
||||||
|
Utils::storeLittleEndian<uint64_t>(reinterpret_cast<uint8_t *>(out) + 8,y);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint64_t _k[R];
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ZeroTier
|
||||||
|
|
||||||
|
#endif
|
|
@ -777,8 +777,8 @@ extern "C" const char *ZTT_crypto()
|
||||||
|
|
||||||
{
|
{
|
||||||
ZT_T_PRINTF("[crypto] Testing MIMC52 VDF... ");
|
ZT_T_PRINTF("[crypto] Testing MIMC52 VDF... ");
|
||||||
const uint64_t proof = mimc52Delay("testing",7,1000);
|
const uint64_t proof = mimc52Delay("",1,1000);
|
||||||
if ((!mimc52Verify("testing",7,1000,proof))||(proof != 0x000b501115c73369)) {
|
if ((!mimc52Verify("",1,1000,proof))||(proof != 0x00036030471c2aec)) {
|
||||||
ZT_T_PRINTF("FAILED (%.16llx)" ZT_EOL_S,proof);
|
ZT_T_PRINTF("FAILED (%.16llx)" ZT_EOL_S,proof);
|
||||||
return "MIMC52 failed simple delay/verify test";
|
return "MIMC52 failed simple delay/verify test";
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue