/** * @cond internal * @file decaf_crypto.c * @copyright * Copyright (c) 2015 Cryptography Research, Inc. \n * Released under the MIT License. See LICENSE.txt for license information. * @author Mike Hamburg * @brief Decaf cyrpto routines. */ #include "decaf_crypto.h" #include #include "sha512.h" static const unsigned int DECAF_448_SCALAR_OVERKILL_BYTES = DECAF_448_SCALAR_BYTES + 8; void decaf_448_derive_private_key ( decaf_448_private_key_t priv, const decaf_448_symmetric_key_t proto ) { const char *magic = "decaf_448_derive_private_key"; uint8_t encoded_scalar[DECAF_448_SCALAR_OVERKILL_BYTES]; decaf_448_point_t pub; keccak_sponge_t sponge; shake256_init(sponge); shake256_update(sponge, proto, sizeof(decaf_448_symmetric_key_t)); shake256_update(sponge, (const unsigned char *)magic, strlen(magic)); shake256_final(sponge, encoded_scalar, sizeof(encoded_scalar)); shake256_destroy(sponge); memcpy(priv->sym, proto, sizeof(decaf_448_symmetric_key_t)); decaf_448_scalar_decode_long(priv->secret_scalar, encoded_scalar, sizeof(encoded_scalar)); decaf_448_precomputed_scalarmul(pub, decaf_448_precomputed_base, priv->secret_scalar); decaf_448_point_encode(priv->pub, pub); decaf_bzero(encoded_scalar, sizeof(encoded_scalar)); } void decaf_448_destroy_private_key ( decaf_448_private_key_t priv ) { decaf_bzero((void*)priv, sizeof(decaf_448_private_key_t)); } void decaf_448_private_to_public ( decaf_448_public_key_t pub, const decaf_448_private_key_t priv ) { memcpy(pub, priv->pub, sizeof(decaf_448_public_key_t)); } decaf_bool_t decaf_448_shared_secret ( uint8_t *shared, size_t shared_bytes, const decaf_448_private_key_t my_privkey, const decaf_448_public_key_t your_pubkey ) { uint8_t ss_ser[DECAF_448_SER_BYTES]; const char *nope = "decaf_448_ss_invalid"; unsigned i; /* Lexsort keys. Less will be -1 if mine is less, and 0 otherwise. */ uint16_t less = 0; for (i=0; ipub[i]; delta -= your_pubkey[i]; /* Case: * = -> delta = 0 -> hi delta-1 = -1, hi delta = 0 * > -> delta > 0 -> hi delta-1 = 0, hi delta = 0 * < -> delta < 0 -> hi delta-1 = (doesnt matter), hi delta = -1 */ less &= delta-1; less |= delta; } less >>= 8; keccak_sponge_t sponge; shake256_init(sponge); /* update the lesser */ for (i=0; ipub[i] & less) | (your_pubkey[i] & ~less); } shake256_update(sponge, ss_ser, sizeof(ss_ser)); /* update the greater */ for (i=0; ipub[i] & ~less) | (your_pubkey[i] & less); } shake256_update(sponge, ss_ser, sizeof(ss_ser)); decaf_bool_t ret = decaf_448_direct_scalarmul(ss_ser, your_pubkey, my_privkey->secret_scalar, DECAF_FALSE, DECAF_TRUE); /* If invalid, then replace ... */ for (i=0; isym)) { ss_ser[i] |= my_privkey->sym[i] & ~ret; } else if (i - sizeof(my_privkey->sym) < strlen(nope)) { ss_ser[i] |= nope[i-sizeof(my_privkey->sym)] & ~ret; } } shake256_update(sponge, ss_ser, sizeof(ss_ser)); shake256_final(sponge, shared, shared_bytes); shake256_destroy(sponge); decaf_bzero(ss_ser, sizeof(ss_ser)); return ret; } void decaf_448_sign_shake ( decaf_448_signature_t sig, const decaf_448_private_key_t priv, const keccak_sponge_t shake ) { const char *magic = "decaf_448_sign_shake"; uint8_t overkill[DECAF_448_SCALAR_OVERKILL_BYTES], encoded[DECAF_448_SER_BYTES]; decaf_448_point_t point; decaf_448_scalar_t nonce, challenge; /* Derive nonce */ keccak_sponge_t ctx; memcpy(ctx, shake, sizeof(ctx)); shake256_update(ctx, priv->sym, sizeof(priv->sym)); shake256_update(ctx, (const unsigned char *)magic, strlen(magic)); shake256_final(ctx, overkill, sizeof(overkill)); decaf_448_scalar_decode_long(nonce, overkill, sizeof(overkill)); decaf_448_precomputed_scalarmul(point, decaf_448_precomputed_base, nonce); decaf_448_point_encode(encoded, point); /* Derive challenge */ memcpy(ctx, shake, sizeof(ctx)); shake256_update(ctx, priv->pub, sizeof(priv->pub)); shake256_update(ctx, encoded, sizeof(encoded)); shake256_final(ctx, overkill, sizeof(overkill)); shake256_destroy(ctx); decaf_448_scalar_decode_long(challenge, overkill, sizeof(overkill)); /* Respond */ decaf_448_scalar_mul(challenge, challenge, priv->secret_scalar); decaf_448_scalar_sub(nonce, nonce, challenge); /* Save results */ memcpy(sig, encoded, sizeof(encoded)); decaf_448_scalar_encode(&sig[sizeof(encoded)], nonce); /* Clean up */ decaf_448_scalar_destroy(nonce); decaf_448_scalar_destroy(challenge); decaf_bzero(overkill,sizeof(overkill)); decaf_bzero(encoded,sizeof(encoded)); } decaf_bool_t decaf_448_verify_shake ( const decaf_448_signature_t sig, const decaf_448_public_key_t pub, const keccak_sponge_t shake ) { decaf_bool_t ret; uint8_t overkill[DECAF_448_SCALAR_OVERKILL_BYTES]; decaf_448_point_t point, pubpoint; decaf_448_scalar_t challenge, response; /* Derive challenge */ keccak_sponge_t ctx; memcpy(ctx, shake, sizeof(ctx)); shake256_update(ctx, pub, sizeof(decaf_448_public_key_t)); shake256_update(ctx, sig, DECAF_448_SER_BYTES); shake256_final(ctx, overkill, sizeof(overkill)); shake256_destroy(ctx); decaf_448_scalar_decode_long(challenge, overkill, sizeof(overkill)); /* Decode points. */ ret = decaf_448_point_decode(point, sig, DECAF_TRUE); ret &= decaf_448_point_decode(pubpoint, pub, DECAF_FALSE); ret &= decaf_448_scalar_decode(response, &sig[DECAF_448_SER_BYTES]); decaf_448_base_double_scalarmul_non_secret ( pubpoint, response, pubpoint, challenge ); ret &= decaf_448_point_eq(pubpoint, point); return ret; } void decaf_448_sign ( decaf_448_signature_t sig, const decaf_448_private_key_t priv, const unsigned char *message, size_t message_len ) { keccak_sponge_t ctx; shake256_init(ctx); shake256_update(ctx, message, message_len); decaf_448_sign_shake(sig, priv, ctx); shake256_destroy(ctx); } decaf_bool_t decaf_448_verify ( const decaf_448_signature_t sig, const decaf_448_public_key_t pub, const unsigned char *message, size_t message_len ) { keccak_sponge_t ctx; shake256_init(ctx); shake256_update(ctx, message, message_len); decaf_bool_t ret = decaf_448_verify_shake(sig, pub, ctx); shake256_destroy(ctx); return ret; }