Browse Source

decaf tests coming online

master
Mike Hamburg 9 years ago
parent
commit
faeb1fb092
6 changed files with 303 additions and 29 deletions
  1. +30
    -11
      Makefile
  2. +2
    -3
      include/decaf.h
  3. +69
    -13
      include/decaf.hxx
  4. +8
    -0
      include/shake.h
  5. +1
    -2
      src/decaf_fast.c
  6. +193
    -0
      test/test_decaf.cxx

+ 30
- 11
Makefile View File

@@ -7,10 +7,13 @@ MACHINE := $(shell uname -m)

ifeq ($(UNAME),Darwin)
CC = clang
CXX = clang++
else
CC = gcc
CXX = g++
endif
LD = $(CC)
LDXX = $(CXX)
ASM ?= $(CC)

DECAF ?= decaf
@@ -30,6 +33,7 @@ WARNFLAGS = -pedantic -Wall -Wextra -Werror -Wunreachable-code \
INCFLAGS = -Isrc/include -Iinclude -Isrc/$(FIELD) -Isrc/$(FIELD)/$(ARCH)
LANGFLAGS = -std=c99 -fno-strict-aliasing
LANGXXFLAGS = -fno-strict-aliasing
GENFLAGS = -ffunction-sections -fdata-sections -fvisibility=hidden -fomit-frame-pointer -fPIC
OFLAGS = -O3

@@ -58,6 +62,7 @@ endif

ARCHFLAGS += $(XARCHFLAGS)
CFLAGS = $(LANGFLAGS) $(WARNFLAGS) $(INCFLAGS) $(OFLAGS) $(ARCHFLAGS) $(GENFLAGS) $(XCFLAGS)
CXXFLAGS = $(LANGXXFLAGS) $(WARNFLAGS) $(INCFLAGS) $(OFLAGS) $(ARCHFLAGS) $(GENFLAGS) $(XCXXFLAGS)
LDFLAGS = $(ARCHFLAGS) $(XLDFLAGS)
ASFLAGS = $(ARCHFLAGS) $(XASFLAGS)

@@ -81,6 +86,8 @@ TESTCOMPONENTS=build/test.o build/test_scalarmul.o build/test_sha512.o \
build/test_pointops.o build/test_arithmetic.o build/test_goldilocks.o build/magic.o \
build/shake.o

TESTDECAFCOMPONENTS=build/test_decaf.o

BENCHCOMPONENTS = build/bench.o build/shake.o

BATBASE=ed448goldilocks-bats-$(TODAY)
@@ -92,42 +99,45 @@ scan: clean
scan-build --use-analyzer=`which clang` \
-enable-checker deadcode -enable-checker llvm \
-enable-checker osx -enable-checker security -enable-checker unix \
make build/bench build/test build/goldilocks.so
make build/bench build/test all

build/bench: $(LIBCOMPONENTS) $(BENCHCOMPONENTS) $(DECAFCOMPONENTS)
$(LD) $(LDFLAGS) -o $@ $^

build/test: $(LIBCOMPONENTS) $(TESTCOMPONENTS) $(DECAFCOMPONENTS)
$(LD) $(LDFLAGS) -o $@ $^ -lgmp

build/test_decaf: $(TESTDECAFCOMPONENTS) decaf_lib
$(LDXX) $(LDFLAGS) -o $@ $< -lgmp -Lbuild -ldecaf
build/shakesum: build/shakesum.o build/shake.o
$(LD) $(LDFLAGS) -o $@ $^

lib: build/goldilocks.so
lib: build/libgoldilocks.so

decaf_lib: build/decaf.so
decaf_lib: build/libdecaf.so

build/goldilocks.so: $(LIBCOMPONENTS)
build/libgoldilocks.so: $(LIBCOMPONENTS)
rm -f $@
ifeq ($(UNAME),Darwin)
libtool -macosx_version_min 10.6 -dynamic -dead_strip -lc -x -o $@ \
$(LIBCOMPONENTS)
else
$(LD) $(LDFLAGS) -shared -Wl,-soname,goldilocks.so.1 -Wl,--gc-sections -o $@ $(LIBCOMPONENTS)
$(LD) $(LDFLAGS) -shared -Wl,-soname,libgoldilocks.so.1 -Wl,--gc-sections -o $@ $(LIBCOMPONENTS)
strip --discard-all $@
ln -sf `basename $@` build/goldilocks.so.1
ln -sf `basename $@` build/libgoldilocks.so.1
endif


build/decaf.so: $(DECAFCOMPONENTS)
build/libdecaf.so: $(DECAFCOMPONENTS)
rm -f $@
ifeq ($(UNAME),Darwin)
libtool -macosx_version_min 10.6 -dynamic -dead_strip -lc -x -o $@ \
$(DECAFCOMPONENTS)
else
$(LD) $(LDFLAGS) -shared -Wl,-soname,goldilocks.so.1 -Wl,--gc-sections -o $@ $(DECAFCOMPONENTS)
$(LD) $(LDFLAGS) -shared -Wl,-soname,libdecaf.so.1 -Wl,--gc-sections -o $@ $(DECAFCOMPONENTS)
strip --discard-all $@
ln -sf `basename $@` build/goldilocks.so.1
ln -sf `basename $@` build/libdecaf.so.1
endif

build/timestamp:
@@ -148,10 +158,16 @@ build/decaf_tables.s: build/decaf_tables.c $(HEADERS)
build/%.s: src/%.c $(HEADERS)
$(CC) $(CFLAGS) -S -c -o $@ $<
build/%.s: src/%.cxx $(HEADERS)
$(CXX) $(CXXFLAGS) -S -c -o $@ $<

build/%.s: test/%.c $(HEADERS)
$(CC) $(CFLAGS) -S -c -o $@ $<

build/%.s: test/%.cxx $(HEADERS)
$(CXX) $(CXXFLAGS) -S -c -o $@ $<

build/%.s: src/$(FIELD)/$(ARCH)/%.c $(HEADERS)
$(CC) $(CFLAGS) -S -c -o $@ $<

@@ -203,8 +219,11 @@ todo::
bench: build/bench
./$<

test: build/test
./$<
test: build/test test_decaf
build/test
test_decaf: build/test_decaf
LD_LIBRARY_PATH=`pwd`/build:$(LD_LIBRARY_PATH) build/test_decaf

clean:
rm -fr build doc $(BATNAME)

+ 2
- 3
include/decaf.h View File

@@ -76,7 +76,7 @@ struct decaf_448_precomputed_s;
typedef struct decaf_448_precomputed_s decaf_448_precomputed_s;

/** Size and alignment of precomputed point tables. */
extern const size_t sizeof_decaf_448_precomputed_s, alignof_decaf_448_precomputed_s;
extern const size_t sizeof_decaf_448_precomputed_s API_VIS, alignof_decaf_448_precomputed_s API_VIS;

/** Scalar is stored packed, because we don't need the speed. */
typedef struct decaf_448_scalar_s {
@@ -520,7 +520,6 @@ void decaf_448_point_from_hash_uniform (

/**
* @brief Overwrite data with zeros. Uses memset_s if available.
* If data is NULL, this function has no effect.
*/
void decaf_bzero (
void *data,
@@ -562,7 +561,7 @@ void decaf_448_precomputed_destroy (
#undef NONNULL5

#ifdef __cplusplus
}; /* extern "C" */
} /* extern "C" */
#endif

#endif /* __DECAF_448_H__ */

+ 69
- 13
include/decaf.hxx View File

@@ -28,6 +28,8 @@

#include "decaf.h"
#include <string>
#include <sys/types.h>
#include <limits.h>

/* TODO: document */
/* TODO: This is incomplete */
@@ -38,7 +40,7 @@
#define EXPLICIT_CON explicit
#define GET_DATA(str) ((const unsigned char *)&(str)[0])
#else
#define NOEXCEPT
#define NOEXCEPT throw()
#define EXPLICIT_CON
#define GET_DATA(str) ((const unsigned char *)((str).data()))
#endif
@@ -50,18 +52,36 @@ void really_bzero(void *data, size_t size);
template<unsigned int bits = 448> struct decaf;
template<> struct decaf<448> {

class CryptoException : public std::exception {
public:
CryptoException() {}
virtual ~CryptoException() NOEXCEPT {}
virtual const char * what() const NOEXCEPT { return "CryptoException"; }
};

class Point;
class Precomputed;

class Scalar {
public:
decaf_448_scalar_t s;
inline Scalar() NOEXCEPT {}
inline Scalar(const decaf_word_t w) NOEXCEPT { decaf_448_scalar_set(s,w); }
inline Scalar(const int w) NOEXCEPT {
Scalar t(-(decaf_word_t)INT_MIN);
decaf_448_scalar_set(s,(decaf_word_t)w - (decaf_word_t)INT_MIN);
*this -= t;
}
inline Scalar(const decaf_448_scalar_t &t) NOEXCEPT { decaf_448_scalar_copy(s,t); }
inline Scalar(const Scalar &x) NOEXCEPT { decaf_448_scalar_copy(s,x.s); }
inline Scalar& operator=(const Scalar &x) NOEXCEPT { decaf_448_scalar_copy(s,x.s); return *this; }
inline ~Scalar() NOEXCEPT { decaf_448_scalar_destroy(s); }
/* Initialize from buffer */
inline explicit Scalar(const std::string &str) NOEXCEPT { decaf_448_scalar_decode_long(s,GET_DATA(str),str.length()); }
inline Scalar &operator=(const std::string &str) NOEXCEPT {
decaf_448_scalar_decode_long(s,GET_DATA(str),str.length()); return *this;
}
inline explicit Scalar(const std::string &str) NOEXCEPT { *this = str; }
inline Scalar(const unsigned char *buffer, size_t n) NOEXCEPT { decaf_448_scalar_decode_long(s,buffer,n); }
inline Scalar(const char *buffer, size_t n) NOEXCEPT { decaf_448_scalar_decode_long(s,(const unsigned char *)buffer,n); }
inline Scalar(const void *buffer, size_t n) NOEXCEPT { decaf_448_scalar_decode_long(s,(const unsigned char *)buffer,n); }
@@ -81,7 +101,7 @@ public:
decaf_448_scalar_encode(buffer, s);
return std::string((char*)buffer,sizeof(buffer));
}
inline void write_to_buffer(unsigned char buffer[DECAF_448_SCALAR_BYTES]) const NOEXCEPT{
inline void encode(unsigned char buffer[DECAF_448_SCALAR_BYTES]) const NOEXCEPT{
decaf_448_scalar_encode(buffer, s);
}
@@ -92,8 +112,15 @@ public:
inline Scalar operator-=(const Scalar &q) NOEXCEPT { decaf_448_scalar_sub(s,s,q.s); return *this; }
inline Scalar operator* (const Scalar &q) const NOEXCEPT { Scalar r; decaf_448_scalar_mul(r.s,s,q.s); return r; }
inline Scalar operator*=(const Scalar &q) NOEXCEPT { decaf_448_scalar_mul(s,s,q.s); return *this; }
inline Scalar inverse() const NOEXCEPT { Scalar r; decaf_448_scalar_invert(r.s,s); return r; }
inline Scalar operator/ (const Scalar &q) const NOEXCEPT { Scalar r; decaf_448_scalar_mul(r.s,s,q.inverse().s); return r; }
inline Scalar operator/=(const Scalar &q) NOEXCEPT { decaf_448_scalar_mul(s,s,q.inverse().s); return *this; }
inline Scalar operator- () const NOEXCEPT { Scalar r; decaf_448_scalar_sub(r.s,decaf_448_scalar_zero,s); return r; }
inline bool operator!=(const Scalar &q) const NOEXCEPT { return ! decaf_448_scalar_eq(s,q.s); }
inline bool operator==(const Scalar &q) const NOEXCEPT { return !!decaf_448_scalar_eq(s,q.s); }
inline Point operator* (const Point &q) const NOEXCEPT { return q * (*this); }
inline Point operator* (const Precomputed &q) const NOEXCEPT { return q * (*this); }
};

class Point {
@@ -105,6 +132,12 @@ public:
inline Point& operator=(const Point &q) { decaf_448_point_copy(p,q.p); return *this; }
inline ~Point() { decaf_448_point_destroy(p); }
inline explicit Point(const std::string &s, decaf_bool_t allow_identity=DECAF_TRUE) throw(CryptoException) {
if (!decode(*this,s,allow_identity)) throw CryptoException();
}
inline explicit Point(const unsigned char buffer[DECAF_448_SER_BYTES], decaf_bool_t allow_identity=DECAF_TRUE)
throw(CryptoException) { if (!decode(*this,buffer,allow_identity)) throw CryptoException(); }
/* serialize / deserialize */
static inline decaf_bool_t __attribute__((warn_unused_result)) decode (
Point &p, const unsigned char buffer[DECAF_448_SER_BYTES], decaf_bool_t allow_identity=DECAF_TRUE
@@ -117,12 +150,31 @@ public:
if (buffer.size() != DECAF_448_SER_BYTES) return DECAF_FAILURE;
return decaf_448_point_decode(p.p,GET_DATA(buffer),allow_identity);
}
static inline Point from_hash_nonuniform ( const unsigned char buffer[DECAF_448_SER_BYTES] ) NOEXCEPT {
Point p; decaf_448_point_from_hash_nonuniform(p.p,buffer); return p;
}
static inline Point from_hash_nonuniform ( const std::string &s ) NOEXCEPT {
std::string t = s;
if (t.size() < DECAF_448_SER_BYTES) t.insert(t.size(),DECAF_448_SER_BYTES-t.size(),0);
Point p; decaf_448_point_from_hash_nonuniform(p.p,GET_DATA(t)); return p;
}
static inline Point from_hash ( const unsigned char buffer[2*DECAF_448_SER_BYTES] ) NOEXCEPT {
Point p; decaf_448_point_from_hash_uniform(p.p,buffer); return p;
}
static inline Point from_hash ( const std::string &s ) NOEXCEPT {
std::string t = s;
if (t.size() < DECAF_448_SER_BYTES) return from_hash_nonuniform(s);
if (t.size() < 2*DECAF_448_SER_BYTES) t.insert(t.size(),2*DECAF_448_SER_BYTES-t.size(),0);
Point p; decaf_448_point_from_hash_uniform(p.p,GET_DATA(t)); return p;
}
inline EXPLICIT_CON operator std::string() const NOEXCEPT {
unsigned char buffer[DECAF_448_SER_BYTES];
decaf_448_point_encode(buffer, p);
return std::string((char*)buffer,sizeof(buffer));
}
inline void write_to_buffer(unsigned char buffer[DECAF_448_SER_BYTES]) const NOEXCEPT{
inline void encode(unsigned char buffer[DECAF_448_SER_BYTES]) const NOEXCEPT{
decaf_448_point_encode(buffer, p);
}
@@ -134,11 +186,13 @@ public:
inline Point operator- () const NOEXCEPT { Point r; decaf_448_point_negate(r.p,p); return r; }
inline Point times_two () const NOEXCEPT { Point r; decaf_448_point_double(r.p,p); return r; }
inline Point &double_in_place() NOEXCEPT { decaf_448_point_double(p,p); return *this; }
inline bool operator!=(const Point &q) const NOEXCEPT { return ! decaf_448_point_eq(p,q.p); }
inline bool operator==(const Point &q) const NOEXCEPT { return !!decaf_448_point_eq(p,q.p); }
/* Scalarmul */
inline Point operator* (const Scalar &s) const NOEXCEPT { Point r; decaf_448_point_scalarmul(r.p,p,s.s); return r; }
inline Point operator*=(const Scalar &s) NOEXCEPT { decaf_448_point_scalarmul(p,p,s.s); return *this; }
inline Point operator/ (const Scalar &s) const NOEXCEPT { return (*this) * s.inverse(); }
static inline Point double_scalar_mul (
const Point &q, const Scalar &qs, const Point &r, const Scalar &rs
@@ -147,8 +201,8 @@ public:
}
/* FIXME: are these defined to be correct? */
static inline const Point &base() NOEXCEPT { return (const Point &)decaf_448_point_base; }
static inline const Point &identity() NOEXCEPT { return (const Point &)decaf_448_point_identity; }
static inline const Point &base() NOEXCEPT { return *(const Point *)decaf_448_point_base; }
static inline const Point &identity() NOEXCEPT { return *(const Point *)decaf_448_point_identity; }
};

class Precomputed {
@@ -181,8 +235,8 @@ private:
public:
inline ~Precomputed() NOEXCEPT { clear(); }
inline Precomputed(const decaf_448_precomputed_s *yours = decaf_448_precomputed_base) NOEXCEPT {
ours.yours = yours;
inline Precomputed(const decaf_448_precomputed_s &yours = *decaf_448_precomputed_base) NOEXCEPT {
ours.yours = &yours;
isMine = false;
}
inline Precomputed &operator=(const Precomputed &it) {
@@ -203,7 +257,8 @@ public:
return *this;
}
inline Precomputed(const Precomputed &it) NOEXCEPT : isMine(false) { *this = it; }
inline Precomputed(const Point &it) NOEXCEPT : isMine(false) { *this = it; }
inline explicit Precomputed(const Point &it) NOEXCEPT : isMine(false) { *this = it; }
#if __cplusplus >= 201103L
inline Precomputed &operator=(Precomputed &&it) NOEXCEPT {
if (this == &it) return *this;
@@ -218,13 +273,14 @@ public:
#endif
inline Point operator* (const Scalar &s) const NOEXCEPT { Point r; decaf_448_precomputed_scalarmul(r.p,get(),s.s); return r; }
inline Point operator/ (const Scalar &s) const NOEXCEPT { return (*this) * s.inverse(); }
static inline const Precomputed base() NOEXCEPT { return Precomputed(decaf_448_precomputed_base); }
static inline const Precomputed base() NOEXCEPT { return Precomputed(*decaf_448_precomputed_base); }
};

#undef NOEXCEPT

}; /* struct decaf<448> */
}; /* namespace decaf */

#undef NOEXCEPT
} /* namespace decaf */

#endif /* __DECAF_448_HXX__ */

+ 8
- 0
include/shake.h View File

@@ -27,6 +27,10 @@
struct kparams_s;
#endif

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Initialize a sponge context object.
* @param [out] sponge The object to initialize.
@@ -220,6 +224,10 @@ void spongerng_stir (
size_t len
) API_VIS;

#ifdef __cplusplus
} /* extern "C" */
#endif

#undef API_VIS
#undef WARN_UNUSED


+ 1
- 2
src/decaf_fast.c View File

@@ -678,7 +678,6 @@ void decaf_bzero (
void *s,
size_t size
) {
if (s==NULL) return;
#ifdef __STDC_LIB_EXT1__
memset_s(s, size, 0, size);
#else
@@ -720,7 +719,7 @@ void decaf_448_scalar_decode_long(
decaf_448_scalar_decode_short(t1, &ser[i], ser_len-i);

if (ser_len == sizeof(*ser)) {
if (ser_len == sizeof(decaf_448_scalar_t)) {
assert(i==0);
/* ham-handed reduce */
decaf_448_montmul(s,t1,decaf_448_scalar_r1);


+ 193
- 0
test/test_decaf.cxx View File

@@ -0,0 +1,193 @@
/**
* @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++ tests, because that's easier.
*/

#include "decaf.hxx"
#include "shake.h"
#include <stdio.h>

typedef decaf::decaf<448>::Scalar Scalar;
typedef decaf::decaf<448>::Point Point;
typedef decaf::decaf<448>::Precomputed Precomputed;

static const long NTESTS = 10000;

static void print(const char *name, const Scalar &x) {
unsigned char buffer[DECAF_448_SCALAR_BYTES];
x.encode(buffer);
printf(" %s = 0x", name);
for (int i=sizeof(buffer)-1; i>=0; i--) {
printf("%02x", buffer[i]);
}
printf("\n");
}

static void print(const char *name, const Point &x) {
unsigned char buffer[DECAF_448_SER_BYTES];
x.encode(buffer);
printf(" %s = 0x", name);
for (int i=sizeof(buffer)-1; i>=0; i--) {
printf("%02x", buffer[i]);
}
printf("\n");
}

static bool passing = true;

class Test {
public:
bool passing_now;
Test(const char *test) {
passing_now = true;
printf("%s...", test);
if (strlen(test) < 27) printf("%*s",int(27-strlen(test)),"");
fflush(stdout);
}
~Test() {
if (std::uncaught_exception()) {
fail();
printf(" due to uncaught exception.\n");
}
if (passing_now) printf("[PASS]\n");
}
void fail() {
if (!passing_now) return;
passing_now = passing = false;
printf("[FAIL]\n");
}
};

static bool arith_check(
Test &test,
const Scalar &x,
const Scalar &y,
const Scalar &z,
const Scalar &r,
const Scalar &l,
const char *name
) {
if (l == r) return true;
test.fail();
printf(" %s", name);
print("x", x);
print("y", y);
print("z", z);
print("lhs", r);
print("rhs", l);
return false;
}

static bool point_check(
Test &test,
const Point &p,
const Point &q,
const Point &R,
const Scalar &x,
const Scalar &y,
const Point &r,
const Point &l,
const char *name
) {
if (l == r) return true;
test.fail();
printf(" %s", name);
print("x", x);
print("y", y);
print("p", p);
print("q", q);
print("r", R);
print("lhs", r);
print("rhs", l);
return false;
}

static void test_arithmetic() {
keccak_sponge_t sponge;
unsigned char buffer[DECAF_448_SCALAR_BYTES+8];
spongerng_init_from_buffer(sponge, (const uint8_t *)"test_arithmetic", 16, 1);
Test test("Arithmetic");
Scalar x(0),y(0),z(0);
arith_check(test,x,y,z,INT_MAX,(decaf_word_t)INT_MAX,"cast from max");
arith_check(test,x,y,z,INT_MIN,-Scalar(1+(decaf_word_t)INT_MAX),"cast from min");
for (int i=0; i<NTESTS*10 && test.passing_now; i++) {
/* TODO: pathological cases */
size_t sob = sizeof(buffer) - (i%16);
spongerng_next(sponge, buffer, sob);
Scalar x(buffer, sob);
spongerng_next(sponge, buffer, sob);
Scalar y(buffer, sob);
spongerng_next(sponge, buffer, sob);
Scalar z(buffer, sob);

arith_check(test,x,y,z,x+y,y+x,"commute add");
arith_check(test,x,y,z,x,x+0,"ident add");
arith_check(test,x,y,z,x,x-0,"ident sub");
arith_check(test,x,y,z,x+(y+z),(x+y)+z,"assoc add");
arith_check(test,x,y,z,x*(y+z),x*y + x*z,"distributive mul/add");
arith_check(test,x,y,z,x*(y-z),x*y - x*z,"distributive mul/add");
arith_check(test,x,y,z,x*(y*z),(x*y)*z,"assoc mul");
arith_check(test,x,y,z,x*y,y*x,"commute mul");
arith_check(test,x,y,z,x,x*1,"ident mul");
arith_check(test,x,y,z,0,x*0,"mul by 0");
arith_check(test,x,y,z,-x,x*-1,"mul by -1");
arith_check(test,x,y,z,x+x,x*2,"mul by 2");
if (i%20) continue;
if (y!=0) arith_check(test,x,y,z,x*y/y,x,"invert");
arith_check(test,x,y,z,x/0,0,"invert0");
}
}


static void test_ec() {
keccak_sponge_t sponge;
unsigned char buffer[2*DECAF_448_SCALAR_BYTES];
spongerng_init_from_buffer(sponge, (const uint8_t *)"test_ec", 8, 1);
Test test("EC");
for (int i=0; i<NTESTS && test.passing_now; i++) {
/* TODO: pathological cases */
size_t sob = sizeof(buffer);
spongerng_next(sponge, buffer, sob);
Scalar x(buffer, sob);
spongerng_next(sponge, buffer, sob);
Scalar y(buffer, sob);
spongerng_next(sponge, buffer, sob);
Point p = Point::from_hash(buffer);
spongerng_next(sponge, buffer, sob);
Point q = Point::from_hash(buffer);
spongerng_next(sponge, buffer, sob);
Point r = Point::from_hash(buffer);
point_check(test,p,q,r,0,0,p,Point((std::string)p),"round-trip");
point_check(test,p,q,r,0,0,p+q,q+p,"commute add");
point_check(test,p,q,r,0,0,p+(q+r),(p+q)+r,"assoc add");
if (i%10) continue;
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*y)*p,x*(y*p),"assoc mul");
point_check(test,p,q,r,x,0,Precomputed(p)*x,p*x,"precomp mul");
}
}

int main(int argc, char **argv) {
(void) argc; (void) argv;
test_arithmetic();
test_ec();
if (passing) printf("Passed all tests.\n");
return passing ? 0 : 1;
}

Loading…
Cancel
Save