@@ -1580,6 +1580,122 @@ decaf_error_t API_NS(direct_scalarmul) ( | |||
return succ; | |||
} | |||
decaf_error_t API_NS(x_direct_scalarmul) ( | |||
uint8_t out[X_PUBLIC_BYTES], | |||
const uint8_t base[X_PUBLIC_BYTES], | |||
const uint8_t scalar[X_PRIVATE_BYTES] | |||
) { | |||
gf x1, x2, z2, x3, z3, t1, t2; | |||
ignore_result(gf_deserialize(x1,base)); | |||
gf_copy(x2,ONE); | |||
gf_copy(z2,ZERO); | |||
gf_copy(x3,x1); | |||
gf_copy(z3,ONE); | |||
int t; | |||
mask_t swap = 0; | |||
for (t = X_PRIVATE_BITS-1; t>=0; t--) { | |||
uint8_t sb = scalar[t/8]; | |||
/* Scalar conditioning */ | |||
if (t/8==0) sb &= -(uint8_t)COFACTOR; | |||
else if (t == X_PRIVATE_BITS-1) sb = -1; | |||
mask_t k_t = (sb>>(t%8)) & 1; | |||
k_t = -k_t; /* set to all 0s or all 1s */ | |||
swap ^= k_t; | |||
cond_swap(x2,x3,swap); | |||
cond_swap(z2,z3,swap); | |||
swap = k_t; | |||
gf_add(t1,x2,z2); /* A = x2 + z2 */ | |||
gf_sub(t2,x2,z2); /* B = x2 - z2 */ | |||
gf_sub(z2,x3,z3); /* D = x3 - z3 */ | |||
gf_mul(x2,t1,z2); /* DA */ | |||
gf_add(z2,z3,x3); /* C = x3 + z3 */ | |||
gf_mul(x3,t2,z2); /* CB */ | |||
gf_sub(z3,x2,x3); /* DA-CB */ | |||
gf_sqr(z2,z3); /* (DA-CB)^2 */ | |||
gf_mul(z3,x1,z2); /* z3 = x1(DA-CB)^2 */ | |||
gf_add(z2,x2,x3); /* (DA+CB) */ | |||
gf_sqr(x3,z2); /* x3 = (DA+CB)^2 */ | |||
gf_sqr(z2,t1); /* AA = A^2 */ | |||
gf_sqr(t1,t2); /* BB = B^2 */ | |||
gf_mul(x2,z2,t1); /* x2 = AA*BB */ | |||
gf_sub(t2,z2,t1); /* E = AA-BB */ | |||
gf_mulw_sgn(t1,t2,-EDWARDS_D); /* E*-d = a24*E */ | |||
gf_add(t1,t1,z2); /* AA + a24*E */ | |||
gf_mul(z2,t2,t1); /* z2 = E(AA+a24*E) */ | |||
} | |||
/* Finish */ | |||
cond_swap(x2,x3,swap); | |||
cond_swap(z2,z3,swap); | |||
gf_invert(z2,z2); | |||
gf_mul(x1,x2,z2); | |||
gf_serialize(out,x1); | |||
mask_t nz = ~gf_eq(x1,ZERO); | |||
decaf_bzero(x1,sizeof(x1)); | |||
decaf_bzero(x2,sizeof(x2)); | |||
decaf_bzero(z2,sizeof(z2)); | |||
decaf_bzero(x3,sizeof(x3)); | |||
decaf_bzero(z3,sizeof(z3)); | |||
decaf_bzero(t1,sizeof(t1)); | |||
decaf_bzero(t2,sizeof(t2)); | |||
return decaf_succeed_if(mask_to_bool(nz)); | |||
} | |||
void API_NS(x_base_scalarmul) ( | |||
uint8_t out[X_PUBLIC_BYTES], | |||
const uint8_t scalar[X_PRIVATE_BYTES] | |||
) { | |||
/* Scalar conditioning */ | |||
uint8_t scalar2[X_PRIVATE_BYTES]; | |||
memcpy(scalar2,scalar,sizeof(scalar2)); | |||
scalar2[0] &= -(uint8_t)COFACTOR; | |||
scalar2[X_PRIVATE_BYTES-1] &= ~(-1<<((X_PRIVATE_BITS+7)%8)); | |||
scalar2[X_PRIVATE_BYTES-1] |= 1<<((X_PRIVATE_BITS+7)%8); | |||
scalar_t the_scalar; | |||
API_NS(scalar_decode_long)(the_scalar,scalar2,sizeof(scalar2)); | |||
/* We're gonna isogenize by 2, so divide by 2. | |||
* | |||
* Why by 2, even though it's a 4-isogeny? | |||
* | |||
* The isogeny map looks like | |||
* Montgomery <-2-> Jacobi <-2-> Edwards | |||
* | |||
* Since the Jacobi base point is the PREimage of the iso to | |||
* the Montgomery curve, and we're going | |||
* Jacobi -> Edwards -> Jacobi -> Montgomery, | |||
* we pick up only a factor of 2 over Jacobi -> Montgomery. | |||
*/ | |||
sc_halve(the_scalar,the_scalar,sc_p); | |||
point_t p; | |||
API_NS(precomputed_scalarmul)(p,API_NS(precomputed_base),the_scalar); | |||
/* Isogenize to Montgomery curve */ | |||
gf_invert(p->t,p->x); /* 1/x */ | |||
gf_mul(p->z,p->t,p->y); /* y/x */ | |||
gf_sqr(p->y,p->z); /* (y/x)^2 */ | |||
#if IMAGINE_TWIST | |||
gf_sub(p->y,ZERO,p->y); | |||
#endif | |||
gf_serialize(out,p->y); | |||
decaf_bzero(scalar2,sizeof(scalar2)); | |||
API_NS(scalar_destroy)(the_scalar); | |||
API_NS(point_destroy)(p); | |||
} | |||
/** | |||
* @cond internal | |||
* Control for variable-time scalar multiply algorithms. | |||
@@ -28,6 +28,7 @@ const API_NS(scalar_t) API_NS(sc_r2) = {{{0}}}; | |||
const decaf_word_t API_NS(MONTGOMERY_FACTOR) = 0; | |||
const API_NS(point_t) API_NS(point_base); | |||
const uint8_t API_NS(x_base_point)[X_PUBLIC_BYTES] = {0}; | |||
struct niels_s; | |||
const gf_s *API_NS(precomputed_wnaf_as_fe); | |||
@@ -170,6 +171,19 @@ int main(int argc, char **argv) { | |||
w *= w*plo + 2; | |||
} | |||
printf("const decaf_word_t API_NS(MONTGOMERY_FACTOR) = (decaf_word_t)0x%016llxull;\n\n", w); | |||
/* Generate the Montgomery ladder version of the base point */ | |||
gf base1,base2; | |||
ret = gf_deserialize(base1,base_point_ser_for_pregen); | |||
if (ret != DECAF_SUCCESS) return 1; | |||
gf_sqr(base2,base1); | |||
uint8_t x_ser[X_PUBLIC_BYTES] = {0}; | |||
gf_serialize(x_ser, base2); | |||
printf("const uint8_t API_NS(x_base_point)[%d] = {", X_PUBLIC_BYTES); | |||
for (i=0; i<X_PUBLIC_BYTES; i++) { | |||
printf("%s%s%d",i?",":"",(i%32==0)?"\n ":"",x_ser[i]); | |||
} | |||
printf("\n};\n"); | |||
return 0; | |||
} |
@@ -49,6 +49,15 @@ def ceil_log2(x): | |||
for field,data in field_data.iteritems(): | |||
if "gf_bits" not in data: | |||
data["gf_bits"] = ceil_log2(data["modulus"]) | |||
if "x_pub_bytes" not in data: | |||
data["x_pub_bytes"] = (data["gf_bits"]-1)//8 + 1 | |||
if "x_priv_bytes" not in data: | |||
data["x_priv_bytes"] = (data["gf_bits"]-1)//8 + 1 | |||
if "x_priv_bits" not in data: | |||
data["x_priv_bits"] = ceil_log2(data["modulus"]*0.99) | |||
for curve,data in curve_data.iteritems(): | |||
for key in field_data[data["field"]]: | |||
@@ -66,7 +75,7 @@ for curve,data in curve_data.iteritems(): | |||
data["bits"] = ceil_log2(data["modulus"]) | |||
if "ser_bytes" not in data: | |||
data["ser_bytes"] = (data["bits"]-1)//8 + 1 | |||
data["ser_bytes"] = (data["bits"]-2)//8 + 1 | |||
if "scalar_ser_bytes" not in data: | |||
data["scalar_ser_bytes"] = (data["scalar_bits"]-1)//8 + 1 | |||
@@ -35,6 +35,12 @@ typedef struct gf_%(gf_shortname)s_s { | |||
/** Number of bytes in a serialized scalar. */ | |||
#define %(C_NS)s_SCALAR_BYTES %(scalar_ser_bytes)d | |||
/** Number of bytes in an x%(gf_shortname)s public key */ | |||
#define X%(gf_shortname)s_PUBLIC_BYTES %(x_pub_bytes)d | |||
/** Number of bytes in an x%(gf_shortname)s private key */ | |||
#define X%(gf_shortname)s_PRIVATE_BYTES %(x_priv_bytes)d | |||
/** Twisted Edwards extended homogeneous coordinates */ | |||
typedef struct %(c_ns)s_point_s { | |||
/** @cond internal */ | |||
@@ -346,6 +352,39 @@ decaf_error_t %(c_ns)s_direct_scalarmul ( | |||
decaf_bool_t short_circuit | |||
) API_VIS NONNULL3 WARN_UNUSED NOINLINE; | |||
/** | |||
* @brief RFC 7748 Diffie-Hellman scalarmul. This function uses a different | |||
* (non-Decaf) encoding. | |||
* | |||
* @param [out] scaled The scaled point base*scalar | |||
* @param [in] base The point to be scaled. | |||
* @param [in] scalar The scalar to multiply by. | |||
* | |||
* @retval DECAF_SUCCESS The scalarmul succeeded. | |||
* @retval DECAF_FAILURE The scalarmul didn't succeed, because the base | |||
* point is in a small subgroup. | |||
*/ | |||
decaf_error_t %(c_ns)s_x_direct_scalarmul ( /* TODO: rename? */ | |||
uint8_t out[X%(gf_shortname)s_PUBLIC_BYTES], | |||
const uint8_t base[X%(gf_shortname)s_PUBLIC_BYTES], | |||
const uint8_t scalar[X%(gf_shortname)s_PRIVATE_BYTES] | |||
) API_VIS NONNULL3 WARN_UNUSED NOINLINE; | |||
/** The base point for X%(gf_shortname)s Diffie-Hellman */ | |||
extern const uint8_t %(c_ns)s_x_base_point[X%(gf_shortname)s_PUBLIC_BYTES] API_VIS; | |||
/** | |||
* @brief RFC 7748 Diffie-Hellman base point scalarmul. This function uses | |||
* a different (non-Decaf) encoding. | |||
* | |||
* @param [out] scaled The scaled point base*scalar | |||
* @param [in] scalar The scalar to multiply by. | |||
*/ | |||
void %(c_ns)s_x_base_scalarmul ( | |||
uint8_t out[X%(gf_shortname)s_PUBLIC_BYTES], | |||
const uint8_t scalar[X%(gf_shortname)s_PRIVATE_BYTES] | |||
) API_VIS NONNULL2 NOINLINE; | |||
/** | |||
* @brief Precompute a table for fast scalar multiplication. | |||
* Some implementations do not include precomputed points; for | |||
@@ -136,7 +136,7 @@ public: | |||
* Decode from correct-length little-endian byte sequence. | |||
* @return DECAF_FAILURE if the scalar is greater than or equal to the group order q. | |||
*/ | |||
static inline decaf_error_t __attribute__((warn_unused_result)) decode ( | |||
static inline decaf_error_t WARN_UNUSED decode ( | |||
Scalar &sc, const FixedBlock<SER_BYTES> buffer | |||
) NOEXCEPT { | |||
return %(c_ns)s_scalar_decode(sc.s,buffer.data()); | |||
@@ -175,7 +175,7 @@ public: | |||
/** Invert with Fermat's Little Theorem (slow!). If *this == 0, set r=0 | |||
* and return DECAF_FAILURE. */ | |||
inline decaf_error_t __attribute__((warn_unused_result)) | |||
inline decaf_error_t WARN_UNUSED | |||
inverse_noexcept(Scalar &r) const NOEXCEPT { | |||
return %(c_ns)s_scalar_invert(r.s,s); | |||
} | |||
@@ -276,7 +276,7 @@ public: | |||
* @return DECAF_FAILURE the string was the wrong length, or wasn't the encoding of a point, | |||
* or was the identity and allow_identity was DECAF_FALSE. Contents of the buffer are undefined. | |||
*/ | |||
static inline decaf_error_t __attribute__((warn_unused_result)) decode ( | |||
static inline decaf_error_t WARN_UNUSED decode ( | |||
Point &p, const FixedBlock<SER_BYTES> &buffer, decaf_bool_t allow_identity=DECAF_TRUE | |||
) NOEXCEPT { | |||
return %(c_ns)s_point_decode(p.p,buffer.data(),allow_identity); | |||
@@ -565,6 +565,64 @@ public: | |||
/** @endcond */ | |||
}; | |||
struct DhLadder { | |||
public: | |||
/** Bytes in an X%(gf_shortname)s public key. */ | |||
static const size_t PUBLIC_BYTES = X%(gf_shortname)s_PUBLIC_BYTES; | |||
/** Bytes in an X%(gf_shortname)s private key. */ | |||
static const size_t PRIVATE_BYTES = X%(gf_shortname)s_PRIVATE_BYTES; | |||
/** Base point for a scalar multiplication. */ | |||
static const FixedBlock<PUBLIC_BYTES> base_point() NOEXCEPT { | |||
return FixedBlock<PUBLIC_BYTES>(%(c_ns)s_x_base_point); | |||
} | |||
/** Generate and return a shared secret with public key. */ | |||
static inline SecureBuffer shared_secret( | |||
const FixedBlock<PUBLIC_BYTES> &pk, | |||
const FixedBlock<PRIVATE_BYTES> &scalar | |||
) throw(std::bad_alloc,CryptoException) { | |||
SecureBuffer out(PUBLIC_BYTES); | |||
if (DECAF_SUCCESS != %(c_ns)s_x_direct_scalarmul(out.data(), pk.data(), scalar.data())) { | |||
throw CryptoException(); | |||
} | |||
return out; | |||
} | |||
/** Generate and return a shared secret with public key, noexcept version. */ | |||
static inline decaf_error_t WARN_UNUSED | |||
shared_secret_noexcept ( | |||
FixedBuffer<PUBLIC_BYTES> &out, | |||
const FixedBlock<PUBLIC_BYTES> &pk, | |||
const FixedBlock<PRIVATE_BYTES> &scalar | |||
) NOEXCEPT { | |||
return %(c_ns)s_x_direct_scalarmul(out.data(), pk.data(), scalar.data()); | |||
} | |||
/** Generate and return a public key; equivalent to shared_secret(base_point(),scalar) | |||
* but possibly faster. | |||
*/ | |||
static inline SecureBuffer generate_key( | |||
const FixedBlock<PRIVATE_BYTES> &scalar | |||
) throw(std::bad_alloc) { | |||
SecureBuffer out(PUBLIC_BYTES); | |||
%(c_ns)s_x_base_scalarmul(out.data(), scalar.data()); | |||
return out; | |||
} | |||
/** Generate and return a public key into a fixed buffer; | |||
* equivalent to shared_secret(base_point(),scalar) but possibly faster. | |||
*/ | |||
static inline void | |||
generate_key_noexcept ( | |||
FixedBuffer<PUBLIC_BYTES> &out, | |||
const FixedBlock<PRIVATE_BYTES> &scalar | |||
) NOEXCEPT { | |||
%(c_ns)s_x_base_scalarmul(out.data(), scalar.data()); | |||
} | |||
}; | |||
}; /* struct %(cxx_ns)s */ | |||
/** @cond internal */ | |||
@@ -14,7 +14,7 @@ f_field_h = gen_file( | |||
#define __DECAF_%(gf_shortname)s_GF_DEFINED__ 1 | |||
#define NLIMBS (%(gf_impl_bits)d/sizeof(word_t)/8) | |||
#define SER_BYTES ((%(gf_bits)d-1)/8 + 1) | |||
#define SER_BYTES ((%(gf_bits)d-1)/8 + 1) /* MAGIC: depends on if high bit known to be clear (eg p521) */ | |||
typedef struct gf_%(gf_shortname)s_s { | |||
word_t limb[NLIMBS]; | |||
} __attribute__((aligned(32))) gf_%(gf_shortname)s_s, gf_%(gf_shortname)s_t[1]; | |||
@@ -42,6 +42,11 @@ typedef struct gf_%(gf_shortname)s_s { | |||
#define gf_serialize gf_%(gf_shortname)s_serialize | |||
#define gf_deserialize gf_%(gf_shortname)s_deserialize | |||
/* RFC 7748 support */ | |||
#define X_PUBLIC_BYTES %(x_pub_bytes)d | |||
#define X_PRIVATE_BYTES %(x_priv_bytes)d | |||
#define X_PRIVATE_BITS %(x_priv_bits)d | |||
#define SQRT_MINUS_ONE P%(gf_shortname)s_SQRT_MINUS_ONE /* might not be defined */ | |||
#define INLINE_UNUSED __inline__ __attribute__((unused,always_inline)) | |||
@@ -41,6 +41,12 @@ private: | |||
keccak_prng_t sp; | |||
public: | |||
/** Deterministic flag. | |||
* The idea is that DETERMINISTIC is used for testing or for lockstep computations, | |||
* and NONDETERMINISTIC is used in production. | |||
*/ | |||
enum Deterministic { RANDOM = 0, DETERMINISTIC = 1 }; | |||
/** Exception thrown when The RNG fails (to seed itself) */ | |||
class RngException : public std::exception { | |||
private: | |||
@@ -54,14 +60,14 @@ public: | |||
}; | |||
/** Initialize, deterministically by default, from block */ | |||
inline SpongeRng( const Block &in, bool deterministic = true ) { | |||
spongerng_init_from_buffer(sp,in.data(),in.size(),deterministic); | |||
inline SpongeRng( const Block &in, Deterministic det ) { | |||
spongerng_init_from_buffer(sp,in.data(),in.size(),(int)det); | |||
} | |||
/** Initialize, non-deterministically by default, from C/C++ filename */ | |||
inline SpongeRng( const std::string &in = "/dev/urandom", size_t len = 32, bool deterministic = false ) | |||
inline SpongeRng( const std::string &in = "/dev/urandom", size_t len = 32, Deterministic det = RANDOM ) | |||
throw(RngException) { | |||
decaf_error_t ret = spongerng_init_from_file(sp,in.c_str(),len,deterministic); | |||
decaf_error_t ret = spongerng_init_from_file(sp,in.c_str(),len,det); | |||
if (!decaf_successful(ret)) { | |||
throw RngException(errno, "Couldn't load from file"); | |||
} | |||
@@ -288,10 +288,21 @@ static void spake2ee( | |||
server.respec(STROBE_KEYED_128); | |||
} | |||
static void cfrg() { | |||
SpongeRng rng(Block("bench_cfrg_crypto"),SpongeRng::DETERMINISTIC); | |||
FixedArrayBuffer<Group::DhLadder::PUBLIC_BYTES> base(rng); | |||
FixedArrayBuffer<Group::DhLadder::PRIVATE_BYTES> s1(rng); | |||
for (Benchmark b("RFC 7748 keygen"); b.iter(); ) { Group::DhLadder::generate_key(s1); } | |||
for (Benchmark b("RFC 7748 shared secret"); b.iter(); ) { Group::DhLadder::shared_secret(base,s1); } | |||
} | |||
static void macro() { | |||
printf("\nMacro-benchmarks for %s:\n", Group::name()); | |||
printf("Crypto benchmarks:\n"); | |||
SpongeRng rng(Block("macro rng seed")); | |||
printf("CFRG crypto benchmarks:\n"); | |||
cfrg(); | |||
printf("\nSample crypto benchmarks:\n"); | |||
SpongeRng rng(Block("macro rng seed"),SpongeRng::DETERMINISTIC); | |||
PrivateKey<Group> s1((NOINIT())), s2(rng); | |||
PublicKey<Group> p1((NOINIT())), p2(s2); | |||
@@ -317,8 +328,8 @@ static void macro() { | |||
} | |||
printf("\nProtocol benchmarks:\n"); | |||
SpongeRng clientRng(Block("client rng seed")); | |||
SpongeRng serverRng(Block("server rng seed")); | |||
SpongeRng clientRng(Block("client rng seed"),SpongeRng::DETERMINISTIC); | |||
SpongeRng serverRng(Block("server rng seed"),SpongeRng::DETERMINISTIC); | |||
SecureBuffer hashedPassword(Block("hello world")); | |||
for (Benchmark b("Spake2ee c+s",0.1); b.iter(); ) { | |||
spake2ee(clientRng, serverRng, hashedPassword,false); | |||
@@ -343,7 +354,7 @@ static void macro() { | |||
} | |||
static void micro() { | |||
SpongeRng rng(Block("per-curve-benchmarks")); | |||
SpongeRng rng(Block("per-curve-benchmarks"),SpongeRng::DETERMINISTIC); | |||
Precomputed pBase; | |||
Point p,q; | |||
Scalar s(1),t(2); | |||
@@ -382,7 +393,7 @@ int main(int argc, char **argv) { | |||
if (argc >= 2 && !strcmp(argv[1], "--micro")) | |||
micro = true; | |||
SpongeRng rng(Block("micro-benchmarks")); | |||
SpongeRng rng(Block("micro-benchmarks"),SpongeRng::DETERMINISTIC); | |||
if (micro) { | |||
printf("\nMicro-benchmarks:\n"); | |||
SHAKE<128> shake1; | |||
@@ -415,7 +426,6 @@ int main(int argc, char **argv) { | |||
Benches<Ed448Goldilocks>::micro(); | |||
} | |||
Benches<IsoEd25519>::macro(); | |||
Benches<Ed448Goldilocks>::macro(); | |||
@@ -92,6 +92,10 @@ static void test_ec() { | |||
} | |||
} | |||
/* TODO: test x25519/x448 */ | |||
/* FUTURE: test ed25519/ed448 */ | |||
/* Specify the same value as you did when compiling decaf_crypto.c */ | |||
#ifndef DECAF_CRYPTO_SHARED_SECRET_SHORT_CIRUIT | |||
#define DECAF_CRYPTO_SHARED_SECRET_SHORT_CIRUIT DECAF_FALSE | |||
@@ -47,6 +47,7 @@ template<typename Group> struct Tests { | |||
typedef typename Group::Scalar Scalar; | |||
typedef typename Group::Point Point; | |||
typedef typename Group::DhLadder DhLadder; | |||
typedef typename Group::Precomputed Precomputed; | |||
static void print(const char *name, const Scalar &x) { | |||
@@ -128,7 +129,7 @@ static bool point_check( | |||
} | |||
static void test_arithmetic() { | |||
SpongeRng rng(Block("test_arithmetic")); | |||
SpongeRng rng(Block("test_arithmetic"),SpongeRng::DETERMINISTIC); | |||
Test test("Arithmetic"); | |||
Scalar x(0),y(0),z(0); | |||
@@ -169,7 +170,7 @@ static void test_arithmetic() { | |||
} | |||
static void test_elligator() { | |||
SpongeRng rng(Block("test_elligator")); | |||
SpongeRng rng(Block("test_elligator"),SpongeRng::DETERMINISTIC); | |||
Test test("Elligator"); | |||
const int NHINTS = Group::REMOVED_COFACTOR * 2; | |||
@@ -265,7 +266,7 @@ static void test_elligator() { | |||
} | |||
static void test_ec() { | |||
SpongeRng rng(Block("test_ec")); | |||
SpongeRng rng(Block("test_ec"),SpongeRng::DETERMINISTIC); | |||
Test test("EC"); | |||
@@ -327,7 +328,7 @@ static void test_ec() { | |||
static void test_crypto() { | |||
Test test("Sample crypto"); | |||
SpongeRng rng(Block("test_decaf_crypto")); | |||
SpongeRng rng(Block("test_decaf_crypto"),SpongeRng::DETERMINISTIC); | |||
for (int i=0; i<NTESTS && test.passing_now; i++) { | |||
PrivateKey<Group> priv1(rng), priv2(rng); | |||
@@ -340,14 +341,123 @@ static void test_crypto() { | |||
SecureBuffer s1(priv1.sharedSecret(pub2,32,true)); | |||
SecureBuffer s2(priv2.sharedSecret(pub1,32,false)); | |||
if (memcmp(s1.data(),s2.data(),s1.size())) { | |||
if (!memeq(s1,s2)) { | |||
test.fail(); | |||
printf(" Shared secrets disagree."); | |||
printf(" Shared secrets disagree on iteration %d.\n",i); | |||
} | |||
} | |||
} | |||
}; /* template<GroupId GROUP> */ | |||
static const uint8_t rfc7748_1[DhLadder::PUBLIC_BYTES]; | |||
static const uint8_t rfc7748_1000[DhLadder::PUBLIC_BYTES]; | |||
static const uint8_t rfc7748_1000000[DhLadder::PUBLIC_BYTES]; | |||
static void test_cfrg_crypto() { | |||
Test test("CFRG crypto"); | |||
SpongeRng rng(Block("test_cfrg_crypto"),SpongeRng::DETERMINISTIC); | |||
for (int i=0; i<NTESTS && test.passing_now; i++) { | |||
FixedArrayBuffer<DhLadder::PUBLIC_BYTES> base(rng); | |||
FixedArrayBuffer<DhLadder::PRIVATE_BYTES> s1(rng), s2(rng); | |||
SecureBuffer p1 = DhLadder::shared_secret(base,s1); | |||
SecureBuffer p2 = DhLadder::shared_secret(base,s2); | |||
SecureBuffer ss1 = DhLadder::shared_secret(p2,s1); | |||
SecureBuffer ss2 = DhLadder::shared_secret(p1,s2); | |||
if (!memeq(ss1,ss2)) { | |||
test.fail(); | |||
printf(" Shared secrets disagree on iteration %d.\n",i); | |||
} | |||
if (!memeq( | |||
DhLadder::shared_secret(DhLadder::base_point(),s1), | |||
DhLadder::generate_key(s1) | |||
)) { | |||
test.fail(); | |||
printf(" Generated keys disagree on iteration %d.\n",i); | |||
} | |||
} | |||
} | |||
static void test_cfrg_vectors() { | |||
Test test("CFRG test vectors"); | |||
SecureBuffer k = DhLadder::base_point(); | |||
SecureBuffer u = DhLadder::base_point(); | |||
int the_ntests = (NTESTS < 1000000) ? 1000 : 1000000; | |||
for (int i=0; i<the_ntests && test.passing_now; i++) { | |||
SecureBuffer n = DhLadder::shared_secret(u,k); | |||
u = k; k = n; | |||
if (i==1-1) { | |||
if (!memeq(k,SecureBuffer(FixedBlock<DhLadder::PUBLIC_BYTES>(rfc7748_1)))) { | |||
test.fail(); | |||
printf(" Test vectors disagree at 1."); | |||
} | |||
} else if (i==1000-1) { | |||
if (!memeq(k,SecureBuffer(FixedBlock<DhLadder::PUBLIC_BYTES>(rfc7748_1000)))) { | |||
test.fail(); | |||
printf(" Test vectors disagree at 1000."); | |||
} | |||
} else if (i==1000000-1) { | |||
if (!memeq(k,SecureBuffer(FixedBlock<DhLadder::PUBLIC_BYTES>(rfc7748_1000000)))) { | |||
test.fail(); | |||
printf(" Test vectors disagree at 1000000."); | |||
} | |||
} | |||
} | |||
} | |||
}; /* template<GroupId GROUP> struct Tests */ | |||
template<> const uint8_t Tests<IsoEd25519>::rfc7748_1[32] = { | |||
0x42,0x2c,0x8e,0x7a,0x62,0x27,0xd7,0xbc, | |||
0xa1,0x35,0x0b,0x3e,0x2b,0xb7,0x27,0x9f, | |||
0x78,0x97,0xb8,0x7b,0xb6,0x85,0x4b,0x78, | |||
0x3c,0x60,0xe8,0x03,0x11,0xae,0x30,0x79 | |||
}; | |||
template<> const uint8_t Tests<IsoEd25519>::rfc7748_1000[32] = { | |||
0x68,0x4c,0xf5,0x9b,0xa8,0x33,0x09,0x55, | |||
0x28,0x00,0xef,0x56,0x6f,0x2f,0x4d,0x3c, | |||
0x1c,0x38,0x87,0xc4,0x93,0x60,0xe3,0x87, | |||
0x5f,0x2e,0xb9,0x4d,0x99,0x53,0x2c,0x51 | |||
}; | |||
template<> const uint8_t Tests<IsoEd25519>::rfc7748_1000000[32] = { | |||
0x7c,0x39,0x11,0xe0,0xab,0x25,0x86,0xfd, | |||
0x86,0x44,0x97,0x29,0x7e,0x57,0x5e,0x6f, | |||
0x3b,0xc6,0x01,0xc0,0x88,0x3c,0x30,0xdf, | |||
0x5f,0x4d,0xd2,0xd2,0x4f,0x66,0x54,0x24 | |||
}; | |||
template<> const uint8_t Tests<Ed448Goldilocks>::rfc7748_1[56] = { | |||
0x3f,0x48,0x2c,0x8a,0x9f,0x19,0xb0,0x1e, | |||
0x6c,0x46,0xee,0x97,0x11,0xd9,0xdc,0x14, | |||
0xfd,0x4b,0xf6,0x7a,0xf3,0x07,0x65,0xc2, | |||
0xae,0x2b,0x84,0x6a,0x4d,0x23,0xa8,0xcd, | |||
0x0d,0xb8,0x97,0x08,0x62,0x39,0x49,0x2c, | |||
0xaf,0x35,0x0b,0x51,0xf8,0x33,0x86,0x8b, | |||
0x9b,0xc2,0xb3,0xbc,0xa9,0xcf,0x41,0x13 | |||
}; | |||
template<> const uint8_t Tests<Ed448Goldilocks>::rfc7748_1000[56] = { | |||
0xaa,0x3b,0x47,0x49,0xd5,0x5b,0x9d,0xaf, | |||
0x1e,0x5b,0x00,0x28,0x88,0x26,0xc4,0x67, | |||
0x27,0x4c,0xe3,0xeb,0xbd,0xd5,0xc1,0x7b, | |||
0x97,0x5e,0x09,0xd4,0xaf,0x6c,0x67,0xcf, | |||
0x10,0xd0,0x87,0x20,0x2d,0xb8,0x82,0x86, | |||
0xe2,0xb7,0x9f,0xce,0xea,0x3e,0xc3,0x53, | |||
0xef,0x54,0xfa,0xa2,0x6e,0x21,0x9f,0x38 | |||
}; | |||
template<> const uint8_t Tests<Ed448Goldilocks>::rfc7748_1000000[56] = { | |||
0x07,0x7f,0x45,0x36,0x81,0xca,0xca,0x36, | |||
0x93,0x19,0x84,0x20,0xbb,0xe5,0x15,0xca, | |||
0xe0,0x00,0x24,0x72,0x51,0x9b,0x3e,0x67, | |||
0x66,0x1a,0x7e,0x89,0xca,0xb9,0x46,0x95, | |||
0xc8,0xf4,0xbc,0xd6,0x6e,0x61,0xb9,0xb9, | |||
0xc9,0x46,0xda,0x8d,0x52,0x4d,0xe3,0xd6, | |||
0x9b,0xd9,0xd9,0xd6,0x6b,0x99,0x7e,0x37 | |||
}; | |||
int main(int argc, char **argv) { | |||
(void) argc; (void) argv; | |||
@@ -356,6 +466,8 @@ int main(int argc, char **argv) { | |||
Tests<IsoEd25519>::test_arithmetic(); | |||
Tests<IsoEd25519>::test_elligator(); | |||
Tests<IsoEd25519>::test_ec(); | |||
Tests<IsoEd25519>::test_cfrg_crypto(); | |||
Tests<IsoEd25519>::test_cfrg_vectors(); | |||
Tests<IsoEd25519>::test_crypto(); | |||
printf("\n"); | |||
@@ -363,6 +475,8 @@ int main(int argc, char **argv) { | |||
Tests<Ed448Goldilocks>::test_arithmetic(); | |||
Tests<Ed448Goldilocks>::test_elligator(); | |||
Tests<Ed448Goldilocks>::test_ec(); | |||
Tests<Ed448Goldilocks>::test_cfrg_crypto(); | |||
Tests<Ed448Goldilocks>::test_cfrg_vectors(); | |||
Tests<Ed448Goldilocks>::test_crypto(); | |||
if (passing) printf("Passed all tests.\n"); | |||