@@ -66,7 +66,7 @@ CXXFLAGS = $(LANGXXFLAGS) $(WARNFLAGS) $(INCFLAGS) $(OFLAGS) $(ARCHFLAGS) $(GENF | |||||
LDFLAGS = $(ARCHFLAGS) $(XLDFLAGS) | LDFLAGS = $(ARCHFLAGS) $(XLDFLAGS) | ||||
ASFLAGS = $(ARCHFLAGS) $(XASFLAGS) | ASFLAGS = $(ARCHFLAGS) $(XASFLAGS) | ||||
.PHONY: clean all test bench todo doc lib bat | |||||
.PHONY: clean all test bench test_decaf bench_decaf todo doc lib bat | |||||
.PRECIOUS: build/%.s | .PRECIOUS: build/%.s | ||||
HEADERS= Makefile $(shell find . -name "*.h") $(shell find . -name "*.hxx") build/timestamp | HEADERS= Makefile $(shell find . -name "*.h") $(shell find . -name "*.hxx") build/timestamp | ||||
@@ -87,6 +87,7 @@ TESTCOMPONENTS=build/test.o build/test_scalarmul.o build/test_sha512.o \ | |||||
build/shake.o | build/shake.o | ||||
TESTDECAFCOMPONENTS=build/test_decaf.o | TESTDECAFCOMPONENTS=build/test_decaf.o | ||||
BENCHDECAFCOMPONENTS=build/bench_decaf.o | |||||
BENCHCOMPONENTS = build/bench.o build/shake.o | BENCHCOMPONENTS = build/bench.o build/shake.o | ||||
@@ -108,7 +109,10 @@ build/test: $(LIBCOMPONENTS) $(TESTCOMPONENTS) $(DECAFCOMPONENTS) | |||||
$(LD) $(LDFLAGS) -o $@ $^ -lgmp | $(LD) $(LDFLAGS) -o $@ $^ -lgmp | ||||
build/test_decaf: $(TESTDECAFCOMPONENTS) decaf_lib | build/test_decaf: $(TESTDECAFCOMPONENTS) decaf_lib | ||||
$(LDXX) $(LDFLAGS) -o $@ $< -lgmp -Lbuild -ldecaf | |||||
$(LDXX) $(LDFLAGS) -o $@ $< -Lbuild -Wl,-rpath=`pwd`/build -ldecaf | |||||
build/bench_decaf: $(BENCHDECAFCOMPONENTS) decaf_lib | |||||
$(LDXX) $(LDFLAGS) -o $@ $< -Lbuild -Wl,-rpath=`pwd`/build -ldecaf | |||||
build/shakesum: build/shakesum.o build/shake.o | build/shakesum: build/shakesum.o build/shake.o | ||||
$(LD) $(LDFLAGS) -o $@ $^ | $(LD) $(LDFLAGS) -o $@ $^ | ||||
@@ -223,7 +227,10 @@ test: build/test test_decaf | |||||
build/test | build/test | ||||
test_decaf: build/test_decaf | test_decaf: build/test_decaf | ||||
LD_LIBRARY_PATH=`pwd`/build:$(LD_LIBRARY_PATH) build/test_decaf | |||||
build/test_decaf | |||||
bench_decaf: build/bench_decaf | |||||
build/bench_decaf | |||||
clean: | clean: | ||||
rm -fr build doc $(BATNAME) | rm -fr build doc $(BATNAME) |
@@ -240,10 +240,10 @@ static inline void NONNULL2 decaf_448_scalar_copy ( | |||||
* @param [out] out Will become equal to a. | * @param [out] out Will become equal to a. | ||||
* @todo Make inline? | * @todo Make inline? | ||||
*/ | */ | ||||
void decaf_448_scalar_set API_VIS NONNULL1 ( | |||||
void decaf_448_scalar_set( | |||||
decaf_448_scalar_t out, | decaf_448_scalar_t out, | ||||
decaf_word_t a | decaf_word_t a | ||||
); | |||||
) API_VIS NONNULL1; | |||||
/** | /** | ||||
* @brief Encode a point as a sequence of bytes. | * @brief Encode a point as a sequence of bytes. | ||||
@@ -317,7 +317,7 @@ void decaf_448_point_add ( | |||||
decaf_448_point_t sum, | decaf_448_point_t sum, | ||||
const decaf_448_point_t a, | const decaf_448_point_t a, | ||||
const decaf_448_point_t b | const decaf_448_point_t b | ||||
) API_VIS NONNULL3; // TODO: NOINLINE? | |||||
) API_VIS NONNULL3; | |||||
/** | /** | ||||
* @brief Double a point. Equivalent to | * @brief Double a point. Equivalent to | ||||
@@ -329,7 +329,7 @@ void decaf_448_point_add ( | |||||
void decaf_448_point_double ( | void decaf_448_point_double ( | ||||
decaf_448_point_t two_a, | decaf_448_point_t two_a, | ||||
const decaf_448_point_t a | const decaf_448_point_t a | ||||
) API_VIS NONNULL2; // TODO: NOINLINE? | |||||
) API_VIS NONNULL2; | |||||
/** | /** | ||||
* @brief Subtract two points to produce a third point. The | * @brief Subtract two points to produce a third point. The | ||||
@@ -455,7 +455,7 @@ void decaf_448_point_double_scalarmul ( | |||||
* scaled = scalar1*decaf_448_point_base + scalar2*base2. | * scaled = scalar1*decaf_448_point_base + scalar2*base2. | ||||
* | * | ||||
* Otherwise equivalent to decaf_448_point_double_scalarmul, but may be | * Otherwise equivalent to decaf_448_point_double_scalarmul, but may be | ||||
* faster. | |||||
* faster at the expense of being variable time. | |||||
* | * | ||||
* @param [out] combo The linear combination scalar1*base + scalar2*base2. | * @param [out] combo The linear combination scalar1*base + scalar2*base2. | ||||
* @param [in] scalar1 A first scalar to multiply by. | * @param [in] scalar1 A first scalar to multiply by. | ||||
@@ -87,13 +87,13 @@ public: | |||||
decaf_448_scalar_t s; | decaf_448_scalar_t s; | ||||
/** @brief Set to an unsigned word */ | /** @brief Set to an unsigned word */ | ||||
inline Scalar(const decaf_word_t w=0) NOEXCEPT { *this = w; } | |||||
inline Scalar(const decaf_word_t w) NOEXCEPT { *this = w; } | |||||
/** @brief Set to a signed word */ | /** @brief Set to a signed word */ | ||||
inline Scalar(const int w) NOEXCEPT { *this = w; } | inline Scalar(const int w) NOEXCEPT { *this = w; } | ||||
/** @brief Construct from decaf_scalar_t object. */ | /** @brief Construct from decaf_scalar_t object. */ | ||||
inline Scalar(const decaf_448_scalar_t &t) NOEXCEPT { decaf_448_scalar_copy(s,t); } | |||||
inline Scalar(const decaf_448_scalar_t &t = decaf_448_scalar_zero) NOEXCEPT { decaf_448_scalar_copy(s,t); } | |||||
/** @brief Copy constructor. */ | /** @brief Copy constructor. */ | ||||
inline Scalar(const Scalar &x) NOEXCEPT { decaf_448_scalar_copy(s,x.s); } | inline Scalar(const Scalar &x) NOEXCEPT { decaf_448_scalar_copy(s,x.s); } | ||||
@@ -385,6 +385,15 @@ public: | |||||
Point p; decaf_448_point_double_scalarmul(p.p,q.p,qs.s,r.p,rs.s); return p; | Point p; decaf_448_point_double_scalarmul(p.p,q.p,qs.s,r.p,rs.s); return p; | ||||
} | } | ||||
/** | |||||
* @brief Double-scalar multiply: this point by the first scalar and base by the second scalar. | |||||
* @warning This function takes variable time, and may leak the scalars (or points, but currently | |||||
* it doesn't). | |||||
*/ | |||||
inline Point non_secret_combo_with_base(const Scalar &s, const Scalar &s_base) { | |||||
Point r; decaf_448_base_double_scalarmul_non_secret(r.p,s_base.s,p,s.s); return r; | |||||
} | |||||
/** @brief Return the base point */ | /** @brief Return the base point */ | ||||
static inline const Point base() NOEXCEPT { return Point(decaf_448_point_base); } | static inline const Point base() NOEXCEPT { return Point(decaf_448_point_base); } | ||||
@@ -438,7 +447,8 @@ public: | |||||
* | * | ||||
* By default, initializes to the table for the base point. | * By default, initializes to the table for the base point. | ||||
* | * | ||||
* @todo: FIXME Harmonize with Point(), which initializes to the identity. | |||||
* @warning The empty initializer makes this equal to base, unlike the empty | |||||
* initializer for points which makes this equal to the identity. | |||||
*/ | */ | ||||
inline Precomputed( | inline Precomputed( | ||||
const decaf_448_precomputed_s &yours = *decaf_448_precomputed_base | const decaf_448_precomputed_s &yours = *decaf_448_precomputed_base | ||||
@@ -47,12 +47,10 @@ typedef struct { | |||||
/** x*Base */ | /** x*Base */ | ||||
decaf_448_public_key_t pub; | decaf_448_public_key_t pub; | ||||
/** @endcond */ | /** @endcond */ | ||||
} | |||||
/** Private key structure for pointers. */ | |||||
decaf_448_private_key_s, | |||||
/** A private key (gmp array[1] style). */ | |||||
decaf_448_private_key_t[1]; | |||||
} /** Private key structure for pointers. */ | |||||
decaf_448_private_key_s, | |||||
/** A private key (gmp array[1] style). */ | |||||
decaf_448_private_key_t[1]; | |||||
#ifdef __cplusplus | #ifdef __cplusplus | ||||
extern "C" { | extern "C" { | ||||
@@ -179,7 +177,7 @@ decaf_448_verify ( | |||||
#undef NONNULL5 | #undef NONNULL5 | ||||
#ifdef __cplusplus | #ifdef __cplusplus | ||||
}; /* extern "C" */ | |||||
} /* extern "C" */ | |||||
#endif | #endif | ||||
#endif /* __DECAF_CRYPTO_H__ */ | #endif /* __DECAF_CRYPTO_H__ */ | ||||
@@ -0,0 +1,145 @@ | |||||
/** | |||||
* @file test_decaf.cxx | |||||
* @author Mike Hamburg | |||||
* | |||||
* @copyright | |||||
* Copyright (c) 2015 Cryptography Research, Inc. \n | |||||
* Released under the MIT License. See LICENSE.txt for license information. | |||||
* | |||||
* @brief C++ benchmarks, because that's easier. | |||||
*/ | |||||
#include "decaf.hxx" | |||||
#include "shake.h" | |||||
#include "decaf_crypto.h" | |||||
#include <stdio.h> | |||||
#include <sys/time.h> | |||||
#include <assert.h> | |||||
#include <stdint.h> | |||||
typedef decaf::decaf<448>::Scalar Scalar; | |||||
typedef decaf::decaf<448>::Point Point; | |||||
typedef decaf::decaf<448>::Precomputed Precomputed; | |||||
static __inline__ void __attribute__((unused)) ignore_result ( int result ) { (void)result; } | |||||
static double now(void) { | |||||
struct timeval tv; | |||||
gettimeofday(&tv, NULL); | |||||
return tv.tv_sec + tv.tv_usec/1000000.0; | |||||
} | |||||
// RDTSC from the chacha code | |||||
#ifndef __has_builtin | |||||
#define __has_builtin(X) 0 | |||||
#endif | |||||
#if defined(__clang__) && __has_builtin(__builtin_readcyclecounter) | |||||
#define rdtsc __builtin_readcyclecounter | |||||
#else | |||||
static inline uint64_t rdtsc(void) { | |||||
u_int64_t out = 0; | |||||
# if (defined(__i386__) || defined(__x86_64__)) | |||||
__asm__ __volatile__ ("rdtsc" : "=A"(out)); | |||||
# endif | |||||
return out; | |||||
} | |||||
#endif | |||||
class Benchmark { | |||||
static const int NTESTS = 1000; | |||||
public: | |||||
int i, ntests; | |||||
double begin; | |||||
uint64_t tsc_begin; | |||||
Benchmark(const char *s, double factor = 1) { | |||||
printf("%s:", s); | |||||
if (strlen(s) < 25) printf("%*s",int(25-strlen(s)),""); | |||||
fflush(stdout); | |||||
i = 0; | |||||
ntests = NTESTS * factor; | |||||
begin = now(); | |||||
tsc_begin = rdtsc(); | |||||
} | |||||
~Benchmark() { | |||||
double tsc = (rdtsc() - tsc_begin) * 1.0 / ntests; | |||||
double t = (now() - begin)/ntests; | |||||
const char *small[] = {" ","m","µ","n","p"}; | |||||
const char *big[] = {" ","k","M","G","T"}; | |||||
unsigned di=0; | |||||
for (di=0; di<sizeof(small)/sizeof(*small)-1 && t && t < 1; di++) { | |||||
t *= 1000.0; | |||||
} | |||||
unsigned bi=0; | |||||
for (bi=0; bi<sizeof(big)/sizeof(*big)-1 && tsc && tsc >= 1000; bi++) { | |||||
tsc /= 1000.0; | |||||
} | |||||
printf("%7.2f %ss", t, small[di]); | |||||
if (tsc) printf(" %7.2f %scy", tsc, big[bi]); | |||||
printf("\n"); | |||||
} | |||||
inline bool iter() { return i++ < ntests; } | |||||
}; | |||||
int main(int argc, char **argv) { | |||||
bool micro = false; | |||||
if (argc >= 2 && !strcmp(argv[1], "--micro")) | |||||
micro = true; | |||||
decaf_448_public_key_t p1,p2; | |||||
decaf_448_private_key_t s1,s2; | |||||
decaf_448_symmetric_key_t r1,r2; | |||||
decaf_448_signature_t sig1; | |||||
unsigned char ss[32]; | |||||
memset(r1,1,sizeof(r1)); | |||||
memset(r2,2,sizeof(r2)); | |||||
unsigned char umessage[] = {1,2,3,4,5}; | |||||
size_t lmessage = sizeof(umessage); | |||||
if (micro) { | |||||
Precomputed pBase; | |||||
Point p,q; | |||||
Scalar s,t; | |||||
printf("Micro:\n"); | |||||
for (Benchmark b("Scalar add", 1000); b.iter(); ) { s+t; } | |||||
for (Benchmark b("Scalar times", 100); b.iter(); ) { s*t; } | |||||
for (Benchmark b("Scalar inv", 10); b.iter(); ) { s.inverse(); } | |||||
for (Benchmark b("Point add", 100); b.iter(); ) { p + q; } | |||||
for (Benchmark b("Point double", 100); b.iter(); ) { p.double_in_place(); } | |||||
for (Benchmark b("Point scalarmul"); b.iter(); ) { p * s; } | |||||
for (Benchmark b("Point double scalarmul"); b.iter(); ) { Point::double_scalarmul(p,s,q,t); } | |||||
for (Benchmark b("Point precmp scalarmul"); b.iter(); ) { pBase * s; } | |||||
/* TODO: scalarmul for verif */ | |||||
printf("\nMacro:\n"); | |||||
} | |||||
for (Benchmark b("Keygen"); b.iter(); ) { | |||||
decaf_448_derive_private_key(s1,r1); | |||||
} | |||||
decaf_448_private_to_public(p1,s1); | |||||
decaf_448_derive_private_key(s2,r2); | |||||
decaf_448_private_to_public(p2,s2); | |||||
for (Benchmark b("Shared secret"); b.iter(); ) { | |||||
decaf_bool_t ret = decaf_448_shared_secret(ss,sizeof(ss),s1,p2); | |||||
ignore_result(ret); | |||||
assert(ret); | |||||
} | |||||
for (Benchmark b("Sign"); b.iter(); ) { | |||||
decaf_448_sign(sig1,s1,umessage,lmessage); | |||||
} | |||||
for (Benchmark b("Verify"); b.iter(); ) { | |||||
decaf_bool_t ret = decaf_448_verify(sig1,p1,umessage,lmessage); | |||||
umessage[0]++; | |||||
ignore_result(ret); | |||||
} | |||||
printf("\n"); | |||||
return 0; | |||||
} |
@@ -157,7 +157,7 @@ static void test_ec() { | |||||
Test test("EC"); | Test test("EC"); | ||||
Point id; | |||||
Point id = Point::identity(), base = Point::base(); | |||||
point_check(test,id,id,id,0,0,Point::from_hash(std::string("")),id,"fh0"); | point_check(test,id,id,id,0,0,Point::from_hash(std::string("")),id,"fh0"); | ||||
point_check(test,id,id,id,0,0,Point::from_hash(std::string("\x01")),id,"fh1"); | point_check(test,id,id,id,0,0,Point::from_hash(std::string("\x01")),id,"fh1"); | ||||
@@ -183,6 +183,7 @@ static void test_ec() { | |||||
point_check(test,p,q,r,x,0,x*(p+q),x*p+x*q,"distr mul"); | point_check(test,p,q,r,x,0,x*(p+q),x*p+x*q,"distr mul"); | ||||
point_check(test,p,q,r,x,y,(x*y)*p,x*(y*p),"assoc mul"); | point_check(test,p,q,r,x,y,(x*y)*p,x*(y*p),"assoc mul"); | ||||
point_check(test,p,q,r,x,y,x*p+y*q,Point::double_scalarmul(x,p,y,q),"ds mul"); | point_check(test,p,q,r,x,y,x*p+y*q,Point::double_scalarmul(x,p,y,q),"ds mul"); | ||||
point_check(test,base,q,r,x,y,x*base+y*q,q.non_secret_combo_with_base(y,x),"ds vt mul"); | |||||
point_check(test,p,q,r,x,0,Precomputed(p)*x,p*x,"precomp mul"); | point_check(test,p,q,r,x,0,Precomputed(p)*x,p*x,"precomp mul"); | ||||
} | } | ||||
} | } | ||||