Browse Source

EdDSA 448 seems to be working. Needs more testing, code moved around. EdDSA 255 not working yet; needs SHA512

master
Michael Hamburg 9 years ago
parent
commit
b1c6de6309
4 changed files with 212 additions and 21 deletions
  1. +73
    -12
      src/per_curve/decaf.tmpl.c
  2. +40
    -2
      src/per_curve/decaf.tmpl.h
  3. +62
    -7
      src/per_curve/decaf.tmpl.hxx
  4. +37
    -0
      test/test_decaf.cxx

+ 73
- 12
src/per_curve/decaf.tmpl.c View File

@@ -1067,18 +1067,17 @@ void API_NS(point_encode_like_eddsa) (
gf u;
gf_sqr ( x, p->x );
gf_sqr ( t, p->y );
gf_add( u, x, t ); // x^2 + y^2
gf_add( u, x, t );
gf_add( z, p->y, p->x );
gf_sqr ( y, z); // (x+y)^2
gf_sub ( y, y, u ); // 2xy
gf_sub ( z, t, x ); // y^2 - x^2
gf_sqr ( x, p->z ); // z^2
gf_add ( t, x, x); // 2z^2
gf_sub ( t, t, z); // 2z^2 - y^2 + x^2
gf_mul ( x, t, y ); // (2z^2 - y^2 + x^2)(2xy)
gf_mul ( y, z, u ); // (y^2 - x^2)(x^2 + y^2)
gf_mul ( z, u, t ); // (x^2 + y^2)(2z^2 - y^2 + x^2)
gf_sqr ( y, z);
gf_sub ( y, y, u );
gf_sub ( z, t, x );
gf_sqr ( x, p->z );
gf_add ( t, x, x);
gf_sub ( t, t, z);
gf_mul ( x, t, y );
gf_mul ( y, z, u );
gf_mul ( z, u, t );
decaf_bzero(t,sizeof(u));
}
#endif
@@ -1090,7 +1089,7 @@ void API_NS(point_encode_like_eddsa) (
/* Encode */
enc[$(C_NS)_EDDSA_PRIVATE_BYTES-1] = 0;
gf_serialize(enc, x, 1);
enc[$(C_NS)_EDDSA_PRIVATE_BYTES-1] |= 0x80 &~ gf_lobit(t);
enc[$(C_NS)_EDDSA_PRIVATE_BYTES-1] |= 0x80 & gf_lobit(t);

decaf_bzero(x,sizeof(x));
decaf_bzero(y,sizeof(y));
@@ -1098,6 +1097,68 @@ void API_NS(point_encode_like_eddsa) (
decaf_bzero(t,sizeof(t));
}


decaf_error_t API_NS(point_decode_like_eddsa) (
point_t p,
const uint8_t enc[$(C_NS)_EDDSA_PUBLIC_BYTES]
) {
uint8_t enc2[$(C_NS)_EDDSA_PUBLIC_BYTES];
memcpy(enc2,enc,sizeof(enc2));

mask_t low = ~word_is_zero(enc2[$(C_NS)_EDDSA_PRIVATE_BYTES-1] & 0x80);
enc2[$(C_NS)_EDDSA_PRIVATE_BYTES-1] &= ~0x80;
mask_t succ = DECAF_TRUE;
#if $(gf_bits % 8) == 0
succ = word_is_zero(enc2[$(C_NS)_EDDSA_PRIVATE_BYTES-1]);
#endif
succ &= gf_deserialize(p->y, enc2, 1);
gf_sqr(p->z,p->y);
gf_mulw(p->t,p->z,EDWARDS_D);
gf_sub(p->z,ONE,p->z); /* 1-y^2 */
gf_sub(p->t,ONE,p->t); /* 1-dy^2 */
gf_mul(p->x,p->z,p->t);
succ &= gf_isr(p->t,p->x); /* 1/sqrt((1-y^2)(1-dy^2)) */
gf_mul(p->x,p->t,p->z); /* sqrt((1-y^2) / (1-dy^2)) */
gf_cond_neg(p->x,gf_lobit(p->x)^low);
gf_copy(p->z,ONE);
#if IMAGINE_TWIST
{
gf_mul(p->t,p->x,SQRT_MINUS_ONE);
gf_copy(p->x,p->t);
point_double_internal(p,p,0);
}
#else
{
/* 4-isogeny */
gf a, b, c, d;
gf_sqr ( c, p->x );
gf_sqr ( a, p->y );
gf_add ( d, c, a );
gf_add ( p->t, p->y, p->x );
gf_sqr ( b, p->t );
gf_sub ( b, b, d );
gf_sub ( p->t, a, c );
gf_sqr ( p->x, p->z );
gf_add ( p->z, p->x, p->x );
gf_sub ( a, p->z, d );
gf_mul ( p->x, a, b );
gf_mul ( p->z, p->t, a );
gf_mul ( p->y, p->t, d );
gf_mul ( p->t, b, d );
decaf_bzero(a,sizeof(a));
decaf_bzero(b,sizeof(b));
decaf_bzero(c,sizeof(c));
decaf_bzero(d,sizeof(d));
}
#endif
decaf_bzero(enc2,sizeof(enc2));
assert(API_NS(point_valid)(p) || ~succ);
return decaf_succeed_if(succ);
}

decaf_error_t API_NS(x_direct_scalarmul) (
uint8_t out[X_PUBLIC_BYTES],
const uint8_t base[X_PUBLIC_BYTES],


+ 40
- 2
src/per_curve/decaf.tmpl.h View File

@@ -429,7 +429,7 @@ void $(c_ns)_eddsa_derive_public_key (
/**
* @brief EdDSA signing.
*
* @param [out] The signature.
* @param [out] signature The signature.
* @param [in] privkey The private key.
* @param [in] pubkey The public key.
* @param [in] context A "context" for this signature of up to 255 bytes.
@@ -447,19 +447,57 @@ void $(c_ns)_eddsa_sign (
const uint8_t *message,
size_t message_len,
uint8_t prehashed
) API_VIS NONNULL NOINLINE;
) API_VIS __attribute__((nonnull(1,2,3))) NOINLINE;

/**
* @brief EdDSA signature verification.
*
* Uses the standard (i.e. less-strict) verification formula.
*
* @param [in] signature The signature.
* @param [in] pubkey The public key.
* @param [in] context A "context" for this signature of up to 255 bytes.
* @param [in] context_len Length of the context.
* @param [in] message The message to verify.
* @param [in] message_len The length of the message.
* @param [in] prehashed Nonzero if the message is actually the hash of something you want to verify.
*/
decaf_error_t $(c_ns)_eddsa_verify (
const uint8_t signature[$(C_NS)_EDDSA_SIGNATURE_BYTES],
const uint8_t pubkey[$(C_NS)_EDDSA_PUBLIC_BYTES],
const uint8_t *context,
uint8_t context_len,
const uint8_t *message,
size_t message_len,
uint8_t prehashed
) API_VIS __attribute__((nonnull(1,2))) NOINLINE;

/**
* @brief EdDSA point encoding.
*
* @param [out] enc The encoded point.
* @param [in] p The point.
*
* FIXME: encode and decode aren't inverses of each other: they
* multiply by a factor. Rename to reflect this once the base
* point doctrine is worked out.
*/
void $(c_ns)_point_encode_like_eddsa (
uint8_t enc[$(C_NS)_EDDSA_PUBLIC_BYTES],
const $(c_ns)_point_t p
) API_VIS NONNULL NOINLINE;

/**
* @brief EdDSA point encoding.
*
* @param [out] enc The encoded point.
* @param [in] p The point.
*/
decaf_error_t $(c_ns)_point_decode_like_eddsa (
$(c_ns)_point_t p,
const uint8_t enc[$(C_NS)_EDDSA_PUBLIC_BYTES]
) API_VIS NONNULL NOINLINE;

/**
* @brief Precompute a table for fast scalar multiplication.
* Some implementations do not include precomputed points; for


+ 62
- 7
src/per_curve/decaf.tmpl.hxx View File

@@ -287,7 +287,7 @@ public:
*/
inline explicit Point(const FixedBlock<SER_BYTES> &buffer, decaf_bool_t allow_identity=DECAF_TRUE)
throw(CryptoException) {
if (DECAF_SUCCESS != decode(*this,buffer,allow_identity)) {
if (DECAF_SUCCESS != decode(buffer,allow_identity)) {
throw CryptoException();
}
}
@@ -300,10 +300,34 @@ 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 WARN_UNUSED decode (
Point &p, const FixedBlock<SER_BYTES> &buffer, decaf_bool_t allow_identity=DECAF_TRUE
inline decaf_error_t WARN_UNUSED decode (
const FixedBlock<SER_BYTES> &buffer, decaf_bool_t allow_identity=DECAF_TRUE
) NOEXCEPT {
return $(c_ns)_point_decode(p,buffer.data(),allow_identity);
}

/**
* Initialize from C++ fixed-length byte string, like EdDSA.
* The all-zero string maps to the identity.
*
* @retval DECAF_SUCCESS the string was successfully decoded.
* @return DECAF_FAILURE the string was the wrong length, or wasn't the encoding of a point.
* Contents of the point are undefined.
* TODO: rename to noexcept?
*/
inline decaf_error_t WARN_UNUSED decode_like_eddsa (
const FixedBlock<$(C_NS)_EDDSA_PUBLIC_BYTES> &buffer
) NOEXCEPT {
return $(c_ns)_point_decode(p.p,buffer.data(),allow_identity);
return $(c_ns)_point_decode_like_eddsa(p,buffer.data());
}

/**
* Encode like EdDSA. FIXME: and multiply by the cofactor...
*/
inline SecureBuffer encode_like_eddsa() const {
SecureBuffer ret($(C_NS)_EDDSA_PUBLIC_BYTES);
$(c_ns)_point_encode_like_eddsa(ret.data(),p);
return ret;
}

/**
@@ -649,8 +673,8 @@ public:
}
};

struct EdDSA {
struct EdDSA { /* TODO: make into a utility class. Possibly move to another include file. */
public:
/** The size of a public key */
static const size_t PUBLIC_BYTES = $(C_NS)_EDDSA_PUBLIC_BYTES;
@@ -661,7 +685,6 @@ public:
/** The size of a private key */
static const size_t SIGNATURE_BYTES = $(C_NS)_EDDSA_SIGNATURE_BYTES;
/* TODO: make into a nice class. Change name. Possibly move to another include file. */
static inline SecureBuffer generate_key (
const FixedBlock<PRIVATE_BYTES> &priv
) {
@@ -691,6 +714,38 @@ public:
);
return out;
}
static inline decaf_error_t WARN_UNUSED verify_noexcept (
const FixedBlock<SIGNATURE_BYTES> &sig,
const FixedBlock<PUBLIC_BYTES> &pub,
const Block &context,
const Block &message,
bool prehashed = false
) {
if (context.size() > 255) return DECAF_FAILURE;
return $(c_ns)_eddsa_verify (
sig.data(),
pub.data(),
context.data(),
context.size(),
message.data(),
message.size(),
prehashed
);
}
static inline void verify (
const FixedBlock<SIGNATURE_BYTES> &sig,
const FixedBlock<PUBLIC_BYTES> &pub,
const Block &context,
const Block &message,
bool prehashed = false
) throw(LengthException,CryptoException) {
if (context.size() > 255) { throw LengthException(); }
if (DECAF_SUCCESS != verify_noexcept( sig, pub, context, message, prehashed )) {
throw CryptoException();
}
}
};

}; /* struct $(cxx_ns) */


+ 37
- 0
test/test_decaf.cxx View File

@@ -394,6 +394,16 @@ static void test_ec() {
);
point_check(test,p,q,r,x,0,Point(x.direct_scalarmul(p.serialize())),x*p,"direct mul");
q=p;
for (int j=1; j<Group::REMOVED_COFACTOR; j<<=1) q = q.times_two();
decaf_error_t error = r.decode_like_eddsa(p.encode_like_eddsa());
if (error != DECAF_SUCCESS) {
test.fail();
printf(" Decode like EdDSA failed.");
}
point_check(test,-q,q,r,0,0,q,r,"Encode like EdDSA round-trip");
}
}

@@ -515,12 +525,39 @@ static void test_cfrg_vectors() {
}
}

static void test_eddsa() {
Test test("EdDSA");
SpongeRng rng(Block("test_cfrg_crypto"),SpongeRng::DETERMINISTIC);
for (int i=0; i<NTESTS && test.passing_now; i++) {
FixedArrayBuffer<EdDSA::PRIVATE_BYTES> priv(rng);
SecureBuffer pub = EdDSA::generate_key(priv);
SecureBuffer message(i);
rng.read(message);
SecureBuffer context(i%256);
rng.read(message);
SecureBuffer sig = EdDSA::sign(priv,pub,context,message,i%2);
try {
EdDSA::verify(sig,pub,context,message,i%2);
} catch(CryptoException) {
test.fail();
printf(" Signature validation failed on sig %d\n", i);
}
}
}

static void run() {
printf("Testing %s:\n",Group::name());
test_arithmetic();
test_elligator();
test_ec();
test_eddsa();
test_cfrg_crypto();
test_cfrg_vectors();
test_crypto();


Loading…
Cancel
Save