diff --git a/Makefile b/Makefile index bb5589e..5561632 100644 --- a/Makefile +++ b/Makefile @@ -66,7 +66,7 @@ CXXFLAGS = $(LANGXXFLAGS) $(WARNFLAGS) $(INCFLAGS) $(OFLAGS) $(ARCHFLAGS) $(GENF LDFLAGS = $(ARCHFLAGS) $(XLDFLAGS) 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 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 TESTDECAFCOMPONENTS=build/test_decaf.o +BENCHDECAFCOMPONENTS=build/bench_decaf.o BENCHCOMPONENTS = build/bench.o build/shake.o @@ -108,7 +109,10 @@ build/test: $(LIBCOMPONENTS) $(TESTCOMPONENTS) $(DECAFCOMPONENTS) $(LD) $(LDFLAGS) -o $@ $^ -lgmp 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 $(LD) $(LDFLAGS) -o $@ $^ @@ -223,7 +227,10 @@ test: build/test test_decaf build/test 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: rm -fr build doc $(BATNAME) diff --git a/include/decaf.h b/include/decaf.h index 4a2991e..f82f2d1 100644 --- a/include/decaf.h +++ b/include/decaf.h @@ -240,10 +240,10 @@ static inline void NONNULL2 decaf_448_scalar_copy ( * @param [out] out Will become equal to a. * @todo Make inline? */ -void decaf_448_scalar_set API_VIS NONNULL1 ( +void decaf_448_scalar_set( decaf_448_scalar_t out, decaf_word_t a -); +) API_VIS NONNULL1; /** * @brief Encode a point as a sequence of bytes. @@ -317,7 +317,7 @@ void decaf_448_point_add ( decaf_448_point_t sum, const decaf_448_point_t a, const decaf_448_point_t b -) API_VIS NONNULL3; // TODO: NOINLINE? +) API_VIS NONNULL3; /** * @brief Double a point. Equivalent to @@ -329,7 +329,7 @@ void decaf_448_point_add ( void decaf_448_point_double ( decaf_448_point_t two_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 @@ -455,7 +455,7 @@ void decaf_448_point_double_scalarmul ( * scaled = scalar1*decaf_448_point_base + scalar2*base2. * * 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 [in] scalar1 A first scalar to multiply by. diff --git a/include/decaf.hxx b/include/decaf.hxx index 210ab72..c3e0f17 100644 --- a/include/decaf.hxx +++ b/include/decaf.hxx @@ -87,13 +87,13 @@ public: decaf_448_scalar_t s; /** @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 */ inline Scalar(const int w) NOEXCEPT { *this = w; } /** @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. */ 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; } + /** + * @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 */ 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. * - * @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( const decaf_448_precomputed_s &yours = *decaf_448_precomputed_base diff --git a/include/decaf_crypto.h b/include/decaf_crypto.h index d63b38c..81c4ad2 100644 --- a/include/decaf_crypto.h +++ b/include/decaf_crypto.h @@ -47,12 +47,10 @@ typedef struct { /** x*Base */ decaf_448_public_key_t pub; /** @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 extern "C" { @@ -179,7 +177,7 @@ decaf_448_verify ( #undef NONNULL5 #ifdef __cplusplus -}; /* extern "C" */ +} /* extern "C" */ #endif #endif /* __DECAF_CRYPTO_H__ */ diff --git a/test/bench_decaf.cxx b/test/bench_decaf.cxx new file mode 100644 index 0000000..ef383c5 --- /dev/null +++ b/test/bench_decaf.cxx @@ -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 +#include +#include +#include + +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= 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; +} diff --git a/test/test_decaf.cxx b/test/test_decaf.cxx index 41b4eda..1daa176 100644 --- a/test/test_decaf.cxx +++ b/test/test_decaf.cxx @@ -157,7 +157,7 @@ static void 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("\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,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,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"); } }