/* Copyright (c) 2014 Cryptography Research, Inc. * Released under the MIT License. See LICENSE.txt for license information. */ #include "goldilocks.h" #include "ec_point.h" #include "scalarmul.h" #include "barrett_field.h" #include "crandom.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 }} }; // 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(p448_affine_validate(&goldilocks_base_point)); /* Convert it to twisted Edwards. */ convert_affine_to_extensible(&ext, &goldilocks_base_point); p448_isogeny_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); } // TODO: move to a better place // TODO: word size void p448_serialize(uint8_t *serial, const struct p448_t *x) { int i,j; p448_t red; p448_copy(&red, x); p448_strong_reduce(&red); for (i=0; i<8; i++) { for (j=0; j<7; j++) { serial[7*i+j] = red.limb[i]; red.limb[i] >>= 8; } assert(red.limb[i] == 0); } } void q448_serialize(uint8_t *serial, const word_t x[7]) { int i,j; for (i=0; i<7; i++) { for (j=0; j<8; j++) { serial[8*i+j] = x[i]>>(8*j); } } } mask_t q448_deserialize(word_t x[7], const uint8_t serial[56]) { int i,j; for (i=0; i<7; i++) { word_t out = 0; for (j=0; j<8; j++) { out |= ((word_t)serial[8*i+j])<<(8*j); } x[i] = out; } // TODO: check for reduction return MASK_SUCCESS; } mask_t p448_deserialize(p448_t *x, const uint8_t serial[56]) { int i,j; for (i=0; i<8; i++) { word_t out = 0; for (j=0; j<7; j++) { out |= ((word_t)serial[7*i+j])<<(8*j); } x->limb[i] = out; } // TODO: check for reduction return MASK_SUCCESS; } static word_t q448_lo[4] = { 0xdc873d6d54a7bb0dull, 0xde933d8d723a70aaull, 0x3bb124b65129c96full, 0x000000008335dc16ull }; int goldilocks_keygen( uint8_t private[56], uint8_t public[56] ) { // 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(private, sk); edwards_comb(&exta, sk, goldilocks_global.combs, 5, 5, 18); isogeny_and_serialize(&pk, &exta); p448_serialize(public, &pk); return ret; } int goldilocks_shared_secret( uint8_t shared[56], const uint8_t private[56], const uint8_t public[56] ) { // TODO: SHA word_t sk[448/WORD_BITS]; struct p448_t pk; mask_t succ = p448_deserialize(&pk,public); succ &= q448_deserialize(sk,private); succ &= p448_montgomery_ladder(&pk,&pk,sk,446,2); p448_serialize(shared,&pk); // TODO: hash if (succ) { return 0; } else { return -1; } }