| @@ -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 | |||
| PER_OBJ_DIRS += $$(BUILD_OBJ)/$(1) | |||
| 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 += $$(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)) | |||
| 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)) | |||
| 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), | |||
| "wnaf":wnaf_config(5,3), | |||
| "window_bits":4 | |||
| "window_bits":4, | |||
| "eddsa_hash": "sha512", | |||
| "eddsa_supports_contexts": 0 | |||
| }, | |||
| "ed448goldilocks" : { | |||
| "name" : "Ed448-Goldilocks", | |||
| @@ -101,6 +104,12 @@ for curve,data in curve_data.iteritems(): | |||
| if "iso_to" not in data: | |||
| 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: | |||
| data["cxx_ns"] = data["name"].replace("-","") | |||
| @@ -5,6 +5,7 @@ | |||
| #include "field.h" | |||
| #include <decaf.h> | |||
| #include <decaf/eddsa_$(gf_bits).h> | |||
| /* Template stuff */ | |||
| #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 */ | |||
| #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 */ | |||
| #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] | |||
| ) 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. | |||
| * Some implementations do not include precomputed points; for | |||
| @@ -21,6 +21,7 @@ | |||
| #include <string.h> /* for memcpy */ | |||
| #include <decaf/decaf_$(gf_bits).h> | |||
| #include <decaf/eddsa_$(gf_bits).h> /* TODO: move eddsa to another file? */ | |||
| #include <decaf/secure_buffer.hxx> | |||
| #include <string> | |||
| #include <sys/types.h> | |||
| @@ -685,6 +686,9 @@ public: | |||
| /** The size of a private key */ | |||
| 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 ( | |||
| const FixedBlock<PRIVATE_BYTES> &priv | |||
| ) { | |||
| @@ -696,21 +700,28 @@ public: | |||
| static inline SecureBuffer sign ( | |||
| const FixedBlock<PRIVATE_BYTES> &priv, | |||
| const FixedBlock<PUBLIC_BYTES> &pub, | |||
| const Block &context, | |||
| const Block &message, | |||
| bool prehashed = false | |||
| bool prehashed = false, | |||
| const Block &context = Block(NULL,0) | |||
| ) throw(LengthException) { | |||
| if (context.size() > 255) { throw LengthException(); } | |||
| if (context.size() > 255 | |||
| || (context.size() != 0 && !SUPPORTS_CONTEXTS) | |||
| ) { | |||
| throw LengthException(); | |||
| } | |||
| SecureBuffer out(SIGNATURE_BYTES); | |||
| $(c_ns)_eddsa_sign ( | |||
| out.data(), | |||
| priv.data(), | |||
| pub.data(), | |||
| context.data(), | |||
| context.size(), | |||
| message.data(), | |||
| message.size(), | |||
| prehashed | |||
| #if $(C_NS)_EDDSA_SUPPORTS_CONTEXTS | |||
| , context.data(), | |||
| context.size() | |||
| #endif | |||
| ); | |||
| return out; | |||
| } | |||
| @@ -718,31 +729,43 @@ public: | |||
| 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 | |||
| 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 ( | |||
| sig.data(), | |||
| pub.data(), | |||
| context.data(), | |||
| context.size(), | |||
| message.data(), | |||
| message.size(), | |||
| prehashed | |||
| #if $(C_NS)_EDDSA_SUPPORTS_CONTEXTS | |||
| , context.data(), | |||
| context.size() | |||
| #endif | |||
| ); | |||
| } | |||
| static inline void verify ( | |||
| const FixedBlock<SIGNATURE_BYTES> &sig, | |||
| const FixedBlock<PUBLIC_BYTES> &pub, | |||
| const Block &context, | |||
| const Block &message, | |||
| bool prehashed = false | |||
| bool prehashed = false, | |||
| const Block &context = Block(NULL,0) | |||
| ) 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(); | |||
| } | |||
| } | |||
| @@ -3,7 +3,7 @@ | |||
| * @brief EdDSA routines. | |||
| */ | |||
| #include "decaf.h" | |||
| #include <decaf/eddsa_$(gf_bits).h> | |||
| #include "decaf/shake.h" | |||
| #include "word.h" | |||
| #include <string.h> | |||
| @@ -11,6 +11,15 @@ | |||
| #define API_NAME "$(c_ns)" | |||
| #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( | |||
| 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; | |||
| } | |||
| 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) ( | |||
| uint8_t pubkey[$(C_NS)_EDDSA_PUBLIC_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 */ | |||
| uint8_t secret_scalar_ser[$(C_NS)_EDDSA_PRIVATE_BYTES]; | |||
| shake256_hash( | |||
| hash_hash( | |||
| secret_scalar_ser, | |||
| sizeof(secret_scalar_ser), | |||
| privkey, | |||
| @@ -55,30 +79,33 @@ void API_NS(eddsa_derive_public_key) ( | |||
| decaf_bzero(secret_scalar_ser, sizeof(secret_scalar_ser)); | |||
| } | |||
| static const char *domS = "SigEd448"; | |||
| void API_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 | |||
| #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 */ | |||
| 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 */ | |||
| struct { | |||
| uint8_t secret_scalar_ser[$(C_NS)_EDDSA_PRIVATE_BYTES]; | |||
| uint8_t seed[$(C_NS)_EDDSA_PRIVATE_BYTES]; | |||
| } __attribute__((packed)) expanded; | |||
| shake256_hash( | |||
| hash_hash( | |||
| (uint8_t *)&expanded, | |||
| sizeof(expanded), | |||
| 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)); | |||
| /* 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)); | |||
| } | |||
| @@ -101,7 +125,7 @@ void API_NS(eddsa_sign) ( | |||
| API_NS(scalar_t) nonce_scalar; | |||
| { | |||
| 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)); | |||
| decaf_bzero(nonce, sizeof(nonce)); | |||
| } | |||
| @@ -123,16 +147,13 @@ void API_NS(eddsa_sign) ( | |||
| API_NS(scalar_t) challenge_scalar; | |||
| { | |||
| /* 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]; | |||
| 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)); | |||
| decaf_bzero(challenge,sizeof(challenge)); | |||
| } | |||
| @@ -153,12 +174,18 @@ void API_NS(eddsa_sign) ( | |||
| decaf_error_t API_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 | |||
| #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; | |||
| decaf_error_t error = API_NS(point_decode_like_eddsa)(pk_point,pubkey); | |||
| if (DECAF_SUCCESS != error) { return error; } | |||
| @@ -169,18 +196,14 @@ decaf_error_t API_NS(eddsa_verify) ( | |||
| API_NS(scalar_t) challenge_scalar; | |||
| { | |||
| /* 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]; | |||
| 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)); | |||
| 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]); | |||
| 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)) { | |||
| test.fail(); | |||
| @@ -527,7 +527,7 @@ static void test_cfrg_vectors() { | |||
| static void 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++) { | |||
| @@ -537,13 +537,13 @@ static void test_eddsa() { | |||
| SecureBuffer message(i); | |||
| rng.read(message); | |||
| SecureBuffer context(i%256); | |||
| SecureBuffer context(EdDSA::SUPPORTS_CONTEXTS ? i%256 : 0); | |||
| rng.read(message); | |||
| SecureBuffer sig = EdDSA::sign(priv,pub,context,message,i%2); | |||
| SecureBuffer sig = EdDSA::sign(priv,pub,message,i%2,context); | |||
| try { | |||
| EdDSA::verify(sig,pub,context,message,i%2); | |||
| EdDSA::verify(sig,pub,message,i%2,context); | |||
| } catch(CryptoException) { | |||
| test.fail(); | |||
| printf(" Signature validation failed on sig %d\n", i); | |||