@@ -169,7 +169,8 @@ LIBCOMPONENTS += $$(BUILD_OBJ)/$(1)/decaf.o $$(BUILD_OBJ)/$(1)/elligator.o $$(BU | |||||
$$(BUILD_OBJ)/$(1)/crypto.o $$(BUILD_OBJ)/$(1)/eddsa.o $$(BUILD_OBJ)/$(1)/decaf_tables.o | $$(BUILD_OBJ)/$(1)/crypto.o $$(BUILD_OBJ)/$(1)/eddsa.o $$(BUILD_OBJ)/$(1)/decaf_tables.o | ||||
PER_OBJ_DIRS += $$(BUILD_OBJ)/$(1) | PER_OBJ_DIRS += $$(BUILD_OBJ)/$(1) | ||||
GLOBAL_HEADERS_OF_$(1) = $(BUILD_INC)/decaf/decaf_$(3).h $(BUILD_INC)/decaf/decaf_$(3).hxx \ | GLOBAL_HEADERS_OF_$(1) = $(BUILD_INC)/decaf/decaf_$(3).h $(BUILD_INC)/decaf/decaf_$(3).hxx \ | ||||
$(BUILD_INC)/decaf/crypto_$(3).h $(BUILD_INC)/decaf/crypto_$(3).hxx | |||||
$(BUILD_INC)/decaf/crypto_$(3).h $(BUILD_INC)/decaf/crypto_$(3).hxx \ | |||||
$(BUILD_INC)/decaf/eddsa_$(3).h | |||||
HEADERS_OF_$(1) = $$(HEADERS_OF_$(2)) $$(GLOBAL_HEADERS_OF_$(1)) | HEADERS_OF_$(1) = $$(HEADERS_OF_$(2)) $$(GLOBAL_HEADERS_OF_$(1)) | ||||
HEADERS += $$(GLOBAL_HEADERS_OF_$(1)) | HEADERS += $$(GLOBAL_HEADERS_OF_$(1)) | ||||
@@ -182,6 +183,9 @@ $$(BUILD_H)/$(1)/%.h: src/per_curve/%.tmpl.h src/gen_headers/* $$(HEADERS_OF_$(2 | |||||
$$(BUILD_INC)/decaf/decaf_$(3).%: src/per_curve/decaf.tmpl.% src/gen_headers/* $$(HEADERS_OF_$(2)) | $$(BUILD_INC)/decaf/decaf_$(3).%: src/per_curve/decaf.tmpl.% src/gen_headers/* $$(HEADERS_OF_$(2)) | ||||
python -B src/gen_headers/template.py --per=curve --item=$(1) --guard=$$(@:$(BUILD_INC)/%=%) -o $$@ $$< | python -B src/gen_headers/template.py --per=curve --item=$(1) --guard=$$(@:$(BUILD_INC)/%=%) -o $$@ $$< | ||||
$$(BUILD_INC)/decaf/eddsa_$(3).%: src/per_curve/eddsa.tmpl.% src/gen_headers/* $$(HEADERS_OF_$(2)) | |||||
python -B src/gen_headers/template.py --per=curve --item=$(1) --guard=$$(@:$(BUILD_INC)/%=%) -o $$@ $$< | |||||
$$(BUILD_INC)/decaf/elligator_$(3).%: src/per_curve/elligator.tmpl.% src/gen_headers/* $$(HEADERS_OF_$(2)) | $$(BUILD_INC)/decaf/elligator_$(3).%: src/per_curve/elligator.tmpl.% src/gen_headers/* $$(HEADERS_OF_$(2)) | ||||
python -B src/gen_headers/template.py --per=curve --item=$(1) --guard=$$(@:$(BUILD_INC)/%=%) -o $$@ $$< | python -B src/gen_headers/template.py --per=curve --item=$(1) --guard=$$(@:$(BUILD_INC)/%=%) -o $$@ $$< | ||||
@@ -33,7 +33,10 @@ curve_data = { | |||||
"combs":comb_config(3,5,17), | "combs":comb_config(3,5,17), | ||||
"wnaf":wnaf_config(5,3), | "wnaf":wnaf_config(5,3), | ||||
"window_bits":4 | |||||
"window_bits":4, | |||||
"eddsa_hash": "sha512", | |||||
"eddsa_supports_contexts": 0 | |||||
}, | }, | ||||
"ed448goldilocks" : { | "ed448goldilocks" : { | ||||
"name" : "Ed448-Goldilocks", | "name" : "Ed448-Goldilocks", | ||||
@@ -101,6 +104,12 @@ for curve,data in curve_data.iteritems(): | |||||
if "iso_to" not in data: | if "iso_to" not in data: | ||||
data["iso_to"] = data["name"] | data["iso_to"] = data["name"] | ||||
if "eddsa_hash" not in data: | |||||
data["edddsa"] = "sha512" | |||||
if "eddsa_supports_contexts" not in data: | |||||
data["eddsa_supports_contexts"] = 1 | |||||
if "cxx_ns" not in data: | if "cxx_ns" not in data: | ||||
data["cxx_ns"] = data["name"].replace("-","") | data["cxx_ns"] = data["name"].replace("-","") | ||||
@@ -5,6 +5,7 @@ | |||||
#include "field.h" | #include "field.h" | ||||
#include <decaf.h> | #include <decaf.h> | ||||
#include <decaf/eddsa_$(gf_bits).h> | |||||
/* Template stuff */ | /* Template stuff */ | ||||
#define API_NS(_id) $(c_ns)_##_id | #define API_NS(_id) $(c_ns)_##_id | ||||
@@ -37,16 +37,6 @@ typedef struct gf_$(gf_shortname)_s { | |||||
/** Number of bits in the "which" field of an elligator inverse */ | /** Number of bits in the "which" field of an elligator inverse */ | ||||
#define $(C_NS)_INVERT_ELLIGATOR_WHICH_BITS $(ceil_log2(cofactor) + 7 + elligator_onto - ((gf_bits-2) % 8)) | #define $(C_NS)_INVERT_ELLIGATOR_WHICH_BITS $(ceil_log2(cofactor) + 7 + elligator_onto - ((gf_bits-2) % 8)) | ||||
/* TODO: move to a different file? */ | |||||
/** Number of bytes in an EdDSA public key. */ | |||||
#define $(C_NS)_EDDSA_PUBLIC_BYTES $((gf_bits)/8 + 1) /* TODO: change name? */ | |||||
/** Number of bytes in an EdDSA private key. */ | |||||
#define $(C_NS)_EDDSA_PRIVATE_BYTES $(C_NS)_EDDSA_PUBLIC_BYTES /* TODO: change name? */ | |||||
/** Number of bytes in an EdDSA private key. */ | |||||
#define $(C_NS)_EDDSA_SIGNATURE_BYTES ($(C_NS)_EDDSA_PUBLIC_BYTES + $(C_NS)_EDDSA_PRIVATE_BYTES) /* TODO: change name? */ | |||||
/** Number of bytes in an x$(gf_shortname) public key */ | /** Number of bytes in an x$(gf_shortname) public key */ | ||||
#define X$(gf_shortname)_PUBLIC_BYTES $((gf_bits-1)/8 + 1) | #define X$(gf_shortname)_PUBLIC_BYTES $((gf_bits-1)/8 + 1) | ||||
@@ -414,90 +404,6 @@ void $(c_ns)_x_base_scalarmul ( | |||||
const uint8_t scalar[X$(gf_shortname)_PRIVATE_BYTES] | const uint8_t scalar[X$(gf_shortname)_PRIVATE_BYTES] | ||||
) API_VIS NONNULL NOINLINE; | ) API_VIS NONNULL NOINLINE; | ||||
/** | |||||
* @brief EdDSA key generation. This function uses a different (non-Decaf) | |||||
* encoding. | |||||
* | |||||
* @param [out] pubkey The public key. | |||||
* @param [in] privkey The private key. | |||||
*/ | |||||
void $(c_ns)_eddsa_derive_public_key ( | |||||
uint8_t pubkey[$(C_NS)_EDDSA_PUBLIC_BYTES], | |||||
const uint8_t privkey[$(C_NS)_EDDSA_PRIVATE_BYTES] | |||||
) API_VIS NONNULL NOINLINE; | |||||
/** | |||||
* @brief EdDSA signing. | |||||
* | |||||
* @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. | |||||
* @param [in] context_len Length of the context. | |||||
* @param [in] message The message to sign. | |||||
* @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 sign. | |||||
*/ | |||||
void $(c_ns)_eddsa_sign ( | |||||
uint8_t signature[$(C_NS)_EDDSA_SIGNATURE_BYTES], | |||||
const uint8_t privkey[$(C_NS)_EDDSA_PRIVATE_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,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. | * @brief Precompute a table for fast scalar multiplication. | ||||
* Some implementations do not include precomputed points; for | * Some implementations do not include precomputed points; for | ||||
@@ -21,6 +21,7 @@ | |||||
#include <string.h> /* for memcpy */ | #include <string.h> /* for memcpy */ | ||||
#include <decaf/decaf_$(gf_bits).h> | #include <decaf/decaf_$(gf_bits).h> | ||||
#include <decaf/eddsa_$(gf_bits).h> /* TODO: move eddsa to another file? */ | |||||
#include <decaf/secure_buffer.hxx> | #include <decaf/secure_buffer.hxx> | ||||
#include <string> | #include <string> | ||||
#include <sys/types.h> | #include <sys/types.h> | ||||
@@ -685,6 +686,9 @@ public: | |||||
/** The size of a private key */ | /** The size of a private key */ | ||||
static const size_t SIGNATURE_BYTES = $(C_NS)_EDDSA_SIGNATURE_BYTES; | static const size_t SIGNATURE_BYTES = $(C_NS)_EDDSA_SIGNATURE_BYTES; | ||||
/** Do we support contexts for signatures? If not, they must always be NULL */ | |||||
static const bool SUPPORTS_CONTEXTS = $(C_NS)_EDDSA_SUPPORTS_CONTEXTS; | |||||
static inline SecureBuffer generate_key ( | static inline SecureBuffer generate_key ( | ||||
const FixedBlock<PRIVATE_BYTES> &priv | const FixedBlock<PRIVATE_BYTES> &priv | ||||
) { | ) { | ||||
@@ -696,21 +700,28 @@ public: | |||||
static inline SecureBuffer sign ( | static inline SecureBuffer sign ( | ||||
const FixedBlock<PRIVATE_BYTES> &priv, | const FixedBlock<PRIVATE_BYTES> &priv, | ||||
const FixedBlock<PUBLIC_BYTES> &pub, | const FixedBlock<PUBLIC_BYTES> &pub, | ||||
const Block &context, | |||||
const Block &message, | const Block &message, | ||||
bool prehashed = false | |||||
bool prehashed = false, | |||||
const Block &context = Block(NULL,0) | |||||
) throw(LengthException) { | ) throw(LengthException) { | ||||
if (context.size() > 255) { throw LengthException(); } | |||||
if (context.size() > 255 | |||||
|| (context.size() != 0 && !SUPPORTS_CONTEXTS) | |||||
) { | |||||
throw LengthException(); | |||||
} | |||||
SecureBuffer out(SIGNATURE_BYTES); | SecureBuffer out(SIGNATURE_BYTES); | ||||
$(c_ns)_eddsa_sign ( | $(c_ns)_eddsa_sign ( | ||||
out.data(), | out.data(), | ||||
priv.data(), | priv.data(), | ||||
pub.data(), | pub.data(), | ||||
context.data(), | |||||
context.size(), | |||||
message.data(), | message.data(), | ||||
message.size(), | message.size(), | ||||
prehashed | prehashed | ||||
#if $(C_NS)_EDDSA_SUPPORTS_CONTEXTS | |||||
, context.data(), | |||||
context.size() | |||||
#endif | |||||
); | ); | ||||
return out; | return out; | ||||
} | } | ||||
@@ -718,31 +729,43 @@ public: | |||||
static inline decaf_error_t WARN_UNUSED verify_noexcept ( | static inline decaf_error_t WARN_UNUSED verify_noexcept ( | ||||
const FixedBlock<SIGNATURE_BYTES> &sig, | const FixedBlock<SIGNATURE_BYTES> &sig, | ||||
const FixedBlock<PUBLIC_BYTES> &pub, | const FixedBlock<PUBLIC_BYTES> &pub, | ||||
const Block &context, | |||||
const Block &message, | const Block &message, | ||||
bool prehashed = false | |||||
bool prehashed = false, | |||||
const Block &context = Block(NULL,0) | |||||
) { | ) { | ||||
if (context.size() > 255) return DECAF_FAILURE; | |||||
if (context.size() > 255 | |||||
|| (context.size() != 0 && !SUPPORTS_CONTEXTS) | |||||
) { | |||||
return DECAF_FAILURE; | |||||
} | |||||
return $(c_ns)_eddsa_verify ( | return $(c_ns)_eddsa_verify ( | ||||
sig.data(), | sig.data(), | ||||
pub.data(), | pub.data(), | ||||
context.data(), | |||||
context.size(), | |||||
message.data(), | message.data(), | ||||
message.size(), | message.size(), | ||||
prehashed | prehashed | ||||
#if $(C_NS)_EDDSA_SUPPORTS_CONTEXTS | |||||
, context.data(), | |||||
context.size() | |||||
#endif | |||||
); | ); | ||||
} | } | ||||
static inline void verify ( | static inline void verify ( | ||||
const FixedBlock<SIGNATURE_BYTES> &sig, | const FixedBlock<SIGNATURE_BYTES> &sig, | ||||
const FixedBlock<PUBLIC_BYTES> &pub, | const FixedBlock<PUBLIC_BYTES> &pub, | ||||
const Block &context, | |||||
const Block &message, | const Block &message, | ||||
bool prehashed = false | |||||
bool prehashed = false, | |||||
const Block &context = Block(NULL,0) | |||||
) throw(LengthException,CryptoException) { | ) throw(LengthException,CryptoException) { | ||||
if (context.size() > 255) { throw LengthException(); } | |||||
if (DECAF_SUCCESS != verify_noexcept( sig, pub, context, message, prehashed )) { | |||||
if (context.size() > 255 | |||||
|| (context.size() != 0 && !SUPPORTS_CONTEXTS) | |||||
) { | |||||
throw LengthException(); | |||||
} | |||||
if (DECAF_SUCCESS != verify_noexcept( sig, pub, message, prehashed, context )) { | |||||
throw CryptoException(); | throw CryptoException(); | ||||
} | } | ||||
} | } | ||||
@@ -3,7 +3,7 @@ | |||||
* @brief EdDSA routines. | * @brief EdDSA routines. | ||||
*/ | */ | ||||
#include "decaf.h" | |||||
#include <decaf/eddsa_$(gf_bits).h> | |||||
#include "decaf/shake.h" | #include "decaf/shake.h" | ||||
#include "word.h" | #include "word.h" | ||||
#include <string.h> | #include <string.h> | ||||
@@ -11,6 +11,15 @@ | |||||
#define API_NAME "$(c_ns)" | #define API_NAME "$(c_ns)" | ||||
#define API_NS(_id) $(c_ns)_##_id | #define API_NS(_id) $(c_ns)_##_id | ||||
#define hash_ctx_t shake256_ctx_t | |||||
#define hash_init shake256_init | |||||
#define hash_update shake256_update | |||||
#define hash_final shake256_final | |||||
#define hash_destroy shake256_destroy | |||||
#define hash_hash shake256_hash | |||||
#define SUPPORTS_CONTEXTS $(C_NS)_EDDSA_SUPPORTS_CONTEXTS | |||||
static void clamp( | static void clamp( | ||||
uint8_t secret_scalar_ser[$(C_NS)_EDDSA_PRIVATE_BYTES] | uint8_t secret_scalar_ser[$(C_NS)_EDDSA_PRIVATE_BYTES] | ||||
) { | ) { | ||||
@@ -22,6 +31,21 @@ static void clamp( | |||||
if (hibit == 0) secret_scalar_ser[$(C_NS)_EDDSA_PRIVATE_BYTES - 2] |= 0x80; | if (hibit == 0) secret_scalar_ser[$(C_NS)_EDDSA_PRIVATE_BYTES - 2] |= 0x80; | ||||
} | } | ||||
static void hash_init_with_dom( | |||||
hash_ctx_t hash, | |||||
uint8_t prehashed, | |||||
const uint8_t *context, | |||||
uint8_t context_len | |||||
) { | |||||
const char *domS = "SigEd448"; | |||||
const uint8_t dom[2] = {1+word_is_zero(prehashed), context_len}; | |||||
hash_init(hash); | |||||
hash_update(hash,(const unsigned char *)domS, strlen(domS)); | |||||
hash_update(hash,dom,2); | |||||
hash_update(hash,context,context_len); | |||||
} | |||||
void API_NS(eddsa_derive_public_key) ( | void API_NS(eddsa_derive_public_key) ( | ||||
uint8_t pubkey[$(C_NS)_EDDSA_PUBLIC_BYTES], | uint8_t pubkey[$(C_NS)_EDDSA_PUBLIC_BYTES], | ||||
const uint8_t privkey[$(C_NS)_EDDSA_PRIVATE_BYTES] | const uint8_t privkey[$(C_NS)_EDDSA_PRIVATE_BYTES] | ||||
@@ -29,7 +53,7 @@ void API_NS(eddsa_derive_public_key) ( | |||||
/* only this much used for keygen */ | /* only this much used for keygen */ | ||||
uint8_t secret_scalar_ser[$(C_NS)_EDDSA_PRIVATE_BYTES]; | uint8_t secret_scalar_ser[$(C_NS)_EDDSA_PRIVATE_BYTES]; | ||||
shake256_hash( | |||||
hash_hash( | |||||
secret_scalar_ser, | secret_scalar_ser, | ||||
sizeof(secret_scalar_ser), | sizeof(secret_scalar_ser), | ||||
privkey, | privkey, | ||||
@@ -55,30 +79,33 @@ void API_NS(eddsa_derive_public_key) ( | |||||
decaf_bzero(secret_scalar_ser, sizeof(secret_scalar_ser)); | decaf_bzero(secret_scalar_ser, sizeof(secret_scalar_ser)); | ||||
} | } | ||||
static const char *domS = "SigEd448"; | |||||
void API_NS(eddsa_sign) ( | void API_NS(eddsa_sign) ( | ||||
uint8_t signature[$(C_NS)_EDDSA_SIGNATURE_BYTES], | uint8_t signature[$(C_NS)_EDDSA_SIGNATURE_BYTES], | ||||
const uint8_t privkey[$(C_NS)_EDDSA_PRIVATE_BYTES], | const uint8_t privkey[$(C_NS)_EDDSA_PRIVATE_BYTES], | ||||
const uint8_t pubkey[$(C_NS)_EDDSA_PUBLIC_BYTES], | const uint8_t pubkey[$(C_NS)_EDDSA_PUBLIC_BYTES], | ||||
const uint8_t *context, | |||||
uint8_t context_len, | |||||
const uint8_t *message, | const uint8_t *message, | ||||
size_t message_len, | size_t message_len, | ||||
uint8_t prehashed | uint8_t prehashed | ||||
#if SUPPORTS_CONTEXTS | |||||
, const uint8_t *context, | |||||
uint8_t context_len | |||||
#endif | |||||
) { | ) { | ||||
#if !SUPPORTS_CONTEXTS | |||||
const uint8_t *const context = NULL; | |||||
const uint8_t context_len = 0; | |||||
#endif | |||||
/* FIXME: of course, need a different hash for Curve25519 */ | /* FIXME: of course, need a different hash for Curve25519 */ | ||||
API_NS(scalar_t) secret_scalar; | API_NS(scalar_t) secret_scalar; | ||||
shake256_ctx_t shake; | |||||
const uint8_t dom[2] = {1+word_is_zero(prehashed), context_len}; | |||||
hash_ctx_t hash; | |||||
{ | { | ||||
/* Schedule the secret key */ | /* Schedule the secret key */ | ||||
struct { | struct { | ||||
uint8_t secret_scalar_ser[$(C_NS)_EDDSA_PRIVATE_BYTES]; | uint8_t secret_scalar_ser[$(C_NS)_EDDSA_PRIVATE_BYTES]; | ||||
uint8_t seed[$(C_NS)_EDDSA_PRIVATE_BYTES]; | uint8_t seed[$(C_NS)_EDDSA_PRIVATE_BYTES]; | ||||
} __attribute__((packed)) expanded; | } __attribute__((packed)) expanded; | ||||
shake256_hash( | |||||
hash_hash( | |||||
(uint8_t *)&expanded, | (uint8_t *)&expanded, | ||||
sizeof(expanded), | sizeof(expanded), | ||||
privkey, | privkey, | ||||
@@ -88,12 +115,9 @@ void API_NS(eddsa_sign) ( | |||||
API_NS(scalar_decode_long)(secret_scalar, expanded.secret_scalar_ser, sizeof(expanded.secret_scalar_ser)); | API_NS(scalar_decode_long)(secret_scalar, expanded.secret_scalar_ser, sizeof(expanded.secret_scalar_ser)); | ||||
/* Hash to create the nonce */ | /* Hash to create the nonce */ | ||||
shake256_init(shake); | |||||
shake256_update(shake,(const unsigned char *)domS, strlen(domS)); | |||||
shake256_update(shake,dom,2); | |||||
shake256_update(shake,context,context_len); | |||||
shake256_update(shake,expanded.seed,sizeof(expanded.seed)); | |||||
shake256_update(shake,message,message_len); | |||||
hash_init_with_dom(hash,prehashed,context,context_len); | |||||
hash_update(hash,expanded.seed,sizeof(expanded.seed)); | |||||
hash_update(hash,message,message_len); | |||||
decaf_bzero(&expanded, sizeof(expanded)); | decaf_bzero(&expanded, sizeof(expanded)); | ||||
} | } | ||||
@@ -101,7 +125,7 @@ void API_NS(eddsa_sign) ( | |||||
API_NS(scalar_t) nonce_scalar; | API_NS(scalar_t) nonce_scalar; | ||||
{ | { | ||||
uint8_t nonce[2*$(C_NS)_EDDSA_PRIVATE_BYTES]; | uint8_t nonce[2*$(C_NS)_EDDSA_PRIVATE_BYTES]; | ||||
shake256_final(shake,nonce,sizeof(nonce)); | |||||
hash_final(hash,nonce,sizeof(nonce)); | |||||
API_NS(scalar_decode_long)(nonce_scalar, nonce, sizeof(nonce)); | API_NS(scalar_decode_long)(nonce_scalar, nonce, sizeof(nonce)); | ||||
decaf_bzero(nonce, sizeof(nonce)); | decaf_bzero(nonce, sizeof(nonce)); | ||||
} | } | ||||
@@ -123,16 +147,13 @@ void API_NS(eddsa_sign) ( | |||||
API_NS(scalar_t) challenge_scalar; | API_NS(scalar_t) challenge_scalar; | ||||
{ | { | ||||
/* Compute the challenge */ | /* Compute the challenge */ | ||||
shake256_init(shake); | |||||
shake256_update(shake,(const unsigned char *)domS, strlen(domS)); | |||||
shake256_update(shake,dom,2); | |||||
shake256_update(shake,context,context_len); | |||||
shake256_update(shake,nonce_point,sizeof(nonce_point)); | |||||
shake256_update(shake,pubkey,$(C_NS)_EDDSA_PUBLIC_BYTES); | |||||
shake256_update(shake,message,message_len); | |||||
hash_init_with_dom(hash,prehashed,context,context_len); | |||||
hash_update(hash,nonce_point,sizeof(nonce_point)); | |||||
hash_update(hash,pubkey,$(C_NS)_EDDSA_PUBLIC_BYTES); | |||||
hash_update(hash,message,message_len); | |||||
uint8_t challenge[2*$(C_NS)_EDDSA_PRIVATE_BYTES]; | uint8_t challenge[2*$(C_NS)_EDDSA_PRIVATE_BYTES]; | ||||
shake256_final(shake,challenge,sizeof(challenge)); | |||||
shake256_destroy(shake); | |||||
hash_final(hash,challenge,sizeof(challenge)); | |||||
hash_destroy(hash); | |||||
API_NS(scalar_decode_long)(challenge_scalar,challenge,sizeof(challenge)); | API_NS(scalar_decode_long)(challenge_scalar,challenge,sizeof(challenge)); | ||||
decaf_bzero(challenge,sizeof(challenge)); | decaf_bzero(challenge,sizeof(challenge)); | ||||
} | } | ||||
@@ -153,12 +174,18 @@ void API_NS(eddsa_sign) ( | |||||
decaf_error_t API_NS(eddsa_verify) ( | decaf_error_t API_NS(eddsa_verify) ( | ||||
const uint8_t signature[$(C_NS)_EDDSA_SIGNATURE_BYTES], | const uint8_t signature[$(C_NS)_EDDSA_SIGNATURE_BYTES], | ||||
const uint8_t pubkey[$(C_NS)_EDDSA_PUBLIC_BYTES], | const uint8_t pubkey[$(C_NS)_EDDSA_PUBLIC_BYTES], | ||||
const uint8_t *context, | |||||
uint8_t context_len, | |||||
const uint8_t *message, | const uint8_t *message, | ||||
size_t message_len, | size_t message_len, | ||||
uint8_t prehashed | uint8_t prehashed | ||||
#if SUPPORTS_CONTEXTS | |||||
, const uint8_t *context, | |||||
uint8_t context_len | |||||
#endif | |||||
) { | ) { | ||||
#if !SUPPORTS_CONTEXTS | |||||
const uint8_t *const context = NULL; | |||||
const uint8_t context_len = 0; | |||||
#endif | |||||
API_NS(point_t) pk_point, r_point; | API_NS(point_t) pk_point, r_point; | ||||
decaf_error_t error = API_NS(point_decode_like_eddsa)(pk_point,pubkey); | decaf_error_t error = API_NS(point_decode_like_eddsa)(pk_point,pubkey); | ||||
if (DECAF_SUCCESS != error) { return error; } | if (DECAF_SUCCESS != error) { return error; } | ||||
@@ -169,18 +196,14 @@ decaf_error_t API_NS(eddsa_verify) ( | |||||
API_NS(scalar_t) challenge_scalar; | API_NS(scalar_t) challenge_scalar; | ||||
{ | { | ||||
/* Compute the challenge */ | /* Compute the challenge */ | ||||
shake256_ctx_t shake; | |||||
const uint8_t dom[2] = {1+word_is_zero(prehashed), context_len}; | |||||
shake256_init(shake); | |||||
shake256_update(shake,(const unsigned char *)domS, strlen(domS)); | |||||
shake256_update(shake,dom,2); | |||||
shake256_update(shake,context,context_len); | |||||
shake256_update(shake,signature,$(C_NS)_EDDSA_PUBLIC_BYTES); | |||||
shake256_update(shake,pubkey,$(C_NS)_EDDSA_PUBLIC_BYTES); | |||||
shake256_update(shake,message,message_len); | |||||
hash_ctx_t hash; | |||||
hash_init_with_dom(hash,prehashed,context,context_len); | |||||
hash_update(hash,signature,$(C_NS)_EDDSA_PUBLIC_BYTES); | |||||
hash_update(hash,pubkey,$(C_NS)_EDDSA_PUBLIC_BYTES); | |||||
hash_update(hash,message,message_len); | |||||
uint8_t challenge[2*$(C_NS)_EDDSA_PRIVATE_BYTES]; | uint8_t challenge[2*$(C_NS)_EDDSA_PRIVATE_BYTES]; | ||||
shake256_final(shake,challenge,sizeof(challenge)); | |||||
shake256_destroy(shake); | |||||
hash_final(hash,challenge,sizeof(challenge)); | |||||
hash_destroy(hash); | |||||
API_NS(scalar_decode_long)(challenge_scalar,challenge,sizeof(challenge)); | API_NS(scalar_decode_long)(challenge_scalar,challenge,sizeof(challenge)); | ||||
decaf_bzero(challenge,sizeof(challenge)); | decaf_bzero(challenge,sizeof(challenge)); | ||||
} | } | ||||
@@ -0,0 +1,113 @@ | |||||
/** @brief A group of prime order p, based on $(iso_to). */ | |||||
#include <decaf/decaf_$(gf_bits).h> | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
/** Number of bytes in an EdDSA public key. */ | |||||
#define $(C_NS)_EDDSA_PUBLIC_BYTES $((gf_bits)/8 + 1) /* TODO: change name? */ | |||||
/** Number of bytes in an EdDSA private key. */ | |||||
#define $(C_NS)_EDDSA_PRIVATE_BYTES $(C_NS)_EDDSA_PUBLIC_BYTES /* TODO: change name? */ | |||||
/** Number of bytes in an EdDSA private key. */ | |||||
#define $(C_NS)_EDDSA_SIGNATURE_BYTES ($(C_NS)_EDDSA_PUBLIC_BYTES + $(C_NS)_EDDSA_PRIVATE_BYTES) /* TODO: change name? */ | |||||
/** Does EdDSA support contexts? */ | |||||
#define $(C_NS)_EDDSA_SUPPORTS_CONTEXTS $(eddsa_supports_contexts) | |||||
/** | |||||
* @brief EdDSA key generation. This function uses a different (non-Decaf) | |||||
* encoding. | |||||
* | |||||
* @param [out] pubkey The public key. | |||||
* @param [in] privkey The private key. | |||||
*/ | |||||
void $(c_ns)_eddsa_derive_public_key ( | |||||
uint8_t pubkey[$(C_NS)_EDDSA_PUBLIC_BYTES], | |||||
const uint8_t privkey[$(C_NS)_EDDSA_PRIVATE_BYTES] | |||||
) API_VIS NONNULL NOINLINE; | |||||
/** | |||||
* @brief EdDSA signing. | |||||
* | |||||
* @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. | |||||
* @param [in] context_len Length of the context. | |||||
* @param [in] message The message to sign. | |||||
* @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 sign. | |||||
*/ | |||||
void $(c_ns)_eddsa_sign ( | |||||
uint8_t signature[$(C_NS)_EDDSA_SIGNATURE_BYTES], | |||||
const uint8_t privkey[$(C_NS)_EDDSA_PRIVATE_BYTES], | |||||
const uint8_t pubkey[$(C_NS)_EDDSA_PUBLIC_BYTES], | |||||
const uint8_t *message, | |||||
size_t message_len, | |||||
uint8_t prehashed | |||||
#if $(C_NS)_EDDSA_SUPPORTS_CONTEXTS | |||||
, const uint8_t *context, | |||||
uint8_t context_len | |||||
#endif | |||||
) 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 *message, | |||||
size_t message_len, | |||||
uint8_t prehashed | |||||
#if $(C_NS)_EDDSA_SUPPORTS_CONTEXTS | |||||
, const uint8_t *context, | |||||
uint8_t context_len | |||||
#endif | |||||
) API_VIS __attribute__((nonnull(1,2))) NOINLINE; | |||||
/** | |||||
* @brief EdDSA point encoding. Used internally, exposed externally. | |||||
* | |||||
* @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; | |||||
#ifdef __cplusplus | |||||
} /* extern "C" */ | |||||
#endif |
@@ -488,7 +488,7 @@ static void test_cfrg_vectors() { | |||||
for (unsigned i=0; i<eddsa_pk2.size(); i++) printf("%02x", eddsa_pk2[i]); | for (unsigned i=0; i<eddsa_pk2.size(); i++) printf("%02x", eddsa_pk2[i]); | ||||
printf("\n"); | printf("\n"); | ||||
} | } | ||||
SecureBuffer sig = EdDSA::sign(eddsa_sk,eddsa_pk,Block(NULL,0),Block(NULL,0)); | |||||
SecureBuffer sig = EdDSA::sign(eddsa_sk,eddsa_pk,Block(NULL,0)); | |||||
if (!memeq(SecureBuffer(eddsa_sig0),sig)) { | if (!memeq(SecureBuffer(eddsa_sig0),sig)) { | ||||
test.fail(); | test.fail(); | ||||
@@ -527,7 +527,7 @@ static void test_cfrg_vectors() { | |||||
static void test_eddsa() { | static void test_eddsa() { | ||||
Test test("EdDSA"); | Test test("EdDSA"); | ||||
SpongeRng rng(Block("test_cfrg_crypto"),SpongeRng::DETERMINISTIC); | |||||
SpongeRng rng(Block("test_eddsa"),SpongeRng::DETERMINISTIC); | |||||
for (int i=0; i<NTESTS && test.passing_now; i++) { | for (int i=0; i<NTESTS && test.passing_now; i++) { | ||||
@@ -537,13 +537,13 @@ static void test_eddsa() { | |||||
SecureBuffer message(i); | SecureBuffer message(i); | ||||
rng.read(message); | rng.read(message); | ||||
SecureBuffer context(i%256); | |||||
SecureBuffer context(EdDSA::SUPPORTS_CONTEXTS ? i%256 : 0); | |||||
rng.read(message); | rng.read(message); | ||||
SecureBuffer sig = EdDSA::sign(priv,pub,context,message,i%2); | |||||
SecureBuffer sig = EdDSA::sign(priv,pub,message,i%2,context); | |||||
try { | try { | ||||
EdDSA::verify(sig,pub,context,message,i%2); | |||||
EdDSA::verify(sig,pub,message,i%2,context); | |||||
} catch(CryptoException) { | } catch(CryptoException) { | ||||
test.fail(); | test.fail(); | ||||
printf(" Signature validation failed on sig %d\n", i); | printf(" Signature validation failed on sig %d\n", i); | ||||