|
- /* Copyright (c) 2014 Cryptography Research, Inc.
- * Released under the MIT License. See LICENSE.txt for license information.
- */
- #include <errno.h>
-
- #include "goldilocks.h"
- #include "ec_point.h"
- #include "scalarmul.h"
- #include "barrett_field.h"
- #include "crandom.h"
- #include "sha512.h"
-
- #ifndef GOLDILOCKS_RANDOM_INIT_FILE
- #define GOLDILOCKS_RANDOM_INIT_FILE "/dev/urandom"
- #endif
-
- #ifndef GOLDILOCKS_RANDOM_RESEED_INTERVAL
- #define GOLDILOCKS_RANDOM_RESEED_INTERVAL 10000
- #endif
-
- /* We'll check it ourselves */
- #ifndef GOLDILOCKS_RANDOM_RESEEDS_MANDATORY
- #define GOLDILOCKS_RANDOM_RESEEDS_MANDATORY 0
- #endif
-
- /* TODO: word size; precompute */
- const struct affine_t goldilocks_base_point = {
- {{ 0xf0de840aed939full, 0xc170033f4ba0c7ull, 0xf3932d94c63d96ull, 0x9cecfa96147eaaull,
- 0x5f065c3c59d070ull, 0x3a6a26adf73324ull, 0x1b4faff4609845ull, 0x297ea0ea2692ffull
- }},
- {{ 19, 0, 0, 0, 0, 0, 0, 0 }}
- };
-
- // /* TODO: direct */
- // void
- // transfer_and_serialize(struct p448_t *out, const struct tw_extensible_t *twext) {
- // struct extensible_t ext;
- // transfer_tw_to_un(&ext, twext);
- // serialize_extensible(out, &ext);
- // }
-
- // FIXME: threading
- // TODO: autogen instead of init
- struct {
- struct tw_niels_t combs[80];
- struct tw_niels_t wnafs[32];
- struct crandom_state_t rand;
- } goldilocks_global;
-
- int
- goldilocks_init () {
- struct extensible_t ext;
- struct tw_extensible_t text;
-
- /* Sanity check: the base point is on the curve. */
- assert(validate_affine(&goldilocks_base_point));
-
- /* Convert it to twisted Edwards. */
- convert_affine_to_extensible(&ext, &goldilocks_base_point);
- twist(&text, &ext);
- //p448_transfer_un_to_tw(&text, &ext);
-
- /* Precompute the tables. */
- precompute_for_combs(goldilocks_global.combs, &text, 5, 5, 18);
- precompute_for_wnaf(goldilocks_global.wnafs, &text, 5);
-
- return crandom_init_from_file(&goldilocks_global.rand,
- GOLDILOCKS_RANDOM_INIT_FILE,
- GOLDILOCKS_RANDOM_RESEED_INTERVAL,
- GOLDILOCKS_RANDOM_RESEEDS_MANDATORY);
- }
-
- static word_t
- q448_lo[4] = {
- 0xdc873d6d54a7bb0dull,
- 0xde933d8d723a70aaull,
- 0x3bb124b65129c96full,
- 0x000000008335dc16ull
- };
-
- static const struct p448_t
- sqrt_d_minus_1 = {{
- 0xd2e21836749f46ull,
- 0x888db42b4f0179ull,
- 0x5a189aabdeea38ull,
- 0x51e65ca6f14c06ull,
- 0xa49f7b424d9770ull,
- 0xdcac4628c5f656ull,
- 0x49443b8748734aull,
- 0x12fec0c0b25b7aull
- }};
-
- int
- goldilocks_keygen (
- struct goldilocks_private_key_t *privkey,
- struct goldilocks_public_key_t *pubkey
- ) {
- // TODO: check for init. Also maybe take CRANDOM object? API...
- word_t sk[448*2/WORD_BITS];
-
- struct tw_extensible_t exta;
- struct p448_t pk;
-
- int ret = crandom_generate(&goldilocks_global.rand, (unsigned char *)sk, sizeof(sk));
- barrett_reduce(sk,sizeof(sk)/sizeof(sk[0]),0,q448_lo,7,4,62); // TODO word size
- q448_serialize(privkey->opaque, sk);
-
- edwards_comb(&exta, sk, goldilocks_global.combs, 5, 5, 18);
- //transfer_and_serialize_qtor(&pk, &sqrt_d_minus_1, &exta);
- untwist_and_double_and_serialize(&pk, &exta);
-
- p448_serialize(pubkey->opaque, &pk);
- memcpy(&privkey->opaque[56], pubkey->opaque, 56);
-
- int ret2 = crandom_generate(&goldilocks_global.rand, &privkey->opaque[112], 32);
- if (!ret) ret = ret2;
-
- return ret ? GOLDI_ENODICE : GOLDI_EOK;
- }
-
- int
- goldilocks_shared_secret (
- uint8_t shared[64],
- const struct goldilocks_private_key_t *my_privkey,
- const struct goldilocks_public_key_t *your_pubkey
- ) {
- word_t sk[448/WORD_BITS];
- struct p448_t pk;
-
- mask_t succ = p448_deserialize(&pk,your_pubkey->opaque), msucc = -1;
-
- #ifdef EXPERIMENT_ECDH_STIR_IN_PUBKEYS
- struct p448_t sum, prod;
- msucc &= p448_deserialize(&sum,&my_privkey->opaque[56]);
- p448_mul(&prod,&pk,&sum);
- p448_add(&sum,&pk,&sum);
- #endif
-
- msucc &= q448_deserialize(sk,my_privkey->opaque);
- succ &= p448_montgomery_ladder(&pk,&pk,sk,446,2);
-
- p448_serialize(shared,&pk);
-
- /* obliterate records of our failure by adjusting with obliteration key */
- struct sha512_ctx_t ctx;
- sha512_init(&ctx);
-
- #ifdef EXPERIMENT_ECDH_OBLITERATE_CT
- uint8_t oblit[40];
- unsigned i;
- for (i=0; i<8; i++) {
- oblit[i] = "noshared"[i] & ~(succ&msucc);
- }
- for (i=0; i<32; i++) {
- oblit[8+i] = my_privkey->opaque[112+i] & ~(succ&msucc);
- }
- sha512_update(&ctx, oblit, 40);
- #endif
-
- #ifdef EXPERIMENT_ECDH_STIR_IN_PUBKEYS
- /* stir in the sum and product of the pubkeys. */
- uint8_t a_pk[56];
- p448_serialize(a_pk, &sum);
- sha512_update(&ctx, a_pk, 56);
- p448_serialize(a_pk, &prod);
- sha512_update(&ctx, a_pk, 56);
- #endif
-
- /* stir in the shared key and finish */
- sha512_update(&ctx, shared, 56);
- sha512_final(&ctx, shared);
-
- return (GOLDI_ECORRUPT & ~msucc)
- | (GOLDI_EINVAL & msucc &~ succ)
- | (GOLDI_EOK & msucc & succ);
- }
-
- int
- goldilocks_sign (
- uint8_t signature_out[56*2],
- const uint8_t *message,
- uint64_t message_len,
- const struct goldilocks_private_key_t *privkey
- ) {
-
- /* challenge = H(pk, [nonceG], message). FIXME: endian. */
- word_t skw[448/WORD_BITS];
- mask_t succ = q448_deserialize(skw,privkey->opaque);
- if (!succ) {
- memset(skw,0,sizeof(skw));
- return GOLDI_ECORRUPT;
- }
-
- /* Derive a nonce. TODO: use HMAC. FIXME: endian. FUTURE: factor. */
- word_t tk[512/WORD_BITS];
- struct sha512_ctx_t ctx;
- sha512_init(&ctx);
- sha512_update(&ctx, (const unsigned char *)"signonce", 8);
- sha512_update(&ctx, &privkey->opaque[112], 32);
- sha512_update(&ctx, message, message_len);
- sha512_update(&ctx, &privkey->opaque[112], 32);
- sha512_final(&ctx, (unsigned char *)tk);
- barrett_reduce(tk,512/WORD_BITS,0,q448_lo,7,4,62); // TODO word size
-
- /* 4[nonce]G */
- uint8_t signature_tmp[56];
- struct tw_extensible_t exta;
- struct p448_t gsk;
- edwards_comb(&exta, tk, goldilocks_global.combs, 5, 5, 18);
- double_tw_extensible(&exta);
- untwist_and_double_and_serialize(&gsk, &exta);
- p448_serialize(signature_tmp, &gsk);
-
- word_t challenge[512/WORD_BITS];
- sha512_update(&ctx, &privkey->opaque[56], 56);
- sha512_update(&ctx, signature_tmp, 56);
- sha512_update(&ctx, message, message_len);
- sha512_final(&ctx, (unsigned char *)challenge);
-
- // reduce challenge and sub.
- barrett_negate(challenge,512/WORD_BITS,q448_lo,7,4,62);
-
- barrett_mac(
- tk,512/WORD_BITS,
- challenge,512/WORD_BITS,
- skw,448/WORD_BITS,
- q448_lo,7,4,62
- );
-
- word_t carry = add_nr_ext_packed(tk,tk,512/WORD_BITS,tk,512/WORD_BITS,-1);
- barrett_reduce(tk,512/WORD_BITS,carry,q448_lo,7,4,62);
-
- memcpy(signature_out, signature_tmp, 56);
- q448_serialize(signature_out+56, tk);
- memset((unsigned char *)tk,0,sizeof(tk));
- memset((unsigned char *)skw,0,sizeof(skw));
- memset((unsigned char *)challenge,0,sizeof(challenge));
-
- /* response = 2(nonce_secret - sk*challenge)
- * Nonce = 8[nonce_secret]*G
- * PK = 2[sk]*G, except doubled (TODO)
- * so [2] ( [response]G + 2[challenge]PK ) = Nonce
- */
-
- return 0;
- }
-
- int
- goldilocks_verify (
- const uint8_t signature[56*2],
- const uint8_t *message,
- uint64_t message_len,
- const struct goldilocks_public_key_t *pubkey
- ) {
- struct p448_t pk;
- word_t s[448/WORD_BITS];
-
- mask_t succ = p448_deserialize(&pk,pubkey->opaque);
- if (!succ) return GOLDI_EINVAL;
-
- succ = q448_deserialize(s, &signature[56]);
- if (!succ) return GOLDI_EINVAL;
-
- /* challenge = H(pk, [nonceG], message). FIXME: endian. */
- word_t challenge[512/WORD_BITS];
- struct sha512_ctx_t ctx;
- sha512_init(&ctx);
- sha512_update(&ctx, pubkey->opaque, 56);
- sha512_update(&ctx, signature, 56);
- sha512_update(&ctx, message, message_len);
- sha512_final(&ctx, (unsigned char *)challenge);
- barrett_reduce(challenge,512/WORD_BITS,0,q448_lo,7,4,62);
-
- struct p448_t eph;
- struct tw_extensible_t pk_text;
-
- /* deserialize [nonce]G */
- succ = p448_deserialize(&eph, signature);
- if (!succ) return GOLDI_EINVAL;
-
-
- // succ = affine_deserialize(&pk_aff,&pk);
- // if (!succ) return EINVAL;
- //
- // convert_affine_to_extensible(&pk_ext,&pk_aff);
- // transfer_un_to_tw(&pk_text,&pk_ext);
- succ = deserialize_and_twist_approx(&pk_text, &sqrt_d_minus_1, &pk);
- if (!succ) return GOLDI_EINVAL;
-
- edwards_combo_var_fixed_vt( &pk_text, challenge, s, goldilocks_global.wnafs, 5 );
-
- untwist_and_double_and_serialize( &pk, &pk_text );
- p448_sub(&eph, &eph, &pk);
- p448_bias(&eph, 2);
-
- succ = p448_is_zero(&eph);
-
- return succ ? 0 : GOLDI_EINVAL;
- }
|