Browse Source

add some pathological test cases, clearing a few TODO items. Also scalar_set_unsigned now takes a uint64_t instead of a word_t

master
Michael Hamburg 8 years ago
parent
commit
c9abcef055
4 changed files with 145 additions and 20 deletions
  1. +10
    -2
      src/decaf.c
  2. +2
    -2
      src/gen_headers/decaf_h.py
  3. +19
    -7
      src/gen_headers/decaf_hxx.py
  4. +114
    -9
      test/test_decaf.cxx

+ 10
- 2
src/decaf.c View File

@@ -356,10 +356,18 @@ sc_halve (
void
API_NS(scalar_set_unsigned) (
scalar_t out,
decaf_word_t w
uint64_t w
) {
memset(out,0,sizeof(scalar_t));
out->limb[0] = w;
if (sizeof(uint64_t) > sizeof(decaf_word_t)) {
unsigned int i = 0;
for (; i<sizeof(uint64_t)/sizeof(decaf_word_t); i++) {
out->limb[i] = w;
w >>= 8*sizeof(decaf_word_t);
}
} else {
out->limb[0] = w;
}
}

decaf_bool_t


+ 2
- 2
src/gen_headers/decaf_h.py View File

@@ -199,13 +199,13 @@ static inline void NONNULL2 %(c_ns)s_scalar_copy (
}

/**
* @brief Set a scalar to an unsigned integer.
* @brief Set a scalar to an unsigned 64-bit integer.
* @param [in] a An integer.
* @param [out] out Will become equal to a.
*/
void %(c_ns)s_scalar_set_unsigned (
%(c_ns)s_scalar_t out,
decaf_word_t a
uint64_t a
) API_VIS NONNULL1;

/**


+ 19
- 7
src/gen_headers/decaf_hxx.py View File

@@ -81,10 +81,16 @@ public:
/** @endcond */

/** Set to an unsigned word */
inline Scalar(const decaf_word_t w) NOEXCEPT { *this = w; }
inline Scalar(uint64_t w) NOEXCEPT { *this = w; }

/** Set to a signed word */
inline Scalar(const int w) NOEXCEPT { *this = w; }
inline Scalar(int64_t w) NOEXCEPT { *this = w; }

/** Set to an unsigned word */
inline Scalar(unsigned int w) NOEXCEPT { *this = w; }

/** Set to a signed word */
inline Scalar(int w) NOEXCEPT { *this = w; }

/** Construct from RNG */
inline explicit Scalar(Rng &rng) NOEXCEPT {
@@ -112,18 +118,24 @@ public:
/** Assignment. */
inline Scalar& operator=(const Scalar &x) NOEXCEPT { %(c_ns)s_scalar_copy(s,x.s); return *this; }

/** Assign from unsigned word. */
inline Scalar& operator=(decaf_word_t w) NOEXCEPT { %(c_ns)s_scalar_set_unsigned(s,w); return *this; }
/** Assign from unsigned 64-bit integer. */
inline Scalar& operator=(uint64_t w) NOEXCEPT { %(c_ns)s_scalar_set_unsigned(s,w); return *this; }


/** Assign from signed int. */
inline Scalar& operator=(int w) NOEXCEPT {
Scalar t(-(decaf_word_t)INT_MIN);
%(c_ns)s_scalar_set_unsigned(s,(decaf_word_t)w - (decaf_word_t)INT_MIN);
inline Scalar& operator=(int64_t w) NOEXCEPT {
Scalar t(-(uint64_t)INT_MIN);
%(c_ns)s_scalar_set_unsigned(s,(uint64_t)w - (uint64_t)INT_MIN);
*this -= t;
return *this;
}

/** Assign from unsigned int. */
inline Scalar& operator=(unsigned int w) NOEXCEPT { return *this = (uint64_t)w; }

/** Assign from signed int. */
inline Scalar& operator=(int w) NOEXCEPT { return *this = (int64_t)w; }

/** Destructor securely zeorizes the scalar. */
inline ~Scalar() NOEXCEPT { %(c_ns)s_scalar_destroy(s); }



+ 114
- 9
test/test_decaf.cxx View File

@@ -43,6 +43,14 @@ public:
}
};

static uint64_t leint(const SecureBuffer &xx) {
uint64_t out = 0;
for (unsigned int i=0; i<xx.size() && i<sizeof(out); i++) {
out |= uint64_t(xx[i]) << (8*i);
}
return out;
}

template<typename Group> struct Tests {

typedef typename Group::Scalar Scalar;
@@ -137,16 +145,20 @@ static void test_arithmetic() {
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 = DECAF_255_SCALAR_BYTES + 8 - (i%16);
Scalar x(rng.read(sob));
Scalar y(rng.read(sob));
Scalar z(rng.read(sob));
size_t sob = i % (2*Group::Scalar::SER_BYTES);
SecureBuffer xx = rng.read(sob), yy = rng.read(sob), zz = rng.read(sob);
Scalar x(xx);
Scalar y(yy);
Scalar z(zz);

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+-x,0,"inverse add");
arith_check(test,x,y,z,x-x,0,"inverse sub");
arith_check(test,x,y,z,x-(x+1),-1,"inverse add2");
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");
@@ -156,6 +168,18 @@ static void test_arithmetic() {
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");
arith_check(test,x,y,z,-(x*y),(-x)*y,"neg prop mul");
arith_check(test,x,y,z,x*y,(-x)*(-y),"double neg prop mul");
arith_check(test,x,y,z,-(x+y),(-x)+(-y),"neg prop add");
arith_check(test,x,y,z,x-y,(x)+(-y),"add neg sub");
arith_check(test,x,y,z,(-x)-y,-(x+y),"neg add");
if (sob <= 4) {
uint64_t xi = leint(xx), yi = leint(yy);
arith_check(test,x,y,z,x,xi,"parse consistency");
arith_check(test,x,y,z,x+y,xi+yi,"add consistency");
arith_check(test,x,y,z,x*y,xi*yi,"mul consistency");
}
if (i%20) continue;
if (y!=0) arith_check(test,x,y,z,x*y/y,x,"invert");
@@ -169,6 +193,10 @@ static void test_arithmetic() {
}
}

static const Block sqrt_minus_one;
static const Block minus_sqrt_minus_one;
static const Block elli_patho;

static void test_elligator() {
SpongeRng rng(Block("test_elligator"),SpongeRng::DETERMINISTIC);
Test test("Elligator");
@@ -179,13 +207,20 @@ static void test_elligator() {
SecureBuffer *alts2[NHINTS];
bool successes2[NHINTS];

for (int i=0; i<NTESTS/10 && (test.passing_now || i < 100); i++) {
for (int i=0; i<NTESTS/10 && test.passing_now; i++) {
size_t len = (i % (2*Point::HASH_BYTES + 3));
SecureBuffer b1(len);
if (i!=Point::HASH_BYTES) rng.read(b1); /* special test case */
if (i==1) b1[0] = 1; /* special case test */
if (len >= Point::HASH_BYTES) b1[Point::HASH_BYTES-1] &= 0x7F; // FIXME MAGIC
/* Pathological cases */
if (i==1) b1[0] = 1;
if (i==2 && sqrt_minus_one.size()) b1 = sqrt_minus_one;
if (i==3 && minus_sqrt_minus_one.size()) b1 = minus_sqrt_minus_one;
if (i==4 && elli_patho.size()) b1 = elli_patho;
len = b1.size();
Point s = Point::from_hash(b1), ss=s;
for (int j=0; j<(i&3); j++) ss = ss.debugging_torque();
@@ -273,6 +308,8 @@ static void test_ec() {
Point id = Point::identity(), base = Point::base();
point_check(test,id,id,id,0,0,Point::from_hash(""),id,"fh0");
unsigned char enc[Point::SER_BYTES] = {0};
if (Group::FIELD_MODULUS_TYPE == 3) {
/* When p == 3 mod 4, the QNR is -1, so u*1^2 = -1 also produces the
* identity.
@@ -280,8 +317,37 @@ static void test_ec() {
point_check(test,id,id,id,0,0,Point::from_hash("\x01"),id,"fh1");
}
point_check(test,id,id,id,0,0,Point(FixedBlock<sizeof(enc)>(enc)),id,"decode [0]");
try {
enc[0] = 1;
Point f((FixedBlock<sizeof(enc)>(enc)));
test.fail();
printf(" Allowed deserialize of [1]: %d", f==id);
} catch (CryptoException) {
/* ok */
}
if (sqrt_minus_one.size()) {
try {
Point f(sqrt_minus_one);
test.fail();
printf(" Allowed deserialize of [i]: %d", f==id);
} catch (CryptoException) {
/* ok */
}
}
if (minus_sqrt_minus_one.size()) {
try {
Point f(minus_sqrt_minus_one);
test.fail();
printf(" Allowed deserialize of [-i]: %d", f==id);
} catch (CryptoException) {
/* ok */
}
}
for (int i=0; i<NTESTS && test.passing_now; i++) {
/* TODO: pathological cases */
Scalar x(rng);
Scalar y(rng);
Point p(rng);
@@ -297,7 +363,15 @@ static void test_ec() {
Point pp = p.debugging_torque().debugging_pscale(rng);
if (!memeq(pp.serialize(),p.serialize())) {
test.fail();
printf("Fail torque seq test\n");
printf(" Fail torque seq test\n");
}
if (!memeq((p-pp).serialize(),id.serialize())) {
test.fail();
printf(" Fail torque id test\n");
}
if (!memeq((p-p).serialize(),id.serialize())) {
test.fail();
printf(" Fail id test\n");
}
point_check(test,p,q,r,0,0,p,pp,"torque eq");
point_check(test,p,q,r,0,0,p+q,q+p,"commute add");
@@ -306,6 +380,7 @@ static void test_ec() {
point_check(test,p,q,r,0,0,p.times_two(),p+p,"dbl add");
if (i%10) continue;
point_check(test,p,q,r,0,0,p.times_two(),p*Scalar(2),"add times two");
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),"double mul");
@@ -461,6 +536,36 @@ template<> const uint8_t Tests<Ed448Goldilocks>::rfc7748_1000000[56] = {
0xc9,0x46,0xda,0x8d,0x52,0x4d,0xe3,0xd6,
0x9b,0xd9,0xd9,0xd6,0x6b,0x99,0x7e,0x37
};

template<> const Block Tests<Ed448Goldilocks>::sqrt_minus_one(NULL,0);
const uint8_t sm1_25519[32] = {
0xb0,0xa0,0x0e,0x4a,0x27,0x1b,0xee,0xc4,
0x78,0xe4,0x2f,0xad,0x06,0x18,0x43,0x2f,
0xa7,0xd7,0xfb,0x3d,0x99,0x00,0x4d,0x2b,
0x0b,0xdf,0xc1,0x4f,0x80,0x24,0x83,0x2b
};
template<> const Block Tests<IsoEd25519>::sqrt_minus_one(sm1_25519,32);

template<> const Block Tests<Ed448Goldilocks>::minus_sqrt_minus_one(NULL,0);
const uint8_t msm1_25519[32] = {
0x3d,0x5f,0xf1,0xb5,0xd8,0xe4,0x11,0x3b,
0x87,0x1b,0xd0,0x52,0xf9,0xe7,0xbc,0xd0,
0x58,0x28,0x04,0xc2,0x66,0xff,0xb2,0xd4,
0xf4,0x20,0x3e,0xb0,0x7f,0xdb,0x7c,0x54
};
template<> const Block Tests<IsoEd25519>::minus_sqrt_minus_one(msm1_25519,32);

const uint8_t elli_patho_448[56] = {
0x14,0xf0,0x70,0x58,0x41,0xc7,0xf9,0xa5,
0xfa,0x2c,0x7d,0x87,0x07,0x89,0xe8,0x61,
0x63,0xe8,0xc8,0xdc,0x06,0x2d,0x39,0x8f,
0x18,0x83,0x1e,0xc6,0x8c,0x6d,0x73,0x24,
0xd4,0xb3,0xd3,0xe1,0xf3,0x51,0x8c,0xee,
0x65,0x79,0x88,0xc1,0x0b,0xcf,0x8e,0xa5,
0x86,0xa9,0x2e,0xc9,0x17,0x68,0x9b,0x20
};
template<> const Block Tests<Ed448Goldilocks>::elli_patho(elli_patho_448,56);
template<> const Block Tests<IsoEd25519>::elli_patho(NULL,0);



Loading…
Cancel
Save