Commit b1c6de63 authored by Michael Hamburg's avatar Michael Hamburg

EdDSA 448 seems to be working. Needs more testing, code moved around. EdDSA...

EdDSA 448 seems to be working.  Needs more testing, code moved around.  EdDSA 255 not working yet; needs SHA512
parent fffb77ac
......@@ -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],
......
......@@ -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
......
......@@ -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) */
......
......@@ -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();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment