@@ -0,0 +1,231 @@ | |||
/** | |||
* @file curve25519/crypto.c | |||
* @author Mike Hamburg | |||
* | |||
* @copyright | |||
* Copyright (c) 2015-2016 Cryptography Research, Inc. \n | |||
* Released under the MIT License. See LICENSE.txt for license information. | |||
* | |||
* @cond internal | |||
* @brief Example Decaf crypto routines | |||
* | |||
* @warning This file was automatically generated in Python. | |||
* Please do not edit it. | |||
*/ | |||
#include <decaf/crypto.h> | |||
#include <string.h> | |||
#define API_NAME "decaf_255" | |||
#define API_NS(_id) decaf_255_##_id | |||
#define API_NS_TOY(_id) decaf_255_TOY_##_id | |||
#define SCALAR_BITS DECAF_255_SCALAR_BITS | |||
#define SCALAR_BYTES ((SCALAR_BITS + 7)/8) | |||
#define SER_BYTES DECAF_255_SER_BYTES | |||
/* TODO: canonicalize and freeze the STROBE constants in this file | |||
* (and STROBE itself for that matter) | |||
*/ | |||
static const char *DERIVE_MAGIC = API_NAME"::derive_private_key"; | |||
static const char *SIGN_MAGIC = API_NAME"::sign"; | |||
static const char *SHARED_SECRET_MAGIC = API_NAME"::shared_secret"; | |||
static const uint16_t SHARED_SECRET_MAX_BLOCK_SIZE = 1<<12; | |||
static const unsigned int SCALAR_OVERKILL_BYTES = SCALAR_BYTES + 8; | |||
void API_NS_TOY(derive_private_key) ( | |||
API_NS_TOY(private_key_t) priv, | |||
const API_NS_TOY(symmetric_key_t) proto | |||
) { | |||
uint8_t encoded_scalar[SCALAR_OVERKILL_BYTES]; | |||
API_NS(point_t) pub; | |||
keccak_decaf_TOY_strobe_t strobe; | |||
decaf_TOY_strobe_init(strobe, &STROBE_256, DERIVE_MAGIC, 0); | |||
decaf_TOY_strobe_fixed_key(strobe, proto, sizeof(API_NS_TOY(symmetric_key_t))); | |||
decaf_TOY_strobe_prng(strobe, encoded_scalar, sizeof(encoded_scalar)); | |||
decaf_TOY_strobe_destroy(strobe); | |||
memcpy(priv->sym, proto, sizeof(API_NS_TOY(symmetric_key_t))); | |||
API_NS(scalar_decode_long)(priv->secret_scalar, encoded_scalar, sizeof(encoded_scalar)); | |||
API_NS(precomputed_scalarmul)(pub, API_NS(precomputed_base), priv->secret_scalar); | |||
API_NS(point_encode)(priv->pub, pub); | |||
decaf_bzero(encoded_scalar, sizeof(encoded_scalar)); | |||
} | |||
void API_NS_TOY(destroy_private_key) ( | |||
API_NS_TOY(private_key_t) priv | |||
) { | |||
decaf_bzero((void*)priv, sizeof(API_NS_TOY(private_key_t))); | |||
} | |||
void API_NS_TOY(private_to_public) ( | |||
API_NS_TOY(public_key_t) pub, | |||
const API_NS_TOY(private_key_t) priv | |||
) { | |||
memcpy(pub, priv->pub, sizeof(API_NS_TOY(public_key_t))); | |||
} | |||
/* Performance vs consttime tuning. | |||
* Specifying true here might give better DOS resistance in certain corner | |||
* cases. Specifying false gives a tighter result in test_ct. | |||
*/ | |||
#ifndef DECAF_CRYPTO_SHARED_SECRET_SHORT_CIRUIT | |||
#define DECAF_CRYPTO_SHARED_SECRET_SHORT_CIRUIT DECAF_FALSE | |||
#endif | |||
decaf_error_t API_NS_TOY(shared_secret) ( | |||
uint8_t *shared, | |||
size_t shared_bytes, | |||
const API_NS_TOY(private_key_t) my_privkey, | |||
const API_NS_TOY(public_key_t) your_pubkey, | |||
int me_first | |||
) { | |||
keccak_decaf_TOY_strobe_t strobe; | |||
decaf_TOY_strobe_init(strobe, &STROBE_256, SHARED_SECRET_MAGIC, 0); | |||
uint8_t ss_ser[SER_BYTES]; | |||
if (me_first) { | |||
decaf_TOY_strobe_ad(strobe,my_privkey->pub,sizeof(API_NS_TOY(public_key_t))); | |||
decaf_TOY_strobe_ad(strobe,your_pubkey,sizeof(API_NS_TOY(public_key_t))); | |||
} else { | |||
decaf_TOY_strobe_ad(strobe,your_pubkey,sizeof(API_NS_TOY(public_key_t))); | |||
decaf_TOY_strobe_ad(strobe,my_privkey->pub,sizeof(API_NS_TOY(public_key_t))); | |||
} | |||
decaf_error_t ret = API_NS(direct_scalarmul)( | |||
ss_ser, your_pubkey, my_privkey->secret_scalar, DECAF_FALSE, | |||
DECAF_CRYPTO_SHARED_SECRET_SHORT_CIRUIT | |||
); | |||
decaf_TOY_strobe_transact(strobe,NULL,ss_ser,sizeof(ss_ser),STROBE_CW_DH_KEY); | |||
while (shared_bytes) { | |||
uint16_t cando = (shared_bytes > SHARED_SECRET_MAX_BLOCK_SIZE) | |||
? SHARED_SECRET_MAX_BLOCK_SIZE : shared_bytes; | |||
decaf_TOY_strobe_prng(strobe,shared,cando); | |||
shared_bytes -= cando; | |||
shared += cando; | |||
} | |||
decaf_TOY_strobe_destroy(strobe); | |||
decaf_bzero(ss_ser, sizeof(ss_ser)); | |||
return ret; | |||
} | |||
void API_NS_TOY(sign_strobe) ( | |||
keccak_decaf_TOY_strobe_t strobe, | |||
API_NS_TOY(signature_t) sig, | |||
const API_NS_TOY(private_key_t) priv | |||
) { | |||
uint8_t overkill[SCALAR_OVERKILL_BYTES]; | |||
API_NS(point_t) point; | |||
API_NS(scalar_t) nonce, challenge; | |||
/* Stir pubkey */ | |||
decaf_TOY_strobe_transact(strobe,NULL,priv->pub,sizeof(API_NS_TOY(public_key_t)),STROBE_CW_SIG_PK); | |||
/* Derive nonce */ | |||
keccak_decaf_TOY_strobe_t strobe2; | |||
memcpy(strobe2,strobe,sizeof(strobe2)); | |||
decaf_TOY_strobe_fixed_key(strobe2,priv->sym,sizeof(API_NS_TOY(symmetric_key_t))); | |||
decaf_TOY_strobe_prng(strobe2,overkill,sizeof(overkill)); | |||
decaf_TOY_strobe_destroy(strobe2); | |||
API_NS(scalar_decode_long)(nonce, overkill, sizeof(overkill)); | |||
API_NS(precomputed_scalarmul)(point, API_NS(precomputed_base), nonce); | |||
API_NS(point_encode)(sig, point); | |||
/* Derive challenge */ | |||
decaf_TOY_strobe_transact(strobe,NULL,sig,SER_BYTES,STROBE_CW_SIG_EPH); | |||
decaf_TOY_strobe_transact(strobe,overkill,NULL,sizeof(overkill),STROBE_CW_SIG_CHAL); | |||
API_NS(scalar_decode_long)(challenge, overkill, sizeof(overkill)); | |||
/* Respond */ | |||
API_NS(scalar_mul)(challenge, challenge, priv->secret_scalar); | |||
API_NS(scalar_sub)(nonce, nonce, challenge); | |||
/* Save results */ | |||
API_NS(scalar_encode)(overkill, nonce); | |||
decaf_TOY_strobe_transact(strobe,&sig[SER_BYTES],overkill,SCALAR_BYTES,STROBE_CW_SIG_RESP); | |||
/* Clean up */ | |||
API_NS(scalar_destroy)(nonce); | |||
API_NS(scalar_destroy)(challenge); | |||
decaf_bzero(overkill,sizeof(overkill)); | |||
} | |||
decaf_error_t API_NS_TOY(verify_strobe) ( | |||
keccak_decaf_TOY_strobe_t strobe, | |||
const API_NS_TOY(signature_t) sig, | |||
const API_NS_TOY(public_key_t) pub | |||
) { | |||
decaf_bool_t ret; | |||
uint8_t overkill[SCALAR_OVERKILL_BYTES]; | |||
API_NS(point_t) point, pubpoint; | |||
API_NS(scalar_t) challenge, response; | |||
/* Stir pubkey */ | |||
decaf_TOY_strobe_transact(strobe,NULL,pub,sizeof(API_NS_TOY(public_key_t)),STROBE_CW_SIG_PK); | |||
/* Derive nonce */ | |||
decaf_TOY_strobe_transact(strobe,NULL,sig,SER_BYTES,STROBE_CW_SIG_EPH); | |||
ret = decaf_successful( API_NS(point_decode)(point, sig, DECAF_TRUE) ); | |||
/* Derive challenge */ | |||
decaf_TOY_strobe_transact(strobe,overkill,NULL,sizeof(overkill),STROBE_CW_SIG_CHAL); | |||
API_NS(scalar_decode_long)(challenge, overkill, sizeof(overkill)); | |||
/* Decode response */ | |||
decaf_TOY_strobe_transact(strobe,overkill,&sig[SER_BYTES],SCALAR_BYTES,STROBE_CW_SIG_RESP); | |||
ret &= decaf_successful( API_NS(scalar_decode)(response, overkill) ); | |||
ret &= decaf_successful( API_NS(point_decode)(pubpoint, pub, DECAF_FALSE) ); | |||
API_NS(base_double_scalarmul_non_secret) ( | |||
pubpoint, response, pubpoint, challenge | |||
); | |||
ret &= API_NS(point_eq)(pubpoint, point); | |||
/* Nothing here is secret, so don't do these things: | |||
decaf_bzero(overkill,sizeof(overkill)); | |||
API_NS(point_destroy)(point); | |||
API_NS(point_destroy)(pubpoint); | |||
API_NS(scalar_destroy)(challenge); | |||
API_NS(scalar_destroy)(response); | |||
*/ | |||
return decaf_succeed_if(ret); | |||
} | |||
void | |||
API_NS_TOY(sign) ( | |||
API_NS_TOY(signature_t) sig, | |||
const API_NS_TOY(private_key_t) priv, | |||
const unsigned char *message, | |||
size_t message_len | |||
) { | |||
keccak_decaf_TOY_strobe_t ctx; | |||
decaf_TOY_strobe_init(ctx,&STROBE_256,SIGN_MAGIC,0); | |||
decaf_TOY_strobe_transact(ctx, NULL, message, message_len, STROBE_CW_STREAMING_PLAINTEXT); | |||
API_NS_TOY(sign_strobe)(ctx, sig, priv); | |||
decaf_TOY_strobe_destroy(ctx); | |||
} | |||
decaf_error_t | |||
API_NS_TOY(verify) ( | |||
const API_NS_TOY(signature_t) sig, | |||
const API_NS_TOY(public_key_t) pub, | |||
const unsigned char *message, | |||
size_t message_len | |||
) { | |||
keccak_decaf_TOY_strobe_t ctx; | |||
decaf_TOY_strobe_init(ctx,&STROBE_256,SIGN_MAGIC,0); | |||
decaf_TOY_strobe_transact(ctx, NULL, message, message_len, STROBE_CW_STREAMING_PLAINTEXT); | |||
decaf_error_t ret = API_NS_TOY(verify_strobe)(ctx, sig, pub); | |||
decaf_TOY_strobe_destroy(ctx); | |||
return ret; | |||
} |
@@ -0,0 +1,116 @@ | |||
/** | |||
* @file curve25519/decaf_gen_tables.c | |||
* @author Mike Hamburg | |||
* | |||
* @copyright | |||
* Copyright (c) 2015-2016 Cryptography Research, Inc. \n | |||
* Released under the MIT License. See LICENSE.txt for license information. | |||
* | |||
* @brief Decaf global constant table precomputation. | |||
* | |||
* @warning This file was automatically generated in Python. | |||
* Please do not edit it. | |||
*/ | |||
#define _XOPEN_SOURCE 600 /* for posix_memalign */ | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include "field.h" | |||
#include "f_field.h" | |||
#include "decaf.h" | |||
#define API_NS(_id) decaf_255_##_id | |||
static const unsigned char base_point_ser_for_pregen[SER_BYTES] = { | |||
0x03 | |||
}; | |||
/* To satisfy linker. */ | |||
const gf API_NS(precomputed_base_as_fe)[1]; | |||
const API_NS(point_t) API_NS(point_base); | |||
struct niels_s; | |||
const gf_s *API_NS(precomputed_wnaf_as_fe); | |||
extern const size_t API_NS(sizeof_precomputed_wnafs); | |||
void API_NS(precompute_wnafs) ( | |||
struct niels_s *out, | |||
const API_NS(point_t) base | |||
); | |||
static void field_print(const gf f) { | |||
unsigned char ser[X_SER_BYTES]; | |||
gf_serialize(ser,f,1); | |||
int b=0, i, comma=0; | |||
unsigned long long limb = 0; | |||
printf("{FIELD_LITERAL("); | |||
for (i=0; i<X_SER_BYTES; i++) { | |||
limb |= ((uint64_t)ser[i])<<b; | |||
b += 8; | |||
if (b >= GF_LIT_LIMB_BITS || i == SER_BYTES-1) { | |||
limb &= (1ull<<GF_LIT_LIMB_BITS) -1; | |||
b -= GF_LIT_LIMB_BITS; | |||
if (comma) printf(","); | |||
comma = 1; | |||
printf("0x%016llx", limb); | |||
limb = ((uint64_t)ser[i])>>(8-b); | |||
} | |||
} | |||
printf(")}"); | |||
assert(b<8); | |||
} | |||
int main(int argc, char **argv) { | |||
(void)argc; (void)argv; | |||
API_NS(point_t) real_point_base; | |||
int ret = API_NS(point_decode)(real_point_base,base_point_ser_for_pregen,0); | |||
if (ret != DECAF_SUCCESS) return 1; | |||
API_NS(precomputed_s) *pre; | |||
ret = posix_memalign((void**)&pre, API_NS(alignof_precomputed_s), API_NS(sizeof_precomputed_s)); | |||
if (ret || !pre) return 1; | |||
API_NS(precompute)(pre, real_point_base); | |||
struct niels_s *pre_wnaf; | |||
ret = posix_memalign((void**)&pre_wnaf, API_NS(alignof_precomputed_s), API_NS(sizeof_precomputed_wnafs)); | |||
if (ret || !pre_wnaf) return 1; | |||
API_NS(precompute_wnafs)(pre_wnaf, real_point_base); | |||
const gf_s *output; | |||
unsigned i; | |||
printf("/** @warning: this file was automatically generated. */\n"); | |||
printf("#include \"field.h\"\n\n"); | |||
printf("#include <decaf.h>\n\n"); | |||
printf("#define API_NS(_id) decaf_255_##_id\n"); | |||
output = (const gf_s *)real_point_base; | |||
printf("const API_NS(point_t) API_NS(point_base) = {{\n"); | |||
for (i=0; i < sizeof(API_NS(point_t)); i+=sizeof(gf)) { | |||
if (i) printf(",\n "); | |||
field_print(output++); | |||
} | |||
printf("\n}};\n"); | |||
output = (const gf_s *)pre; | |||
printf("const gf API_NS(precomputed_base_as_fe)[%d]\n", | |||
(int)(API_NS(sizeof_precomputed_s) / sizeof(gf))); | |||
printf("__attribute__((aligned(%d),visibility(\"hidden\"))) = {\n ", (int)API_NS(alignof_precomputed_s)); | |||
for (i=0; i < API_NS(sizeof_precomputed_s); i+=sizeof(gf)) { | |||
if (i) printf(",\n "); | |||
field_print(output++); | |||
} | |||
printf("\n};\n"); | |||
output = (const gf_s *)pre_wnaf; | |||
printf("const gf API_NS(precomputed_wnaf_as_fe)[%d]\n", | |||
(int)(API_NS(sizeof_precomputed_wnafs) / sizeof(gf))); | |||
printf("__attribute__((aligned(%d),visibility(\"hidden\"))) = {\n ", (int)API_NS(alignof_precomputed_s)); | |||
for (i=0; i < API_NS(sizeof_precomputed_wnafs); i+=sizeof(gf)) { | |||
if (i) printf(",\n "); | |||
field_print(output++); | |||
} | |||
printf("\n};\n"); | |||
return 0; | |||
} |
@@ -0,0 +1,339 @@ | |||
/** | |||
* @file curve25519/eddsa.c | |||
* @author Mike Hamburg | |||
* | |||
* @copyright | |||
* Copyright (c) 2015-2016 Cryptography Research, Inc. \n | |||
* Released under the MIT License. See LICENSE.txt for license information. | |||
* | |||
* @cond internal | |||
* @brief EdDSA routines. | |||
* | |||
* @warning This file was automatically generated in Python. | |||
* Please do not edit it. | |||
*/ | |||
#include "word.h" | |||
#include <decaf/ed255.h> | |||
#include <decaf/shake.h> | |||
#include <decaf/sha512.h> | |||
#include <string.h> | |||
#define API_NAME "decaf_255" | |||
#define API_NS(_id) decaf_255_##_id | |||
#define hash_ctx_t decaf_sha512_ctx_t | |||
#define hash_init decaf_sha512_init | |||
#define hash_update decaf_sha512_update | |||
#define hash_final decaf_sha512_final | |||
#define hash_destroy decaf_sha512_destroy | |||
#define hash_hash decaf_sha512_hash | |||
#define SUPPORTS_CONTEXTS DECAF_EDDSA_25519_SUPPORTS_CONTEXTS | |||
#define EDDSA_USE_SIGMA_ISOGENY 1 | |||
#define COFACTOR 8 | |||
/* EDDSA_BASE_POINT_RATIO = 1 or 2 | |||
* Because EdDSA25519 is not on E_d but on the isogenous E_sigma_d, | |||
* its base point is twice ours. | |||
*/ | |||
#define EDDSA_BASE_POINT_RATIO (1+EDDSA_USE_SIGMA_ISOGENY) | |||
static void clamp ( | |||
uint8_t secret_scalar_ser[DECAF_EDDSA_25519_PRIVATE_BYTES] | |||
) { | |||
/* Blarg */ | |||
secret_scalar_ser[0] &= -COFACTOR; | |||
uint8_t hibit = (1<<7)>>1; | |||
if (hibit == 0) { | |||
secret_scalar_ser[DECAF_EDDSA_25519_PRIVATE_BYTES - 1] = 0; | |||
secret_scalar_ser[DECAF_EDDSA_25519_PRIVATE_BYTES - 2] |= 0x80; | |||
} else { | |||
secret_scalar_ser[DECAF_EDDSA_25519_PRIVATE_BYTES - 1] &= hibit-1; | |||
secret_scalar_ser[DECAF_EDDSA_25519_PRIVATE_BYTES - 1] |= hibit; | |||
} | |||
} | |||
static void hash_init_with_dom( | |||
hash_ctx_t hash, | |||
uint8_t prehashed, | |||
uint8_t for_prehash, | |||
const uint8_t *context, | |||
uint8_t context_len | |||
) { | |||
hash_init(hash); | |||
#if SUPPORTS_CONTEXTS | |||
const char *dom_s = ""; | |||
const uint8_t dom[2] = {2+word_is_zero(prehashed)+word_is_zero(for_prehash), context_len}; | |||
hash_update(hash,(const unsigned char *)dom_s, strlen(dom_s)); | |||
hash_update(hash,dom,2); | |||
hash_update(hash,context,context_len); | |||
#else | |||
(void)prehashed; | |||
(void)for_prehash; | |||
(void)context; | |||
assert(context==NULL); | |||
(void)context_len; | |||
assert(context_len == 0); | |||
#endif | |||
} | |||
void decaf_ed25519_prehash_init ( | |||
hash_ctx_t hash | |||
#if DECAF_EDDSA_25519_SUPPORTS_CONTEXTS | |||
, const uint8_t *context, | |||
uint8_t context_len | |||
#endif | |||
) { | |||
#if DECAF_EDDSA_25519_SUPPORTS_CONTEXTS | |||
hash_init_with_dom(hash,1,1,context,context_len); | |||
#else | |||
hash_init_with_dom(hash,1,1,NULL,0); | |||
#endif | |||
} | |||
void decaf_ed25519_derive_public_key ( | |||
uint8_t pubkey[DECAF_EDDSA_25519_PUBLIC_BYTES], | |||
const uint8_t privkey[DECAF_EDDSA_25519_PRIVATE_BYTES] | |||
) { | |||
/* only this much used for keygen */ | |||
uint8_t secret_scalar_ser[DECAF_EDDSA_25519_PRIVATE_BYTES]; | |||
hash_hash( | |||
secret_scalar_ser, | |||
sizeof(secret_scalar_ser), | |||
privkey, | |||
DECAF_EDDSA_25519_PRIVATE_BYTES | |||
); | |||
clamp(secret_scalar_ser); | |||
API_NS(scalar_t) secret_scalar; | |||
API_NS(scalar_decode_long)(secret_scalar, secret_scalar_ser, sizeof(secret_scalar_ser)); | |||
/* Since we are going to mul_by_cofactor during encoding, divide by it here. | |||
* However, the EdDSA base point is not the same as the decaf base point if | |||
* the sigma isogeny is in use: the EdDSA base point is on Etwist_d/(1-d) and | |||
* the decaf base point is on Etwist_d, and when converted it effectively | |||
* picks up a factor of 2 from the isogenies. So we might start at 2 instead of 1. | |||
*/ | |||
for (unsigned int c = EDDSA_BASE_POINT_RATIO; c < COFACTOR; c <<= 1) { | |||
API_NS(scalar_halve)(secret_scalar,secret_scalar); | |||
} | |||
API_NS(point_t) p; | |||
API_NS(precomputed_scalarmul)(p,API_NS(precomputed_base),secret_scalar); | |||
API_NS(point_mul_by_cofactor_and_encode_like_eddsa)(pubkey, p); | |||
/* Cleanup */ | |||
API_NS(scalar_destroy)(secret_scalar); | |||
API_NS(point_destroy)(p); | |||
decaf_bzero(secret_scalar_ser, sizeof(secret_scalar_ser)); | |||
} | |||
void decaf_ed25519_sign ( | |||
uint8_t signature[DECAF_EDDSA_25519_SIGNATURE_BYTES], | |||
const uint8_t privkey[DECAF_EDDSA_25519_PRIVATE_BYTES], | |||
const uint8_t pubkey[DECAF_EDDSA_25519_PUBLIC_BYTES], | |||
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(scalar_t) secret_scalar; | |||
hash_ctx_t hash; | |||
{ | |||
/* Schedule the secret key */ | |||
struct { | |||
uint8_t secret_scalar_ser[DECAF_EDDSA_25519_PRIVATE_BYTES]; | |||
uint8_t seed[DECAF_EDDSA_25519_PRIVATE_BYTES]; | |||
} __attribute__((packed)) expanded; | |||
hash_hash( | |||
(uint8_t *)&expanded, | |||
sizeof(expanded), | |||
privkey, | |||
DECAF_EDDSA_25519_PRIVATE_BYTES | |||
); | |||
clamp(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_init_with_dom(hash,prehashed,0,context,context_len); | |||
hash_update(hash,expanded.seed,sizeof(expanded.seed)); | |||
hash_update(hash,message,message_len); | |||
decaf_bzero(&expanded, sizeof(expanded)); | |||
} | |||
/* Decode the nonce */ | |||
API_NS(scalar_t) nonce_scalar; | |||
{ | |||
uint8_t nonce[2*DECAF_EDDSA_25519_PRIVATE_BYTES]; | |||
hash_final(hash,nonce,sizeof(nonce)); | |||
API_NS(scalar_decode_long)(nonce_scalar, nonce, sizeof(nonce)); | |||
decaf_bzero(nonce, sizeof(nonce)); | |||
} | |||
uint8_t nonce_point[DECAF_EDDSA_25519_PUBLIC_BYTES] = {0}; | |||
{ | |||
/* Scalarmul to create the nonce-point */ | |||
API_NS(scalar_t) nonce_scalar_2; | |||
API_NS(scalar_halve)(nonce_scalar_2,nonce_scalar); | |||
for (unsigned int c = 2*EDDSA_BASE_POINT_RATIO; c < COFACTOR; c <<= 1) { | |||
API_NS(scalar_halve)(nonce_scalar_2,nonce_scalar_2); | |||
} | |||
API_NS(point_t) p; | |||
API_NS(precomputed_scalarmul)(p,API_NS(precomputed_base),nonce_scalar_2); | |||
API_NS(point_mul_by_cofactor_and_encode_like_eddsa)(nonce_point, p); | |||
API_NS(point_destroy)(p); | |||
API_NS(scalar_destroy)(nonce_scalar_2); | |||
} | |||
API_NS(scalar_t) challenge_scalar; | |||
{ | |||
/* Compute the challenge */ | |||
hash_init_with_dom(hash,prehashed,0,context,context_len); | |||
hash_update(hash,nonce_point,sizeof(nonce_point)); | |||
hash_update(hash,pubkey,DECAF_EDDSA_25519_PUBLIC_BYTES); | |||
hash_update(hash,message,message_len); | |||
uint8_t challenge[2*DECAF_EDDSA_25519_PRIVATE_BYTES]; | |||
hash_final(hash,challenge,sizeof(challenge)); | |||
hash_destroy(hash); | |||
API_NS(scalar_decode_long)(challenge_scalar,challenge,sizeof(challenge)); | |||
decaf_bzero(challenge,sizeof(challenge)); | |||
} | |||
API_NS(scalar_mul)(challenge_scalar,challenge_scalar,secret_scalar); | |||
API_NS(scalar_add)(challenge_scalar,challenge_scalar,nonce_scalar); | |||
decaf_bzero(signature,DECAF_EDDSA_25519_SIGNATURE_BYTES); | |||
memcpy(signature,nonce_point,sizeof(nonce_point)); | |||
API_NS(scalar_encode)(&signature[DECAF_EDDSA_25519_PUBLIC_BYTES],challenge_scalar); | |||
API_NS(scalar_destroy)(secret_scalar); | |||
API_NS(scalar_destroy)(nonce_scalar); | |||
API_NS(scalar_destroy)(challenge_scalar); | |||
} | |||
void decaf_ed25519_sign_prehash ( | |||
uint8_t signature[DECAF_EDDSA_25519_SIGNATURE_BYTES], | |||
const uint8_t privkey[DECAF_EDDSA_25519_PRIVATE_BYTES], | |||
const uint8_t pubkey[DECAF_EDDSA_25519_PUBLIC_BYTES], | |||
const decaf_ed25519_prehash_ctx_t hash | |||
#if DECAF_EDDSA_25519_SUPPORTS_CONTEXTS | |||
, const uint8_t *context, | |||
uint8_t context_len | |||
#endif | |||
) { | |||
uint8_t hash_output[64]; /* MAGIC but true for all existing schemes */ | |||
{ | |||
decaf_ed25519_prehash_ctx_t hash_too; | |||
memcpy(hash_too,hash,sizeof(hash_too)); | |||
hash_final(hash_too,hash_output,sizeof(hash_output)); | |||
hash_destroy(hash_too); | |||
} | |||
#if DECAF_EDDSA_25519_SUPPORTS_CONTEXTS | |||
decaf_ed25519_sign(signature,privkey,pubkey,hash_output,sizeof(hash_output),1,context,context_len); | |||
#else | |||
decaf_ed25519_sign(signature,privkey,pubkey,hash_output,sizeof(hash_output),1); | |||
#endif | |||
decaf_bzero(hash_output,sizeof(hash_output)); | |||
} | |||
decaf_error_t decaf_ed25519_verify ( | |||
const uint8_t signature[DECAF_EDDSA_25519_SIGNATURE_BYTES], | |||
const uint8_t pubkey[DECAF_EDDSA_25519_PUBLIC_BYTES], | |||
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_and_ignore_cofactor)(pk_point,pubkey); | |||
if (DECAF_SUCCESS != error) { return error; } | |||
error = API_NS(point_decode_like_eddsa_and_ignore_cofactor)(r_point,signature); | |||
if (DECAF_SUCCESS != error) { return error; } | |||
API_NS(scalar_t) challenge_scalar; | |||
{ | |||
/* Compute the challenge */ | |||
hash_ctx_t hash; | |||
hash_init_with_dom(hash,prehashed,0,context,context_len); | |||
hash_update(hash,signature,DECAF_EDDSA_25519_PUBLIC_BYTES); | |||
hash_update(hash,pubkey,DECAF_EDDSA_25519_PUBLIC_BYTES); | |||
hash_update(hash,message,message_len); | |||
uint8_t challenge[2*DECAF_EDDSA_25519_PRIVATE_BYTES]; | |||
hash_final(hash,challenge,sizeof(challenge)); | |||
hash_destroy(hash); | |||
API_NS(scalar_decode_long)(challenge_scalar,challenge,sizeof(challenge)); | |||
decaf_bzero(challenge,sizeof(challenge)); | |||
} | |||
API_NS(scalar_sub)(challenge_scalar, API_NS(scalar_zero), challenge_scalar); | |||
API_NS(scalar_t) response_scalar; | |||
API_NS(scalar_decode_long)( | |||
response_scalar, | |||
&signature[DECAF_EDDSA_25519_PUBLIC_BYTES], | |||
DECAF_EDDSA_25519_PRIVATE_BYTES | |||
); | |||
#if EDDSA_BASE_POINT_RATIO == 2 | |||
API_NS(scalar_add)(response_scalar,response_scalar,response_scalar); | |||
#endif | |||
/* pk_point = -c(x(P)) + (cx + k)G = kG */ | |||
API_NS(base_double_scalarmul_non_secret)( | |||
pk_point, | |||
response_scalar, | |||
pk_point, | |||
challenge_scalar | |||
); | |||
return decaf_succeed_if(API_NS(point_eq(pk_point,r_point))); | |||
} | |||
decaf_error_t decaf_ed25519_verify_prehash ( | |||
const uint8_t signature[DECAF_EDDSA_25519_SIGNATURE_BYTES], | |||
const uint8_t pubkey[DECAF_EDDSA_25519_PUBLIC_BYTES], | |||
const decaf_ed25519_prehash_ctx_t hash | |||
#if DECAF_EDDSA_25519_SUPPORTS_CONTEXTS | |||
, const uint8_t *context, | |||
uint8_t context_len | |||
#endif | |||
) { | |||
decaf_error_t ret; | |||
uint8_t hash_output[64]; /* MAGIC but true for all existing schemes */ | |||
{ | |||
decaf_ed25519_prehash_ctx_t hash_too; | |||
memcpy(hash_too,hash,sizeof(hash_too)); | |||
hash_final(hash_too,hash_output,sizeof(hash_output)); | |||
hash_destroy(hash_too); | |||
} | |||
#if DECAF_EDDSA_25519_SUPPORTS_CONTEXTS | |||
ret = decaf_ed25519_verify(signature,pubkey,hash_output,sizeof(hash_output),1,context,context_len); | |||
#else | |||
ret = decaf_ed25519_verify(signature,pubkey,hash_output,sizeof(hash_output),1); | |||
#endif | |||
return ret; | |||
} |
@@ -0,0 +1,339 @@ | |||
/** | |||
* @file curve25519/scalar.c | |||
* @author Mike Hamburg | |||
* | |||
* @copyright | |||
* Copyright (c) 2015-2016 Cryptography Research, Inc. \n | |||
* Released under the MIT License. See LICENSE.txt for license information. | |||
* | |||
* @brief Decaf high-level functions. | |||
* | |||
* @warning This file was automatically generated in Python. | |||
* Please do not edit it. | |||
*/ | |||
#include "word.h" | |||
#include "constant_time.h" | |||
#include <decaf.h> | |||
/* Template stuff */ | |||
#define API_NS(_id) decaf_255_##_id | |||
#define SCALAR_BITS DECAF_255_SCALAR_BITS | |||
#define SCALAR_SER_BYTES DECAF_255_SCALAR_BYTES | |||
#define SCALAR_LIMBS DECAF_255_SCALAR_LIMBS | |||
#define scalar_t API_NS(scalar_t) | |||
static const decaf_word_t MONTGOMERY_FACTOR = (decaf_word_t)0xd2b51da312547e1bull; | |||
static const scalar_t sc_p = {{{ | |||
SC_LIMB(0x5812631a5cf5d3ed), SC_LIMB(0x14def9dea2f79cd6), SC_LIMB(0x0000000000000000), SC_LIMB(0x1000000000000000) | |||
}}}, sc_r2 = {{{ | |||
SC_LIMB(0xa40611e3449c0f01), SC_LIMB(0xd00e1ba768859347), SC_LIMB(0xceec73d217f5be65), SC_LIMB(0x0399411b7c309a3d) | |||
}}}; | |||
/* End of template stuff */ | |||
#define WBITS DECAF_WORD_BITS /* NB this may be different from ARCH_WORD_BITS */ | |||
const scalar_t API_NS(scalar_one) = {{{1}}}, API_NS(scalar_zero) = {{{0}}}; | |||
/** {extra,accum} - sub +? p | |||
* Must have extra <= 1 | |||
*/ | |||
static NOINLINE void sc_subx( | |||
scalar_t out, | |||
const decaf_word_t accum[SCALAR_LIMBS], | |||
const scalar_t sub, | |||
const scalar_t p, | |||
decaf_word_t extra | |||
) { | |||
decaf_dsword_t chain = 0; | |||
unsigned int i; | |||
for (i=0; i<SCALAR_LIMBS; i++) { | |||
chain = (chain + accum[i]) - sub->limb[i]; | |||
out->limb[i] = chain; | |||
chain >>= WBITS; | |||
} | |||
decaf_word_t borrow = chain+extra; /* = 0 or -1 */ | |||
chain = 0; | |||
for (i=0; i<SCALAR_LIMBS; i++) { | |||
chain = (chain + out->limb[i]) + (p->limb[i] & borrow); | |||
out->limb[i] = chain; | |||
chain >>= WBITS; | |||
} | |||
} | |||
static NOINLINE void sc_montmul ( | |||
scalar_t out, | |||
const scalar_t a, | |||
const scalar_t b | |||
) { | |||
unsigned int i,j; | |||
decaf_word_t accum[SCALAR_LIMBS+1] = {0}; | |||
decaf_word_t hi_carry = 0; | |||
for (i=0; i<SCALAR_LIMBS; i++) { | |||
decaf_word_t mand = a->limb[i]; | |||
const decaf_word_t *mier = b->limb; | |||
decaf_dword_t chain = 0; | |||
for (j=0; j<SCALAR_LIMBS; j++) { | |||
chain += ((decaf_dword_t)mand)*mier[j] + accum[j]; | |||
accum[j] = chain; | |||
chain >>= WBITS; | |||
} | |||
accum[j] = chain; | |||
mand = accum[0] * MONTGOMERY_FACTOR; | |||
chain = 0; | |||
mier = sc_p->limb; | |||
for (j=0; j<SCALAR_LIMBS; j++) { | |||
chain += (decaf_dword_t)mand*mier[j] + accum[j]; | |||
if (j) accum[j-1] = chain; | |||
chain >>= WBITS; | |||
} | |||
chain += accum[j]; | |||
chain += hi_carry; | |||
accum[j-1] = chain; | |||
hi_carry = chain >> WBITS; | |||
} | |||
sc_subx(out, accum, sc_p, sc_p, hi_carry); | |||
} | |||
void API_NS(scalar_mul) ( | |||
scalar_t out, | |||
const scalar_t a, | |||
const scalar_t b | |||
) { | |||
sc_montmul(out,a,b); | |||
sc_montmul(out,out,sc_r2); | |||
} | |||
/* PERF: could implement this */ | |||
static INLINE void sc_montsqr (scalar_t out, const scalar_t a) { | |||
sc_montmul(out,a,a); | |||
} | |||
decaf_error_t API_NS(scalar_invert) ( | |||
scalar_t out, | |||
const scalar_t a | |||
) { | |||
/* Fermat's little theorem, sliding window. | |||
* Sliding window is fine here because the modulus isn't secret. | |||
*/ | |||
const int SCALAR_WINDOW_BITS = 3; | |||
scalar_t precmp[1<<SCALAR_WINDOW_BITS]; | |||
const int LAST = (1<<SCALAR_WINDOW_BITS)-1; | |||
/* Precompute precmp = [a^1,a^3,...] */ | |||
sc_montmul(precmp[0],a,sc_r2); | |||
if (LAST > 0) sc_montmul(precmp[LAST],precmp[0],precmp[0]); | |||
int i; | |||
for (i=1; i<=LAST; i++) { | |||
sc_montmul(precmp[i],precmp[i-1],precmp[LAST]); | |||
} | |||
/* Sliding window */ | |||
unsigned residue = 0, trailing = 0, started = 0; | |||
for (i=SCALAR_BITS-1; i>=-SCALAR_WINDOW_BITS; i--) { | |||
if (started) sc_montsqr(out,out); | |||
decaf_word_t w = (i>=0) ? sc_p->limb[i/WBITS] : 0; | |||
< |