Commit 608eb2e0 authored by Michael Hamburg's avatar Michael Hamburg

Begin work on decaf_crypto. Have an ECDH analog now. Add decaf_bzero. ...

Begin work on decaf_crypto.  Have an ECDH analog now.  Add decaf_bzero.  Remove a bunch of testing from bench.c.
parent b274e35d
......@@ -66,18 +66,20 @@ HEADERS= Makefile $(shell find . -name "*.h") build/timestamp
LIBCOMPONENTS= build/goldilocks.o build/barrett_field.o build/crandom.o \
build/$(FIELD).o build/ec_point.o build/scalarmul.o build/sha512.o build/magic.o \
build/f_arithmetic.o build/arithmetic.o build/decaf.o build/shake.o
build/f_arithmetic.o build/arithmetic.o
DECAFCOMPONENTS= build/decaf.o build/shake.o build/decaf_crypto.o
TESTCOMPONENTS=build/test.o build/test_scalarmul.o build/test_sha512.o \
build/test_pointops.o build/test_arithmetic.o build/test_goldilocks.o build/magic.o \
build/shake.o
BENCHCOMPONENTS=build/bench.o build/shake.o
BENCHCOMPONENTS = build/bench.o build/shake.o
BATBASE=ed448goldilocks-bats-$(TODAY)
BATNAME=build/$(BATBASE)
all: lib build/test build/bench build/shakesum
all: lib decaf_lib build/test build/bench build/shakesum
scan: clean
scan-build --use-analyzer=`which clang` \
......@@ -85,10 +87,10 @@ scan: clean
-enable-checker osx -enable-checker security -enable-checker unix \
make build/bench build/test build/goldilocks.so
build/bench: $(LIBCOMPONENTS) $(BENCHCOMPONENTS)
build/bench: $(LIBCOMPONENTS) $(BENCHCOMPONENTS) $(DECAFCOMPONENTS)
$(LD) $(LDFLAGS) -o $@ $^
build/test: $(LIBCOMPONENTS) $(TESTCOMPONENTS)
build/test: $(LIBCOMPONENTS) $(TESTCOMPONENTS) $(DECAFCOMPONENTS)
$(LD) $(LDFLAGS) -o $@ $^ -lgmp
build/shakesum: build/shakesum.o build/shake.o
......@@ -96,6 +98,8 @@ build/shakesum: build/shakesum.o build/shake.o
lib: build/goldilocks.so
decaf_lib: build/decaf.so
build/goldilocks.so: $(LIBCOMPONENTS)
rm -f $@
ifeq ($(UNAME),Darwin)
......@@ -107,6 +111,17 @@ else
ln -sf `basename $@` build/goldilocks.so.1
endif
build/decaf.so: $(DECAFCOMPONENTS)
rm -f $@
ifeq ($(UNAME),Darwin)
libtool -macosx_version_min 10.6 -dynamic -dead_strip -lc -x -o $@ \
$(DECAFCOMPONENTS)
else
$(LD) $(LDFLAGS) -shared -Wl,-soname,goldilocks.so.1 -Wl,--gc-sections -o $@ $(DECAFCOMPONENTS)
strip --discard-all $@
ln -sf `basename $@` build/goldilocks.so.1
endif
build/timestamp:
mkdir -p build
touch $@
......
/* Copyright (c) 2015 Cryptography Research, Inc.
* Released under the MIT License. See LICENSE.txt for license information.
*/
/**
* @file decaf.h
* @author Mike Hamburg
*
* @copyright
* Copyright (c) 2015 Cryptography Research, Inc. \n
* Released under the MIT License. See LICENSE.txt for license information.
*
* @brief A group of prime order p.
*
* The Decaf library implements cryptographic operations on a an elliptic curve
......@@ -24,6 +25,7 @@
#define __DECAF_448_H__ 1
#include <stdint.h>
#include <sys/types.h>
/* Goldilocks' build flags default to hidden and stripping executables. */
/** @cond internal */
......@@ -113,18 +115,30 @@ extern "C" {
/**
* @brief Read a scalar from wire format or from bytes.
*
* Return DECAF_SUCCESS if the scalar was in reduced form. This
* function is not WARN_UNUSED because eg challenges in signatures
* may need to be longer.
*
* TODO: create a decode long function, and make this WARN_UNUSED.
*
* @param [in] ser Serialized form of a scalar.
* @param [out] out Deserialized form.
*
* @retval DECAF_SUCCESS The scalar was correctly encoded.
* @retval DECAF_FAILURE The scalar was greater than the modulus,
* and has been reduced modulo that modulus.
*/
decaf_bool_t decaf_448_scalar_decode (
decaf_448_scalar_t s,
const unsigned char ser[DECAF_448_SCALAR_BYTES]
) API_VIS WARN_UNUSED NONNULL2;
/**
* @brief Read a scalar from wire format or from bytes. Reduces mod
* scalar prime.
*
* @param [in] ser Serialized form of a scalar.
* @param [in] ser_len Length of serialized form.
* @param [out] out Deserialized form.
*/
void decaf_448_scalar_decode_long (
decaf_448_scalar_t s,
const unsigned char *ser,
size_t ser_len
) API_VIS NONNULL2;
/**
......@@ -417,6 +431,21 @@ void decaf_448_point_from_hash_uniform (
const unsigned char hashed_data[2*DECAF_448_SER_BYTES]
) API_VIS NONNULL2;
/**
* @brief Overwrite data with zeros. Use memset_s if available.
*/
void decaf_bzero (
void *data,
size_t size
) NONNULL1 API_VIS;
/**
* @brief Overwrite scalar with zeros.
*/
void decaf_448_scalar_destroy (
decaf_448_scalar_t scalar
) NONNULL1 API_VIS;
/* TODO: functions to invert point_from_hash?? */
#undef API_VIS
......
/**
* @file decaf_crypto.h
* @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.
* @warning Experimental! The names, parameter orders etc are likely to change.
*/
#ifndef __DECAF_CRYPTO_H__
#define __DECAF_CRYPTO_H__ 1
#include "decaf.h"
#include "shake.h"
#define DECAF_448_SYMMETRIC_KEY_BYTES 32
/** @cond internal */
#define API_VIS __attribute__((visibility("default")))
#define WARN_UNUSED __attribute__((warn_unused_result))
#define NONNULL1 __attribute__((nonnull(1)))
#define NONNULL2 __attribute__((nonnull(1,2)))
#define NONNULL3 __attribute__((nonnull(1,2,3)))
#define NONNULL134 __attribute__((nonnull(1,3,4)))
#define NONNULL5 __attribute__((nonnull(1,2,3,4,5)))
/** @endcond */
/** A symmetric key, the compressed point of a private key. */
typedef unsigned char decaf_448_symmetric_key_t[DECAF_448_SYMMETRIC_KEY_BYTES];
/** An encoded public key. */
typedef unsigned char decaf_448_public_key_t[DECAF_448_SER_BYTES];
/** A private key. */
typedef struct {
decaf_448_symmetric_key_t sym;
decaf_448_scalar_t secret_scalar;
decaf_448_public_key_t pub;
} decaf_448_private_key_t[1];
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Derive a key from its compressed form.
* @param [out] privkey The derived private key.
* @param [in] proto The compressed or proto-key, which must be 32 random bytes.
*/
void decaf_448_derive_private_key (
decaf_448_private_key_t priv,
const decaf_448_symmetric_key_t proto
) NONNULL2 API_VIS;
/**
* @brief Destroy a private key.
*/
void decaf_448_destroy_private_key (
decaf_448_private_key_t priv
) NONNULL1 API_VIS;
/**
* @brief Convert a private key to a public one.
* @param [out] pub The extracted private key.
* @param [in] priv The private key.
*/
void decaf_448_private_to_public (
decaf_448_public_key_t pub,
const decaf_448_private_key_t priv
) NONNULL2 API_VIS;
/**
* @brief Compute a Diffie-Hellman shared secret.
*
* This is an example routine; real protocols would use something
* protocol-specific.
*
* @param [out] shared A buffer to store the shared secret.
* @param [in] shared_bytes The size of the buffer.
* @param [in] my_privkey My private key.
* @param [in] your_pubkey Your public key.
*
* @retval DECAF_SUCCESS Key exchange was successful.
* @retval DECAF_FAILURE Key exchange failed.
*/
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
) NONNULL134 WARN_UNUSED API_VIS;
#undef API_VIS
#undef WARN_UNUSED
#undef NONNULL1
#undef NONNULL2
#undef NONNULL3
#undef NONNULL134
#undef NONNULL5
#ifdef __cplusplus
}; /* extern "C" */
#endif
#endif /* __DECAF_CRYPTO_H__ */
......@@ -13,6 +13,7 @@
#define __SHAKE_H__
#include <stdint.h>
#include <sys/types.h>
#define API_VIS __attribute__((visibility("default")))
......@@ -98,7 +99,7 @@ void sponge_hash (
sha3_output(sponge, out, outlen); \
sponge_init(sponge, SHAKE##n##_params); \
} \
static inline void shake##n##_hash(const uint8_t *in, size_t inlen, uint8_t *out, size_t outlen ) { \
static inline void shake##n##_hash(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) { \
sponge_hash(in,inlen,out,outlen,SHAKE##n##_params); \
} \
static inline void shake##n##_destroy( keccak_sponge_t sponge ) { \
......@@ -117,7 +118,7 @@ void sponge_hash (
sha3_output(sponge, out, outlen); \
sponge_init(sponge, SHA3_##n##_params); \
} \
static inline void sha3_##n##_hash(const uint8_t *in, size_t inlen, uint8_t *out, size_t outlen ) { \
static inline void sha3_##n##_hash(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) { \
sponge_hash(in,inlen,out,outlen,SHA3_##n##_params); \
} \
static inline void sha3_##n##_destroy( keccak_sponge_t sponge ) { \
......
......@@ -8,7 +8,9 @@
* @brief Decaf high-level functions.
*/
#define __STDC_WANT_LIB_EXT1__ 1 /* for memset_s */
#include "decaf.h"
#include <string.h>
#define WBITS DECAF_WORD_BITS
......@@ -548,6 +550,65 @@ decaf_bool_t decaf_448_scalar_decode(
return accum;
}
void decaf_bzero (
void *s,
size_t size
) {
#ifdef __STDC_LIB_EXT1__
memset_s(s, size, 0, size);
#else
volatile uint8_t *destroy = (volatile uint8_t *)s;
unsigned i;
for (i=0; i<size; i++) {
destroy[i] = 0;
}
#endif
}
void decaf_448_scalar_destroy (
decaf_448_scalar_t scalar
) {
decaf_bzero(scalar, sizeof(decaf_448_scalar_t));
}
static inline void ignore_result ( decaf_bool_t boo ) {
(void)boo;
}
void decaf_448_scalar_decode_long(
decaf_448_scalar_t s,
const unsigned char *ser,
size_t ser_len
) {
if (ser_len == 0) {
decaf_448_scalar_copy(s, decaf_448_scalar_zero);
return;
}
size_t i;
unsigned char tmp[DECAF_448_SER_BYTES] = {0};
decaf_448_scalar_t t1, t2;
i = ser_len - (ser_len%DECAF_448_SER_BYTES);
if (i==ser_len) i -= DECAF_448_SER_BYTES;
memcpy(tmp, ser+i, ser_len - i);
ignore_result( decaf_448_scalar_decode(t1, tmp) );
decaf_bzero(tmp, sizeof(tmp));
while (i) {
i -= DECAF_448_SER_BYTES;
decaf_448_montmul(t1,t1,decaf_448_scalar_r2,decaf_448_scalar_p,DECAF_MONTGOMERY_FACTOR);
ignore_result( decaf_448_scalar_decode(t2, ser+i) );
decaf_448_scalar_add(t1, t1, t2);
}
decaf_448_scalar_copy(s, t1);
decaf_448_scalar_destroy(t1);
decaf_448_scalar_destroy(t2);
}
void decaf_448_scalar_encode(
unsigned char ser[DECAF_448_SER_BYTES],
const decaf_448_scalar_t s
......
/**
* @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 <string.h>
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";
keccak_sponge_t sponge;
uint8_t encoded_scalar[64];
decaf_448_point_t pub;
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
) {
decaf_448_point_t point;
uint8_t ss_ser[DECAF_448_SER_BYTES];
const char *nope = "decaf_448_ss_invalid";
decaf_bool_t ret = decaf_448_point_decode(point, your_pubkey, DECAF_FALSE);
decaf_448_point_scalarmul(point, point, my_privkey->secret_scalar);
unsigned i;
/* Lexsort keys. Less will be -1 if mine is less, and 0 otherwise. */
uint16_t less = 0;
for (i=0; i<DECAF_448_SER_BYTES; i++) {
uint16_t delta = my_privkey->pub[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; i<sizeof(ss_ser); i++) {
ss_ser[i] = (my_privkey->pub[i] & less) | (your_pubkey[i] & ~less);
}
shake256_update(sponge, ss_ser, sizeof(ss_ser));
/* update the greater */
for (i=0; i<sizeof(ss_ser); i++) {
ss_ser[i] = (my_privkey->pub[i] & ~less) | (your_pubkey[i] & less);
}
shake256_update(sponge, ss_ser, sizeof(ss_ser));
/* encode the shared secret but mask with secret key */
decaf_448_point_encode(ss_ser, point);
/* If invalid, then replace ... */
for (i=0; i<sizeof(ss_ser); i++) {
ss_ser[i] &= ret;
if (i < sizeof(my_privkey->sym)) {
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;
}
......@@ -197,6 +197,7 @@ void sha3_output (
}
}
/** TODO: unify with decaf_bzero? */
void sponge_destroy (
keccak_sponge_t sponge
) {
......
......@@ -17,6 +17,7 @@
#include "goldilocks.h"
#include "sha512.h"
#include "decaf.h"
#include "decaf_crypto.h"
#include "shake.h"
static __inline__ void
......@@ -65,15 +66,6 @@ field_print_full (
printf("\n");
}
static void q448_print( const char *descr, const word_t secret[SCALAR_WORDS] ) {
int j;
printf("%s = 0x", descr);
for (j=SCALAR_WORDS-1; j>=0; j--) {
printf(PRIxWORDfull, secret[j]);
}
printf("\n");
}
#ifndef N_TESTS_BASE
#define N_TESTS_BASE 10000
#endif
......@@ -687,135 +679,37 @@ int main(int argc, char **argv) {
when = now() - when;
printf("ecdh pre: %5.1fµs\n", when * 1e6 / i);
printf("\nTesting...\n");
printf("\nDecaf slow:\n");
decaf_448_symmetric_key_t sym[2] = {{0},{1}};
decaf_448_private_key_t dpriv[2];
decaf_448_public_key_t dpub[2];
int failures=0, successes = 0;
for (i=0; i<nbase/10; i++) {
ignore_result(goldilocks_keygen(&gsk,&gpk));
goldilocks_sign(sout,(const unsigned char *)message,message_len,&gsk);
res = goldilocks_verify(sout,(const unsigned char *)message,message_len,&gpk);
if (res) failures++;
}
if (failures) {
printf("FAIL %d/%d signature checks!\n", failures, i);
}
unsigned char dshared[2][32];
failures=0; successes = 0;
when = now();
for (i=0; i<nbase/10; i++) {
field_randomize(&crand, a);
word_t two = 2;
mask_t good = montgomery_ladder(b,a,&two,2,0);
if (!good) continue;
word_t x,y;
crandom_generate(&crand, (unsigned char *)&x, sizeof(x));
crandom_generate(&crand, (unsigned char *)&y, sizeof(y));
x = (hword_t)x;
y = (hword_t)y;
word_t z=x*y;
ignore_result(montgomery_ladder(b,a,&x,WORD_BITS,0));
ignore_result(montgomery_ladder(c,b,&y,WORD_BITS,0));
ignore_result(montgomery_ladder(b,a,&z,WORD_BITS,0));
field_sub(d,b,c);
if (!field_is_zero(d)) {
printf("Odd ladder validation failure %d!\n", ++failures);
field_print("a", a);
printf("x=%"PRIxWORD", y=%"PRIxWORD", z=%"PRIxWORD"\n", x,y,z);
field_print("c", c);
field_print("b", b);
printf("\n");
}
decaf_448_derive_private_key(dpriv[i&1], sym[i&1]);
}
when = now() - when;
printf("derive priv: %5.1fµs\n", when * 1e6 / i);
failures = 0;
for (i=0; i<nbase/10; i++) {
mask_t good;
do {
field_randomize(&crand, a);
good = deserialize_affine(&affine, a);
} while (!good);
convert_affine_to_extensible(&exta,&affine);
twist_and_double(&ext,&exta);
untwist_and_double(&exta,&ext);
serialize_extensible(b, &exta);
untwist_and_double_and_serialize(c, &ext);
field_sub(d,b,c);
if (good && !field_is_zero(d)){
printf("Iso+serial validation failure %d!\n", ++failures);
field_print("a", a);
field_print("b", b);
field_print("c", c);
printf("\n");
} else if (good) {
successes ++;
}
}
if (successes < i/3) {
printf("Iso+serial variation: only %d/%d successful.\n", successes, i);
}
decaf_448_private_to_public(dpub[0], dpriv[0]);
decaf_448_private_to_public(dpub[1], dpriv[1]);
successes = failures = 0;
when = now();
for (i=0; i<nbase/10; i++) {
field_a_t aa;
struct tw_extensible_t exu,exv,exw;
mask_t good;
do {
field_randomize(&crand, a);
good = deserialize_affine(&affine, a);
convert_affine_to_extensible(&exta,&affine);
twist_and_double(&ext,&exta);
} while (!good);
do {
field_randomize(&crand, aa);
good = deserialize_affine(&affine, aa);
convert_affine_to_extensible(&exta,&affine);
twist_and_double(&exu,&exta);
} while (!good);
field_randomize(&crand, aa);
q448_randomize(&crand, sk);
if (i==0 || i==2) memset(&sk, 0, sizeof(sk));
q448_randomize(&crand, tk);
if (i==0 || i==1) memset(&tk, 0, sizeof(tk));
copy_tw_extensible(&exv, &ext);
copy_tw_extensible(&exw, &exu);
scalarmul(&exv,sk);
scalarmul(&exw,tk);
convert_tw_extensible_to_tw_pniels(&pniels, &exw);
add_tw_pniels_to_tw_extensible(&exv,&pniels);
untwist_and_double(&exta,&exv);
serialize_extensible(b, &exta);
ignore_result(precompute_fixed_base_wnaf(wnaft,&exu,5));
linear_combo_var_fixed_vt(&ext,sk,FIELD_BITS,tk,FIELD_BITS,(const tw_niels_a_t*)wnaft,5);
untwist_and_double(&exta,&exv);
serialize_extensible(c, &exta);
field_sub(d,b,c);
if (!field_is_zero(d)){
printf("PreWNAF combo validation failure %d!\n", ++failures);
field_print("a", a);
field_print("A", aa);
q448_print("s", sk);
q448_print("t", tk);
field_print("c", c);
field_print("b", b);
printf("\n\n");
} else if (good) {
successes ++;
decaf_bool_t ret = decaf_448_shared_secret(dshared[i&1], 32, dpriv[i&1], dpub[(i+1)&1]);
if (ret != DECAF_SUCCESS) {
printf("BUG: shared secret returns failure on %d.\n", i);
break;
}
}
if (successes < i) {
printf("PreWNAF combo variation: only %d/%d successful.\n", successes, i);
when = now() - when;
printf("ecdh: %5.1fµs\n", when * 1e6 / i);
if (memcmp(dshared[0], dshared[1], 32)) {
printf("BUG: mismatched shared secrets\n");
}
return 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment