| @@ -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); | ||||