@@ -28,7 +28,7 @@ endif | |||||
FIELD ?= p448 | FIELD ?= p448 | ||||
WARNFLAGS = -pedantic -Wall -Wextra -Werror -Wunreachable-code \ | WARNFLAGS = -pedantic -Wall -Wextra -Werror -Wunreachable-code \ | ||||
-Wmissing-declarations -Wunused-function -Wno-overlength-strings $(EXWARN) | |||||
-Wmissing-declarations -Wunused-function $(EXWARN) | |||||
INCFLAGS = -Isrc/include -Iinclude -Isrc/$(FIELD) -Isrc/$(FIELD)/$(ARCH) | INCFLAGS = -Isrc/include -Iinclude -Isrc/$(FIELD) -Isrc/$(FIELD)/$(ARCH) | ||||
@@ -55,26 +55,17 @@ ifeq ($(CC),clang) | |||||
WARNFLAGS += -Wgcc-compat | WARNFLAGS += -Wgcc-compat | ||||
endif | endif | ||||
ifeq (,$(findstring 64,$(ARCH))$(findstring gcc,$(CC))) | |||||
# ARCHFLAGS += -m32 | |||||
XCFLAGS += -DGOLDI_FORCE_32_BIT=1 | |||||
endif | |||||
ARCHFLAGS += $(XARCHFLAGS) | ARCHFLAGS += $(XARCHFLAGS) | ||||
CFLAGS = $(LANGFLAGS) $(WARNFLAGS) $(INCFLAGS) $(OFLAGS) $(ARCHFLAGS) $(GENFLAGS) $(XCFLAGS) | CFLAGS = $(LANGFLAGS) $(WARNFLAGS) $(INCFLAGS) $(OFLAGS) $(ARCHFLAGS) $(GENFLAGS) $(XCFLAGS) | ||||
CXXFLAGS = $(LANGXXFLAGS) $(WARNFLAGS) $(INCFLAGS) $(OFLAGS) $(ARCHFLAGS) $(GENFLAGS) $(XCXXFLAGS) | CXXFLAGS = $(LANGXXFLAGS) $(WARNFLAGS) $(INCFLAGS) $(OFLAGS) $(ARCHFLAGS) $(GENFLAGS) $(XCXXFLAGS) | ||||
LDFLAGS = $(ARCHFLAGS) $(XLDFLAGS) | LDFLAGS = $(ARCHFLAGS) $(XLDFLAGS) | ||||
ASFLAGS = $(ARCHFLAGS) $(XASFLAGS) | ASFLAGS = $(ARCHFLAGS) $(XASFLAGS) | ||||
.PHONY: clean all test bench test_decaf bench_decaf todo doc lib bat | |||||
.PHONY: clean all test bench todo doc lib bat | |||||
.PRECIOUS: build/%.s | .PRECIOUS: build/%.s | ||||
HEADERS= Makefile $(shell find . -name "*.h") $(shell find . -name "*.hxx") build/timestamp | HEADERS= Makefile $(shell find . -name "*.h") $(shell find . -name "*.hxx") 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 | |||||
DECAFCOMPONENTS= build/$(DECAF).o build/shake.o build/decaf_crypto.o \ | DECAFCOMPONENTS= build/$(DECAF).o build/shake.o build/decaf_crypto.o \ | ||||
build/$(FIELD).o build/f_arithmetic.o # TODO | build/$(FIELD).o build/f_arithmetic.o # TODO | ||||
@@ -82,19 +73,12 @@ ifeq ($(DECAF),decaf_fast) | |||||
DECAFCOMPONENTS += build/decaf_tables.o | DECAFCOMPONENTS += build/decaf_tables.o | ||||
endif | endif | ||||
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 | |||||
TESTDECAFCOMPONENTS=build/test_decaf.o | |||||
BENCHDECAFCOMPONENTS=build/bench_decaf.o | |||||
BENCHCOMPONENTS = build/bench.o build/shake.o | BENCHCOMPONENTS = build/bench.o build/shake.o | ||||
BATBASE=ed448goldilocks-bats-$(TODAY) | |||||
BATBASE=ed448goldilocks-decaf-bats-$(TODAY) | |||||
BATNAME=build/$(BATBASE) | BATNAME=build/$(BATBASE) | ||||
all: lib decaf_lib build/test build/bench build/shakesum | |||||
all: lib build/test build/bench build/shakesum | |||||
scan: clean | scan: clean | ||||
scan-build --use-analyzer=`which clang` \ | scan-build --use-analyzer=`which clang` \ | ||||
@@ -102,36 +86,16 @@ scan: clean | |||||
-enable-checker osx -enable-checker security -enable-checker unix \ | -enable-checker osx -enable-checker security -enable-checker unix \ | ||||
make build/bench build/test all | make build/bench build/test all | ||||
build/bench: $(LIBCOMPONENTS) $(BENCHCOMPONENTS) $(DECAFCOMPONENTS) | |||||
$(LD) $(LDFLAGS) -o $@ $^ | |||||
build/test: $(LIBCOMPONENTS) $(TESTCOMPONENTS) $(DECAFCOMPONENTS) | |||||
$(LD) $(LDFLAGS) -o $@ $^ -lgmp | |||||
build/test_decaf: $(TESTDECAFCOMPONENTS) decaf_lib | |||||
$(LDXX) $(LDFLAGS) -o $@ $< -Lbuild -Wl,-rpath=`pwd`/build -ldecaf | |||||
build/test: build/test_decaf.o lib | |||||
$(LDXX) $(LDFLAGS) -o $@ $< -Lbuild -ldecaf | |||||
build/bench_decaf: $(BENCHDECAFCOMPONENTS) decaf_lib | |||||
$(LDXX) $(LDFLAGS) -o $@ $< -Lbuild -Wl,-rpath=`pwd`/build -ldecaf | |||||
build/bench: build/bench_decaf.o lib | |||||
$(LDXX) $(LDFLAGS) -o $@ $< -Lbuild -ldecaf | |||||
build/shakesum: build/shakesum.o build/shake.o | build/shakesum: build/shakesum.o build/shake.o | ||||
$(LD) $(LDFLAGS) -o $@ $^ | $(LD) $(LDFLAGS) -o $@ $^ | ||||
lib: build/libgoldilocks.so | |||||
decaf_lib: build/libdecaf.so | |||||
build/libgoldilocks.so: $(LIBCOMPONENTS) | |||||
rm -f $@ | |||||
ifeq ($(UNAME),Darwin) | |||||
libtool -macosx_version_min 10.6 -dynamic -dead_strip -lc -x -o $@ \ | |||||
$(LIBCOMPONENTS) | |||||
else | |||||
$(LD) $(LDFLAGS) -shared -Wl,-soname,libgoldilocks.so.1 -Wl,--gc-sections -o $@ $(LIBCOMPONENTS) | |||||
strip --discard-all $@ | |||||
ln -sf `basename $@` build/libgoldilocks.so.1 | |||||
endif | |||||
lib: build/libdecaf.so | |||||
build/libdecaf.so: $(DECAFCOMPONENTS) | build/libdecaf.so: $(DECAFCOMPONENTS) | ||||
rm -f $@ | rm -f $@ | ||||
@@ -190,18 +154,17 @@ bat: $(BATNAME) | |||||
$(BATNAME): include/* src/* src/*/* test/batarch.map | $(BATNAME): include/* src/* src/*/* test/batarch.map | ||||
rm -fr $@ | rm -fr $@ | ||||
for prim in dh sign; do \ | for prim in dh sign; do \ | ||||
targ="$@/crypto_$$prim/ed448goldilocks"; \ | |||||
targ="$@/crypto_$$prim/ed448goldilocks-decaf"; \ | |||||
(while read arch where; do \ | (while read arch where; do \ | ||||
mkdir -p $$targ/`basename $$arch`; \ | mkdir -p $$targ/`basename $$arch`; \ | ||||
cp include/*.h src/*.c src/include/*.h src/bat/$$prim.c src/p448/$$where/*.c src/p448/$$where/*.h src/p448/*.c src/p448/*.h $$targ/`basename $$arch`; \ | cp include/*.h src/*.c src/include/*.h src/bat/$$prim.c src/p448/$$where/*.c src/p448/$$where/*.h src/p448/*.c src/p448/*.h $$targ/`basename $$arch`; \ | ||||
cp src/bat/api_$$prim.h $$targ/`basename $$arch`/api.h; \ | cp src/bat/api_$$prim.h $$targ/`basename $$arch`/api.h; \ | ||||
perl -p -i -e 's/.*endif.*GOLDILOCKS_CONFIG_H/#define SUPERCOP_WONT_LET_ME_OPEN_FILES 1\n\n$$&/' $$targ/`basename $$arch`/config.h; \ | |||||
perl -p -i -e 's/SYSNAME/'`basename $(BATNAME)`_`basename $$arch`'/g' $$targ/`basename $$arch`/api.h; \ | perl -p -i -e 's/SYSNAME/'`basename $(BATNAME)`_`basename $$arch`'/g' $$targ/`basename $$arch`/api.h; \ | ||||
perl -p -i -e 's/__TODAY__/'$(TODAY)'/g' $$targ/`basename $$arch`/api.h; \ | perl -p -i -e 's/__TODAY__/'$(TODAY)'/g' $$targ/`basename $$arch`/api.h; \ | ||||
done \ | done \ | ||||
) < test/batarch.map; \ | ) < test/batarch.map; \ | ||||
echo 'Mike Hamburg' > $$targ/designers; \ | echo 'Mike Hamburg' > $$targ/designers; \ | ||||
echo 'Ed448-Goldilocks sign and dh' > $$targ/description; \ | |||||
echo 'Ed448-Goldilocks Decaf sign and dh' > $$targ/description; \ | |||||
done | done | ||||
(cd build && tar czf $(BATBASE).tgz $(BATBASE) ) | (cd build && tar czf $(BATBASE).tgz $(BATBASE) ) | ||||
@@ -223,17 +186,11 @@ todo:: | |||||
bench: build/bench | bench: build/bench | ||||
./$< | ./$< | ||||
test: build/test test_decaf | |||||
test: build/test | |||||
build/test | build/test | ||||
test_decaf: build/test_decaf | |||||
build/test_decaf | |||||
bench_decaf: build/bench_decaf | |||||
build/bench_decaf | |||||
microbench_decaf: build/bench_decaf | |||||
build/bench_decaf --micro | |||||
microbench: build/bench | |||||
./$< --micro | |||||
clean: | clean: | ||||
rm -fr build doc $(BATNAME) | rm -fr build doc $(BATNAME) |
@@ -1,380 +0,0 @@ | |||||
/* Copyright (c) 2014-2015 Cryptography Research, Inc. | |||||
* Released under the MIT License. See LICENSE.txt for license information. | |||||
*/ | |||||
/** | |||||
* @file goldilocks.h | |||||
* @author Mike Hamburg | |||||
* @brief Goldilocks high-level functions. | |||||
*/ | |||||
#ifndef __GOLDILOCKS_H__ | |||||
#define __GOLDILOCKS_H__ 1 | |||||
#include <stdint.h> | |||||
#ifndef GOLDI_IMPLEMENT_PRECOMPUTED_KEYS | |||||
/** If nonzero, implement precomputation for verify and ECDH. */ | |||||
#define GOLDI_IMPLEMENT_PRECOMPUTED_KEYS 1 | |||||
#endif | |||||
#ifndef GOLDI_IMPLEMENT_SIGNATURES | |||||
/** If nonzero, implement signatures. */ | |||||
#define GOLDI_IMPLEMENT_SIGNATURES 1 | |||||
#endif | |||||
/** The size of the Goldilocks field, in bits. | |||||
* Ifdef'd so you can override when testing experimental Ed480-Ridinghood or E-521. | |||||
*/ | |||||
#ifndef GOLDI_FIELD_BITS | |||||
#define GOLDI_FIELD_BITS 448 | |||||
#endif | |||||
/** The size of the Goldilocks scalars, in bits. */ | |||||
#define GOLDI_SCALAR_BITS (GOLDI_FIELD_BITS-2) | |||||
/** The same size, in bytes. */ | |||||
#define GOLDI_FIELD_BYTES ((GOLDI_FIELD_BITS+7)/8) | |||||
/** The size of a Goldilocks public key, in bytes. */ | |||||
#define GOLDI_PUBLIC_KEY_BYTES GOLDI_FIELD_BYTES | |||||
/** The extra bytes in a Goldilocks private key for the symmetric key. */ | |||||
#define GOLDI_SYMKEY_BYTES 32 | |||||
/** The size of a shared secret. */ | |||||
#define GOLDI_SHARED_SECRET_BYTES 64 | |||||
/** The size of a Goldilocks private key, in bytes. */ | |||||
#define GOLDI_PRIVATE_KEY_BYTES (2*GOLDI_FIELD_BYTES + GOLDI_SYMKEY_BYTES) | |||||
/** The size of a Goldilocks signature, in bytes. */ | |||||
#define GOLDI_SIGNATURE_BYTES (2*GOLDI_FIELD_BYTES) | |||||
/** | |||||
* @brief Serialized form of a Goldilocks public key. | |||||
* | |||||
* @warning This isn't even my final form! | |||||
*/ | |||||
struct goldilocks_public_key_t { | |||||
uint8_t opaque[GOLDI_PUBLIC_KEY_BYTES]; /**< Serialized data. */ | |||||
}; | |||||
/** | |||||
* @brief Serialized form of a Goldilocks private key. | |||||
* | |||||
* Contains 56 bytes of actual private key, 56 bytes of | |||||
* public key, and 32 bytes of symmetric key for randomization. | |||||
* | |||||
* @warning This isn't even my final form! | |||||
*/ | |||||
struct goldilocks_private_key_t { | |||||
uint8_t opaque[GOLDI_PRIVATE_KEY_BYTES]; /**< Serialized data. */ | |||||
}; | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
/** @brief No error. */ | |||||
static const int GOLDI_EOK = 0; | |||||
/** @brief Error: your key or other state is corrupt. */ | |||||
static const int GOLDI_ECORRUPT = 44801; | |||||
/** @brief Error: other party's key is corrupt. */ | |||||
static const int GOLDI_EINVAL = 44802; | |||||
/** @brief Error: not enough entropy. */ | |||||
static const int GOLDI_ENODICE = 44804; | |||||
/** @brief Error: you need to initialize the library first. */ | |||||
static const int GOLDI_EUNINIT = 44805; | |||||
/** @brief Error: called init() but we are already initialized. */ | |||||
static const int GOLDI_EALREADYINIT = 44805; | |||||
/** | |||||
* @brief Initialize Goldilocks' precomputed tables and | |||||
* random number generator. This function must be called before | |||||
* any of the other Goldilocks routines (except | |||||
* goldilocks_shared_secret in the current version) and should be | |||||
* called only once per process. | |||||
* | |||||
* There is currently no way to tear down this state. It is possible | |||||
* that a future version of this library will not require this function. | |||||
* | |||||
* @retval GOLDI_EOK Success. | |||||
* @retval GOLDI_EALREADYINIT Already initialized. | |||||
* @retval GOLDI_ECORRUPT Memory is corrupted, or another thread is already init'ing. | |||||
* @retval Nonzero An error occurred. | |||||
*/ | |||||
int | |||||
goldilocks_init (void) | |||||
__attribute__((warn_unused_result,visibility ("default"))); | |||||
/** | |||||
* @brief Generate a new random keypair. | |||||
* @param [out] privkey The generated private key. | |||||
* @param [out] pubkey The generated public key. | |||||
* | |||||
* @warning This isn't even my final form! | |||||
* | |||||
* @retval GOLDI_EOK Success. | |||||
* @retval GOLDI_ENODICE Insufficient entropy. | |||||
* @retval GOLDI_EUNINIT You must call goldilocks_init() first. | |||||
*/ | |||||
int | |||||
goldilocks_keygen ( | |||||
struct goldilocks_private_key_t *privkey, | |||||
struct goldilocks_public_key_t *pubkey | |||||
) __attribute__((warn_unused_result,nonnull(1,2),visibility ("default"))); | |||||
/** | |||||
* @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. | |||||
* | |||||
* @warning This isn't even my final form! | |||||
* | |||||
* @retval GOLDI_EOK Success. | |||||
* @retval GOLDI_EUNINIT You must call goldilocks_init() first. | |||||
*/ | |||||
int | |||||
goldilocks_derive_private_key ( | |||||
struct goldilocks_private_key_t *privkey, | |||||
const unsigned char proto[GOLDI_SYMKEY_BYTES] | |||||
) __attribute__((nonnull(1,2),visibility ("default"))); | |||||
/** | |||||
* @brief Compress a private key (by copying out the proto-key) | |||||
* @param [out] proto The proto-key. | |||||
* @param [in] privkey The private key. | |||||
* | |||||
* @warning This isn't even my final form! | |||||
* @todo test. | |||||
* | |||||
* @retval GOLDI_EOK Success. | |||||
* @retval GOLDI_EUNINIT You must call goldilocks_init() first. | |||||
*/ | |||||
void | |||||
goldilocks_underive_private_key ( | |||||
unsigned char proto[GOLDI_SYMKEY_BYTES], | |||||
const struct goldilocks_private_key_t *privkey | |||||
) __attribute__((nonnull(1,2),visibility ("default"))); | |||||
/** | |||||
* @brief Extract the public key from a private key. | |||||
* | |||||
* This is essentially a memcpy from the public part of the privkey. | |||||
* | |||||
* @param [out] pubkey The extracted private key. | |||||
* @param [in] privkey The private key. | |||||
* | |||||
* @retval GOLDI_EOK Success. | |||||
* @retval GOLDI_ECORRUPT The private key is corrupt. | |||||
*/ | |||||
int | |||||
goldilocks_private_to_public ( | |||||
struct goldilocks_public_key_t *pubkey, | |||||
const struct goldilocks_private_key_t *privkey | |||||
) __attribute__((nonnull(1,2),visibility ("default"))); | |||||
/** | |||||
* @brief Generate a Diffie-Hellman shared secret in constant time. | |||||
* | |||||
* This function uses some compile-time flags whose merit remains to | |||||
* be decided. | |||||
* | |||||
* If the flag EXPERIMENT_ECDH_OBLITERATE_CT is set, prepend 40 bytes | |||||
* of zeros to the secret before hashing. In the case that the other | |||||
* party's key is detectably corrupt, instead the symmetric part | |||||
* of the secret key is used to produce a pseudorandom value. | |||||
* | |||||
* If EXPERIMENT_ECDH_STIR_IN_PUBKEYS is set, the sum and product of | |||||
* the two parties' public keys is prepended to the hash. | |||||
* | |||||
* In the current version, this function can safely be run even without | |||||
* goldilocks_init(). But this property is not guaranteed for future | |||||
* versions, so call it anyway. | |||||
* | |||||
* @warning This isn't even my final form! | |||||
* | |||||
* @param [out] shared The shared secret established with the other party. | |||||
* @param [in] my_privkey My private key. | |||||
* @param [in] your_pubkey The other party's public key. | |||||
* | |||||
* @retval GOLDI_EOK Success. | |||||
* @retval GOLDI_ECORRUPT My key is corrupt. | |||||
* @retval GOLDI_EINVAL The other party's key is corrupt. | |||||
* @retval GOLDI_EUNINIT You must call goldilocks_init() first. | |||||
*/ | |||||
int | |||||
goldilocks_shared_secret ( | |||||
uint8_t shared[GOLDI_SHARED_SECRET_BYTES], | |||||
const struct goldilocks_private_key_t *my_privkey, | |||||
const struct goldilocks_public_key_t *your_pubkey | |||||
) __attribute__((warn_unused_result,nonnull(1,2,3),visibility ("default"))); | |||||
#if GOLDI_IMPLEMENT_SIGNATURES | |||||
/** | |||||
* @brief Sign a message. | |||||
* | |||||
* The signature is deterministic, using the symmetric secret found in the | |||||
* secret key to form a nonce. | |||||
* | |||||
* The technique used in signing is a modified Schnorr system, like EdDSA. | |||||
* | |||||
* @warning This isn't even my final form! | |||||
* | |||||
* @param [out] signature_out Space for the output signature. | |||||
* @param [in] message The message to be signed. | |||||
* @param [in] message_len The length of the message to be signed. | |||||
* @param [in] privkey My private key. | |||||
* | |||||
* @retval GOLDI_EOK Success. | |||||
* @retval GOLDI_ECORRUPT My key is corrupt. | |||||
* @retval GOLDI_EUNINIT You must call goldilocks_init() first. | |||||
*/ | |||||
int | |||||
goldilocks_sign ( | |||||
uint8_t signature_out[GOLDI_SIGNATURE_BYTES], | |||||
const uint8_t *message, | |||||
uint64_t message_len, | |||||
const struct goldilocks_private_key_t *privkey | |||||
) __attribute__((nonnull(1,2,4),visibility ("default"))); | |||||
/** | |||||
* @brief Verify a signature. | |||||
* | |||||
* This function is fairly strict. It will correctly detect when | |||||
* the signature has the wrong cofactor component, or when the sig | |||||
* values aren't less than p or q. | |||||
* | |||||
* Currently this function does not detect when the public key is weird, | |||||
* eg 0, has cofactor, etc. As a result, a party with a bogus public | |||||
* key could create signatures that succeed on some systems and fail on | |||||
* others. | |||||
* | |||||
* @warning This isn't even my final form! | |||||
* | |||||
* @param [in] signature The signature. | |||||
* @param [in] message The message to be verified. | |||||
* @param [in] message_len The length of the message to be verified. | |||||
* @param [in] pubkey The signer's public key. | |||||
* | |||||
* @retval GOLDI_EOK Success. | |||||
* @retval GOLDI_EINVAL The public key or signature is corrupt. | |||||
* @retval GOLDI_EUNINIT You must call goldilocks_init() first. | |||||
*/ | |||||
int | |||||
goldilocks_verify ( | |||||
const uint8_t signature[GOLDI_SIGNATURE_BYTES], | |||||
const uint8_t *message, | |||||
uint64_t message_len, | |||||
const struct goldilocks_public_key_t *pubkey | |||||
) __attribute__((warn_unused_result,nonnull(1,2,4),visibility ("default"))); | |||||
#endif | |||||
#if GOLDI_IMPLEMENT_PRECOMPUTED_KEYS | |||||
/** A public key which has been expanded by precomputation for higher speed. */ | |||||
struct goldilocks_precomputed_public_key_t; | |||||
/** | |||||
* @brief Expand a public key by precomputation. | |||||
* | |||||
* @todo Give actual error returns, instead of ambiguous NULL. | |||||
* | |||||
* @warning This isn't even my final form! | |||||
* | |||||
* @param [in] pub The public key. | |||||
* @retval NULL We ran out of memory, or the | |||||
*/ | |||||
struct goldilocks_precomputed_public_key_t * | |||||
goldilocks_precompute_public_key ( | |||||
const struct goldilocks_public_key_t *pub | |||||
) __attribute__((warn_unused_result,nonnull(1),visibility ("default"))); | |||||
/** | |||||
* @brief Overwrite an expanded public key with zeros, then destroy it. | |||||
* | |||||
* If the input is NULL, this function does nothing. | |||||
* | |||||
* @param [in] precom The public key. | |||||
*/ | |||||
void | |||||
goldilocks_destroy_precomputed_public_key ( | |||||
struct goldilocks_precomputed_public_key_t *precom | |||||
) __attribute__((visibility ("default"))); | |||||
/** | |||||
* @brief Verify a signature. | |||||
* | |||||
* This function is fairly strict. It will correctly detect when | |||||
* the signature has the wrong cofactor component, or when the sig | |||||
* values aren't less than p or q. | |||||
* | |||||
* @warning This isn't even my final form! | |||||
* | |||||
* @param [in] signature The signature. | |||||
* @param [in] message The message to be verified. | |||||
* @param [in] message_len The length of the message to be verified. | |||||
* @param [in] pubkey The signer's public key, expanded by precomputation. | |||||
* | |||||
* @retval GOLDI_EOK Success. | |||||
* @retval GOLDI_EINVAL The public key or signature is corrupt. | |||||
* @retval GOLDI_EUNINIT You must call goldilocks_init() first. | |||||
*/ | |||||
int | |||||
goldilocks_verify_precomputed ( | |||||
const uint8_t signature[GOLDI_SIGNATURE_BYTES], | |||||
const uint8_t *message, | |||||
uint64_t message_len, | |||||
const struct goldilocks_precomputed_public_key_t *pubkey | |||||
) __attribute__((warn_unused_result,nonnull(1,2,4),visibility ("default"))); | |||||
/** | |||||
* @brief Generate a Diffie-Hellman shared secret in constant time. | |||||
* Uses a precomputation on the other party's public key for efficiency. | |||||
* | |||||
* This function uses some compile-time flags whose merit remains to | |||||
* be decided. | |||||
* | |||||
* If the flag EXPERIMENT_ECDH_OBLITERATE_CT is set, prepend 40 bytes | |||||
* of zeros to the secret before hashing. In the case that the other | |||||
* party's key is detectably corrupt, instead the symmetric part | |||||
* of the secret key is used to produce a pseudorandom value. | |||||
* | |||||
* If EXPERIMENT_ECDH_STIR_IN_PUBKEYS is set, the sum and product of | |||||
* the two parties' public keys is prepended to the hash. | |||||
* | |||||
* In the current version, this function can safely be run even without | |||||
* goldilocks_init(). But this property is not guaranteed for future | |||||
* versions, so call it anyway. | |||||
* | |||||
* @warning This isn't even my final form! | |||||
* | |||||
* @param [out] shared The shared secret established with the other party. | |||||
* @param [in] my_privkey My private key. | |||||
* @param [in] your_pubkey The other party's precomputed public key. | |||||
* | |||||
* @retval GOLDI_EOK Success. | |||||
* @retval GOLDI_ECORRUPT My key is corrupt. | |||||
* @retval GOLDI_EINVAL The other party's key is corrupt. | |||||
* @retval GOLDI_EUNINIT You must call goldilocks_init() first. | |||||
*/ | |||||
int | |||||
goldilocks_shared_secret_precomputed ( | |||||
uint8_t shared[GOLDI_SHARED_SECRET_BYTES], | |||||
const struct goldilocks_private_key_t *my_privkey, | |||||
const struct goldilocks_precomputed_public_key_t *your_pubkey | |||||
) __attribute__((warn_unused_result,nonnull(1,2,3),visibility ("default"))); | |||||
#endif /* GOLDI_IMPLEMENT_PRECOMPUTED_KEYS */ | |||||
#ifdef __cplusplus | |||||
}; /* extern "C" */ | |||||
#endif | |||||
#endif /* __GOLDILOCKS_H__ */ |
@@ -1,376 +0,0 @@ | |||||
/* Copyright (c) 2014 Cryptography Research, Inc. | |||||
* Released under the MIT License. See LICENSE.txt for license information. | |||||
*/ | |||||
/** | |||||
* @file goldilocks.h | |||||
* @author Mike Hamburg | |||||
* @brief Goldilocks high-level functions. | |||||
*/ | |||||
#ifndef __GOLDILOCKS_H__ | |||||
#define __GOLDILOCKS_H__ 1 | |||||
#include <stdint.h> | |||||
#ifndef GOLDI_IMPLEMENT_PRECOMPUTED_KEYS | |||||
/** If nonzero, implement precomputation for verify and ECDH. */ | |||||
#define GOLDI_IMPLEMENT_PRECOMPUTED_KEYS 1 | |||||
#endif | |||||
#ifndef GOLDI_IMPLEMENT_SIGNATURES | |||||
/** If nonzero, implement signatures. */ | |||||
#define GOLDI_IMPLEMENT_SIGNATURES 1 | |||||
#endif | |||||
/** The size of the Goldilocks field, in bits. */ | |||||
#define GOLDI_FIELD_BITS 448 | |||||
/** The size of the Goldilocks scalars, in bits. */ | |||||
#define GOLDI_SCALAR_BITS 446 | |||||
/** The same size, in bytes. */ | |||||
#define GOLDI_FIELD_BYTES (GOLDI_FIELD_BITS/8) | |||||
/** The size of a Goldilocks public key, in bytes. */ | |||||
#define GOLDI_PUBLIC_KEY_BYTES GOLDI_FIELD_BYTES | |||||
/** The extra bytes in a Goldilocks private key for the symmetric key. */ | |||||
#define GOLDI_SYMKEY_BYTES 32 | |||||
/** The size of a shared secret. */ | |||||
#define GOLDI_SHARED_SECRET_BYTES 64 | |||||
/** The size of a Goldilocks private key, in bytes. */ | |||||
#define GOLDI_PRIVATE_KEY_BYTES (2*GOLDI_FIELD_BYTES + GOLDI_SYMKEY_BYTES) | |||||
/** The size of a Goldilocks signature, in bytes. */ | |||||
#define GOLDI_SIGNATURE_BYTES (2*GOLDI_FIELD_BYTES) | |||||
/** | |||||
* @brief Serialized form of a Goldilocks public key. | |||||
* | |||||
* @warning This isn't even my final form! | |||||
*/ | |||||
struct goldilocks_public_key_t { | |||||
uint8_t opaque[GOLDI_PUBLIC_KEY_BYTES]; /**< Serialized data. */ | |||||
}; | |||||
/** | |||||
* @brief Serialized form of a Goldilocks private key. | |||||
* | |||||
* Contains 56 bytes of actual private key, 56 bytes of | |||||
* public key, and 32 bytes of symmetric key for randomization. | |||||
* | |||||
* @warning This isn't even my final form! | |||||
*/ | |||||
struct goldilocks_private_key_t { | |||||
uint8_t opaque[GOLDI_PRIVATE_KEY_BYTES]; /**< Serialized data. */ | |||||
}; | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
/** @brief No error. */ | |||||
static const int GOLDI_EOK = 0; | |||||
/** @brief Error: your key or other state is corrupt. */ | |||||
static const int GOLDI_ECORRUPT = 44801; | |||||
/** @brief Error: other party's key is corrupt. */ | |||||
static const int GOLDI_EINVAL = 44802; | |||||
/** @brief Error: not enough entropy. */ | |||||
static const int GOLDI_ENODICE = 44804; | |||||
/** @brief Error: you need to initialize the library first. */ | |||||
static const int GOLDI_EUNINIT = 44805; | |||||
/** @brief Error: called init() but we are already initialized. */ | |||||
static const int GOLDI_EALREADYINIT = 44805; | |||||
/** | |||||
* @brief Initialize Goldilocks' precomputed tables and | |||||
* random number generator. This function must be called before | |||||
* any of the other Goldilocks routines (except | |||||
* goldilocks_shared_secret in the current version) and should be | |||||
* called only once per process. | |||||
* | |||||
* There is currently no way to tear down this state. It is possible | |||||
* that a future version of this library will not require this function. | |||||
* | |||||
* @retval GOLDI_EOK Success. | |||||
* @retval GOLDI_EALREADYINIT Already initialized. | |||||
* @retval GOLDI_ECORRUPT Memory is corrupted, or another thread is already init'ing. | |||||
* @retval Nonzero An error occurred. | |||||
*/ | |||||
int | |||||
goldilocks_init (void) | |||||
__attribute__((warn_unused_result,visibility ("default"))); | |||||
/** | |||||
* @brief Generate a new random keypair. | |||||
* @param [out] privkey The generated private key. | |||||
* @param [out] pubkey The generated public key. | |||||
* | |||||
* @warning This isn't even my final form! | |||||
* | |||||
* @retval GOLDI_EOK Success. | |||||
* @retval GOLDI_ENODICE Insufficient entropy. | |||||
* @retval GOLDI_EUNINIT You must call goldilocks_init() first. | |||||
*/ | |||||
int | |||||
goldilocks_keygen ( | |||||
struct goldilocks_private_key_t *privkey, | |||||
struct goldilocks_public_key_t *pubkey | |||||
) __attribute__((warn_unused_result,nonnull(1,2),visibility ("default"))); | |||||
/** | |||||
* @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. | |||||
* | |||||
* @warning This isn't even my final form! | |||||
* | |||||
* @retval GOLDI_EOK Success. | |||||
* @retval GOLDI_EUNINIT You must call goldilocks_init() first. | |||||
*/ | |||||
int | |||||
goldilocks_derive_private_key ( | |||||
struct goldilocks_private_key_t *privkey, | |||||
const unsigned char proto[GOLDI_SYMKEY_BYTES] | |||||
) __attribute__((nonnull(1,2),visibility ("default"))); | |||||
/** | |||||
* @brief Compress a private key (by copying out the proto-key) | |||||
* @param [out] proto The proto-key. | |||||
* @param [in] privkey The private key. | |||||
* | |||||
* @warning This isn't even my final form! | |||||
* @todo test. | |||||
* | |||||
* @retval GOLDI_EOK Success. | |||||
* @retval GOLDI_EUNINIT You must call goldilocks_init() first. | |||||
*/ | |||||
void | |||||
goldilocks_underive_private_key ( | |||||
unsigned char proto[GOLDI_SYMKEY_BYTES], | |||||
const struct goldilocks_private_key_t *privkey | |||||
) __attribute__((nonnull(1,2),visibility ("default"))); | |||||
/** | |||||
* @brief Extract the public key from a private key. | |||||
* | |||||
* This is essentially a memcpy from the public part of the privkey. | |||||
* | |||||
* @param [out] pubkey The extracted private key. | |||||
* @param [in] privkey The private key. | |||||
* | |||||
* @retval GOLDI_EOK Success. | |||||
* @retval GOLDI_ECORRUPT The private key is corrupt. | |||||
*/ | |||||
int | |||||
goldilocks_private_to_public ( | |||||
struct goldilocks_public_key_t *pubkey, | |||||
const struct goldilocks_private_key_t *privkey | |||||
) __attribute__((nonnull(1,2),visibility ("default"))); | |||||
/** | |||||
* @brief Generate a Diffie-Hellman shared secret in constant time. | |||||
* | |||||
* This function uses some compile-time flags whose merit remains to | |||||
* be decided. | |||||
* | |||||
* If the flag EXPERIMENT_ECDH_OBLITERATE_CT is set, prepend 40 bytes | |||||
* of zeros to the secret before hashing. In the case that the other | |||||
* party's key is detectably corrupt, instead the symmetric part | |||||
* of the secret key is used to produce a pseudorandom value. | |||||
* | |||||
* If EXPERIMENT_ECDH_STIR_IN_PUBKEYS is set, the sum and product of | |||||
* the two parties' public keys is prepended to the hash. | |||||
* | |||||
* In the current version, this function can safely be run even without | |||||
* goldilocks_init(). But this property is not guaranteed for future | |||||
* versions, so call it anyway. | |||||
* | |||||
* @warning This isn't even my final form! | |||||
* | |||||
* @param [out] shared The shared secret established with the other party. | |||||
* @param [in] my_privkey My private key. | |||||
* @param [in] your_pubkey The other party's public key. | |||||
* | |||||
* @retval GOLDI_EOK Success. | |||||
* @retval GOLDI_ECORRUPT My key is corrupt. | |||||
* @retval GOLDI_EINVAL The other party's key is corrupt. | |||||
* @retval GOLDI_EUNINIT You must call goldilocks_init() first. | |||||
*/ | |||||
int | |||||
goldilocks_shared_secret ( | |||||
uint8_t shared[GOLDI_SHARED_SECRET_BYTES], | |||||
const struct goldilocks_private_key_t *my_privkey, | |||||
const struct goldilocks_public_key_t *your_pubkey | |||||
) __attribute__((warn_unused_result,nonnull(1,2,3),visibility ("default"))); | |||||
#if GOLDI_IMPLEMENT_SIGNATURES | |||||
/** | |||||
* @brief Sign a message. | |||||
* | |||||
* The signature is deterministic, using the symmetric secret found in the | |||||
* secret key to form a nonce. | |||||
* | |||||
* The technique used in signing is a modified Schnorr system, like EdDSA. | |||||
* | |||||
* @warning This isn't even my final form! | |||||
* | |||||
* @param [out] signature_out Space for the output signature. | |||||
* @param [in] message The message to be signed. | |||||
* @param [in] message_len The length of the message to be signed. | |||||
* @param [in] privkey My private key. | |||||
* | |||||
* @retval GOLDI_EOK Success. | |||||
* @retval GOLDI_ECORRUPT My key is corrupt. | |||||
* @retval GOLDI_EUNINIT You must call goldilocks_init() first. | |||||
*/ | |||||
int | |||||
goldilocks_sign ( | |||||
uint8_t signature_out[GOLDI_SIGNATURE_BYTES], | |||||
const uint8_t *message, | |||||
uint64_t message_len, | |||||
const struct goldilocks_private_key_t *privkey | |||||
) __attribute__((nonnull(1,2,4),visibility ("default"))); | |||||
/** | |||||
* @brief Verify a signature. | |||||
* | |||||
* This function is fairly strict. It will correctly detect when | |||||
* the signature has the wrong cofactor component, or when the sig | |||||
* values aren't less than p or q. | |||||
* | |||||
* Currently this function does not detect when the public key is weird, | |||||
* eg 0, has cofactor, etc. As a result, a party with a bogus public | |||||
* key could create signatures that succeed on some systems and fail on | |||||
* others. | |||||
* | |||||
* @warning This isn't even my final form! | |||||
* | |||||
* @param [in] signature The signature. | |||||
* @param [in] message The message to be verified. | |||||
* @param [in] message_len The length of the message to be verified. | |||||
* @param [in] pubkey The signer's public key. | |||||
* | |||||
* @retval GOLDI_EOK Success. | |||||
* @retval GOLDI_EINVAL The public key or signature is corrupt. | |||||
* @retval GOLDI_EUNINIT You must call goldilocks_init() first. | |||||
*/ | |||||
int | |||||
goldilocks_verify ( | |||||
const uint8_t signature[GOLDI_SIGNATURE_BYTES], | |||||
const uint8_t *message, | |||||
uint64_t message_len, | |||||
const struct goldilocks_public_key_t *pubkey | |||||
) __attribute__((warn_unused_result,nonnull(1,2,4),visibility ("default"))); | |||||
#endif | |||||
#if GOLDI_IMPLEMENT_PRECOMPUTED_KEYS | |||||
/** A public key which has been expanded by precomputation for higher speed. */ | |||||
struct goldilocks_precomputed_public_key_t; | |||||
/** | |||||
* @brief Expand a public key by precomputation. | |||||
* | |||||
* @todo Give actual error returns, instead of ambiguous NULL. | |||||
* | |||||
* @warning This isn't even my final form! | |||||
* | |||||
* @param [in] pub The public key. | |||||
* @retval NULL We ran out of memory, or the | |||||
*/ | |||||
struct goldilocks_precomputed_public_key_t * | |||||
goldilocks_precompute_public_key ( | |||||
const struct goldilocks_public_key_t *pub | |||||
) __attribute__((warn_unused_result,nonnull(1),visibility ("default"))); | |||||
/** | |||||
* @brief Overwrite an expanded public key with zeros, then destroy it. | |||||
* | |||||
* If the input is NULL, this function does nothing. | |||||
* | |||||
* @param [in] precom The public key. | |||||
*/ | |||||
void | |||||
goldilocks_destroy_precomputed_public_key ( | |||||
struct goldilocks_precomputed_public_key_t *precom | |||||
) __attribute__((visibility ("default"))); | |||||
/** | |||||
* @brief Verify a signature. | |||||
* | |||||
* This function is fairly strict. It will correctly detect when | |||||
* the signature has the wrong cofactor component, or when the sig | |||||
* values aren't less than p or q. | |||||
* | |||||
* @warning This isn't even my final form! | |||||
* | |||||
* @param [in] signature The signature. | |||||
* @param [in] message The message to be verified. | |||||
* @param [in] message_len The length of the message to be verified. | |||||
* @param [in] pubkey The signer's public key, expanded by precomputation. | |||||
* | |||||
* @retval GOLDI_EOK Success. | |||||
* @retval GOLDI_EINVAL The public key or signature is corrupt. | |||||
* @retval GOLDI_EUNINIT You must call goldilocks_init() first. | |||||
*/ | |||||
int | |||||
goldilocks_verify_precomputed ( | |||||
const uint8_t signature[GOLDI_SIGNATURE_BYTES], | |||||
const uint8_t *message, | |||||
uint64_t message_len, | |||||
const struct goldilocks_precomputed_public_key_t *pubkey | |||||
) __attribute__((warn_unused_result,nonnull(1,2,4),visibility ("default"))); | |||||
/** | |||||
* @brief Generate a Diffie-Hellman shared secret in constant time. | |||||
* Uses a precomputation on the other party's public key for efficiency. | |||||
* | |||||
* This function uses some compile-time flags whose merit remains to | |||||
* be decided. | |||||
* | |||||
* If the flag EXPERIMENT_ECDH_OBLITERATE_CT is set, prepend 40 bytes | |||||
* of zeros to the secret before hashing. In the case that the other | |||||
* party's key is detectably corrupt, instead the symmetric part | |||||
* of the secret key is used to produce a pseudorandom value. | |||||
* | |||||
* If EXPERIMENT_ECDH_STIR_IN_PUBKEYS is set, the sum and product of | |||||
* the two parties' public keys is prepended to the hash. | |||||
* | |||||
* In the current version, this function can safely be run even without | |||||
* goldilocks_init(). But this property is not guaranteed for future | |||||
* versions, so call it anyway. | |||||
* | |||||
* @warning This isn't even my final form! | |||||
* | |||||
* @param [out] shared The shared secret established with the other party. | |||||
* @param [in] my_privkey My private key. | |||||
* @param [in] your_pubkey The other party's precomputed public key. | |||||
* | |||||
* @retval GOLDI_EOK Success. | |||||
* @retval GOLDI_ECORRUPT My key is corrupt. | |||||
* @retval GOLDI_EINVAL The other party's key is corrupt. | |||||
* @retval GOLDI_EUNINIT You must call goldilocks_init() first. | |||||
*/ | |||||
int | |||||
goldilocks_shared_secret_precomputed ( | |||||
uint8_t shared[GOLDI_SHARED_SECRET_BYTES], | |||||
const struct goldilocks_private_key_t *my_privkey, | |||||
const struct goldilocks_precomputed_public_key_t *your_pubkey | |||||
) __attribute__((warn_unused_result,nonnull(1,2,3),visibility ("default"))); | |||||
#endif /* GOLDI_IMPLEMENT_PRECOMPUTED_KEYS */ | |||||
#ifdef __cplusplus | |||||
}; /* extern "C" */ | |||||
#endif | |||||
#endif /* __GOLDILOCKS_H__ */ |
@@ -1,87 +0,0 @@ | |||||
/** | |||||
* @cond internal | |||||
* @file field.c | |||||
* @copyright | |||||
* Copyright (c) 2014 Cryptography Research, Inc. \n | |||||
* Released under the MIT License. See LICENSE.txt for license information. | |||||
* @author Mike Hamburg | |||||
* @brief High-level arithmetic routines, independent of field (except 3 mod 4). | |||||
*/ | |||||
#include "field.h" | |||||
#include "ec_point.h" | |||||
mask_t | |||||
field_eq ( | |||||
const field_a_t a, | |||||
const field_a_t b | |||||
) { | |||||
field_a_t ra, rb; | |||||
field_copy(ra, a); | |||||
field_copy(rb, b); | |||||
field_weak_reduce(ra); | |||||
field_weak_reduce(rb); | |||||
field_sub_RAW(ra, ra, rb); | |||||
field_bias(ra, 2); | |||||
return field_is_zero(ra); | |||||
} | |||||
void | |||||
field_inverse ( | |||||
field_a_t a, | |||||
const field_a_t x | |||||
) { | |||||
field_a_t L0, L1; | |||||
field_isr ( L0, x ); | |||||
field_sqr ( L1, L0 ); | |||||
field_sqr ( L0, L1 ); | |||||
field_mul ( a, x, L0 ); | |||||
} | |||||
mask_t | |||||
field_is_square ( | |||||
const field_a_t x | |||||
) { | |||||
field_a_t L0, L1; | |||||
field_isr ( L0, x ); | |||||
field_sqr ( L1, L0 ); | |||||
field_mul ( L0, x, L1 ); | |||||
field_subw( L0, 1 ); | |||||
return field_is_zero( L0 ) | field_is_zero( x ); | |||||
} | |||||
void | |||||
field_simultaneous_invert ( | |||||
field_a_t *__restrict__ out, | |||||
const field_a_t *in, | |||||
unsigned int n | |||||
) { | |||||
if (n==0) { | |||||
return; | |||||
} else if (n==1) { | |||||
field_inverse(out[0],in[0]); | |||||
return; | |||||
} | |||||
field_copy(out[1], in[0]); | |||||
int i; | |||||
for (i=1; i<(int) (n-1); i++) { | |||||
field_mul(out[i+1], out[i], in[i]); | |||||
} | |||||
field_mul(out[0], out[n-1], in[n-1]); | |||||
field_a_t tmp; | |||||
field_inverse(tmp, out[0]); | |||||
field_copy(out[0], tmp); | |||||
/* at this point, out[0] = product(in[i]) ^ -1 | |||||
* out[i] = product(in[0]..in[i-1]) if i != 0 | |||||
*/ | |||||
for (i=n-1; i>0; i--) { | |||||
field_mul(tmp, out[i], out[0]); | |||||
field_copy(out[i], tmp); | |||||
field_mul(tmp, out[0], in[i]); | |||||
field_copy(out[0], tmp); | |||||
} | |||||
} |
@@ -1,349 +0,0 @@ | |||||
/* Copyright (c) 2014 Cryptography Research, Inc. | |||||
* Released under the MIT License. See LICENSE.txt for license information. | |||||
*/ | |||||
#include "barrett_field.h" | |||||
#include <string.h> | |||||
#include <assert.h> | |||||
word_t | |||||
add_nr_ext_packed( | |||||
word_t *out, | |||||
const word_t *a, | |||||
uint32_t nwords_a, | |||||
const word_t *c, | |||||
uint32_t nwords_c, | |||||
word_t mask | |||||
) { | |||||
uint32_t i; | |||||
dword_t carry = 0; | |||||
for (i=0; i<nwords_c; i++) { | |||||
out[i] = carry = carry + a[i] + (c[i]&mask); | |||||
carry >>= WORD_BITS; | |||||
} | |||||
for (; i<nwords_a; i++) { | |||||
out[i] = carry = carry + a[i]; | |||||
carry >>= WORD_BITS; | |||||
} | |||||
return carry; | |||||
} | |||||
static __inline__ word_t | |||||
add_nr_packed( | |||||
word_t *a, | |||||
const word_t *c, | |||||
uint32_t nwords | |||||
) { | |||||
uint32_t i; | |||||
dword_t carry = 0; | |||||
for (i=0; i<nwords; i++) { | |||||
a[i] = carry = carry + a[i] + c[i]; | |||||
carry >>= WORD_BITS; | |||||
} | |||||
return carry; | |||||
} | |||||
word_t | |||||
sub_nr_ext_packed( | |||||
word_t *out, | |||||
const word_t *a, | |||||
uint32_t nwords_a, | |||||
const word_t *c, | |||||
uint32_t nwords_c, | |||||
word_t mask | |||||
) { | |||||
uint32_t i; | |||||
dsword_t carry = 0; | |||||
for (i=0; i<nwords_c; i++) { | |||||
out[i] = carry = carry + a[i] - (c[i]&mask); | |||||
carry >>= WORD_BITS; | |||||
} | |||||
for (; i<nwords_a; i++) { | |||||
out[i] = carry = carry + a[i]; | |||||
carry >>= WORD_BITS; | |||||
} | |||||
return carry; | |||||
} | |||||
static word_t | |||||
widemac( | |||||
word_t *accum, | |||||
uint32_t nwords_accum, | |||||
const word_t *mier, | |||||
uint32_t nwords_mier, | |||||
word_t mand, | |||||
word_t carry | |||||
) { | |||||
uint32_t i; | |||||
assert(nwords_mier <= nwords_accum); | |||||
for (i=0; i<nwords_mier; i++) { | |||||
#ifdef __clang_analyzer__ | |||||
/* always true, but this satisfies scan-build (bug in scan-build?) */ | |||||
assert(i<nwords_accum); | |||||
#endif | |||||
/* UMAAL chain for the wordy part of p */ | |||||
dword_t product = ((dword_t)mand) * mier[i]; | |||||
product += accum[i]; | |||||
product += carry; | |||||
accum[i] = product; | |||||
carry = product >> WORD_BITS; | |||||
} | |||||
for (; i<nwords_accum; i++) { | |||||
dword_t sum = ((dword_t)carry) + accum[i]; | |||||
accum[i] = sum; | |||||
carry = sum >> WORD_BITS; | |||||
} | |||||
return carry; | |||||
} | |||||
void | |||||
barrett_negate ( | |||||
word_t *a, | |||||
uint32_t nwords_a, | |||||
const struct barrett_prime_t *prime | |||||
) { | |||||
uint32_t i; | |||||
dsword_t carry = 0; | |||||
barrett_reduce(a,nwords_a,0,prime); | |||||
/* Have p = 2^big - p_lo. Want p - a = 2^big - p_lo - a */ | |||||
for (i=0; i<prime->nwords_lo; i++) { | |||||
a[i] = carry = carry - prime->p_lo[i] - a[i]; | |||||
carry >>= WORD_BITS; | |||||
} | |||||
for (; i<prime->nwords_p; i++) { | |||||
a[i] = carry = carry - a[i]; | |||||
if (i<prime->nwords_p-1) { | |||||
carry >>= WORD_BITS; | |||||
} | |||||
} | |||||
a[prime->nwords_p-1] = carry = carry + (((word_t)1) << prime->p_shift); | |||||
for (; i<nwords_a; i++) { | |||||
assert(!a[i]); | |||||
} | |||||
assert(!(carry>>WORD_BITS)); | |||||
} | |||||
void | |||||
barrett_reduce( | |||||
word_t *a, | |||||
uint32_t nwords_a, | |||||
word_t a_carry, | |||||
const struct barrett_prime_t *prime | |||||
) { | |||||
uint32_t repeat, nwords_left_in_a=nwords_a; | |||||
/* Is there a point to this a_carry business? */ | |||||
assert(a_carry < ((word_t)1) << prime->p_shift); | |||||
assert(nwords_a >= prime->nwords_p); | |||||
assert(prime->nwords_p > 0); /* scan-build: prevent underflow */ | |||||
for (; nwords_left_in_a >= prime->nwords_p; nwords_left_in_a--) { | |||||
for (repeat=0; repeat<2; repeat++) { | |||||
/* PERF: surely a more careful implementation could | |||||
* avoid this double round | |||||
*/ | |||||
word_t mand = a[nwords_left_in_a-1] >> prime->p_shift; | |||||
a[nwords_left_in_a-1] &= (((word_t)1)<<prime->p_shift)-1; | |||||
if (prime->p_shift && !repeat) { | |||||
/* collect high bits when there are any */ | |||||
if (nwords_left_in_a < nwords_a) { | |||||
mand |= a[nwords_left_in_a] << (WORD_BITS-prime->p_shift); | |||||
a[nwords_left_in_a] = 0; | |||||
} else { | |||||
mand |= a_carry << (WORD_BITS-prime->p_shift); | |||||
} | |||||
} | |||||
word_t carry = widemac( | |||||
a+nwords_left_in_a-prime->nwords_p, | |||||
prime->nwords_p, | |||||
prime->p_lo, | |||||
prime->nwords_lo, | |||||
mand, | |||||
0 | |||||
); | |||||
assert(!carry); | |||||
(void)carry; | |||||
} | |||||
} | |||||
assert(nwords_left_in_a == prime->nwords_p-1); | |||||
/* OK, but it still isn't reduced. Add and subtract p_lo. */ | |||||
word_t cout = add_nr_ext_packed(a,a,prime->nwords_p,prime->p_lo,prime->nwords_lo,-1); | |||||
if (prime->p_shift) { | |||||
cout = (cout<<(WORD_BITS-prime->p_shift)) + (a[prime->nwords_p-1]>>prime->p_shift); | |||||
a[prime->nwords_p-1] &= (((word_t)1)<<prime->p_shift)-1; | |||||
} | |||||
/* mask = carry-1: if no carry then do sub, otherwise don't */ | |||||
sub_nr_ext_packed(a,a,prime->nwords_p,prime->p_lo,prime->nwords_lo,cout-1); | |||||
} | |||||
/* PERF: This function is horribly slow. Enough to break 1%. */ | |||||
void | |||||
barrett_mul_or_mac( | |||||
word_t *accum, | |||||
uint32_t nwords_accum, | |||||
const word_t *a, | |||||
uint32_t nwords_a, | |||||
const word_t *b, | |||||
uint32_t nwords_b, | |||||
const struct barrett_prime_t *prime, | |||||
mask_t doMac | |||||
) { | |||||
assert(nwords_accum >= prime->nwords_p); | |||||
/* nwords_tmp = max(nwords_a + 1, nwords_p + 1, nwords_accum if doMac); */ | |||||
uint32_t nwords_tmp = (nwords_a > prime->nwords_p) ? nwords_a : prime->nwords_p; | |||||
nwords_tmp++; | |||||
assert(nwords_tmp > 0); /* scan-build: prevent underflow. */ | |||||
if (nwords_tmp < nwords_accum && doMac) | |||||
nwords_tmp = nwords_accum; | |||||
word_t tmp[nwords_tmp]; | |||||
int bpos, idown; | |||||
uint32_t i; | |||||
for (i=0; i<nwords_tmp; i++) { | |||||
tmp[i] = 0; | |||||
} | |||||
for (bpos=nwords_b-1; bpos >= 0; bpos--) { | |||||
/* Invariant at the beginning of the loop: the high word is unused. */ | |||||
assert(tmp[nwords_tmp-1] == 0); | |||||
/* shift up */ | |||||
for (idown=nwords_tmp-2; idown>=0; idown--) { | |||||
tmp[idown+1] = tmp[idown]; | |||||
} | |||||
tmp[0] = 0; | |||||
/* mac and reduce */ | |||||
word_t carry = widemac(tmp, nwords_tmp, a, nwords_a, b[bpos], 0); | |||||
/* the mac can't carry, because nwords_tmp >= nwords_a+1 and its high word is clear */ | |||||
assert(!carry); | |||||
barrett_reduce(tmp, nwords_tmp, carry, prime); | |||||
/* at this point, the number of words used is nwords_p <= nwords_tmp-1, | |||||
* so the high word is again clear */ | |||||
} | |||||
if (doMac) { | |||||
word_t cout = add_nr_packed(tmp, accum, nwords_accum); | |||||
barrett_reduce(tmp, nwords_tmp, cout, prime); | |||||
} | |||||
for (i=0; i<nwords_tmp && i<nwords_accum; i++) { | |||||
accum[i] = tmp[i]; | |||||
} | |||||
for (; i<nwords_tmp; i++) { | |||||
assert(tmp[i] == 0); | |||||
} | |||||
for (; i<nwords_accum; i++) { | |||||
accum[i] = 0; | |||||
} | |||||
} | |||||
mask_t | |||||
barrett_deserialize ( | |||||
word_t *x, | |||||
const uint8_t *serial, | |||||
const struct barrett_prime_t *prime | |||||
) { | |||||
unsigned int i,j,nserial = prime->nwords_p * sizeof(word_t); | |||||
if (prime->p_shift) { | |||||
nserial -= (WORD_BITS - prime->p_shift) / 8; | |||||
} | |||||
/* Track x < p, p = 2^k - p_lo <==> x + p_lo < 2^k */ | |||||
dword_t carry = 0; | |||||
for (i=0; i*sizeof(word_t)<nserial; i++) { | |||||
carry >>= WORD_BITS; | |||||
word_t the = 0; | |||||
for (j=0; j<sizeof(word_t) && sizeof(word_t)*i+j < nserial; j++) { | |||||
the |= ((word_t)serial[sizeof(word_t)*i+j]) << (8*j); | |||||
} | |||||
x[i] = the; | |||||
carry += the; | |||||
if (i < prime->nwords_lo) carry += prime->p_lo[i]; | |||||
} | |||||
/* check for reduction */ | |||||
if (prime->p_shift) { | |||||
carry >>= prime->p_shift; | |||||
} else { | |||||
carry >>= WORD_BITS; | |||||
} | |||||
/* at this point, carry > 0 indicates failure */ | |||||
dsword_t scarry = carry; | |||||
scarry = -scarry; | |||||
scarry >>= WORD_BITS; | |||||
scarry >>= WORD_BITS; | |||||
return (mask_t) ~scarry; | |||||
} | |||||
void | |||||
barrett_deserialize_and_reduce ( | |||||
word_t *x, | |||||
const uint8_t *serial, | |||||
uint32_t nserial, | |||||
const struct barrett_prime_t *prime | |||||
) { | |||||
unsigned int size = (nserial + sizeof(word_t) - 1)/sizeof(word_t); | |||||
if (size < prime->nwords_p) { | |||||
size = prime->nwords_p; | |||||
} | |||||
word_t tmp[size]; | |||||
memset(tmp,0,sizeof(tmp)); | |||||
unsigned int i,j; | |||||
for (i=0; i*sizeof(word_t)<nserial; i++) { | |||||
word_t the = 0; | |||||
for (j=0; j<sizeof(word_t) && sizeof(word_t)*i+j < nserial; j++) { | |||||
the |= ((word_t)serial[sizeof(word_t)*i+j]) << (8*j); | |||||
} | |||||
tmp[i] = the; | |||||
} | |||||
barrett_reduce(tmp,size,0,prime); | |||||
for (i=0; i<prime->nwords_p; i++) { | |||||
x[i] = tmp[i]; | |||||
} | |||||
for (; i<size; i++) { | |||||
assert(!tmp[i]); | |||||
} | |||||
} | |||||
void | |||||
barrett_serialize ( | |||||
uint8_t *serial, | |||||
const word_t *x, | |||||
uint32_t nserial | |||||
) { | |||||
unsigned int i,j; | |||||
for (i=0; i*sizeof(word_t)<nserial; i++) { | |||||
for (j=0; j<sizeof(word_t); j++) { | |||||
serial[sizeof(word_t)*i+j] = x[i]>>(8*j); | |||||
} | |||||
} | |||||
} |
@@ -8,11 +8,11 @@ | |||||
*/ | */ | ||||
#include <string.h> | #include <string.h> | ||||
#include "goldilocks.h" | |||||
#include "decaf_crypto.h" | |||||
#define PUBLICKEY_BYTES GOLDI_PUBLIC_KEY_BYTES | |||||
#define SECRETKEY_BYTES GOLDI_PRIVATE_KEY_BYTES | |||||
#define SHAREDSECRET_BYTES GOLDI_SHARED_SECRET_BYTES | |||||
#define PUBLICKEY_BYTES (sizeof(decaf_448_public_key_t)) | |||||
#define SECRETKEY_BYTES (sizeof(decaf_448_private_key_t)) | |||||
#define SHAREDSECRET_BYTES 32 | |||||
#define CRYPTO_PUBLICKEYBYTES PUBLICKEY_BYTES | #define CRYPTO_PUBLICKEYBYTES PUBLICKEY_BYTES | ||||
#define CRYPTO_SECRETKEYBYTES SECRETKEY_BYTES | #define CRYPTO_SECRETKEYBYTES SECRETKEY_BYTES | ||||
@@ -10,9 +10,9 @@ | |||||
#include <string.h> | #include <string.h> | ||||
#include "goldilocks.h" | #include "goldilocks.h" | ||||
#define PUBLICKEY_BYTES GOLDI_PUBLIC_KEY_BYTES | |||||
#define SECRETKEY_BYTES GOLDI_PRIVATE_KEY_BYTES | |||||
#define SIGNATURE_BYTES GOLDI_SIGNATURE_BYTES | |||||
#define PUBLICKEY_BYTES (sizeof(decaf_448_public_key_t)) | |||||
#define SECRETKEY_BYTES (sizeof(decaf_448_private_key_t)) | |||||
#define SIGNATURE_BYTES (sizeof(decaf_448_signature_t)) | |||||
#define CRYPTO_PUBLICKEYBYTES PUBLICKEY_BYTES | #define CRYPTO_PUBLICKEYBYTES PUBLICKEY_BYTES | ||||
#define CRYPTO_SECRETKEYBYTES SECRETKEY_BYTES | #define CRYPTO_SECRETKEYBYTES SECRETKEY_BYTES | ||||
@@ -11,20 +11,20 @@ | |||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include "api.h" | #include "api.h" | ||||
#include "crypto_dh.h" | #include "crypto_dh.h" | ||||
#include "randombytes.h" | |||||
int crypto_dh_keypair ( | int crypto_dh_keypair ( | ||||
unsigned char pk[SECRETKEY_BYTES], | unsigned char pk[SECRETKEY_BYTES], | ||||
unsigned char sk[PUBLICKEY_BYTES] | unsigned char sk[PUBLICKEY_BYTES] | ||||
) { | ) { | ||||
int ret; | |||||
ret = goldilocks_init(); | |||||
if (ret && ret != GOLDI_EALREADYINIT) | |||||
return ret; | |||||
if ((ret = goldilocks_keygen( | |||||
(struct goldilocks_private_key_t *)sk, | |||||
(struct goldilocks_public_key_t *)pk | |||||
))) abort(); | |||||
return ret; | |||||
decaf_448_symmetric_key_t proto; | |||||
randombytes(proto,sizeof(proto)); | |||||
decaf_448_derive_private_key((decaf_448_private_key_s *)sk,proto); | |||||
decaf_448_private_to_public( | |||||
(decaf_448_public_key_s *)pk, | |||||
(decaf_448_private_key_s *)sk | |||||
); | |||||
return 0; | |||||
} | } | ||||
int crypto_dh ( | int crypto_dh ( | ||||
@@ -32,9 +32,10 @@ int crypto_dh ( | |||||
const unsigned char pk[PUBLICKEY_BYTES], | const unsigned char pk[PUBLICKEY_BYTES], | ||||
const unsigned char sk[SECRETKEY_BYTES] | const unsigned char sk[SECRETKEY_BYTES] | ||||
) { | ) { | ||||
return goldilocks_shared_secret ( | |||||
return !decaf_448_shared_secret ( | |||||
s, | s, | ||||
(const struct goldilocks_private_key_t *)sk, | |||||
(const struct goldilocks_public_key_t *)pk | |||||
); | |||||
SHAREDSECRET_BYTES, | |||||
(const decaf_448_private_key_s *)sk, | |||||
(const decaf_448_public_key_s *)pk | |||||
); | |||||
} | } |
@@ -16,15 +16,14 @@ int crypto_sign_keypair ( | |||||
unsigned char pk[SECRETKEY_BYTES], | unsigned char pk[SECRETKEY_BYTES], | ||||
unsigned char sk[PUBLICKEY_BYTES] | unsigned char sk[PUBLICKEY_BYTES] | ||||
) { | ) { | ||||
int ret; | |||||
ret = goldilocks_init(); | |||||
if (ret && ret != GOLDI_EALREADYINIT) | |||||
return ret; | |||||
if ((ret = goldilocks_keygen( | |||||
(struct goldilocks_private_key_t *)sk, | |||||
(struct goldilocks_public_key_t *)pk | |||||
))) abort(); | |||||
return ret; | |||||
decaf_448_symmetric_key_t proto; | |||||
randombytes(proto,sizeof(proto)); | |||||
decaf_448_derive_private_key((decaf_448_private_key_s *)sk,proto); | |||||
decaf_448_private_to_public( | |||||
(decaf_448_public_key_s *)pk, | |||||
(decaf_448_private_key_s *)sk | |||||
); | |||||
return 0; | |||||
} | } | ||||
int crypto_sign ( | int crypto_sign ( | ||||
@@ -35,16 +34,15 @@ int crypto_sign ( | |||||
const unsigned char sk[SECRETKEY_BYTES] | const unsigned char sk[SECRETKEY_BYTES] | ||||
) { | ) { | ||||
unsigned char sig[SIGNATURE_BYTES]; | unsigned char sig[SIGNATURE_BYTES]; | ||||
int ret = goldilocks_sign( | |||||
sig, m, mlen, | |||||
(const struct goldilocks_private_key_t *)sk | |||||
decaf_448_sign( | |||||
sig, | |||||
(const struct goldilocks_private_key_t *)sk, | |||||
m, mlen | |||||
); | ); | ||||
if (!ret) { | |||||
memmove(sm + SIGNATURE_BYTES, m, mlen); | |||||
memcpy(sm, sig, SIGNATURE_BYTES); | |||||
*smlen = mlen + SIGNATURE_BYTES; | |||||
} | |||||
return ret ? -1 : 0; | |||||
memmove(sm + SIGNATURE_BYTES, m, mlen); | |||||
memcpy(sm, sig, SIGNATURE_BYTES); | |||||
*smlen = mlen + SIGNATURE_BYTES; | |||||
return 0; | |||||
} | } | ||||
int crypto_sign_open ( | int crypto_sign_open ( | ||||
@@ -54,13 +52,14 @@ int crypto_sign_open ( | |||||
unsigned long long smlen, | unsigned long long smlen, | ||||
const unsigned char pk[PUBLICKEY_BYTES] | const unsigned char pk[PUBLICKEY_BYTES] | ||||
) { | ) { | ||||
int ret = goldilocks_verify( | |||||
sm, sm + SIGNATURE_BYTES, smlen - SIGNATURE_BYTES, | |||||
(const struct goldilocks_public_key_t *)pk | |||||
int ret = decaf_448_verify( | |||||
sm, | |||||
(const struct goldilocks_public_key_t *)pk, | |||||
sm + SIGNATURE_BYTES, smlen - SIGNATURE_BYTES | |||||
); | ); | ||||
if (!ret) { | |||||
if (ret) { | |||||
*mlen = smlen - SIGNATURE_BYTES; | *mlen = smlen - SIGNATURE_BYTES; | ||||
memmove(m, sm + SIGNATURE_BYTES, *mlen); | memmove(m, sm + SIGNATURE_BYTES, *mlen); | ||||
} | } | ||||
return ret ? -1 : 0; | |||||
return ret ? 0 : -1; | |||||
} | } |
@@ -1,488 +0,0 @@ | |||||
/* Copyright (c) 2011 Stanford University. | |||||
* Copyright (c) 2014 Cryptography Research, Inc. | |||||
* Released under the MIT License. See LICENSE.txt for license information. | |||||
*/ | |||||
/* Chacha random number generator code copied from crandom */ | |||||
#include "crandom.h" | |||||
#include "intrinsics.h" | |||||
#include "config.h" | |||||
#include "magic.h" | |||||
#include <stdio.h> | |||||
volatile unsigned int crandom_features = 0; | |||||
unsigned int crandom_detect_features(void) { | |||||
unsigned int out = GEN; | |||||
# if (defined(__i386__) || defined(__x86_64__)) | |||||
u_int32_t a,b,c,d; | |||||
a=1; __asm__("cpuid" : "+a"(a), "=b"(b), "=c"(c), "=d"(d)); | |||||
out |= GEN; | |||||
if (d & 1<<26) out |= SSE2; | |||||
if (d & 1<< 9) out |= SSSE3; | |||||
if (c & 1<<25) out |= AESNI; | |||||
if (c & 1<<28) out |= AVX; | |||||
if (b & 1<<5) out |= AVX2; | |||||
if (c & 1<<30) out |= RDRAND; | |||||
a=0x80000001; __asm__("cpuid" : "+a"(a), "=b"(b), "=c"(c), "=d"(d)); | |||||
if (c & 1<<11) out |= XOP; | |||||
# endif | |||||
return out; | |||||
} | |||||
INTRINSIC u_int64_t rdrand(int abort_on_fail) { | |||||
uint64_t out = 0; | |||||
int tries = 1000; | |||||
if (HAVE(RDRAND)) { | |||||
# if defined(__x86_64__) | |||||
u_int64_t out, a=0; | |||||
for (; tries && !a; tries--) { | |||||
__asm__ __volatile__ ( | |||||
"rdrand %0\n\tsetc %%al" | |||||
: "=r"(out), "+a"(a) :: "cc" | |||||
); | |||||
} | |||||
# elif (defined(__i386__)) | |||||
u_int32_t reg, a=0; | |||||
uint64_t out; | |||||
for (; tries && !a; tries--) { | |||||
__asm__ __volatile__ ( | |||||
"rdrand %0\n\tsetc %%al" | |||||
: "=r"(reg), "+a"(a) :: "cc" | |||||
); | |||||
} | |||||
out = reg; a = 0; | |||||
for (; tries && !a; tries--) { | |||||
__asm__ __volatile__ ( | |||||
"rdrand %0\n\tsetc %%al" | |||||
: "=r"(reg), "+a"(a) :: "cc" | |||||
); | |||||
} | |||||
out = out << 32 | reg; | |||||
return out; | |||||
# else | |||||
abort(); /* whut */ | |||||
# endif | |||||
} else { | |||||
tries = 0; | |||||
} | |||||
if (abort_on_fail && !tries) { | |||||
abort(); | |||||
} | |||||
return out; | |||||
} | |||||
/* ------------------------------- Vectorized code ------------------------------- */ | |||||
#define shuffle(x,i) _mm_shuffle_epi32(x, \ | |||||
i + ((i+1)&3)*4 + ((i+2)&3)*16 + ((i+3)&3)*64) | |||||
#define add _mm_add_epi32 | |||||
#define add64 _mm_add_epi64 | |||||
#define NEED_XOP (MIGHT_HAVE(XOP)) | |||||
#define NEED_SSSE3 (MIGHT_HAVE(SSSE3) && !MUST_HAVE(XOP)) | |||||
#define NEED_SSE2 (MIGHT_HAVE(SSE2) && !MUST_HAVE(SSSE3)) | |||||
#define NEED_CONV (!MUST_HAVE(SSE2)) | |||||
#if NEED_XOP | |||||
static __inline__ void | |||||
quarter_round_xop( | |||||
ssereg *a, | |||||
ssereg *b, | |||||
ssereg *c, | |||||
ssereg *d | |||||
) { | |||||
*a = add(*a,*b); *d = xop_rotate(16, *d ^ *a); | |||||
*c = add(*c,*d); *b = xop_rotate(12, *b ^ *c); | |||||
*a = add(*a,*b); *d = xop_rotate(8, *d ^ *a); | |||||
*c = add(*c,*d); *b = xop_rotate(7, *b ^ *c); | |||||
} | |||||
#endif | |||||
#if NEED_SSSE3 | |||||
static const ssereg shuffle8 = { 0x0605040702010003ull, 0x0E0D0C0F0A09080Bull }; | |||||
static const ssereg shuffle16 = { 0x0504070601000302ull, 0x0D0C0F0E09080B0Aull }; | |||||
INTRINSIC ssereg ssse3_rotate_8(ssereg a) { | |||||
return _mm_shuffle_epi8(a, shuffle8); | |||||
} | |||||
INTRINSIC ssereg ssse3_rotate_16(ssereg a) { | |||||
return _mm_shuffle_epi8(a, shuffle16); | |||||
} | |||||
static __inline__ void | |||||
quarter_round_ssse3( | |||||
ssereg *a, | |||||
ssereg *b, | |||||
ssereg *c, | |||||
ssereg *d | |||||
) { | |||||
*a = add(*a,*b); *d = ssse3_rotate_16(*d ^ *a); | |||||
*c = add(*c,*d); *b = sse2_rotate(12, *b ^ *c); | |||||
*a = add(*a,*b); *d = ssse3_rotate_8( *d ^ *a); | |||||
*c = add(*c,*d); *b = sse2_rotate(7, *b ^ *c); | |||||
} | |||||
#endif /* MIGHT_HAVE(SSSE3) && !MUST_HAVE(XOP) */ | |||||
#if NEED_SSE2 | |||||
static __inline__ void | |||||
quarter_round_sse2( | |||||
ssereg *a, | |||||
ssereg *b, | |||||
ssereg *c, | |||||
ssereg *d | |||||
) { | |||||
*a = add(*a,*b); *d = sse2_rotate(16, *d ^ *a); | |||||
*c = add(*c,*d); *b = sse2_rotate(12, *b ^ *c); | |||||
*a = add(*a,*b); *d = sse2_rotate(8, *d ^ *a); | |||||
*c = add(*c,*d); *b = sse2_rotate(7, *b ^ *c); | |||||
} | |||||
#endif | |||||
#define DOUBLE_ROUND(qrf) { \ | |||||
qrf(&a1,&b1,&c1,&d1); \ | |||||
qrf(&a2,&b2,&c2,&d2); \ | |||||
b1 = shuffle(b1,1); \ | |||||
c1 = shuffle(c1,2); \ | |||||
d1 = shuffle(d1,3); \ | |||||
b2 = shuffle(b2,1); \ | |||||
c2 = shuffle(c2,2); \ | |||||
d2 = shuffle(d2,3); \ | |||||
\ | |||||
qrf(&a1,&b1,&c1,&d1); \ | |||||
qrf(&a2,&b2,&c2,&d2); \ | |||||
b1 = shuffle(b1,3); \ | |||||
c1 = shuffle(c1,2); \ | |||||
d1 = shuffle(d1,1); \ | |||||
b2 = shuffle(b2,3); \ | |||||
c2 = shuffle(c2,2); \ | |||||
d2 = shuffle(d2,1); \ | |||||
} | |||||
#define OUTPUT_FUNCTION { \ | |||||
output[0] = add(a1,aa); \ | |||||
output[1] = add(b1,bb); \ | |||||
output[2] = add(c1,cc); \ | |||||
output[3] = add(d1,dd); \ | |||||
output[4] = add(a2,aa); \ | |||||
output[5] = add(b2,bb); \ | |||||
output[6] = add(c2,add(cc,p)); \ | |||||
output[7] = add(d2,dd); \ | |||||
\ | |||||
output += 8; \ | |||||
\ | |||||
cc = add64(add64(cc,p), p); \ | |||||
a1 = a2 = aa; \ | |||||
b1 = b2 = bb; \ | |||||
c1 = cc; c2 = add64(cc,p);\ | |||||
d1 = d2 = dd; \ | |||||
} | |||||
/* ------------------------------------------------------------------------------- */ | |||||
INTRINSIC u_int32_t rotate(int r, u_int32_t a) { | |||||
return a<<r ^ a>>(32-r); | |||||
} | |||||
static __inline__ __attribute__((unused)) void | |||||
quarter_round(u_int32_t *a, u_int32_t *b, u_int32_t *c, u_int32_t *d) { | |||||
*a = *a + *b; *d = rotate(16, *d^*a); | |||||
*c = *c + *d; *b = rotate(12, *b^*c); | |||||
*a = *a + *b; *d = rotate(8, *d^*a); | |||||
*c = *c + *d; *b = rotate(7, *b^*c); | |||||
} | |||||
static void | |||||
crandom_chacha_expand(u_int64_t iv, | |||||
u_int64_t ctr, | |||||
int nr, | |||||
int output_size, | |||||
const unsigned char *key_, | |||||
unsigned char *output_) { | |||||
# if MIGHT_HAVE_SSE2 | |||||
if (HAVE(SSE2)) { | |||||
ssereg *key = (ssereg *)key_; | |||||
ssereg *output = (ssereg *)output_; | |||||
ssereg a1 = key[0], a2 = a1, aa = a1, | |||||
b1 = key[1], b2 = b1, bb = b1, | |||||
c1 = {iv, ctr}, c2 = {iv, ctr+1}, cc = c1, | |||||
d1 = {0x3320646e61707865ull, 0x6b20657479622d32ull}, | |||||
d2 = d1, dd = d1, | |||||
p = {0, 1}; | |||||
int i,r; | |||||
# if (NEED_XOP) | |||||
if (HAVE(XOP)) { | |||||
for (i=0; i<output_size; i+=128) { | |||||
for (r=nr; r>0; r-=2) | |||||
DOUBLE_ROUND(quarter_round_xop); | |||||
OUTPUT_FUNCTION; | |||||
} | |||||
return; | |||||
} | |||||
# endif | |||||
# if (NEED_SSSE3) | |||||
if (HAVE(SSSE3)) { | |||||
for (i=0; i<output_size; i+=128) { | |||||
for (r=nr; r>0; r-=2) | |||||
DOUBLE_ROUND(quarter_round_ssse3); | |||||
OUTPUT_FUNCTION; | |||||
} | |||||
return; | |||||
} | |||||
# endif | |||||
# if (NEED_SSE2) | |||||
if (HAVE(SSE2)) { | |||||
for (i=0; i<output_size; i+=128) { | |||||
for (r=nr; r>0; r-=2) | |||||
DOUBLE_ROUND(quarter_round_sse2); | |||||
OUTPUT_FUNCTION; | |||||
} | |||||
return; | |||||
} | |||||
# endif | |||||
} | |||||
# endif | |||||
# if NEED_CONV | |||||
{ | |||||
const u_int32_t *key = (const u_int32_t *)key_; | |||||
u_int32_t | |||||
x[16], | |||||
input[16] = { | |||||
key[0], key[1], key[2], key[3], | |||||
key[4], key[5], key[6], key[7], | |||||
iv, iv>>32, ctr, ctr>>32, | |||||
0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 | |||||
}, | |||||
*output = (u_int32_t *)output_; | |||||
int i, r; | |||||
for (i=0; i<output_size; i+= 64) { | |||||
for (r=0; r<16; r++) { | |||||
x[r] = input[r]; | |||||
} | |||||
for (r=nr; r>0; r-=2) { | |||||
quarter_round(&x[0], &x[4], &x[8], &x[12]); | |||||
quarter_round(&x[1], &x[5], &x[9], &x[13]); | |||||
quarter_round(&x[2], &x[6], &x[10], &x[14]); | |||||
quarter_round(&x[3], &x[7], &x[11], &x[15]); | |||||
quarter_round(&x[0], &x[5], &x[10], &x[15]); | |||||
quarter_round(&x[1], &x[6], &x[11], &x[12]); | |||||
quarter_round(&x[2], &x[7], &x[8], &x[13]); | |||||
quarter_round(&x[3], &x[4], &x[9], &x[14]); | |||||
} | |||||
for (r=0; r<16; r++) { | |||||
output[r] = x[r] + input[r]; | |||||
} | |||||
output += 16; | |||||
input[11] ++; | |||||
if (!input[11]) input[12]++; | |||||
} | |||||
} | |||||
#endif /* NEED_CONV */ | |||||
} | |||||
int | |||||
crandom_init_from_file( | |||||
crandom_state_a_t state, | |||||
const char *filename, | |||||
int reseed_interval, | |||||
int reseeds_mandatory | |||||
) { | |||||
state->fill = 0; | |||||
state->reseed_countdown = reseed_interval; | |||||
state->reseed_interval = reseed_interval; | |||||
state->ctr = 0; | |||||
state->randomfd = open(filename, O_RDONLY); | |||||
if (state->randomfd == -1) { | |||||
int err = errno; | |||||
return err ? err : -1; | |||||
} | |||||
ssize_t offset = 0, red; | |||||
do { | |||||
red = read(state->randomfd, state->seedBuffer + offset, 32 - offset); | |||||
if (red > 0) offset += red; | |||||
} while (red > 0 && offset < 32); | |||||
if (offset < 32) { | |||||
int err = errno; | |||||
return err ? err : -1; | |||||
} | |||||
memset(state->seedBuffer+32, 0, 96); | |||||
state->magic = CRANDOM_MAGIC; | |||||
state->reseeds_mandatory = reseeds_mandatory; | |||||
return 0; | |||||
} | |||||
void | |||||
crandom_init_from_buffer( | |||||
crandom_state_a_t state, | |||||
const char initial_seed[32] | |||||
) { | |||||
memcpy(state->seedBuffer, initial_seed, 32); | |||||
memset(state->seedBuffer+32, 0, 96); | |||||
state->reseed_countdown = state->reseed_interval = state->fill = state->ctr = state->reseeds_mandatory = 0; | |||||
state->randomfd = -1; | |||||
state->magic = CRANDOM_MAGIC; | |||||
} | |||||
int | |||||
crandom_generate( | |||||
crandom_state_a_t state, | |||||
unsigned char *output, | |||||
unsigned long long length | |||||
) { | |||||
/* the generator isn't seeded; maybe they ignored the return value of init_from_file */ | |||||
if (unlikely(state->magic != CRANDOM_MAGIC)) { | |||||
abort(); | |||||
} | |||||
int ret = 0; | |||||
/* | |||||
* Addition 5/21/2014. | |||||
* | |||||
* If this is used in an application inside a VM, and the VM | |||||
* is snapshotted and restored, then crandom_generate() would | |||||
* produce the same output. | |||||
* | |||||
* Of course, the real defense against this is "don't do that", | |||||
* but we mitigate it by the RDRAND and/or rdtsc() in the refilling | |||||
* code. Since chacha is pseudorandom, when the attacker doesn't | |||||
* know the state, it's good enough if RDRAND/rdtsc() return | |||||
* different results. However, if (part of) the request is filled | |||||
* from the buffer, this won't help. | |||||
* | |||||
* So, add a flag EXPERIMENT_CRANDOM_BUFFER_CUTOFF_BYTES which | |||||
* disables the buffer for requests larger than this size. | |||||
* | |||||
* Suggest EXPERIMENT_CRANDOM_BUFFER_CUTOFF_BYTES = 0, which | |||||
* disables the buffer. But instead you can set it to say 16, | |||||
* so that pulls of at least 128 bits will be stirred. This | |||||
* could still be a problem for eg 64-bit nonces, but those | |||||
* aren't entirely collision-resistant anyway. | |||||
* | |||||
* Heuristic: large requests are more likely to be | |||||
* cryptographically important, and the buffer doesn't impact | |||||
* their performance as much. So if the request is bigger | |||||
* than a certain size, just drop the buffer on the floor. | |||||
* | |||||
* This code isn't activated if state->reseed_interval == 0, | |||||
* because then the PRNG is deterministic anyway. | |||||
* | |||||
* TODO: sample 128 bits out of RDRAND() instead of 64 bits. | |||||
* TODO: option to completely remove the buffer and fill? | |||||
* FUTURE: come up with a less band-aid-y solution to this problem. | |||||
*/ | |||||
#ifdef EXPERIMENT_CRANDOM_BUFFER_CUTOFF_BYTES | |||||
if (state->reseed_interval | |||||
#if EXPERIMENT_CRANDOM_CUTOFF_BYTES > 0 | |||||
/* #if'd to a warning from -Wtype-limits in GCC when it's zero */ | |||||
&& length >= EXPERIMENT_CRANDOM_BUFFER_CUTOFF_BYTES | |||||
#endif | |||||
) { | |||||
state->fill = 0; | |||||
} | |||||
#endif | |||||
while (length) { | |||||
if (unlikely(state->fill <= 0)) { | |||||
uint64_t iv = 0; | |||||
if (state->reseed_interval) { | |||||
/* it's nondeterministic, stir in some rdrand() or rdtsc() */ | |||||
if (HAVE(RDRAND)) { | |||||
iv = rdrand(0); | |||||
if (!iv) iv = rdtsc(); | |||||
} else { | |||||
iv = rdtsc(); | |||||
} | |||||
state->reseed_countdown--; | |||||
if (unlikely(state->reseed_countdown <= 0)) { | |||||
/* reseed by xoring in random state */ | |||||
state->reseed_countdown = state->reseed_interval; | |||||
ssize_t offset = 0, red; | |||||
do { | |||||
red = read(state->randomfd, state->seedBuffer + 32 + offset, 32 - offset); | |||||
if (red > 0) offset += red; | |||||
} while (red > 0 && offset < 32); | |||||
if (offset < 32) { | |||||
/* The read failed. Signal an error with the return code. | |||||
* | |||||
* If reseeds are mandatory, crash. | |||||
* | |||||
* If not, the generator is still probably safe to use, because reseeding | |||||
* is basically over-engineering for caution. Also, the user might ignore | |||||
* the return code, so we still need to fill the request. | |||||
* | |||||
* Set reseed_countdown = 1 so we'll try again later. If the user's | |||||
* performance sucks as a result of ignoring the error code while calling | |||||
* us in a loop, well, that's life. | |||||
*/ | |||||
if (state->reseeds_mandatory) { | |||||
abort(); | |||||
} | |||||
ret = errno; | |||||
if (ret == 0) ret = -1; | |||||
state->reseed_countdown = 1; | |||||
} | |||||
int i; | |||||
for (i=0; i<32; i++) { | |||||
/* Stir in the buffer. If somehow the read failed, it'll be zeros. */ | |||||
state->seedBuffer[i] ^= state->seedBuffer[i+32]; | |||||
} | |||||
} | |||||
} | |||||
crandom_chacha_expand(iv,state->ctr,20,128,state->seedBuffer,state->seedBuffer); | |||||
state->ctr++; | |||||
state->fill = sizeof(state->seedBuffer)-32; | |||||
} | |||||
unsigned long long copy = (length > state->fill) ? state->fill : length; | |||||
state->fill -= copy; | |||||
memcpy(output, state->seedBuffer + 32 + state->fill, copy); | |||||
really_memset(state->seedBuffer + 32 + state->fill, 0, copy); | |||||
output += copy; length -= copy; | |||||
} | |||||
return ret; | |||||
} | |||||
void | |||||
crandom_destroy( | |||||
crandom_state_a_t state | |||||
) { | |||||
if (state->magic == CRANDOM_MAGIC && state->randomfd) { | |||||
(void) close(state->randomfd); | |||||
/* Ignore the return value from close(), because what would it mean? | |||||
* "Your random device, which you were reading over NFS, lost some data"? | |||||
*/ | |||||
} | |||||
really_memset(state, 0, sizeof(*state)); | |||||
} |
@@ -10,7 +10,6 @@ | |||||
#include "decaf_crypto.h" | #include "decaf_crypto.h" | ||||
#include <string.h> | #include <string.h> | ||||
#include "sha512.h" | |||||
static const unsigned int DECAF_448_SCALAR_OVERKILL_BYTES = DECAF_448_SCALAR_BYTES + 8; | static const unsigned int DECAF_448_SCALAR_OVERKILL_BYTES = DECAF_448_SCALAR_BYTES + 8; | ||||
@@ -1,576 +0,0 @@ | |||||
/* Copyright (c) 2014 Cryptography Research, Inc. | |||||
* Released under the MIT License. See LICENSE.txt for license information. | |||||
*/ | |||||
#include "config.h" | |||||
#include "word.h" | |||||
#include <errno.h> | |||||
#if GOLDILOCKS_USE_PTHREAD | |||||
#include <pthread.h> | |||||
#endif | |||||
#include "goldilocks.h" | |||||
#include "ec_point.h" | |||||
#include "scalarmul.h" | |||||
#include "barrett_field.h" | |||||
#include "crandom.h" | |||||
#include "sha512.h" | |||||
#include "intrinsics.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 | |||||
#define GOLDI_DIVERSIFY_BYTES 8 | |||||
#if FIELD_BYTES <= SHA512_OUTPUT_BYTES | |||||
#define FIELD_HASH_BYTES SHA512_OUTPUT_BYTES | |||||
#define field_hash_final sha512_final | |||||
#else | |||||
#define FIELD_HASH_BYTES (SHA512_OUTPUT_BYTES * ((FIELD_BYTES-1)/SHA512_OUTPUT_BYTES + 1)) | |||||
static inline void field_hash_final ( | |||||
sha512_ctx_a_t ctx, | |||||
unsigned char out[FIELD_HASH_BYTES] | |||||
) { | |||||
/* SHA PRNG I guess? I really should have used SHAKE */ | |||||
int i; | |||||
for (i=0; i<= (FIELD_BYTES-1) / SHA512_OUTPUT_BYTES; i++) { | |||||
if (i) | |||||
sha512_update(ctx, &out[(i-1)*SHA512_OUTPUT_BYTES], SHA512_OUTPUT_BYTES); | |||||
sha512_final(ctx, &out[i*SHA512_OUTPUT_BYTES]); | |||||
} | |||||
} | |||||
#endif | |||||
/* These are just unique identifiers */ | |||||
static const char *G_INITING = "initializing"; | |||||
static const char *G_INITED = "initialized"; | |||||
static const char *G_FAILED = "failed to initialize"; | |||||
struct goldilocks_precomputed_public_key_t { | |||||
struct goldilocks_public_key_t pub; | |||||
struct fixed_base_table_t table; | |||||
}; | |||||
/* FUTURE: auto. */ | |||||
static struct { | |||||
const char * volatile status; | |||||
#if GOLDILOCKS_USE_PTHREAD | |||||
pthread_mutex_t mutex; | |||||
#endif | |||||
tw_niels_a_t combs[COMB_N << (COMB_T-1)]; | |||||
struct fixed_base_table_t fixed_base; | |||||
tw_niels_a_t wnafs[1<<WNAF_PRECMP_BITS]; | |||||
crandom_state_a_t rand; | |||||
} goldilocks_global; | |||||
static inline mask_t | |||||
goldilocks_check_init(void) { | |||||
if (likely(goldilocks_global.status == G_INITED)) { | |||||
return MASK_SUCCESS; | |||||
} else { | |||||
return MASK_FAILURE; | |||||
} | |||||
} | |||||
int | |||||
goldilocks_init (void) { | |||||
const char *res = compare_and_swap(&goldilocks_global.status, NULL, G_INITING); | |||||
if (res == G_INITED) return GOLDI_EALREADYINIT; | |||||
else if (res) { | |||||
return GOLDI_ECORRUPT; | |||||
} | |||||
#if GOLDILOCKS_USE_PTHREAD | |||||
int ret = pthread_mutex_init(&goldilocks_global.mutex, NULL); | |||||
if (ret) goto fail; | |||||
#endif | |||||
extensible_a_t ext; | |||||
tw_extensible_a_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_even(text, ext); | |||||
/* Precompute the tables. */ | |||||
mask_t succ; | |||||
succ = precompute_fixed_base(&goldilocks_global.fixed_base, text, | |||||
COMB_N, COMB_T, COMB_S, goldilocks_global.combs); | |||||
succ &= precompute_fixed_base_wnaf(goldilocks_global.wnafs, text, WNAF_PRECMP_BITS); | |||||
int criff_res = crandom_init_from_file(goldilocks_global.rand, | |||||
GOLDILOCKS_RANDOM_INIT_FILE, | |||||
GOLDILOCKS_RANDOM_RESEED_INTERVAL, | |||||
GOLDILOCKS_RANDOM_RESEEDS_MANDATORY); | |||||
#ifdef SUPERCOP_WONT_LET_ME_OPEN_FILES | |||||
if (criff_res == EMFILE) { | |||||
crandom_init_from_buffer(goldilocks_global.rand, "SUPERCOP won't let me open files"); | |||||
criff_res = 0; | |||||
} | |||||
#endif | |||||
if (succ & !criff_res) { | |||||
if (!bool_compare_and_swap(&goldilocks_global.status, G_INITING, G_INITED)) { | |||||
abort(); | |||||
} | |||||
return 0; | |||||
} | |||||
/* it failed! fall though... */ | |||||
fail: | |||||
if (!bool_compare_and_swap(&goldilocks_global.status, G_INITING, G_FAILED)) { | |||||
/* ok something is seriously wrong */ | |||||
abort(); | |||||
} | |||||
return -1; | |||||
} | |||||
int | |||||
goldilocks_derive_private_key ( | |||||
struct goldilocks_private_key_t *privkey, | |||||
const unsigned char proto[GOLDI_SYMKEY_BYTES] | |||||
) { | |||||
if (!goldilocks_check_init()) { | |||||
return GOLDI_EUNINIT; | |||||
} | |||||
memcpy(&privkey->opaque[2*GOLDI_FIELD_BYTES], proto, GOLDI_SYMKEY_BYTES); | |||||
unsigned char skb[FIELD_HASH_BYTES]; | |||||
word_t sk[GOLDI_FIELD_WORDS]; | |||||
assert(sizeof(skb) >= sizeof(sk)); | |||||
sha512_ctx_a_t ctx; | |||||
tw_extensible_a_t exta; | |||||
field_a_t pk; | |||||
sha512_init(ctx); | |||||
sha512_update(ctx, (const unsigned char *)"derivepk", GOLDI_DIVERSIFY_BYTES); | |||||
sha512_update(ctx, proto, GOLDI_SYMKEY_BYTES); | |||||
field_hash_final(ctx, (unsigned char *)skb); | |||||
barrett_deserialize_and_reduce(sk, skb, sizeof(skb), &curve_prime_order); | |||||
barrett_serialize(privkey->opaque, sk, GOLDI_FIELD_BYTES); | |||||
scalarmul_fixed_base(exta, sk, GOLDI_SCALAR_BITS, &goldilocks_global.fixed_base); | |||||
untwist_and_double_and_serialize(pk, exta); | |||||
field_serialize(&privkey->opaque[GOLDI_FIELD_BYTES], pk); | |||||
return GOLDI_EOK; | |||||
} | |||||
void | |||||
goldilocks_underive_private_key ( | |||||
unsigned char proto[GOLDI_SYMKEY_BYTES], | |||||
const struct goldilocks_private_key_t *privkey | |||||
) { | |||||
memcpy(proto, &privkey->opaque[2*GOLDI_FIELD_BYTES], GOLDI_SYMKEY_BYTES); | |||||
} | |||||
int | |||||
goldilocks_keygen ( | |||||
struct goldilocks_private_key_t *privkey, | |||||
struct goldilocks_public_key_t *pubkey | |||||
) { | |||||
if (!goldilocks_check_init()) { | |||||
return GOLDI_EUNINIT; | |||||
} | |||||
unsigned char proto[GOLDI_SYMKEY_BYTES]; | |||||
#if GOLDILOCKS_USE_PTHREAD | |||||
int ml_ret = pthread_mutex_lock(&goldilocks_global.mutex); | |||||
if (ml_ret) return ml_ret; | |||||
#endif | |||||
int ret = crandom_generate(goldilocks_global.rand, proto, sizeof(proto)); | |||||
#if GOLDILOCKS_USE_PTHREAD | |||||
ml_ret = pthread_mutex_unlock(&goldilocks_global.mutex); | |||||
if (ml_ret) abort(); | |||||
#endif | |||||
int ret2 = goldilocks_derive_private_key(privkey, proto); | |||||
if (!ret) ret = ret2; | |||||
ret2 = goldilocks_private_to_public(pubkey, privkey); | |||||
if (!ret) ret = ret2; | |||||
return ret ? GOLDI_ENODICE : GOLDI_EOK; | |||||
} | |||||
int | |||||
goldilocks_private_to_public ( | |||||
struct goldilocks_public_key_t *pubkey, | |||||
const struct goldilocks_private_key_t *privkey | |||||
) { | |||||
field_a_t pk; | |||||
mask_t msucc = field_deserialize(pk,&privkey->opaque[GOLDI_FIELD_BYTES]); | |||||
if (msucc) { | |||||
field_serialize(pubkey->opaque, pk); | |||||
return GOLDI_EOK; | |||||
} else { | |||||
return GOLDI_ECORRUPT; | |||||
} | |||||
} | |||||
static int | |||||
goldilocks_shared_secret_core ( | |||||
uint8_t shared[GOLDI_SHARED_SECRET_BYTES], | |||||
const struct goldilocks_private_key_t *my_privkey, | |||||
const struct goldilocks_public_key_t *your_pubkey, | |||||
const struct goldilocks_precomputed_public_key_t *pre | |||||
) { | |||||
uint8_t gxy[GOLDI_FIELD_BYTES]; | |||||
/* This function doesn't actually need anything in goldilocks_global, | |||||
* so it doesn't check init. | |||||
*/ | |||||
assert(GOLDI_SHARED_SECRET_BYTES == SHA512_OUTPUT_BYTES); | |||||
word_t sk[GOLDI_FIELD_WORDS]; | |||||
field_a_t pk; | |||||
mask_t succ = field_deserialize(pk,your_pubkey->opaque), msucc = -1; | |||||
#ifdef EXPERIMENT_ECDH_STIR_IN_PUBKEYS | |||||
field_a_t sum, prod; | |||||
msucc &= field_deserialize(sum,&my_privkey->opaque[GOLDI_FIELD_BYTES]); | |||||
field_mul(prod,pk,sum); | |||||
field_add(sum,pk,sum); | |||||
#endif | |||||
msucc &= barrett_deserialize(sk,my_privkey->opaque,&curve_prime_order); | |||||
#if GOLDI_IMPLEMENT_PRECOMPUTED_KEYS | |||||
if (pre) { | |||||
tw_extensible_a_t tw; | |||||
succ &= scalarmul_fixed_base(tw, sk, GOLDI_SCALAR_BITS, &pre->table); | |||||
untwist_and_double_and_serialize(pk, tw); | |||||
} else { | |||||
succ &= montgomery_ladder(pk,pk,sk,GOLDI_SCALAR_BITS,1); | |||||
} | |||||
#else | |||||
(void)pre; | |||||
succ &= montgomery_ladder(pk,pk,sk,GOLDI_SCALAR_BITS,1); | |||||
#endif | |||||
field_serialize(gxy,pk); | |||||
/* obliterate records of our failure by adjusting with obliteration key */ | |||||
sha512_ctx_a_t ctx; | |||||
sha512_init(ctx); | |||||
#ifdef EXPERIMENT_ECDH_OBLITERATE_CT | |||||
uint8_t oblit[GOLDI_DIVERSIFY_BYTES + GOLDI_SYMKEY_BYTES]; | |||||
unsigned i; | |||||
for (i=0; i<GOLDI_DIVERSIFY_BYTES; i++) { | |||||
oblit[i] = "noshared"[i] & ~(succ&msucc); | |||||
} | |||||
for (i=0; i<GOLDI_SYMKEY_BYTES; i++) { | |||||
oblit[GOLDI_DIVERSIFY_BYTES+i] = my_privkey->opaque[2*GOLDI_FIELD_BYTES+i] & ~(succ&msucc); | |||||
} | |||||
sha512_update(ctx, oblit, sizeof(oblit)); | |||||
#endif | |||||
#ifdef EXPERIMENT_ECDH_STIR_IN_PUBKEYS | |||||
/* stir in the sum and product of the pubkeys. */ | |||||
uint8_t a_pk[GOLDI_FIELD_BYTES]; | |||||
field_serialize(a_pk, sum); | |||||
sha512_update(ctx, a_pk, GOLDI_FIELD_BYTES); | |||||
field_serialize(a_pk, prod); | |||||
sha512_update(ctx, a_pk, GOLDI_FIELD_BYTES); | |||||
#endif | |||||
/* stir in the shared key and finish */ | |||||
sha512_update(ctx, gxy, GOLDI_FIELD_BYTES); | |||||
sha512_final(ctx, shared); | |||||
return (GOLDI_ECORRUPT & ~msucc) | |||||
| (GOLDI_EINVAL & msucc &~ succ) | |||||
| (GOLDI_EOK & msucc & succ); | |||||
} | |||||
int | |||||
goldilocks_shared_secret ( | |||||
uint8_t shared[GOLDI_SHARED_SECRET_BYTES], | |||||
const struct goldilocks_private_key_t *my_privkey, | |||||
const struct goldilocks_public_key_t *your_pubkey | |||||
) { | |||||
return goldilocks_shared_secret_core( | |||||
shared, | |||||
my_privkey, | |||||
your_pubkey, | |||||
NULL | |||||
); | |||||
} | |||||
#if GOLDI_IMPLEMENT_SIGNATURES | |||||
static void | |||||
goldilocks_derive_challenge( | |||||
word_t challenge[GOLDI_FIELD_WORDS], | |||||
const unsigned char pubkey[GOLDI_FIELD_BYTES], | |||||
const unsigned char gnonce[GOLDI_FIELD_BYTES], | |||||
const unsigned char *message, | |||||
uint64_t message_len | |||||
) { | |||||
/* challenge = H(pk, [nonceG], message). */ | |||||
unsigned char sha_out[FIELD_HASH_BYTES]; | |||||
sha512_ctx_a_t ctx; | |||||
sha512_init(ctx); | |||||
sha512_update(ctx, pubkey, GOLDI_FIELD_BYTES); | |||||
sha512_update(ctx, gnonce, GOLDI_FIELD_BYTES); | |||||
sha512_update(ctx, message, message_len); | |||||
field_hash_final(ctx, sha_out); | |||||
barrett_deserialize_and_reduce(challenge, sha_out, sizeof(sha_out), &curve_prime_order); | |||||
} | |||||
int | |||||
goldilocks_sign ( | |||||
uint8_t signature_out[GOLDI_SIGNATURE_BYTES], | |||||
const uint8_t *message, | |||||
uint64_t message_len, | |||||
const struct goldilocks_private_key_t *privkey | |||||
) { | |||||
if (!goldilocks_check_init()) { | |||||
return GOLDI_EUNINIT; | |||||
} | |||||
/* challenge = H(pk, [nonceG], message). */ | |||||
word_t skw[GOLDI_FIELD_WORDS]; | |||||
mask_t succ = barrett_deserialize(skw,privkey->opaque,&curve_prime_order); | |||||
if (!succ) { | |||||
really_memset(skw,0,sizeof(skw)); | |||||
return GOLDI_ECORRUPT; | |||||
} | |||||
/* Derive a nonce. TODO: use HMAC. FUTURE: factor. */ | |||||
unsigned char sha_out[FIELD_HASH_BYTES]; | |||||
word_t tk[GOLDI_FIELD_WORDS]; | |||||
sha512_ctx_a_t ctx; | |||||
sha512_init(ctx); | |||||
sha512_update(ctx, (const unsigned char *)"signonce", 8); | |||||
sha512_update(ctx, &privkey->opaque[2*GOLDI_FIELD_BYTES], GOLDI_SYMKEY_BYTES); | |||||
sha512_update(ctx, message, message_len); | |||||
sha512_update(ctx, &privkey->opaque[2*GOLDI_FIELD_BYTES], GOLDI_SYMKEY_BYTES); | |||||
field_hash_final(ctx, sha_out); | |||||
barrett_deserialize_and_reduce(tk, sha_out, sizeof(sha_out), &curve_prime_order); | |||||
/* 4[nonce]G */ | |||||
uint8_t signature_tmp[GOLDI_FIELD_BYTES]; | |||||
tw_extensible_a_t exta; | |||||
field_a_t gsk; | |||||
scalarmul_fixed_base(exta, tk, GOLDI_SCALAR_BITS, &goldilocks_global.fixed_base); | |||||
double_tw_extensible(exta); | |||||
untwist_and_double_and_serialize(gsk, exta); | |||||
field_serialize(signature_tmp, gsk); | |||||
word_t challenge[GOLDI_FIELD_WORDS]; | |||||
goldilocks_derive_challenge ( | |||||
challenge, | |||||
&privkey->opaque[GOLDI_FIELD_BYTES], | |||||
signature_tmp, | |||||
message, | |||||
message_len | |||||
); | |||||
/* reduce challenge and sub. */ | |||||
barrett_negate(challenge,GOLDI_FIELD_WORDS,&curve_prime_order); | |||||
barrett_mac( | |||||
tk,GOLDI_FIELD_WORDS, | |||||
challenge,GOLDI_FIELD_WORDS, | |||||
skw,GOLDI_FIELD_WORDS, | |||||
&curve_prime_order | |||||
); | |||||
word_t carry = add_nr_ext_packed(tk,tk,GOLDI_FIELD_WORDS,tk,GOLDI_FIELD_WORDS,-1); | |||||
barrett_reduce(tk,GOLDI_FIELD_WORDS,carry,&curve_prime_order); | |||||
memcpy(signature_out, signature_tmp, GOLDI_FIELD_BYTES); | |||||
barrett_serialize(signature_out+GOLDI_FIELD_BYTES, tk, GOLDI_FIELD_BYTES); | |||||
really_memset((unsigned char *)tk,0,sizeof(tk)); | |||||
really_memset((unsigned char *)skw,0,sizeof(skw)); | |||||
really_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[GOLDI_SIGNATURE_BYTES], | |||||
const uint8_t *message, | |||||
uint64_t message_len, | |||||
const struct goldilocks_public_key_t *pubkey | |||||
) { | |||||
if (!goldilocks_check_init()) { | |||||
return GOLDI_EUNINIT; | |||||
} | |||||
field_a_t pk; | |||||
word_t s[GOLDI_FIELD_WORDS]; | |||||
mask_t succ = field_deserialize(pk,pubkey->opaque); | |||||
if (!succ) return GOLDI_EINVAL; | |||||
succ = barrett_deserialize(s, &signature[GOLDI_FIELD_BYTES], &curve_prime_order); | |||||
if (!succ) return GOLDI_EINVAL; | |||||
word_t challenge[GOLDI_FIELD_WORDS]; | |||||
goldilocks_derive_challenge(challenge, pubkey->opaque, signature, message, message_len); | |||||
field_a_t eph; | |||||
tw_extensible_a_t pk_text; | |||||
/* deserialize [nonce]G */ | |||||
succ = field_deserialize(eph, signature); | |||||
if (!succ) return GOLDI_EINVAL; | |||||
succ = deserialize_and_twist_approx(pk_text, pk); | |||||
if (!succ) return GOLDI_EINVAL; | |||||
linear_combo_var_fixed_vt( pk_text, | |||||
challenge, GOLDI_SCALAR_BITS, | |||||
s, GOLDI_SCALAR_BITS, | |||||
(const tw_niels_a_t*)goldilocks_global.wnafs, WNAF_PRECMP_BITS ); | |||||
untwist_and_double_and_serialize( pk, pk_text ); | |||||
succ = field_eq(eph, pk); | |||||
return succ ? 0 : GOLDI_EINVAL; | |||||
} | |||||
#endif | |||||
#if GOLDI_IMPLEMENT_PRECOMPUTED_KEYS | |||||
struct goldilocks_precomputed_public_key_t * | |||||
goldilocks_precompute_public_key ( | |||||
const struct goldilocks_public_key_t *pub | |||||
) { | |||||
struct goldilocks_precomputed_public_key_t *precom; | |||||
precom = (struct goldilocks_precomputed_public_key_t *) | |||||
malloc(sizeof(*precom)); | |||||
if (!precom) return NULL; | |||||
tw_extensible_a_t pk_text; | |||||
field_a_t pk; | |||||
mask_t succ = field_deserialize(pk, pub->opaque); | |||||
if (!succ) { | |||||
free(precom); | |||||
return NULL; | |||||
} | |||||
succ = deserialize_and_twist_approx(pk_text, pk); | |||||
if (!succ) { | |||||
free(precom); | |||||
return NULL; | |||||
} | |||||
succ = precompute_fixed_base(&precom->table, pk_text, | |||||
COMB_N, COMB_T, COMB_S, NULL); | |||||
if (!succ) { | |||||
free(precom); | |||||
return NULL; | |||||
} | |||||
memcpy(&precom->pub,pub,sizeof(*pub)); | |||||
return precom; | |||||
} | |||||
void | |||||
goldilocks_destroy_precomputed_public_key ( | |||||
struct goldilocks_precomputed_public_key_t *precom | |||||
) { | |||||
if (!precom) return; | |||||
destroy_fixed_base(&precom->table); | |||||
really_memset(&precom->pub.opaque, 0, sizeof(precom->pub)); | |||||
free(precom); | |||||
} | |||||
int | |||||
goldilocks_verify_precomputed ( | |||||
const uint8_t signature[GOLDI_SIGNATURE_BYTES], | |||||
const uint8_t *message, | |||||
uint64_t message_len, | |||||
const struct goldilocks_precomputed_public_key_t *pubkey | |||||
) { | |||||
if (!goldilocks_check_init()) { | |||||
return GOLDI_EUNINIT; | |||||
} | |||||
word_t s[GOLDI_FIELD_WORDS]; | |||||
mask_t succ = barrett_deserialize(s, &signature[GOLDI_FIELD_BYTES], &curve_prime_order); | |||||
if (!succ) return GOLDI_EINVAL; | |||||
word_t challenge[GOLDI_FIELD_WORDS]; | |||||
goldilocks_derive_challenge(challenge, pubkey->pub.opaque, signature, message, message_len); | |||||
field_a_t eph, pk; | |||||
tw_extensible_a_t pk_text; | |||||
/* deserialize [nonce]G */ | |||||
succ = field_deserialize(eph, signature); | |||||
if (!succ) return GOLDI_EINVAL; | |||||
succ = linear_combo_combs_vt ( | |||||
pk_text, | |||||
challenge, GOLDI_SCALAR_BITS, &pubkey->table, | |||||
s, GOLDI_SCALAR_BITS, &goldilocks_global.fixed_base | |||||
); | |||||
if (!succ) return GOLDI_EINVAL; | |||||
untwist_and_double_and_serialize( pk, pk_text ); | |||||
succ = field_eq(eph, pk); | |||||
return succ ? 0 : GOLDI_EINVAL; | |||||
} | |||||
int | |||||
goldilocks_shared_secret_precomputed ( | |||||
uint8_t shared[GOLDI_SHARED_SECRET_BYTES], | |||||
const struct goldilocks_private_key_t *my_privkey, | |||||
const struct goldilocks_precomputed_public_key_t *your_pubkey | |||||
) { | |||||
return goldilocks_shared_secret_core( | |||||
shared, | |||||
my_privkey, | |||||
&your_pubkey->pub, | |||||
your_pubkey | |||||
); | |||||
} | |||||
#endif /* GOLDI_IMPLEMENT_PRECOMPUTED_KEYS */ | |||||
@@ -1,190 +0,0 @@ | |||||
/* Copyright (c) 2014 Cryptography Research, Inc. | |||||
* Released under the MIT License. See LICENSE.txt for license information. | |||||
*/ | |||||
#ifndef __BARRETT_FIELD_H__ | |||||
#define __BARRETT_FIELD_H__ 1 | |||||
/** | |||||
* @file barrett_field.h | |||||
* @brief Slow routines for generic primes in Barrett form. | |||||
* | |||||
* @warning These routines are very slow, roughly implemented, and should be made more | |||||
* flexible in the future. I might even outright switch to Montgomery form. | |||||
*/ | |||||
#include "word.h" | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
/** | |||||
* @brief A Barrett-form prime, 2^k - c. | |||||
* @todo Support primes of other forms. | |||||
*/ | |||||
struct barrett_prime_t { | |||||
uint32_t nwords_p; /**< The number of bits in p, i.e. ceiling((k-1) / WORD_BITS) */ | |||||
uint32_t p_shift; /**< c mod WORD_BITS. */ | |||||
uint32_t nwords_lo; /**< The number of nonzero low words. */ | |||||
const word_t *p_lo; /**< The low words. */ | |||||
}; | |||||
/** | |||||
* The Goldilocks prime. I'm not sure this is the right place for it, but oh well. | |||||
*/ | |||||
extern const struct barrett_prime_t curve_prime_order; | |||||
/** | |||||
* Reduce a number (with optional high carry word) mod p. | |||||
* | |||||
* @param [in,out] a The value to be reduced. | |||||
* @param [in] nwords_a The number of words in a. | |||||
* @param [in] a_carry A high word to be carried into the computation. | |||||
* @param [in] prime The Barrett prime. | |||||
*/ | |||||
void | |||||
barrett_reduce( | |||||
word_t *a, | |||||
uint32_t nwords_a, | |||||
word_t a_carry, | |||||
const struct barrett_prime_t *prime | |||||
); | |||||
/** | |||||
* out = a+(c&mask), returning a carry. | |||||
* | |||||
* @param [out] out The output, of length nwords_a. | |||||
* @param [in] a The "always" addend. | |||||
* @param [in] nwords_a The number of words in a. | |||||
* @param [in] c The "sometimes" addend. | |||||
* @param [in] nwords_c The number of words in c. | |||||
* @param [in] mask A mask of whether to add or not. | |||||
* @return A carry word. | |||||
*/ | |||||
word_t | |||||
add_nr_ext_packed( | |||||
word_t *out, | |||||
const word_t *a, | |||||
uint32_t nwords_a, | |||||
const word_t *c, | |||||
uint32_t nwords_c, | |||||
word_t mask | |||||
); | |||||
/** | |||||
* out = a-(c&mask), returning a borrow. | |||||
* | |||||
* @param [out] out The output, of length nwords_a. | |||||
* @param [in] a The "always" minuend. | |||||
* @param [in] nwords_a The number of words in a. | |||||
* @param [in] c The "sometimes" subtrahend. | |||||
* @param [in] nwords_c The number of words in c. | |||||
* @param [in] mask A mask of whether to add or not. | |||||
* @return A borrow word. | |||||
*/ | |||||
word_t | |||||
sub_nr_ext_packed( | |||||
word_t *out, | |||||
const word_t *a, | |||||
uint32_t nwords_a, | |||||
const word_t *c, | |||||
uint32_t nwords_c, | |||||
word_t mask | |||||
); | |||||
/** | |||||
* a -> reduce(-a) mod p | |||||
* | |||||
* @param [in] a The value to be reduced and negated. | |||||
* @param [in] nwords_a The number of words in a. Must be >= nwords_p. | |||||
* @param [in] prime The prime. | |||||
*/ | |||||
void | |||||
barrett_negate ( | |||||
word_t *a, | |||||
uint32_t nwords_a, | |||||
const struct barrett_prime_t *prime | |||||
); | |||||
/* | |||||
* If doMac, accum = accum + a*b mod p. | |||||
* Otherwise, accum = a*b mod p. | |||||
* | |||||
* This function is not __restrict__; you may pass accum, | |||||
* a, b, etc all from the same location. | |||||
*/ | |||||
void | |||||
barrett_mul_or_mac( | |||||
word_t *accum, | |||||
uint32_t nwords_accum, | |||||
const word_t *a, | |||||
uint32_t nwords_a, | |||||
const word_t *b, | |||||
uint32_t nwords_b, | |||||
const struct barrett_prime_t *prime, | |||||
mask_t doMac | |||||
); | |||||
static inline void | |||||
barrett_mul( | |||||
word_t *out, | |||||
uint32_t nwords_out, | |||||
const word_t *a, | |||||
uint32_t nwords_a, | |||||
const word_t *b, | |||||
uint32_t nwords_b, | |||||
const struct barrett_prime_t *prime | |||||
) { | |||||
barrett_mul_or_mac(out,nwords_out,a,nwords_a,b,nwords_b,prime,0); | |||||
} | |||||
static inline void | |||||
barrett_mac( | |||||
word_t *out, | |||||
uint32_t nwords_out, | |||||
const word_t *a, | |||||
uint32_t nwords_a, | |||||
const word_t *b, | |||||
uint32_t nwords_b, | |||||
const struct barrett_prime_t *prime | |||||
) { | |||||
barrett_mul_or_mac(out,nwords_out,a,nwords_a,b,nwords_b,prime,-(mask_t)1); | |||||
} | |||||
mask_t | |||||
barrett_deserialize ( | |||||
word_t *x, | |||||
const uint8_t *serial, | |||||
const struct barrett_prime_t *prime | |||||
); | |||||
void | |||||
barrett_serialize ( | |||||
uint8_t *serial, | |||||
const word_t *x, | |||||
uint32_t nserial | |||||
); | |||||
void | |||||
barrett_deserialize_and_reduce ( | |||||
word_t *x, | |||||
const uint8_t *serial, | |||||
uint32_t nserial, | |||||
const struct barrett_prime_t *prime | |||||
); | |||||
#ifdef __cplusplus | |||||
}; /* extern "C" */ | |||||
#endif | |||||
#endif /* __BARRETT_FIELD_H__ */ |
@@ -1,76 +0,0 @@ | |||||
/** | |||||
* @file config.h | |||||
* @copyright | |||||
* Copyright (c) 2014 Cryptography Research, Inc. \n | |||||
* Released under the MIT License. See LICENSE.txt for license information. | |||||
* @author Mike Hamburg | |||||
* @brief Goldilocks top-level configuration flags. | |||||
*/ | |||||
#ifndef __GOLDILOCKS_CONFIG_H__ | |||||
#define __GOLDILOCKS_CONFIG_H__ 1 | |||||
/** @brief crandom architecture detection. | |||||
* With this flag set to 1, crandom will assume that any flag | |||||
* supported by -march and friends (MIGHT_HAVE) will actually | |||||
* be available on the target machine (MUST_HAVE), instead of | |||||
* trying to detect it. | |||||
* | |||||
* Without this flag, crandom can detect, eg, that while -mavx | |||||
* was passed, the currint machine doesn't support AVX, and can | |||||
* fall back to SSE2 or whatever. But the rest of the | |||||
* Goldilocks code doesn't support this, so it'll still crash | |||||
* with an illegal instruction error. | |||||
* | |||||
* Setting this flag will make the library smaller. | |||||
*/ | |||||
#define CRANDOM_MIGHT_IS_MUST 1 | |||||
/** | |||||
* @brief Causes crandom to refuse to buffer requests bigger | |||||
* than this size. Setting 0 disables buffering for all | |||||
* requests, which hurts performance. | |||||
* | |||||
* The advantage is that if a user process forks or is VM- | |||||
* snapshotted, the buffer is not adjusted (FUTURE). However, | |||||
* with the buffer disabled, the refresh routines will stir | |||||
* in entropy from RDTSC and/or RDRAND, making this operation | |||||
* mostly-safe. | |||||
*/ | |||||
#define EXPERIMENT_CRANDOM_BUFFER_CUTOFF_BYTES 0 | |||||
/** | |||||
* @brief Goldilocks uses libpthread mutexes to provide | |||||
* thread-safety. If you disable this flag, it won't link | |||||
* libpthread, but it won't be thread-safe either. | |||||
*/ | |||||
#define GOLDILOCKS_USE_PTHREAD 1 | |||||
/** | |||||
* @brief Experiment to change the hash inputs for ECDH, | |||||
* in a way that obliterates the result -- overwriting it with | |||||
* a safe pseudorandom value -- if the public key is invalid. | |||||
* That way users who ignore the status result won't be | |||||
* exposed to invalid key attacks. | |||||
*/ | |||||
#define EXPERIMENT_ECDH_OBLITERATE_CT 1 | |||||
/** | |||||
* @brief Whether or not define the signing functions, which | |||||
* currently require SHA-512. | |||||
*/ | |||||
#define GOLDI_IMPLEMENT_SIGNATURES 1 | |||||
/** | |||||
* @brief Whether or not to define and implement functions | |||||
* working with pre-computed keys. | |||||
*/ | |||||
#define GOLDI_IMPLEMENT_PRECOMPUTED_KEYS 1 | |||||
/** | |||||
* @brief ECDH adds public keys into the hash, to prevent | |||||
* esoteric attacks. | |||||
*/ | |||||
#define EXPERIMENT_ECDH_STIR_IN_PUBKEYS 1 | |||||
#endif /* __GOLDILOCKS_CONFIG_H__ */ |
@@ -1,143 +0,0 @@ | |||||
/* Copyright (c) 2011 Stanford University. | |||||
* Copyright (c) 2014-2015 Cryptography Research, Inc. | |||||
* Released under the MIT License. See LICENSE.txt for license information. | |||||
*/ | |||||
/** | |||||
* @file crandom.h | |||||
* @author Mike Hamburg | |||||
* @brief A miniature version of the (as of yet incomplete) crandom project. | |||||
*/ | |||||
#ifndef __GOLDI_CRANDOM_H__ | |||||
#define __GOLDI_CRANDOM_H__ 1 | |||||
#define _XOPEN_SOURCE 600 | |||||
#include <stdint.h> /* for uint64_t */ | |||||
#include <fcntl.h> /* for open */ | |||||
#include <errno.h> /* for returning errors after open */ | |||||
#include <stdlib.h> /* for abort */ | |||||
#include <string.h> /* for memcpy */ | |||||
#include <strings.h> /* for bzero */ | |||||
#include <unistd.h> /* for read */ | |||||
/** | |||||
* @brief The state of a crandom generator. | |||||
* | |||||
* This object is opaque. It is not protected by a lock, and so must | |||||
* not be accessed by multiple threads at the same time. | |||||
*/ | |||||
struct crandom_state_t { | |||||
/** @privatesection */ | |||||
/* unsigned char seed[32]; */ | |||||
/* unsigned char buffer[96]; */ | |||||
unsigned char seedBuffer[32+96]; | |||||
uint64_t ctr; | |||||
uint64_t magic; | |||||
unsigned int fill; | |||||
int reseed_countdown; | |||||
int reseed_interval; | |||||
int reseeds_mandatory; | |||||
int randomfd; | |||||
} __attribute__((aligned(16))) ; | |||||
typedef struct crandom_state_t crandom_state_a_t[1]; | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
/** | |||||
* Initialize a crandom state from the chosen file. | |||||
* | |||||
* This function initializes a state from a given state file, or | |||||
* from a random device (eg. /dev/random or /dev/urandom). | |||||
* | |||||
* You must check the return value of this function. | |||||
* | |||||
* @param [out] state The crandom state variable to initalize. | |||||
* @param [in] filename The name of the seed file or random device. | |||||
* @param [in] reseed_interval The number of 96-byte blocks which can be | |||||
* generated without reseeding. Suggest 10000. | |||||
* @param [in] reseeds_mandatory If nonzero, call abort() if a reseed fails. | |||||
* Suggest 1. | |||||
* | |||||
* @retval 0 Success. | |||||
* @retval Nonzero An error to be interpreted by strerror(). | |||||
*/ | |||||
int | |||||
crandom_init_from_file ( | |||||
crandom_state_a_t state, | |||||
const char *filename, | |||||
int reseed_interval, | |||||
int reseeds_mandatory | |||||
) __attribute__((warn_unused_result)); | |||||
/** | |||||
* Initialize a crandom state from a buffer, for deterministic operation. | |||||
* | |||||
* This function is used to initialize a crandom state deterministically, | |||||
* mainly for testing purposes. It can also be used to expand a secret | |||||
* random value deterministically. | |||||
* | |||||
* @warning The crandom implementation is not guaranteed to be stable. | |||||
* That is, a later release might produce a different random stream from | |||||
* the same seed. | |||||
* | |||||
* @param [out] state The crandom state variable to initalize. | |||||
* @param [in] initial_seed The seed value. | |||||
*/ | |||||
void | |||||
crandom_init_from_buffer ( | |||||
crandom_state_a_t state, | |||||
const char initial_seed[32] | |||||
); | |||||
/** | |||||
* Fill the output buffer with random data. | |||||
* | |||||
* This function uses the given crandom state to produce pseudorandom data | |||||
* in the output buffer. | |||||
* | |||||
* This function may perform reads from the state's random device if it needs | |||||
* to reseed. This could block if that file is a blocking source, such as | |||||
* a pipe or /dev/random on Linux. If reseeding fails and the state has | |||||
* reseeds_mandatory set, this function will call abort(). Otherwise, it will | |||||
* return an error code, but it will still randomize the buffer. | |||||
* | |||||
* If called on a corrupted, uninitialized or destroyed state, this function | |||||
* will abort(). | |||||
* | |||||
* @warning This function is not thread-safe with respect to the state. Don't | |||||
* call it from multiple threads with the same state at the same time. | |||||
* | |||||
* @param [inout] state The crandom state to use for generation. | |||||
* @param [out] output The buffer to fill with random data. | |||||
* @param [in] length The length of the buffer. | |||||
* | |||||
* @retval 0 Success. | |||||
* @retval Nonezero A non-mandatory reseed operation failed. | |||||
*/ | |||||
int | |||||
crandom_generate ( | |||||
crandom_state_a_t state, | |||||
unsigned char *output, | |||||
unsigned long long length | |||||
); | |||||
/** | |||||
* Destroy the random state. Further calls to crandom_generate() on that state | |||||
* will abort(). | |||||
* | |||||
* @param [inout] state The state to be destroyed. | |||||
*/ | |||||
void | |||||
crandom_destroy ( | |||||
crandom_state_a_t state | |||||
); | |||||
#ifdef __cplusplus | |||||
}; /* extern "C" */ | |||||
#endif | |||||
#endif /* __GOLDI_CRANDOM_H__ */ |
@@ -1,697 +0,0 @@ | |||||
/** | |||||
* @file ec_point.h | |||||
* @copyright | |||||
* Copyright (c) 2014 Cryptography Research, Inc. \n | |||||
* Released under the MIT License. See LICENSE.txt for license information. | |||||
* @author Mike Hamburg | |||||
* | |||||
* This file contains a huge number of different options for EC point arithmetic, | |||||
* but only a few of them will be used by any given library. They are here for | |||||
* reference and for consistency checks. The Goldilocks library link step strips | |||||
* out unused functions. | |||||
*/ | |||||
#ifndef __CC_INCLUDED_EC_POINT_H__ | |||||
#define __CC_INCLUDED_EC_POINT_H__ | |||||
#include "field.h" | |||||
#include "constant_time.h" | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
/** | |||||
* Affine point on an Edwards curve. | |||||
*/ | |||||
typedef struct affine_t { | |||||
field_a_t x, y; | |||||
} affine_a_t[1]; | |||||
/** | |||||
* Affine point on a twisted Edwards curve. | |||||
*/ | |||||
typedef struct tw_affine_t { | |||||
field_a_t x, y; | |||||
} tw_affine_a_t[1]; | |||||
/** | |||||
* Montgomery buffer. | |||||
*/ | |||||
typedef struct montgomery_t { | |||||
field_a_t z0, xd, zd, xa, za; | |||||
} montgomery_a_t[1]; | |||||
/** | |||||
* Montgomery buffer, augmented version. | |||||
*/ | |||||
typedef struct montgomery_aux_t { | |||||
field_a_t s0, xd, zd, xa, za, xs, zs; | |||||
} montgomery_aux_a_t[1]; | |||||
/** | |||||
* Extensible coordinates for Edwards curves, suitable for | |||||
* accumulators. | |||||
* | |||||
* Represents the point (x/z, y/z). The extra coordinates | |||||
* t,u satisfy xy = tuz, allowing for conversion to Extended | |||||
* form by multiplying t and u. | |||||
* | |||||
* The idea is that you don't have to do this multiplication | |||||
* when doubling the accumulator, because the t-coordinate | |||||
* isn't used there. At the same time, as long as you only | |||||
* have one point in extensible form, additions don't cost | |||||
* extra. | |||||
* | |||||
* This is essentially a lazier version of Hisil et al's | |||||
* lookahead trick. It might be worth considering that trick | |||||
* instead. | |||||
*/ | |||||
typedef struct extensible_t { | |||||
field_a_t x, y, z, t, u; | |||||
} extensible_a_t[1]; | |||||
/** | |||||
* Extensible coordinates for twisted Edwards curves, | |||||
* suitable for accumulators. | |||||
*/ | |||||
typedef struct tw_extensible_t { | |||||
field_a_t x, y, z, t, u; | |||||
} tw_extensible_a_t[1]; | |||||
/** | |||||
* Extended coordinates for twisted Edwards curves. | |||||
* Jack of all trades, master of none. | |||||
*/ | |||||
typedef struct tw_extended_t { | |||||
field_a_t x, y, z, t; | |||||
} tw_extended_a_t[1]; | |||||
/** | |||||
* Niels coordinates for twisted Edwards curves. | |||||
* | |||||
* Good for mixed readdition; suitable for fixed tables. | |||||
*/ | |||||
typedef struct tw_niels_t { | |||||
field_a_t a, b, c; | |||||
} tw_niels_a_t[1]; | |||||
/** | |||||
* Projective niels coordinates for twisted Edwards curves. | |||||
* | |||||
* Good for readdition; suitable for temporary tables. | |||||
*/ | |||||
typedef struct tw_pniels_t { | |||||
tw_niels_a_t n; | |||||
field_a_t z; | |||||
} tw_pniels_a_t[1]; | |||||
/** | |||||
* Auto-generated copy method. | |||||
*/ | |||||
static __inline__ void | |||||
copy_affine ( | |||||
affine_a_t a, | |||||
const affine_a_t ds | |||||
) __attribute__((unused,always_inline)); | |||||
/** | |||||
* Auto-generated copy method. | |||||
*/ | |||||
static __inline__ void | |||||
copy_tw_affine ( | |||||
tw_affine_a_t a, | |||||
const tw_affine_a_t ds | |||||
) __attribute__((unused,always_inline)); | |||||
/** | |||||
* Auto-generated copy method. | |||||
*/ | |||||
static __inline__ void | |||||
copy_montgomery ( | |||||
montgomery_a_t a, | |||||
const montgomery_a_t ds | |||||
) __attribute__((unused,always_inline)); | |||||
/** | |||||
* Auto-generated copy method. | |||||
*/ | |||||
static __inline__ void | |||||
copy_extensible ( | |||||
extensible_a_t a, | |||||
const extensible_a_t ds | |||||
) __attribute__((unused,always_inline)); | |||||
/** | |||||
* Auto-generated copy method. | |||||
*/ | |||||
static __inline__ void | |||||
copy_tw_extensible ( | |||||
tw_extensible_a_t a, | |||||
const tw_extensible_a_t ds | |||||
) __attribute__((unused,always_inline)); | |||||
/** | |||||
* Auto-generated copy method. | |||||
*/ | |||||
static __inline__ void | |||||
copy_tw_extended ( | |||||
tw_extended_a_t a, | |||||
const tw_extended_a_t ds | |||||
) __attribute__((unused,always_inline)); | |||||
/** | |||||
* Auto-generated copy method. | |||||
*/ | |||||
static __inline__ void | |||||
copy_tw_niels ( | |||||
tw_niels_a_t a, | |||||
const tw_niels_a_t ds | |||||
) __attribute__((unused,always_inline)); | |||||
/** | |||||
* Auto-generated copy method. | |||||
*/ | |||||
static __inline__ void | |||||
copy_tw_pniels ( | |||||
tw_pniels_a_t a, | |||||
const tw_pniels_a_t ds | |||||
) __attribute__((unused,always_inline)); | |||||
/** | |||||
* Add two points on a twisted Edwards curve, one in Extensible form | |||||
* and the other in half-Niels form. | |||||
*/ | |||||
void | |||||
add_tw_niels_to_tw_extensible ( | |||||
tw_extensible_a_t d, | |||||
const tw_niels_a_t e | |||||
); | |||||
/** | |||||
* Add two points on a twisted Edwards curve, one in Extensible form | |||||
* and the other in half-Niels form. | |||||
*/ | |||||
void | |||||
sub_tw_niels_from_tw_extensible ( | |||||
tw_extensible_a_t d, | |||||
const tw_niels_a_t e | |||||
); | |||||
/** | |||||
* Add two points on a twisted Edwards curve, one in Extensible form | |||||
* and the other in projective Niels form. | |||||
*/ | |||||
void | |||||
add_tw_pniels_to_tw_extensible ( | |||||
tw_extensible_a_t e, | |||||
const tw_pniels_a_t a | |||||
); | |||||
/** | |||||
* Add two points on a twisted Edwards curve, one in Extensible form | |||||
* and the other in projective Niels form. | |||||
*/ | |||||
void | |||||
sub_tw_pniels_from_tw_extensible ( | |||||
tw_extensible_a_t e, | |||||
const tw_pniels_a_t a | |||||
); | |||||
/** | |||||
* Double a point on a twisted Edwards curve, in "extensible" coordinates. | |||||
*/ | |||||
void | |||||
double_tw_extensible ( | |||||
tw_extensible_a_t a | |||||
); | |||||
/** | |||||
* Double a point on an Edwards curve, in "extensible" coordinates. | |||||
*/ | |||||
void | |||||
double_extensible ( | |||||
extensible_a_t a | |||||
); | |||||
/** | |||||
* Double a point, and transfer it to the twisted curve. | |||||
* | |||||
* That is, apply the 4-isogeny. | |||||
*/ | |||||
void | |||||
twist_and_double ( | |||||
tw_extensible_a_t b, | |||||
const extensible_a_t a | |||||
); | |||||
/** | |||||
* Double a point, and transfer it to the untwisted curve. | |||||
* | |||||
* That is, apply the dual isogeny. | |||||
*/ | |||||
void | |||||
untwist_and_double ( | |||||
extensible_a_t b, | |||||
const tw_extensible_a_t a | |||||
); | |||||
void | |||||
convert_tw_affine_to_tw_pniels ( | |||||
tw_pniels_a_t b, | |||||
const tw_affine_a_t a | |||||
); | |||||
void | |||||
convert_tw_affine_to_tw_extensible ( | |||||
tw_extensible_a_t b, | |||||
const tw_affine_a_t a | |||||
); | |||||
void | |||||
convert_affine_to_extensible ( | |||||
extensible_a_t b, | |||||
const affine_a_t a | |||||
); | |||||
void | |||||
convert_tw_extensible_to_tw_pniels ( | |||||
tw_pniels_a_t b, | |||||
const tw_extensible_a_t a | |||||
); | |||||
void | |||||
convert_tw_pniels_to_tw_extensible ( | |||||
tw_extensible_a_t e, | |||||
const tw_pniels_a_t d | |||||
); | |||||
void | |||||
convert_tw_niels_to_tw_extensible ( | |||||
tw_extensible_a_t e, | |||||
const tw_niels_a_t d | |||||
); | |||||
void | |||||
convert_tw_extensible_to_tw_extended ( | |||||
tw_extended_a_t b, | |||||
const tw_extensible_a_t a | |||||
); | |||||
void | |||||
add_tw_extended ( | |||||
tw_extended_a_t d, | |||||
const tw_extended_a_t e | |||||
); | |||||
void | |||||
add_sub_tw_extended ( | |||||
tw_extended_a_t c, | |||||
const tw_extended_a_t d, | |||||
const tw_extended_a_t e, | |||||
mask_t sub | |||||
); | |||||
void | |||||
montgomery_step ( | |||||
montgomery_a_t a | |||||
); | |||||
void | |||||
montgomery_aux_step ( | |||||
montgomery_aux_a_t a | |||||
); | |||||
void | |||||
deserialize_montgomery ( | |||||
montgomery_a_t a, | |||||
const field_a_t sbz | |||||
); | |||||
mask_t | |||||
serialize_montgomery ( | |||||
field_a_t b, | |||||
const montgomery_a_t a, | |||||
const field_a_t sbz | |||||
); | |||||
mask_t | |||||
decaf_serialize_montgomery ( | |||||
field_a_t b, | |||||
const montgomery_aux_a_t a, | |||||
mask_t swapped | |||||
); | |||||
void | |||||
decaf_deserialize_montgomery ( | |||||
montgomery_aux_a_t a, | |||||
const field_a_t s | |||||
); | |||||
/** | |||||
* Serialize a point on an Edwards curve. | |||||
* | |||||
* The serialized form would be sqrt((z-y)/(z+y)) with sign of xz. | |||||
* | |||||
* It would be on 4y^2/(1-d) = x^3 + 2(1+d)/(1-d) * x^2 + x. | |||||
* | |||||
* But 4/(1-d) isn't square, so we need to twist it: | |||||
* | |||||
* -x is on 4y^2/(d-1) = x^3 + 2(d+1)/(d-1) * x^2 + x | |||||
*/ | |||||
void | |||||
serialize_extensible ( | |||||
field_a_t b, | |||||
const extensible_a_t a | |||||
); | |||||
/** | |||||
* | |||||
*/ | |||||
void | |||||
untwist_and_double_and_serialize ( | |||||
field_a_t b, | |||||
const tw_extensible_a_t a | |||||
); | |||||
/** | |||||
* Expensive transfer from untwisted to twisted. Roughly equivalent to halve and isogeny. | |||||
* Correctly transfers point of order 2. | |||||
* | |||||
* Can't have x=+1 (it's not even). There is code to fix the exception that would otherwise | |||||
* occur at (0,1). | |||||
* | |||||
* Input point must be even. | |||||
*/ | |||||
void | |||||
twist_even ( | |||||
tw_extensible_a_t b, | |||||
const extensible_a_t a | |||||
); | |||||
/** | |||||
* Expensive transfer from untwisted to twisted. Roughly equivalent to halve and isogeny. | |||||
* | |||||
* This function is for testing purposes only, because it can return odd points on the | |||||
* twist. This can cause exceptions in the point addition formula. What's more, this | |||||
* function should be able to return points of order 4, which are at infinity. | |||||
* | |||||
* This function probably doesn't properly handle special cases, such as the point at | |||||
* infinity (FUTURE). | |||||
* | |||||
* This function probably isn't a homomorphism, in that it probably doesn't consistently | |||||
* handle adjustments by the point of order 2 when the input is odd. (FUTURE) | |||||
*/ | |||||
void | |||||
test_only_twist ( | |||||
tw_extensible_a_t b, | |||||
const extensible_a_t a | |||||
); | |||||
mask_t | |||||
field_is_square ( | |||||
const field_a_t x | |||||
); | |||||
mask_t | |||||
is_even_pt ( | |||||
const extensible_a_t a | |||||
); | |||||
mask_t | |||||
is_even_tw ( | |||||
const tw_extensible_a_t a | |||||
); | |||||
/** | |||||
* Deserialize a point to an untwisted affine curve. | |||||
*/ | |||||
mask_t | |||||
deserialize_affine ( | |||||
affine_a_t a, | |||||
const field_a_t sz | |||||
); | |||||
/** | |||||
* Deserialize a point and transfer it to the twist. | |||||
* | |||||
* Not guaranteed to preserve the 4-torsion component. | |||||
* | |||||
* Refuses to deserialize +-1, which are the points of order 2. | |||||
*/ | |||||
mask_t | |||||
deserialize_and_twist_approx ( | |||||
tw_extensible_a_t a, | |||||
const field_a_t sz | |||||
) | |||||
__attribute__((warn_unused_result)); | |||||
mask_t | |||||
decaf_deserialize_affine ( | |||||
affine_a_t a, | |||||
const field_a_t s, | |||||
mask_t allow_identity | |||||
) | |||||
__attribute__((warn_unused_result)); | |||||
void | |||||
decaf_serialize_extensible ( | |||||
field_a_t b, | |||||
const extensible_a_t a | |||||
); | |||||
mask_t | |||||
decaf_deserialize_tw_affine ( | |||||
tw_affine_a_t a, | |||||
const field_a_t s, | |||||
mask_t allow_identity | |||||
) | |||||
__attribute__((warn_unused_result)); | |||||
void | |||||
decaf_serialize_tw_extensible ( | |||||
field_a_t b, | |||||
const tw_extensible_a_t a | |||||
); | |||||
mask_t | |||||
decaf_deserialize_tw_extended ( | |||||
tw_extended_a_t a, | |||||
const field_a_t s, | |||||
mask_t allow_identity | |||||
) | |||||
__attribute__((warn_unused_result)); | |||||
void | |||||
decaf_serialize_tw_extended ( | |||||
field_a_t b, | |||||
const tw_extended_a_t a | |||||
); | |||||
void | |||||
set_identity_extensible ( | |||||
extensible_a_t a | |||||
); | |||||
void | |||||
set_identity_tw_extensible ( | |||||
tw_extensible_a_t a | |||||
); | |||||
void | |||||
set_identity_tw_extended ( | |||||
tw_extended_a_t a | |||||
); | |||||
void | |||||
set_identity_affine ( | |||||
affine_a_t a | |||||
); | |||||
mask_t | |||||
eq_affine ( | |||||
const affine_a_t a, | |||||
const affine_a_t b | |||||
); | |||||
mask_t | |||||
eq_extensible ( | |||||
const extensible_a_t a, | |||||
const extensible_a_t b | |||||
); | |||||
mask_t | |||||
eq_tw_extensible ( | |||||
const tw_extensible_a_t a, | |||||
const tw_extensible_a_t b | |||||
); | |||||
void | |||||
elligator_2s_inject ( | |||||
affine_a_t a, | |||||
const field_a_t r | |||||
); | |||||
mask_t | |||||
validate_affine ( | |||||
const affine_a_t a | |||||
); | |||||
mask_t | |||||
decaf_eq_tw_extensible ( | |||||
const tw_extensible_a_t a, | |||||
const tw_extensible_a_t b | |||||
) | |||||
__attribute__((warn_unused_result)); | |||||
mask_t | |||||
decaf_eq_tw_extended ( | |||||
const tw_extended_a_t a, | |||||
const tw_extended_a_t b | |||||
) | |||||
__attribute__((warn_unused_result)); | |||||
mask_t | |||||
decaf_eq_extensible ( | |||||
const extensible_a_t a, | |||||
const extensible_a_t b | |||||
) | |||||
__attribute__((warn_unused_result)); | |||||
/** | |||||
* Check the invariants for struct tw_extensible_t. | |||||
* NOTE: This function was automatically generated | |||||
* with no regard for speed. | |||||
*/ | |||||
mask_t | |||||
validate_tw_extensible ( | |||||
const tw_extensible_a_t ext | |||||
); | |||||
/** | |||||
* Check the invariants for struct extensible_t. | |||||
* NOTE: This function was automatically generated | |||||
* with no regard for speed. | |||||
*/ | |||||
mask_t | |||||
validate_extensible ( | |||||
const extensible_a_t ext | |||||
); | |||||
/** | |||||
* If doNegate, then negate a twisted niels point. | |||||
*/ | |||||
static __inline__ void | |||||
__attribute__((unused)) | |||||
cond_negate_tw_niels ( | |||||
tw_niels_a_t n, | |||||
mask_t doNegate | |||||
) { | |||||
constant_time_cond_swap(n->a, n->b, sizeof(n->a), doNegate); | |||||
field_cond_neg(n->c, doNegate); | |||||
} | |||||
/** | |||||
* If doNegate, then negate a twisted projective niels point. | |||||
*/ | |||||
static __inline__ void | |||||
__attribute__((unused)) | |||||
cond_negate_tw_pniels ( | |||||
tw_pniels_a_t n, | |||||
mask_t doNegate | |||||
) { | |||||
cond_negate_tw_niels(n->n, doNegate); | |||||
} | |||||
void | |||||
copy_affine ( | |||||
affine_a_t a, | |||||
const affine_a_t ds | |||||
) { | |||||
field_copy ( a->x, ds->x ); | |||||
field_copy ( a->y, ds->y ); | |||||
} | |||||
void | |||||
copy_tw_affine ( | |||||
tw_affine_a_t a, | |||||
const tw_affine_a_t ds | |||||
) { | |||||
field_copy ( a->x, ds->x ); | |||||
field_copy ( a->y, ds->y ); | |||||
} | |||||
void | |||||
copy_montgomery ( | |||||
montgomery_a_t a, | |||||
const montgomery_a_t ds | |||||
) { | |||||
field_copy ( a->z0, ds->z0 ); | |||||
field_copy ( a->xd, ds->xd ); | |||||
field_copy ( a->zd, ds->zd ); | |||||
field_copy ( a->xa, ds->xa ); | |||||
field_copy ( a->za, ds->za ); | |||||
} | |||||
void | |||||
copy_extensible ( | |||||
extensible_a_t a, | |||||
const extensible_a_t ds | |||||
) { | |||||
field_copy ( a->x, ds->x ); | |||||
field_copy ( a->y, ds->y ); | |||||
field_copy ( a->z, ds->z ); | |||||
field_copy ( a->t, ds->t ); | |||||
field_copy ( a->u, ds->u ); | |||||
} | |||||
void | |||||
copy_tw_extensible ( | |||||
tw_extensible_a_t a, | |||||
const tw_extensible_a_t ds | |||||
) { | |||||
field_copy ( a->x, ds->x ); | |||||
field_copy ( a->y, ds->y ); | |||||
field_copy ( a->z, ds->z ); | |||||
field_copy ( a->t, ds->t ); | |||||
field_copy ( a->u, ds->u ); | |||||
} | |||||
void | |||||
copy_tw_extended ( | |||||
tw_extended_a_t a, | |||||
const tw_extended_a_t ds | |||||
) { | |||||
field_copy ( a->x, ds->x ); | |||||
field_copy ( a->y, ds->y ); | |||||
field_copy ( a->z, ds->z ); | |||||
field_copy ( a->t, ds->t ); | |||||
} | |||||
void | |||||
copy_tw_niels ( | |||||
tw_niels_a_t a, | |||||
const tw_niels_a_t ds | |||||
) { | |||||
field_copy ( a->a, ds->a ); | |||||
field_copy ( a->b, ds->b ); | |||||
field_copy ( a->c, ds->c ); | |||||
} | |||||
void | |||||
copy_tw_pniels ( | |||||
tw_pniels_a_t a, | |||||
const tw_pniels_a_t ds | |||||
) { | |||||
copy_tw_niels( a->n, ds->n ); | |||||
field_copy ( a->z, ds->z ); | |||||
} | |||||
#ifdef __cplusplus | |||||
}; /* extern "C" */ | |||||
#endif | |||||
#endif /* __CC_INCLUDED_EC_POINT_H__ */ |
@@ -1,276 +0,0 @@ | |||||
/* Copyright (c) 2011 Stanford University. | |||||
* Copyright (c) 2014 Cryptography Research, Inc. | |||||
* Released under the MIT License. See LICENSE.txt for license information. | |||||
*/ | |||||
/** @file intrinsics.h | |||||
* @brief cRandom intrinsics header. | |||||
*/ | |||||
#ifndef __CRANDOM_INTRINSICS_H__ | |||||
#define __CRANDOM_INTRINSICS_H__ 1 | |||||
#include <sys/types.h> | |||||
#include "config.h" | |||||
#if defined(__i386__) || defined(__x86_64__) | |||||
#include <immintrin.h> | |||||
#endif | |||||
/** @brief Macro to make a function static, forcibly inlined and possibly unused. */ | |||||
#define INTRINSIC \ | |||||
static __inline__ __attribute__((__gnu_inline__, __always_inline__, unused)) | |||||
#define GEN 1 /**< @brief Intrinsics field has been generated. */ | |||||
#define SSE2 2 /**< @brief Machine supports SSE2 */ | |||||
#define SSSE3 4 /**< @brief Machine supports SSSE3 (for shuffles) */ | |||||
#define AESNI 8 /**< @brief Machine supports Intel AES-NI */ | |||||
#define XOP 16 /**< @brief Machine supports AMD XOP */ | |||||
#define AVX 32 /**< @brief Machine supports Intel AVX (for masking) */ | |||||
#define AVX2 64 /**< @brief Machine supports Intel AVX2 (for bignums) */ | |||||
#define RDRAND 128 /**< @brief Machine supports Intel RDRAND */ | |||||
/** | |||||
* @brief If on x86, read the timestamp counter. Otherwise, return 0. | |||||
*/ | |||||
#ifndef __has_builtin | |||||
#define __has_builtin(X) 0 | |||||
#endif | |||||
#if defined(__clang__) && __has_builtin(__builtin_readcyclecounter) | |||||
#define rdtsc __builtin_readcyclecounter | |||||
#else | |||||
INTRINSIC u_int64_t rdtsc(void) { | |||||
u_int64_t out = 0; | |||||
# if (defined(__i386__) || defined(__x86_64__)) | |||||
__asm__ __volatile__ ("rdtsc" : "=A"(out)); | |||||
# endif | |||||
return out; | |||||
} | |||||
#endif | |||||
/** | |||||
* Return x unchanged, but confuse the compiler. | |||||
* | |||||
* This is mainly for use in test scripts, to prevent the value from | |||||
* being constant-folded or removed by dead code elimination. | |||||
* | |||||
* @param x A 64-bit number. | |||||
* @return The same number in a register. | |||||
*/ | |||||
INTRINSIC u_int64_t opacify(u_int64_t x) { | |||||
__asm__ volatile("mov %0, %0" : "+r"(x)); | |||||
return x; | |||||
} | |||||
/** @cond internal */ | |||||
#ifdef __AVX2__ | |||||
# define MIGHT_HAVE_AVX2 1 | |||||
# ifndef MUST_HAVE_AVX2 | |||||
# define MUST_HAVE_AVX2 0 | |||||
# endif | |||||
#else | |||||
# define MIGHT_HAVE_AVX2 0 | |||||
# define MUST_HAVE_AVX2 0 | |||||
#endif | |||||
#ifdef __AVX__ | |||||
# define MIGHT_HAVE_AVX 1 | |||||
# ifndef MUST_HAVE_AVX | |||||
# define MUST_HAVE_AVX MUST_HAVE_AVX2 | |||||
# endif | |||||
#else | |||||
# define MIGHT_HAVE_AVX 0 | |||||
# define MUST_HAVE_AVX 0 | |||||
#endif | |||||
#ifdef __SSSE3__ | |||||
# define MIGHT_HAVE_SSSE3 1 | |||||
# ifndef MUST_HAVE_SSSE3 | |||||
# define MUST_HAVE_SSSE3 MUST_HAVE_AVX | |||||
# endif | |||||
#else | |||||
# define MIGHT_HAVE_SSSE3 0 | |||||
# define MUST_HAVE_SSSE3 0 | |||||
#endif | |||||
#ifdef __SSE2__ | |||||
# define MIGHT_HAVE_SSE2 1 | |||||
# ifndef MUST_HAVE_SSE2 | |||||
# define MUST_HAVE_SSE2 MUST_HAVE_SSSE3 | |||||
# endif | |||||
typedef __m128i ssereg; | |||||
# define pslldq _mm_slli_epi32 | |||||
# define pshufd _mm_shuffle_epi32 | |||||
#else | |||||
# define MIGHT_HAVE_SSE2 0 | |||||
# define MUST_HAVE_SSE2 0 | |||||
#endif | |||||
#ifdef __AES__ | |||||
/* don't include intrinsics file, because not all platforms have it */ | |||||
# define MIGHT_HAVE_AESNI 1 | |||||
# ifndef MIGHT_HAVE_RDRAND | |||||
# define MIGHT_HAVE_RDRAND 1 | |||||
# endif | |||||
# ifndef MUST_HAVE_RDRAND | |||||
# define MUST_HAVE_RDRAND 0 | |||||
# endif | |||||
# ifndef MUST_HAVE_AESNI | |||||
# define MUST_HAVE_AESNI 0 | |||||
# endif | |||||
#else | |||||
# define MIGHT_HAVE_AESNI 0 | |||||
# define MUST_HAVE_AESNI 0 | |||||
# define MIGHT_HAVE_RDRAND 0 | |||||
# define MUST_HAVE_RDRAND 0 | |||||
#endif | |||||
#ifdef __XOP__ | |||||
/* don't include intrinsics file, because not all platforms have it */ | |||||
# define MIGHT_HAVE_XOP 1 | |||||
# ifndef MUST_HAVE_XOP | |||||
# define MUST_HAVE_XOP 0 | |||||
# endif | |||||
#else | |||||
# define MIGHT_HAVE_XOP 0 | |||||
# define MUST_HAVE_XOP 0 | |||||
#endif | |||||
#define MIGHT_MASK \ | |||||
( SSE2 * MIGHT_HAVE_SSE2 \ | |||||
| SSSE3 * MIGHT_HAVE_SSSE3 \ | |||||
| AESNI * MIGHT_HAVE_AESNI \ | |||||
| XOP * MIGHT_HAVE_XOP \ | |||||
| AVX * MIGHT_HAVE_AVX \ | |||||
| RDRAND * MIGHT_HAVE_RDRAND \ | |||||
| AVX2 * MIGHT_HAVE_AVX2) | |||||
#if CRANDOM_MIGHT_IS_MUST | |||||
#define MUST_MASK MIGHT_MASK | |||||
#else | |||||
#define MUST_MASK \ | |||||
( SSE2 * MUST_HAVE_SSE2 \ | |||||
| SSSE3 * MUST_HAVE_SSSE3 \ | |||||
| AESNI * MUST_HAVE_AESNI \ | |||||
| XOP * MUST_HAVE_XOP \ | |||||
| AVX * MUST_HAVE_AVX \ | |||||
| RDRAND * MUST_HAVE_RDRAND \ | |||||
| AVX2 * MUST_HAVE_AVX2 ) | |||||
#endif | |||||
/** @endcond */ | |||||
#ifdef __SSE2__ | |||||
/** Rotate a register by some amount using SSE2. */ | |||||
INTRINSIC ssereg sse2_rotate(int r, ssereg a) { | |||||
return _mm_slli_epi32(a, r) ^ _mm_srli_epi32(a, 32-r); | |||||
} | |||||
#endif | |||||
#ifdef __XOP__ | |||||
/** Rotate a register by some amount using AMD XOP. */ | |||||
INTRINSIC ssereg xop_rotate(int amount, ssereg x) { | |||||
ssereg out; | |||||
__asm__ ("vprotd %1, %2, %0" : "=x"(out) : "x"(x), "g"(amount)); | |||||
return out; | |||||
} | |||||
#endif | |||||
/** | |||||
* @brief Macro which detects that targets might support this feature, | |||||
* so that we can include code for it. | |||||
*/ | |||||
#define MIGHT_HAVE(feature) ((MIGHT_MASK & feature) == feature) | |||||
/** | |||||
* @brief Macro which detects that targets must support this feature, | |||||
* so we can omit fallback code. | |||||
*/ | |||||
#define MUST_HAVE(feature) ((MUST_MASK & feature) == feature) | |||||
/** | |||||
* @brief Make a functiona available by C API. | |||||
*/ | |||||
#ifdef __cplusplus | |||||
# define extern_c extern "C" | |||||
#else | |||||
# define extern_c | |||||
#endif | |||||
/** @cond internal | |||||
* @brief Detect platform features and return them as a flagfield int. | |||||
*/ | |||||
extern_c | |||||
unsigned int crandom_detect_features(); | |||||
/** @endcond */ | |||||
#ifndef likely | |||||
# define likely(x) __builtin_expect((x),1) \ | |||||
/**< @brief Tell the compiler that a branch is likely, for optimization. */ | |||||
# define unlikely(x) __builtin_expect((x),0) \ | |||||
/**< @brief Tell the compiler that a branch is unlikely, for optimization. */ | |||||
#endif | |||||
/** | |||||
* Atomic compare and swap, return by fetching. | |||||
* | |||||
* Equivalent to: | |||||
* ret = *target; if (*target == old) *target = new; return ret; | |||||
* | |||||
* @param [inout] target The volatile memory area to be CAS'd | |||||
* @param [in] old The expected old value of the target. | |||||
* @param [in] new A value to replace the target on success. | |||||
*/ | |||||
INTRINSIC const char * | |||||
compare_and_swap ( | |||||
const char *volatile* target, | |||||
const char *old, | |||||
const char *new | |||||
) { | |||||
return __sync_val_compare_and_swap(target,old,new); | |||||
} | |||||
/** | |||||
* Atomic compare and swap. Return whether successful. | |||||
* | |||||
* Equivalent to: | |||||
* if (*target == old) { *target = new; return nonzero; } else { return 0; } | |||||
* | |||||
* @param [inout] target The volatile memory area to be CAS'd | |||||
* @param [in] old The expected old value of the target. | |||||
* @param [in] new A value to replace the target on success. | |||||
*/ | |||||
INTRINSIC int | |||||
bool_compare_and_swap ( | |||||
const char *volatile* target, | |||||
const char *old, | |||||
const char *new | |||||
) { | |||||
return __sync_bool_compare_and_swap(target,old,new); | |||||
} | |||||
/** | |||||
* Determine whether the current processor supports the given feature. | |||||
* | |||||
* This function is designed so that it should only have runtime overhead | |||||
* if the feature is not known at compile time -- that is, if | |||||
* MIGHT_HAVE(feature) is set, but MUST_HAVE(feature) is not. | |||||
*/ | |||||
extern volatile unsigned int crandom_features; | |||||
/** @brief Determine if a given CPU feature is available. */ | |||||
INTRINSIC int HAVE(unsigned int feature); | |||||
int HAVE(unsigned int feature) { | |||||
unsigned int features; | |||||
if (!MIGHT_HAVE(feature)) return 0; | |||||
if (MUST_HAVE(feature)) return 1; | |||||
features = crandom_features; | |||||
if (unlikely(!features)) | |||||
crandom_features = features = crandom_detect_features(); | |||||
return likely((features & feature) == feature); | |||||
} | |||||
#endif /* __CRANDOM_INTRINSICS_H__ */ |
@@ -1,95 +0,0 @@ | |||||
/** | |||||
* @file magic.h | |||||
* @copyright | |||||
* Copyright (c) 2014 Cryptography Research, Inc. \n | |||||
* Released under the MIT License. See LICENSE.txt for license information. | |||||
* @author Mike Hamburg | |||||
* @brief Curve-independent declarations of magic numbers. | |||||
*/ | |||||
#ifndef __GOLDI_MAGIC_H__ | |||||
#define __GOLDI_MAGIC_H__ 1 | |||||
#include "word.h" | |||||
/** | |||||
* @brief If true, use wider tables for the precomputed combs. | |||||
*/ | |||||
#ifndef USE_BIG_COMBS | |||||
#if defined(__ARM_NEON__) | |||||
#define USE_BIG_COMBS 1 | |||||
#else | |||||
#define USE_BIG_COMBS (WORD_BITS==64) | |||||
#endif | |||||
#endif | |||||
/* TODO: standardize notation */ | |||||
/** @brief The number of words in the Goldilocks field. */ | |||||
#define GOLDI_FIELD_WORDS DIV_CEIL(FIELD_BITS,WORD_BITS) | |||||
/** @brief The number of bits in the Goldilocks curve's cofactor (cofactor=4). */ | |||||
#define COFACTOR_BITS 2 | |||||
/** @brief The number of bits in a Goldilocks scalar. */ | |||||
#define SCALAR_BITS (FIELD_BITS - COFACTOR_BITS) | |||||
/** @brief The number of bytes in a Goldilocks scalar. */ | |||||
#define SCALAR_BYTES (1+(SCALAR_BITS)/8) | |||||
/** @brief The number of words in the Goldilocks field. */ | |||||
#define SCALAR_WORDS WORDS_FOR_BITS(SCALAR_BITS) | |||||
#include "f_magic.h" | |||||
/** | |||||
* @brief sqrt(d-1), used for point formats and twisting. | |||||
*/ | |||||
extern const field_a_t sqrt_d_minus_1; | |||||
/** | |||||
* @brief The base point for Goldilocks. | |||||
*/ | |||||
extern const affine_a_t goldilocks_base_point; | |||||
/** | |||||
* @brief The Goldilocks prime subgroup order. | |||||
*/ | |||||
extern const struct barrett_prime_t curve_prime_order; | |||||
/** | |||||
* @brief Window size for fixed-window signed binary scalarmul. | |||||
* Table size is 2^(this - 1). | |||||
*/ | |||||
#define SCALARMUL_FIXED_WINDOW_SIZE 5 | |||||
/** | |||||
* @brief Even/odd adjustments for fixed window with | |||||
* ROUNDUP(SCALAR_BITS,SCALARMUL_FIXED_WINDOW_SIZE). | |||||
*/ | |||||
extern const word_t SCALARMUL_FIXED_WINDOW_ADJUSTMENT[2*SCALAR_WORDS]; | |||||
/** | |||||
* @brief Table size for wNAF signed binary (variable-time) scalarmul. | |||||
* Table size is 2^this. | |||||
*/ | |||||
#define SCALARMUL_WNAF_TABLE_BITS 3 | |||||
/** | |||||
* @brief Table size for wNAF signed binary (variable-time) linear combo. | |||||
* Table size is 2^this. | |||||
*/ | |||||
#define SCALARMUL_WNAF_COMBO_TABLE_BITS 4 | |||||
/** | |||||
* @brief The bit width of the precomputed WNAF tables. Size is 2^this elements. | |||||
*/ | |||||
#define WNAF_PRECMP_BITS 5 | |||||
/** | |||||
* @brief crandom magic structure guard constant = "return 4", cf xkcd #221 | |||||
*/ | |||||
#define CRANDOM_MAGIC 0x72657475726e2034ull | |||||
#endif /* __GOLDI_MAGIC_H__ */ |
@@ -1,373 +0,0 @@ | |||||
/** | |||||
* @file scalarmul.h | |||||
* @copyright | |||||
* Copyright (c) 2014 Cryptography Research, Inc. \n | |||||
* Released under the MIT License. See LICENSE.txt for license information. | |||||
* @author Mike Hamburg | |||||
*/ | |||||
#ifndef __P448_ALGO_H__ | |||||
#define __P448_ALGO_H__ 1 | |||||
#include "ec_point.h" | |||||
#include "field.h" | |||||
#include "intrinsics.h" | |||||
#include "magic.h" | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
/** | |||||
* A word array containing a scalar | |||||
*/ | |||||
typedef word_t scalar_t[SCALAR_WORDS]; | |||||
/** | |||||
* A precomputed table for fixed-base scalar multiplication. | |||||
* | |||||
* This uses a signed combs format. | |||||
*/ | |||||
struct fixed_base_table_t { | |||||
/** Comb tables containing multiples of the base point. */ | |||||
tw_niels_a_t *table; | |||||
/** Adjustments to the scalar in even and odd cases, respectively. */ | |||||
word_t scalar_adjustments[2*SCALAR_WORDS]; | |||||
/** The number of combs in the table. */ | |||||
unsigned int n; | |||||
/** The number of teeth in each comb. */ | |||||
unsigned int t; | |||||
/** The spacing between the teeth. */ | |||||
unsigned int s; | |||||
/** If nonzero, the table was malloc'd by precompute_for_combs. */ | |||||
unsigned int own_table; | |||||
}; | |||||
/** | |||||
* Full Montgomery ladder in inverse square root format. | |||||
* | |||||
* Out = [2^n_extra_doubles * scalar] * in, where | |||||
* scalar is little-endian and has length $nbits$ bits. | |||||
* | |||||
* If the scalar is even and/or n_extra_doubles >= 1, | |||||
* then this function will reject points which are not | |||||
* on the curve by returning MASK_FAILURE. | |||||
* | |||||
* This function will also reject multiplies which output | |||||
* the identity or the point of order 2. It may be worth | |||||
* revisiting this decision in the FUTURE. The idea is that | |||||
* this can only happen when: the input is the identity or the | |||||
* point of order 2; or the input is the point of order 4 on | |||||
* the twist; or the scalar is 0 or a multiple of the curve | |||||
* order; or the scalar is a multiple of the twist order and | |||||
* the input point is on the twist. | |||||
* | |||||
* This function takes constant time with respect to $*in$ | |||||
* and $*scalar$, but not of course with respect to nbits or | |||||
* n_extra_doubles. | |||||
* | |||||
* For security, we recommend setting n_extra_doubles = 1. | |||||
* Because the cofactor of Goldilocks is 4 and input points | |||||
* are always even (when on the curve), this will cancel the | |||||
* cofactor. | |||||
* | |||||
* @param [out] out The output point. | |||||
* @param [in] in The base point. | |||||
* @param [in] scalar The scalar's little-endian representation. | |||||
* @param [in] nbits The number of bits in the scalar. Note that | |||||
* unlike in Curve25519, we do not require the top bit to be set. | |||||
* @param [in] n_extra_doubles The number of extra doubles to do at | |||||
* the end. | |||||
* | |||||
* @retval MASK_SUCCESS The operation was successful. | |||||
* @retval MASK_FAILURE The input point was invalid, or the output | |||||
* would be the identity or the point of order 2. | |||||
*/ | |||||
mask_t | |||||
montgomery_ladder ( | |||||
field_a_t out, | |||||
const field_a_t in, | |||||
const word_t *scalar, | |||||
unsigned int nbits, | |||||
unsigned int n_extra_doubles | |||||
) __attribute__((warn_unused_result)); | |||||
/** | |||||
* Full Montgomery aux ladder in decaf format. | |||||
* | |||||
* Out = scalar * in, where | |||||
* scalar is little-endian and has length $nbits$ bits. | |||||
* | |||||
* This function (once it's done; TODO) will always reject points | |||||
* on the twist. | |||||
* | |||||
* This function takes constant time with respect to $*in$ | |||||
* and $*scalar$, but not of course with respect to nbits or | |||||
* n_extra_doubles. | |||||
* | |||||
* @param [out] out The output point. | |||||
* @param [in] in The base point. | |||||
* @param [in] scalar The scalar's little-endian representation. | |||||
* @param [in] nbits The number of bits in the scalar. Note that | |||||
* unlike in Curve25519, we do not require the top bit to be set. | |||||
* | |||||
* @retval MASK_SUCCESS The operation was successful. | |||||
* @retval MASK_FAILURE The input point was invalid, or the output | |||||
* would be the identity or the point of order 2. | |||||
*/ | |||||
mask_t | |||||
decaf_montgomery_ladder ( | |||||
field_a_t out, | |||||
const field_a_t in, | |||||
const word_t *scalar, | |||||
unsigned int nbits | |||||
) __attribute__((warn_unused_result)); | |||||
/** | |||||
* Scalar multiply a twisted Edwards-form point. | |||||
* | |||||
* This function takes constant time. | |||||
* | |||||
* Currently the scalar is always exactly 448 bits long. | |||||
* | |||||
* @param [inout] working The point to multply. | |||||
* @param [in] scalar The scalar, in little-endian form. | |||||
*/ | |||||
void | |||||
scalarmul ( | |||||
tw_extensible_a_t working, | |||||
const word_t scalar[SCALAR_WORDS] | |||||
/* TODO? int nbits */ | |||||
); | |||||
/** | |||||
* Scalar multiply a twisted Edwards-form point, simply, in extended coordinates. | |||||
* | |||||
* This function takes constant time. | |||||
* | |||||
* Currently the scalar is always exactly 448 bits long. | |||||
* | |||||
* @param [inout] working The point to multply. | |||||
* @param [in] scalar The scalar, in little-endian form. | |||||
*/ | |||||
void | |||||
scalarmul_ed ( | |||||
tw_extended_a_t working, | |||||
const word_t scalar[SCALAR_WORDS] | |||||
/* TODO? int nbits */ | |||||
); | |||||
/** | |||||
* Scalar multiply a twisted Edwards-form point. Use the same | |||||
* algorithm as scalarmul(), but uses variable array indices. | |||||
* | |||||
* Currently the scalar is always exactly 448 bits long. | |||||
* | |||||
* @warning This function uses variable array indices, | |||||
* so it is insecure against cache-timing attacks. It is intended | |||||
* for microbenchmarking, to see how much constant-time arithmetic | |||||
* costs us. | |||||
* | |||||
* @param [inout] working The point to multply. | |||||
* @param [in] scalar The scalar, in little-endian form. | |||||
*/ | |||||
void | |||||
scalarmul_vlook ( | |||||
tw_extensible_a_t working, | |||||
const word_t scalar[SCALAR_WORDS] | |||||
); | |||||
/** | |||||
* Precompute a table to accelerate fixed-point scalar | |||||
* multiplication using the "multiple signed combs" approach. | |||||
* | |||||
* This function computes $n$ "comb" tables, each containing | |||||
* 2^(t-1) points in tw_niels_t format. You must have | |||||
* n * t * s >= SCALAR_BITS = 446 for complete coverage. | |||||
* | |||||
* The scalar multiplication algorithm may adjust the scalar by | |||||
* a multiple of q. Therefore, we strongly recommend to use base | |||||
* points in the q-torsion group (i.e. doubly even points). | |||||
* | |||||
* @param [out] out The table to compute. | |||||
* @param [in] base The base point. | |||||
* @param [in] n The number of combs in the table. | |||||
* @param [in] t The number of teeth in each comb. | |||||
* @param [in] s The spacing between the teeth. | |||||
* @param [out] prealloc An optional preallocated array containing | |||||
* space for n<<(t-1) values of type tw_niels_t. | |||||
* | |||||
* @retval MASK_SUCCESS Success. | |||||
* @retval MASK_FAILURE Failure, most likely because we are out | |||||
* of memory. | |||||
*/ | |||||
mask_t | |||||
precompute_fixed_base ( | |||||
struct fixed_base_table_t *out, | |||||
const tw_extensible_a_t base, | |||||
unsigned int n, | |||||
unsigned int t, | |||||
unsigned int s, | |||||
tw_niels_a_t *prealloc | |||||
) __attribute__((warn_unused_result)); | |||||
/** | |||||
* Destroy a fixed-base table. Frees any memory that we allocated | |||||
* for the combs. | |||||
* | |||||
* @param [in] table The table to destroy. | |||||
*/ | |||||
void | |||||
destroy_fixed_base ( | |||||
struct fixed_base_table_t *table | |||||
); | |||||
/** | |||||
* Scalar multiplication with precomputation. Set working to | |||||
* to [scalar] * Base, where Base is the base point passed to | |||||
* precompute_for_combs(). | |||||
* | |||||
* The scalar may be adjusted by a multiple of q, so this routine | |||||
* can be wrong by a cofactor if the base has cofactor components. | |||||
* | |||||
* @param [out] out The output point. | |||||
* @param [in] scalar The scalar. | |||||
* @param [in] nbits The number of bits in the scalar. Must be <= n*t*s. | |||||
* @param [in] table The precomputed table. | |||||
* | |||||
* @retval MASK_SUCCESS Success. | |||||
* @retval MASK_FAILURE Failure, because n*t*s < nbits | |||||
*/ | |||||
mask_t | |||||
scalarmul_fixed_base ( | |||||
tw_extensible_a_t out, | |||||
const word_t *scalar, | |||||
unsigned int nbits, | |||||
const struct fixed_base_table_t *table | |||||
); | |||||
/** | |||||
* Variable-time scalar multiplication. | |||||
* | |||||
* @warning This function takes variable time. It is intended for | |||||
* microbenchmarking. | |||||
* | |||||
* @param [inout] working The input and output point. | |||||
* @param [in] scalar The scalar. | |||||
* @param [in] nbits The number of bits in the scalar | |||||
*/ | |||||
void | |||||
scalarmul_vt ( | |||||
tw_extensible_a_t working, | |||||
const word_t *scalar, | |||||
unsigned int nbits | |||||
); | |||||
/** | |||||
* Precompute a table to accelerate fixed-point scalar | |||||
* multiplication (and, more importantly, linear combos) | |||||
* using the "windowed non-adjacent form" approach. | |||||
* | |||||
* @param [out] out The output table. Must have room for 1<<i entries. | |||||
* @param [in] base The base point. | |||||
* @param [in] tbits The number of bits to put in the table. | |||||
* | |||||
* @retval MASK_SUCCESS Success. | |||||
* @retval MASK_FAILURE Failure, most likely because we are out | |||||
* of memory. | |||||
*/ | |||||
mask_t | |||||
precompute_fixed_base_wnaf ( | |||||
tw_niels_a_t *out, | |||||
const tw_extensible_a_t base, | |||||
unsigned int tbits | |||||
) __attribute__((warn_unused_result)); | |||||
/** | |||||
* Variable-time scalar multiplication with precomputed WNAF | |||||
* tables. | |||||
* | |||||
* @warning This function takes variable time. It is intended for | |||||
* microbenchmarking. | |||||
* | |||||
* @param [out] out The output point. | |||||
* @param [in] scalar The scalar. | |||||
* @param [in] nbits The number of bits in the scalar. | |||||
* @param [in] precmp The precomputed WNAF table. | |||||
* @param [in] table_bits The number of bits in the WNAF table. | |||||
*/ | |||||
void | |||||
scalarmul_fixed_base_wnaf_vt ( | |||||
tw_extensible_a_t out, | |||||
const word_t *scalar, | |||||
unsigned int nbits, | |||||
const tw_niels_a_t *precmp, | |||||
unsigned int table_bits | |||||
); | |||||
/** | |||||
* Variable-time scalar linear combination of two points: one | |||||
* variable, and one fixed (with fixed-base WNAF tables) | |||||
* | |||||
* @warning This function takes variable time. It is intended for | |||||
* signature verification. | |||||
* | |||||
* @param [inout] working The output point, and also the variable input. | |||||
* @param [in] scalar_var The scalar for the variable input. | |||||
* @param [in] nbits_var The number of bits in scalar_var. | |||||
* @param [in] scalar_pre The scalar for the fixed input. | |||||
* @param [in] nbits_pre The number of bits in scalar_pre. | |||||
* @param [in] precmp The precomputed WNAF table. | |||||
* @param [in] table_bits_pre The number of bits in the WNAF table. | |||||
*/ | |||||
void | |||||
linear_combo_var_fixed_vt ( | |||||
tw_extensible_a_t working, | |||||
const word_t scalar_var[SCALAR_WORDS], | |||||
unsigned int nbits_var, | |||||
const word_t scalar_pre[SCALAR_WORDS], | |||||
unsigned int nbits_pre, | |||||
const tw_niels_a_t *precmp, | |||||
unsigned int table_bits_pre | |||||
); | |||||
/** | |||||
* Variable-time scalar linear combination of two fixed points. | |||||
* | |||||
* @warning This function takes variable time. It is intended for | |||||
* signature verification. | |||||
* | |||||
* @param [out] working The output point. | |||||
* @param [in] scalar1 The first scalar. | |||||
* @param [in] nbits1 The number of bits in the first scalar. | |||||
* @param [in] table1 The first precomputed table. | |||||
* @param [in] scalar2 The second scalar. | |||||
* @param [in] nbits1 The number of bits in the second scalar. | |||||
* @param [in] table1 The second precomputed table. | |||||
* | |||||
* @retval MASK_SUCCESS Success. | |||||
* @retval MASK_FAILURE Failure, because eg the tables are too small. | |||||
*/ | |||||
mask_t | |||||
linear_combo_combs_vt ( | |||||
tw_extensible_a_t out, | |||||
const word_t scalar1[SCALAR_WORDS], | |||||
unsigned int nbits1, | |||||
const struct fixed_base_table_t *table1, | |||||
const word_t scalar2[SCALAR_WORDS], | |||||
unsigned int nbits2, | |||||
const struct fixed_base_table_t *table2 | |||||
); | |||||
#ifdef __cplusplus | |||||
}; | |||||
#endif | |||||
#endif /* __P448_ALGO_H__ */ |
@@ -1,49 +0,0 @@ | |||||
/* Copyright (c) 2014 Cryptography Research, Inc. | |||||
* Released under the MIT License. See LICENSE.txt for license information. | |||||
*/ | |||||
#ifndef __GOLDI_SHA512_H__ | |||||
#define __GOLDI_SHA512_H__ 1 | |||||
#include <stdint.h> | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
#define SHA512_OUTPUT_BYTES 64 | |||||
/** | |||||
* SHA512 hashing context. | |||||
* | |||||
* This structure is opaque. | |||||
*/ | |||||
typedef struct { | |||||
/** @privatesection */ | |||||
uint64_t chain[8]; | |||||
uint8_t block[128]; | |||||
uint64_t nbytes; | |||||
} sha512_ctx_a_t[1]; | |||||
void | |||||
sha512_init ( | |||||
sha512_ctx_a_t ctx | |||||
); | |||||
void | |||||
sha512_update ( | |||||
sha512_ctx_a_t ctx, | |||||
const unsigned char *data, | |||||
uint64_t bytes | |||||
); | |||||
void | |||||
sha512_final ( | |||||
sha512_ctx_a_t ctx, | |||||
uint8_t result[SHA512_OUTPUT_BYTES] | |||||
); | |||||
#ifdef __cplusplus | |||||
}; /* extern "C" */ | |||||
#endif | |||||
#endif /* __GOLDI_SHA512_H__ */ |
@@ -75,7 +75,7 @@ mask_t | |||||
p448_is_zero ( | p448_is_zero ( | ||||
const p448_t *in | const p448_t *in | ||||
); | ); | ||||
static __inline__ void | static __inline__ void | ||||
p448_bias ( | p448_bias ( | ||||
p448_t *inout, | p448_t *inout, | ||||
@@ -8,7 +8,7 @@ | |||||
* @brief Field-specific arithmetic. | * @brief Field-specific arithmetic. | ||||
*/ | */ | ||||
#include "ec_point.h" | |||||
#include "field.h" | |||||
void | void | ||||
field_isr ( | field_isr ( | ||||
@@ -1,30 +0,0 @@ | |||||
/** | |||||
* @file f_magic.h | |||||
* @copyright | |||||
* Copyright (c) 2014 Cryptography Research, Inc. \n | |||||
* Released under the MIT License. See LICENSE.txt for license information. | |||||
* @author Mike Hamburg | |||||
* @brief Goldilocks magic numbers (group orders, coefficients, algo params etc). | |||||
*/ | |||||
#ifndef __GOLDI_F_MAGIC_H__ | |||||
#define __GOLDI_F_MAGIC_H__ 1 | |||||
#include "field.h" | |||||
#include "ec_point.h" | |||||
/** | |||||
* @brief The Edwards "d" term for this curve. | |||||
*/ | |||||
static const int64_t EDWARDS_D = -39081; | |||||
/** @brief The number of combs to use for signed comb algo */ | |||||
#define COMB_N (USE_BIG_COMBS ? 5 : 8) | |||||
/** @brief The number of teeth of the combs for signed comb algo */ | |||||
#define COMB_T (USE_BIG_COMBS ? 5 : 4) | |||||
/** @brief The spacing the of combs for signed comb algo */ | |||||
#define COMB_S (USE_BIG_COMBS ? 18 : 14) | |||||
#endif /* __GOLDI_F_MAGIC_H__ */ |
@@ -1,81 +0,0 @@ | |||||
/* Copyright (c) 2014 Cryptography Research, Inc. | |||||
* Released under the MIT License. See LICENSE.txt for license information. | |||||
*/ | |||||
#include "field.h" | |||||
#include "magic.h" | |||||
#include "barrett_field.h" | |||||
/* FUTURE: automatically generate this file? */ | |||||
const uint8_t FIELD_MODULUS[FIELD_BYTES] = { | |||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |||||
/*!*/ 0xfe, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF | |||||
}; | |||||
const word_t SCALARMUL_FIXED_WINDOW_ADJUSTMENT[2*SCALAR_WORDS] = { | |||||
U64LE(0xebec9967f5d3f5c2), | |||||
U64LE(0x0aa09b49b16c9a02), | |||||
U64LE(0x7f6126aec172cd8e), | |||||
U64LE(0x00000007b027e54d), | |||||
U64LE(0x0000000000000000), | |||||
U64LE(0x0000000000000000), | |||||
U64LE(0x4000000000000000), | |||||
U64LE(0xc873d6d54a7bb0cf), | |||||
U64LE(0xe933d8d723a70aad), | |||||
U64LE(0xbb124b65129c96fd), | |||||
U64LE(0x00000008335dc163), | |||||
U64LE(0x0000000000000000), | |||||
U64LE(0x0000000000000000), | |||||
U64LE(0x0000000000000000) | |||||
}; | |||||
const affine_a_t goldilocks_base_point = {{ | |||||
#ifdef USE_NEON_PERM | |||||
{{{ 0xaed939f,0xc59d070,0xf0de840,0x5f065c3, 0xf4ba0c7,0xdf73324,0xc170033,0x3a6a26a, | |||||
0x4c63d96,0x4609845,0xf3932d9,0x1b4faff, 0x6147eaa,0xa2692ff,0x9cecfa9,0x297ea0e | |||||
}}}, | |||||
#else | |||||
{{{ U56LE(0xf0de840aed939f), U56LE(0xc170033f4ba0c7), | |||||
U56LE(0xf3932d94c63d96), U56LE(0x9cecfa96147eaa), | |||||
U56LE(0x5f065c3c59d070), U56LE(0x3a6a26adf73324), | |||||
U56LE(0x1b4faff4609845), U56LE(0x297ea0ea2692ff) | |||||
}}}, | |||||
#endif | |||||
{{{ 19 }}} | |||||
}}; | |||||
static const word_t curve_prime_order_lo[(224+WORD_BITS-1)/WORD_BITS] = { | |||||
U64LE(0xdc873d6d54a7bb0d), | |||||
U64LE(0xde933d8d723a70aa), | |||||
U64LE(0x3bb124b65129c96f), | |||||
0x8335dc16 | |||||
}; | |||||
const struct barrett_prime_t curve_prime_order = { | |||||
GOLDI_FIELD_WORDS, | |||||
62 % WORD_BITS, | |||||
sizeof(curve_prime_order_lo)/sizeof(curve_prime_order_lo[0]), | |||||
curve_prime_order_lo | |||||
}; | |||||
const field_a_t | |||||
sqrt_d_minus_1 = {{{ | |||||
#ifdef USE_NEON_PERM | |||||
0x6749f46,0x24d9770,0xd2e2183,0xa49f7b4, | |||||
0xb4f0179,0x8c5f656,0x888db42,0xdcac462, | |||||
0xbdeea38,0x748734a,0x5a189aa,0x49443b8, | |||||
0x6f14c06,0x0b25b7a,0x51e65ca,0x12fec0c | |||||
#else | |||||
U56LE(0xd2e21836749f46), | |||||
U56LE(0x888db42b4f0179), | |||||
U56LE(0x5a189aabdeea38), | |||||
U56LE(0x51e65ca6f14c06), | |||||
U56LE(0xa49f7b424d9770), | |||||
U56LE(0xdcac4628c5f656), | |||||
U56LE(0x49443b8748734a), | |||||
U56LE(0x12fec0c0b25b7a) | |||||
#endif | |||||
}}}; |
@@ -8,7 +8,7 @@ | |||||
* @brief Field-specific arithmetic. | * @brief Field-specific arithmetic. | ||||
*/ | */ | ||||
#include "ec_point.h" | |||||
#include "field.h" | |||||
void | void | ||||
field_isr ( | field_isr ( | ||||
@@ -1,30 +0,0 @@ | |||||
/** | |||||
* @file f_magic.h | |||||
* @copyright | |||||
* Copyright (c) 2014 Cryptography Research, Inc. \n | |||||
* Released under the MIT License. See LICENSE.txt for license information. | |||||
* @author Mike Hamburg | |||||
* @brief Goldilocks magic numbers (group orders, coefficients, algo params etc). | |||||
*/ | |||||
#ifndef __GOLDI_F_MAGIC_H__ | |||||
#define __GOLDI_F_MAGIC_H__ 1 | |||||
#include "field.h" | |||||
#include "ec_point.h" | |||||
/** | |||||
* @brief The Edwards "d" term for this curve. | |||||
*/ | |||||
static const int64_t EDWARDS_D = 53825; | |||||
/** @brief The number of combs to use for signed comb algo */ | |||||
#define COMB_N (USE_BIG_COMBS ? 6 : 5) | |||||
/** @brief The number of teeth of the combs for signed comb algo */ | |||||
#define COMB_T (USE_BIG_COMBS ? 5 : 4) | |||||
/** @brief The spacing the of combs for signed comb algo */ | |||||
#define COMB_S (USE_BIG_COMBS ? 16 : 24) | |||||
#endif /* __GOLDI_F_MAGIC_H__ */ |
@@ -1,68 +0,0 @@ | |||||
/* Copyright (c) 2014 Cryptography Research, Inc. | |||||
* Released under the MIT License. See LICENSE.txt for license information. | |||||
*/ | |||||
#include "field.h" | |||||
#include "magic.h" | |||||
#include "barrett_field.h" | |||||
/* FUTURE: automatically generate this file? */ | |||||
const uint8_t FIELD_MODULUS[FIELD_BYTES] = { | |||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |||||
/*!*/ 0xfe, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF | |||||
}; | |||||
const word_t SCALARMUL_FIXED_WINDOW_ADJUSTMENT[2*SCALAR_WORDS] = { | |||||
U64LE(0x58b51bc56ea8f0c4), | |||||
U64LE(0xd361f6a2348b50c9), | |||||
U64LE(0x08089c139c0002ae), | |||||
U64LE(0x0001d2ac3d9503a0), | |||||
U64LE(0x0000000000000000), | |||||
U64LE(0x0000000000000000), | |||||
U64LE(0x0000000000000000), | |||||
0x40000000, | |||||
U64LE(0xcb9c25073e36965b), | |||||
U64LE(0x6f2d48d8460f1661), | |||||
U64LE(0x0ab6256f7aaaae3e), | |||||
U64LE(0x00026e3afcc6af80), | |||||
U64LE(0x0000000000000000), | |||||
U64LE(0x0000000000000000), | |||||
U64LE(0x0000000000000000), | |||||
0x00000000 | |||||
}; | |||||
const affine_a_t goldilocks_base_point = {{ | |||||
{{{ | |||||
U60LE(0x849ff7f845c30d3), | |||||
U60LE(0x7dda488553a4c5b), | |||||
U60LE(0x1d3a2d9844831ea), | |||||
U60LE(0xb33ecf6ade470a2), | |||||
U60LE(0x8b3cb95210bd3c3), | |||||
U60LE(0xfc955e59aeefa65), | |||||
U60LE(0x3ab247cd530013c), | |||||
U60LE(0x7ca42af3d564280) | |||||
}}}, | |||||
{{{ 5 }}} | |||||
}}; | |||||
static const word_t curve_prime_order_lo[(240+WORD_BITS-1)/WORD_BITS] = { | |||||
U64LE(0x72e70941cf8da597), | |||||
U64LE(0x9bcb52361183c598), | |||||
U64LE(0x02ad895bdeaaab8f), | |||||
U64LE(0x9b8ebf31abe0) | |||||
}; | |||||
const struct barrett_prime_t curve_prime_order = { | |||||
GOLDI_FIELD_WORDS, | |||||
30 % WORD_BITS, | |||||
sizeof(curve_prime_order_lo)/sizeof(curve_prime_order_lo[0]), | |||||
curve_prime_order_lo | |||||
}; | |||||
const field_a_t | |||||
sqrt_d_minus_1 = {{{ | |||||
232 /* Whoa, it comes out even. */ | |||||
}}}; |
@@ -8,7 +8,7 @@ | |||||
* @brief Field-specific arithmetic. | * @brief Field-specific arithmetic. | ||||
*/ | */ | ||||
#include "ec_point.h" | |||||
#include "field.h" | |||||
void | void | ||||
field_isr ( | field_isr ( | ||||
@@ -1,30 +0,0 @@ | |||||
/** | |||||
* @file f_magic.h | |||||
* @copyright | |||||
* Copyright (c) 2014 Cryptography Research, Inc. \n | |||||
* Released under the MIT License. See LICENSE.txt for license information. | |||||
* @author Mike Hamburg | |||||
* @brief Goldilocks magic numbers (group orders, coefficients, algo params etc). | |||||
*/ | |||||
#ifndef __GOLDI_F_MAGIC_H__ | |||||
#define __GOLDI_F_MAGIC_H__ 1 | |||||
#include "field.h" | |||||
#include "ec_point.h" | |||||
/** | |||||
* @brief The Edwards "d" term for this curve. | |||||
*/ | |||||
static const int64_t EDWARDS_D = -376014; | |||||
/** @brief The number of combs to use for signed comb algo */ | |||||
#define COMB_N (USE_BIG_COMBS ? 4 : 5) | |||||
/** @brief The number of teeth of the combs for signed comb algo */ | |||||
#define COMB_T (USE_BIG_COMBS ? 5 : 4) | |||||
/** @brief The spacing the of combs for signed comb algo */ | |||||
#define COMB_S (USE_BIG_COMBS ? 26 : 26) | |||||
#endif /* __GOLDI_F_MAGIC_H__ */ |
@@ -1,111 +0,0 @@ | |||||
/* Copyright (c) 2014 Cryptography Research, Inc. | |||||
* Released under the MIT License. See LICENSE.txt for license information. | |||||
*/ | |||||
#include "field.h" | |||||
#include "magic.h" | |||||
#include "barrett_field.h" | |||||
/* FUTURE: automatically generate this file? */ | |||||
const uint8_t FIELD_MODULUS[FIELD_BYTES] = { | |||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, | |||||
0xFF, 0x01 | |||||
}; | |||||
const word_t SCALARMUL_FIXED_WINDOW_ADJUSTMENT[2*SCALAR_WORDS] = { | |||||
U64LE(0xbf15dbca0ae7f294), | |||||
U64LE(0x04273ba96570e0ba), | |||||
U64LE(0xc94750a1813ac0fb), | |||||
U64LE(0xea4939b8b9037a08), | |||||
U64LE(0x0000000000000002), | |||||
U64LE(0x0000000000000000), | |||||
U64LE(0x0000000000000000), | |||||
U64LE(0x0000000000000000), | |||||
0x80, | |||||
U64LE(0x7e2bb79415cfe529), | |||||
U64LE(0x084e7752cae1c175), | |||||
U64LE(0x928ea143027581f6), | |||||
U64LE(0xd49273717206f411), | |||||
U64LE(0x0000000000000005), | |||||
U64LE(0x0000000000000000), | |||||
U64LE(0x0000000000000000), | |||||
U64LE(0x0000000000000000), | |||||
0x0 | |||||
}; | |||||
const affine_a_t goldilocks_base_point = {{ | |||||
{{{ | |||||
#ifdef USE_P521_3x3_TRANSPOSE | |||||
U58LE(0x02a940a2f19ba6c), | |||||
U58LE(0x3331c90d2c6ba52), | |||||
U58LE(0x2878a3bfd9f42fc), | |||||
0, | |||||
U58LE(0x03ec4cd920e2a8c), | |||||
U58LE(0x0c6203913f6ecc5), | |||||
U58LE(0x06277e432c8a5ac), | |||||
0, | |||||
U58LE(0x1d568fc99c6059d), | |||||
U58LE(0x1b2063b22fcf270), | |||||
U58LE(0x0752cb45c48648b), | |||||
0 | |||||
#else | |||||
U58LE(0x02a940a2f19ba6c), | |||||
U58LE(0x03ec4cd920e2a8c), | |||||
U58LE(0x1d568fc99c6059d), | |||||
U58LE(0x3331c90d2c6ba52), | |||||
U58LE(0x0c6203913f6ecc5), | |||||
U58LE(0x1b2063b22fcf270), | |||||
U58LE(0x2878a3bfd9f42fc), | |||||
U58LE(0x06277e432c8a5ac), | |||||
U58LE(0x0752cb45c48648b) | |||||
#endif | |||||
}}}, | |||||
{{{ 12 }}} | |||||
}}; | |||||
static const word_t curve_prime_order_lo[(261+WORD_BITS-1)/WORD_BITS] = { | |||||
U64LE(0xbf15dbca0ae7f295), | |||||
U64LE(0x4273ba96570e0ba), | |||||
U64LE(0xc94750a1813ac0fb), | |||||
U64LE(0xea4939b8b9037a08), | |||||
2 | |||||
}; | |||||
const struct barrett_prime_t curve_prime_order = { | |||||
GOLDI_FIELD_WORDS, | |||||
7 % WORD_BITS, | |||||
sizeof(curve_prime_order_lo)/sizeof(curve_prime_order_lo[0]), | |||||
curve_prime_order_lo | |||||
}; | |||||
const field_a_t | |||||
sqrt_d_minus_1 = {{{ | |||||
#ifdef USE_P521_3x3_TRANSPOSE | |||||
U58LE(0x1e2be72c1c81990), | |||||
U58LE(0x207dfc238a33e46), | |||||
U58LE(0x2264cfb418c4c30), | |||||
0, | |||||
U58LE(0x1135002ad596c69), | |||||
U58LE(0x0e30107cd79d1f6), | |||||
U58LE(0x0524b9e715937f5), | |||||
0, | |||||
U58LE(0x2ab3a257a22666d), | |||||
U58LE(0x2d80cc2936a1824), | |||||
U58LE(0x0a9ea3ac10d6aed), | |||||
0 | |||||
#else | |||||
U58LE(0x1e2be72c1c81990), | |||||
U58LE(0x1135002ad596c69), | |||||
U58LE(0x2ab3a257a22666d), | |||||
U58LE(0x207dfc238a33e46), | |||||
U58LE(0x0e30107cd79d1f6), | |||||
U58LE(0x2d80cc2936a1824), | |||||
U58LE(0x2264cfb418c4c30), | |||||
U58LE(0x0524b9e715937f5), | |||||
U58LE(0x0a9ea3ac10d6aed) | |||||
#endif | |||||
}}}; |
@@ -1,987 +0,0 @@ | |||||
/* Copyright (c) 2014 Cryptography Research, Inc. | |||||
* Released under the MIT License. See LICENSE.txt for license information. | |||||
*/ | |||||
#include "word.h" | |||||
#include <stdlib.h> | |||||
#include <limits.h> | |||||
#include <string.h> | |||||
#include "intrinsics.h" | |||||
#include "scalarmul.h" | |||||
#include "barrett_field.h" | |||||
#include "constant_time.h" | |||||
mask_t | |||||
montgomery_ladder ( | |||||
field_a_t out, | |||||
const field_a_t in, | |||||
const word_t *scalar, | |||||
unsigned int nbits, | |||||
unsigned int n_extra_doubles | |||||
) { | |||||
montgomery_a_t mont; | |||||
deserialize_montgomery(mont, in); | |||||
int i,j,n=(nbits-1)%WORD_BITS; | |||||
mask_t pflip = 0; | |||||
for (j=(nbits+WORD_BITS-1)/WORD_BITS-1; j>=0; j--) { | |||||
word_t w = scalar[j]; | |||||
for (i=n; i>=0; i--) { | |||||
mask_t flip = -((w>>i)&1); | |||||
constant_time_cond_swap(mont->xa,mont->xd,sizeof(mont->xd),flip^pflip); | |||||
constant_time_cond_swap(mont->za,mont->zd,sizeof(mont->xd),flip^pflip); | |||||
montgomery_step(mont); | |||||
pflip = flip; | |||||
} | |||||
n = WORD_BITS-1; | |||||
} | |||||
constant_time_cond_swap(mont->xa,mont->xd,sizeof(mont->xd),pflip); | |||||
constant_time_cond_swap(mont->za,mont->zd,sizeof(mont->xd),pflip); | |||||
assert(n_extra_doubles < INT_MAX); | |||||
for (j=0; j<(int)n_extra_doubles; j++) { | |||||
montgomery_step(mont); | |||||
} | |||||
return serialize_montgomery(out, mont, in); | |||||
} | |||||
mask_t | |||||
decaf_montgomery_ladder ( | |||||
field_a_t out, | |||||
const field_a_t in, | |||||
const word_t *scalar, | |||||
unsigned int nbits | |||||
) { | |||||
montgomery_aux_a_t mont; | |||||
decaf_deserialize_montgomery(mont, in); | |||||
int i,j,n=(nbits-1)%WORD_BITS; | |||||
mask_t pflip = 0; | |||||
for (j=(nbits+WORD_BITS-1)/WORD_BITS-1; j>=0; j--) { | |||||
word_t w = scalar[j]; | |||||
for (i=n; i>=0; i--) { | |||||
mask_t flip = -((w>>i)&1); | |||||
constant_time_cond_swap(mont->xa,mont->xd,sizeof(mont->xd),flip^pflip); | |||||
constant_time_cond_swap(mont->za,mont->zd,sizeof(mont->xd),flip^pflip); | |||||
montgomery_aux_step(mont); | |||||
pflip = flip; | |||||
} | |||||
n = WORD_BITS-1; | |||||
} | |||||
constant_time_cond_swap(mont->xa,mont->xd,sizeof(mont->xd),pflip); | |||||
constant_time_cond_swap(mont->za,mont->zd,sizeof(mont->xd),pflip); | |||||
return decaf_serialize_montgomery(out, mont, pflip); | |||||
} | |||||
static __inline__ void | |||||
__attribute__((unused,always_inline)) | |||||
constant_time_lookup_tw_pniels ( | |||||
tw_pniels_a_t out, | |||||
const tw_pniels_a_t *in, | |||||
int nin, | |||||
int idx | |||||
) { | |||||
constant_time_lookup(out,in,sizeof(*out),nin,idx); | |||||
} | |||||
static __inline__ void | |||||
__attribute__((unused,always_inline)) | |||||
constant_time_lookup_tw_extended ( | |||||
tw_extended_a_t out, | |||||
const tw_extended_a_t *in, | |||||
int nin, | |||||
int idx | |||||
) { | |||||
constant_time_lookup(out,in,sizeof(*out),nin,idx); | |||||
} | |||||
static __inline__ void | |||||
__attribute__((unused,always_inline)) | |||||
constant_time_lookup_tw_niels ( | |||||
tw_niels_a_t out, | |||||
const tw_niels_a_t *in, | |||||
int nin, | |||||
int idx | |||||
) { | |||||
constant_time_lookup(out,in,sizeof(*out),nin,idx); | |||||
} | |||||
static void | |||||
convert_to_signed_window_form ( | |||||
word_t *out, | |||||
const word_t *scalar, | |||||
int nwords_scalar, | |||||
const word_t *prepared_data, | |||||
int nwords_pd | |||||
) { | |||||
assert(nwords_pd <= nwords_scalar); | |||||
mask_t mask = -(scalar[0]&1); | |||||
word_t carry = add_nr_ext_packed(out, scalar, nwords_scalar, prepared_data, nwords_pd, ~mask); | |||||
carry += add_nr_ext_packed(out, out, nwords_scalar, prepared_data+nwords_pd, nwords_pd, mask); | |||||
assert(!(out[0]&1)); | |||||
int i; | |||||
for (i=0; i<nwords_scalar; i++) { | |||||
out[i] >>= 1; | |||||
if (i<nwords_scalar-1) { | |||||
out[i] |= out[i+1]<<(WORD_BITS-1); | |||||
} else { | |||||
out[i] |= carry<<(WORD_BITS-1); | |||||
} | |||||
} | |||||
} | |||||
void | |||||
scalarmul ( | |||||
tw_extensible_a_t working, | |||||
const word_t scalar[SCALAR_WORDS] | |||||
) { | |||||
const int WINDOW = SCALARMUL_FIXED_WINDOW_SIZE, | |||||
WINDOW_MASK = (1<<WINDOW)-1, WINDOW_T_MASK = WINDOW_MASK >> 1, | |||||
NTABLE = 1<<(WINDOW-1), | |||||
nbits = ROUND_UP(SCALAR_BITS,WINDOW); | |||||
word_t scalar2[SCALAR_WORDS]; | |||||
convert_to_signed_window_form ( | |||||
scalar2, scalar, SCALAR_WORDS, | |||||
SCALARMUL_FIXED_WINDOW_ADJUSTMENT, SCALAR_WORDS | |||||
); | |||||
/* FIXME: tabulator is redundant */ | |||||
tw_extensible_a_t tabulator; | |||||
copy_tw_extensible(tabulator, working); | |||||
double_tw_extensible(tabulator); | |||||
tw_pniels_a_t | |||||
pn VECTOR_ALIGNED, | |||||
multiples[NTABLE] VECTOR_ALIGNED; | |||||
convert_tw_extensible_to_tw_pniels(pn, tabulator); | |||||
convert_tw_extensible_to_tw_pniels(multiples[0], working); | |||||
int i,j; | |||||
for (i=1; i<NTABLE; i++) { | |||||
add_tw_pniels_to_tw_extensible(working, pn); | |||||
convert_tw_extensible_to_tw_pniels(multiples[i], working); | |||||
} | |||||
i = nbits - WINDOW; | |||||
int bits = scalar2[i/WORD_BITS] >> (i%WORD_BITS) & WINDOW_MASK, | |||||
inv = (bits>>(WINDOW-1))-1; | |||||
bits ^= inv; | |||||
constant_time_lookup_tw_pniels(pn, (const tw_pniels_a_t*)multiples, NTABLE, bits & WINDOW_T_MASK); | |||||
cond_negate_tw_pniels(pn, inv); | |||||
convert_tw_pniels_to_tw_extensible(working, pn); | |||||
for (i-=WINDOW; i>=0; i-=WINDOW) { | |||||
for (j=0; j<WINDOW; j++) { | |||||
double_tw_extensible(working); | |||||
} | |||||
bits = scalar2[i/WORD_BITS] >> (i%WORD_BITS); | |||||
if (i/WORD_BITS < SCALAR_WORDS-1 && i%WORD_BITS >= WORD_BITS-WINDOW) { | |||||
bits ^= scalar2[i/WORD_BITS+1] << (WORD_BITS - (i%WORD_BITS)); | |||||
} | |||||
bits &= WINDOW_MASK; | |||||
inv = (bits>>(WINDOW-1))-1; | |||||
bits ^= inv; | |||||
constant_time_lookup_tw_pniels(pn, (const tw_pniels_a_t*)multiples, NTABLE, bits & WINDOW_T_MASK); | |||||
cond_negate_tw_pniels(pn, inv); | |||||
add_tw_pniels_to_tw_extensible(working, pn); | |||||
} | |||||
} | |||||
void | |||||
scalarmul_ed ( | |||||
tw_extended_a_t working, | |||||
const word_t scalar[SCALAR_WORDS] | |||||
) { | |||||
const int WINDOW = SCALARMUL_FIXED_WINDOW_SIZE, | |||||
WINDOW_MASK = (1<<WINDOW)-1, WINDOW_T_MASK = WINDOW_MASK >> 1, | |||||
NTABLE = 1<<(WINDOW-1), | |||||
nbits = ROUND_UP(SCALAR_BITS,WINDOW); | |||||
word_t scalar2[SCALAR_WORDS]; | |||||
convert_to_signed_window_form ( | |||||
scalar2, scalar, SCALAR_WORDS, | |||||
SCALARMUL_FIXED_WINDOW_ADJUSTMENT, SCALAR_WORDS | |||||
); | |||||
tw_extended_a_t | |||||
tmp VECTOR_ALIGNED, | |||||
multiples[NTABLE] VECTOR_ALIGNED; | |||||
copy_tw_extended(tmp, working); | |||||
add_tw_extended(tmp, tmp); | |||||
copy_tw_extended(multiples[0], working); | |||||
int i,j; | |||||
for (i=1; i<NTABLE; i++) { | |||||
add_tw_extended(working, tmp); | |||||
copy_tw_extended(multiples[i], working); | |||||
} | |||||
i = nbits - WINDOW; | |||||
int bits, inv; | |||||
set_identity_tw_extended(working); | |||||
for (; i>=0; i-=WINDOW) { | |||||
if (i != nbits-WINDOW) { | |||||
for (j=0; j<WINDOW; j++) { | |||||
add_tw_extended(working,working); | |||||
} | |||||
} | |||||
bits = scalar2[i/WORD_BITS] >> (i%WORD_BITS); | |||||
if (i/WORD_BITS < SCALAR_WORDS-1 && i%WORD_BITS >= WORD_BITS-WINDOW) { | |||||
bits ^= scalar2[i/WORD_BITS+1] << (WORD_BITS - (i%WORD_BITS)); | |||||
} | |||||
bits &= WINDOW_MASK; | |||||
inv = (bits>>(WINDOW-1))-1; | |||||
bits ^= inv; | |||||
constant_time_lookup_tw_extended(tmp, (const tw_extended_a_t*)multiples, NTABLE, bits & WINDOW_T_MASK); | |||||
add_sub_tw_extended(working, working, tmp, inv); | |||||
} | |||||
} | |||||
void | |||||
scalarmul_vlook ( | |||||
tw_extensible_a_t working, | |||||
const word_t scalar[SCALAR_WORDS] | |||||
) { | |||||
const int WINDOW = SCALARMUL_FIXED_WINDOW_SIZE, | |||||
WINDOW_MASK = (1<<WINDOW)-1, WINDOW_T_MASK = WINDOW_MASK >> 1, | |||||
NTABLE = 1<<(WINDOW-1), | |||||
nbits = ROUND_UP(SCALAR_BITS,WINDOW); | |||||
word_t scalar2[SCALAR_WORDS]; | |||||
convert_to_signed_window_form( | |||||
scalar2, scalar, SCALAR_WORDS, | |||||
SCALARMUL_FIXED_WINDOW_ADJUSTMENT, SCALAR_WORDS | |||||
); | |||||
tw_extensible_a_t tabulator; | |||||
copy_tw_extensible(tabulator, working); | |||||
double_tw_extensible(tabulator); | |||||
tw_pniels_a_t | |||||
pn VECTOR_ALIGNED, | |||||
multiples[NTABLE] VECTOR_ALIGNED; | |||||
convert_tw_extensible_to_tw_pniels(pn, tabulator); | |||||
convert_tw_extensible_to_tw_pniels(multiples[0], working); | |||||
int i,j; | |||||
for (i=1; i<NTABLE; i++) { | |||||
add_tw_pniels_to_tw_extensible(working, pn); | |||||
convert_tw_extensible_to_tw_pniels(multiples[i], working); | |||||
} | |||||
i = nbits - WINDOW; | |||||
int bits = scalar2[i/WORD_BITS] >> (i%WORD_BITS) & WINDOW_MASK, | |||||
inv = (bits>>(WINDOW-1))-1; | |||||
bits ^= inv; | |||||
copy_tw_pniels(pn, multiples[bits & WINDOW_T_MASK]); | |||||
cond_negate_tw_pniels(pn, inv); | |||||
convert_tw_pniels_to_tw_extensible(working, pn); | |||||
for (i-=WINDOW; i>=0; i-=WINDOW) { | |||||
for (j=0; j<WINDOW; j++) { | |||||
double_tw_extensible(working); | |||||
} | |||||
bits = scalar2[i/WORD_BITS] >> (i%WORD_BITS); | |||||
if (i/WORD_BITS < SCALAR_WORDS-1 && i%WORD_BITS >= WORD_BITS-WINDOW) { | |||||
bits ^= scalar2[i/WORD_BITS+1] << (WORD_BITS - (i%WORD_BITS)); | |||||
} | |||||
bits &= WINDOW_MASK; | |||||
inv = (bits>>(WINDOW-1))-1; | |||||
bits ^= inv; | |||||
copy_tw_pniels(pn, multiples[bits & WINDOW_T_MASK]); | |||||
cond_negate_tw_pniels(pn, inv); | |||||
add_tw_pniels_to_tw_extensible(working, pn); | |||||
} | |||||
} | |||||
static mask_t | |||||
schedule_scalar_for_combs ( | |||||
word_t *scalar2, | |||||
const word_t *scalar, | |||||
unsigned int nbits, | |||||
const struct fixed_base_table_t* table | |||||
) { | |||||
unsigned int i; | |||||
unsigned int n = table->n, t = table->t, s = table->s; | |||||
if (n*t*s < nbits || n < 1 || t < 1 || s < 1) { | |||||
return MASK_FAILURE; | |||||
} | |||||
unsigned int scalar_words = (nbits + WORD_BITS - 1)/WORD_BITS, | |||||
scalar2_words = scalar_words; | |||||
if (scalar2_words < SCALAR_WORDS) | |||||
scalar2_words = SCALAR_WORDS; | |||||
word_t scalar3[scalar2_words]; | |||||
/* Copy scalar to scalar3, but clear its high bits (if there are any) */ | |||||
for (i=0; i<scalar_words; i++) { | |||||
scalar3[i] = scalar[i]; | |||||
} | |||||
if (likely(i) && (nbits % WORD_BITS)) { | |||||
scalar3[i-1] &= (((word_t)1) << (nbits%WORD_BITS)) - 1; | |||||
} | |||||
for (; i<scalar2_words; i++) { | |||||
scalar3[i] = 0; | |||||
} | |||||
convert_to_signed_window_form ( | |||||
scalar2, | |||||
scalar3, scalar2_words, | |||||
table->scalar_adjustments , SCALAR_WORDS | |||||
); | |||||
return MASK_SUCCESS; | |||||
} | |||||
mask_t | |||||
scalarmul_fixed_base ( | |||||
tw_extensible_a_t out, | |||||
const word_t scalar[SCALAR_WORDS], | |||||
unsigned int nbits, | |||||
const struct fixed_base_table_t* table | |||||
) { | |||||
unsigned int i,j,k; | |||||
unsigned int n = table->n, t = table->t, s = table->s; | |||||
unsigned int scalar2_words = (nbits + WORD_BITS - 1)/WORD_BITS; | |||||
if (scalar2_words < SCALAR_WORDS) scalar2_words = SCALAR_WORDS; | |||||
word_t scalar2[scalar2_words]; | |||||
mask_t succ = schedule_scalar_for_combs(scalar2, scalar, nbits, table); | |||||
if (!succ) return MASK_FAILURE; | |||||
#ifdef __clang_analyzer__ | |||||
assert(t >= 1); | |||||
#endif | |||||
tw_niels_a_t ni; | |||||
for (i=0; i<s; i++) { | |||||
if (i) double_tw_extensible(out); | |||||
for (j=0; j<n; j++) { | |||||
int tab = 0; | |||||
/* | |||||
* PERF: This computation takes about 1.5µs on SBR, i.e. 2-3% of the | |||||
* time of a keygen or sign op. Surely it is possible to speed it up. | |||||
*/ | |||||
for (k=0; k<t; k++) { | |||||
unsigned int bit = (s-1-i) + k*s + j*(s*t); | |||||
if (bit < scalar2_words * WORD_BITS) { | |||||
tab |= (scalar2[bit/WORD_BITS] >> (bit%WORD_BITS) & 1) << k; | |||||
} | |||||
} | |||||
mask_t invert = (tab>>(t-1))-1; | |||||
tab ^= invert; | |||||
tab &= (1<<(t-1)) - 1; | |||||
constant_time_lookup_tw_niels(ni, (const tw_niels_a_t*)table->table + (j<<(t-1)), 1<<(t-1), tab); | |||||
cond_negate_tw_niels(ni, invert); | |||||
if (i||j) { | |||||
add_tw_niels_to_tw_extensible(out, ni); | |||||
} else { | |||||
convert_tw_niels_to_tw_extensible(out, ni); | |||||
} | |||||
} | |||||
} | |||||
return MASK_SUCCESS; | |||||
} | |||||
mask_t | |||||
linear_combo_combs_vt ( | |||||
tw_extensible_a_t out, | |||||
const word_t scalar1[SCALAR_WORDS], | |||||
unsigned int nbits1, | |||||
const struct fixed_base_table_t* table1, | |||||
const word_t scalar2[SCALAR_WORDS], | |||||
unsigned int nbits2, | |||||
const struct fixed_base_table_t* table2 | |||||
) { | |||||
unsigned int i,j,k,sc; | |||||
unsigned int s1 = table1->s, s2 = table2->s, smax = (s1 > s2) ? s1 : s2; | |||||
unsigned int scalar1b_words = (nbits1 + WORD_BITS - 1)/WORD_BITS; | |||||
if (scalar1b_words < SCALAR_WORDS) scalar1b_words = SCALAR_WORDS; | |||||
unsigned int scalar2b_words = (nbits2 + WORD_BITS - 1)/WORD_BITS; | |||||
if (scalar2b_words < SCALAR_WORDS) scalar2b_words = SCALAR_WORDS; | |||||
word_t scalar1b[scalar1b_words], scalar2b[scalar2b_words]; | |||||
/* Schedule the scalars */ | |||||
mask_t succ; | |||||
succ = schedule_scalar_for_combs(scalar1b, scalar1, nbits1, table1); | |||||
if (!succ) return MASK_FAILURE; | |||||
succ = schedule_scalar_for_combs(scalar2b, scalar2, nbits2, table2); | |||||
if (!succ) return MASK_FAILURE; | |||||
#ifdef __clang_analyzer__ | |||||
assert(table1->t >= 1); | |||||
assert(table2->t >= 1); | |||||
#endif | |||||
const struct tw_niels_t *ni; | |||||
unsigned int swords[2] = {scalar1b_words, scalar2b_words}; | |||||
word_t *scalars[2] = {scalar1b,scalar2b}; | |||||
set_identity_tw_extensible(out); | |||||
for (i=0; i<smax; i++) { | |||||
if (i) double_tw_extensible(out); | |||||
for (sc=0; sc<2; sc++) { | |||||
const struct fixed_base_table_t* table = sc ? table2 : table1; | |||||
int ii = i-smax+table->s; | |||||
if (ii < 0) continue; | |||||
assert(ii < (int)table->s); | |||||
for (j=0; j<table->n; j++) { | |||||
int tab = 0; | |||||
for (k=0; k<table->t; k++) { | |||||
unsigned int bit = (table->s-1-ii) + k*table->s + j*(table->s*table->t); | |||||
if (bit < swords[sc] * WORD_BITS) { | |||||
tab |= (scalars[sc][bit/WORD_BITS] >> (bit%WORD_BITS) & 1) << k; | |||||
} | |||||
} | |||||
mask_t invert = (tab>>(table->t-1))-1; | |||||
tab ^= invert; | |||||
tab &= (1<<(table->t-1)) - 1; | |||||
ni = table->table[tab + (j<<(table->t-1))]; | |||||
if (invert) sub_tw_niels_from_tw_extensible(out, ni); | |||||
else add_tw_niels_to_tw_extensible(out, ni); | |||||
} | |||||
} | |||||
} | |||||
return MASK_SUCCESS; | |||||
} | |||||
mask_t | |||||
precompute_fixed_base ( | |||||
struct fixed_base_table_t* out, | |||||
const tw_extensible_a_t base, | |||||
unsigned int n, | |||||
unsigned int t, | |||||
unsigned int s, | |||||
tw_niels_a_t *prealloc | |||||
) { | |||||
if (s < 1 || t < 1 || n < 1 || n*t*s < SCALAR_BITS) { | |||||
really_memset(out, 0, sizeof(*out)); | |||||
return 0; | |||||
} | |||||
out->n = n; | |||||
out->t = t; | |||||
out->s = s; | |||||
tw_extensible_a_t working, start; | |||||
copy_tw_extensible(working, base); | |||||
tw_pniels_a_t pn_tmp; | |||||
tw_pniels_a_t *doubles = (tw_pniels_a_t *) malloc_vector(sizeof(*doubles) * (t-1)); | |||||
field_a_t *zs = (field_a_t *) malloc_vector(sizeof(*zs) * (n<<(t-1))); | |||||
field_a_t *zis = (field_a_t *) malloc_vector(sizeof(*zis) * (n<<(t-1))); | |||||
tw_niels_a_t *table = prealloc; | |||||
if (prealloc) { | |||||
out->own_table = 0; | |||||
} else { | |||||
table = (tw_niels_a_t *) malloc_vector(sizeof(*table) * (n<<(t-1))); | |||||
out->own_table = 1; | |||||
} | |||||
out->table = table; | |||||
if (!doubles || !zs || !zis || !table) { | |||||
free(doubles); | |||||
free(zs); | |||||
free(zis); | |||||
really_memset(out, 0, sizeof(*out)); | |||||
really_memset(table, 0, sizeof(*table) * (n<<(t-1))); | |||||
if (!prealloc) free(table); | |||||
return 0; | |||||
} | |||||
unsigned int i,j,k; | |||||
/* Compute the scalar adjustments, equal to 2^nbits-1 mod q */ | |||||
unsigned int adjustment_size = (n*t*s)/WORD_BITS + 1; | |||||
assert(adjustment_size >= SCALAR_WORDS); | |||||
word_t adjustment[adjustment_size]; | |||||
for (i=0; i<adjustment_size; i++) { | |||||
adjustment[i] = -1; | |||||
} | |||||
adjustment[(n*t*s) / WORD_BITS] += ((word_t)1) << ((n*t*s) % WORD_BITS); | |||||
/* The low adjustment is 2^nbits - 1 mod q */ | |||||
barrett_reduce(adjustment, adjustment_size, 0, &curve_prime_order); | |||||
word_t *low_adjustment = &out->scalar_adjustments[(SCALAR_WORDS)*(adjustment[0] & 1)], | |||||
*high_adjustment = &out->scalar_adjustments[(SCALAR_WORDS)*((~adjustment[0]) & 1)]; | |||||
for (i=0; i<SCALAR_WORDS; i++) { | |||||
low_adjustment[i] = adjustment[i]; | |||||
} | |||||
/* The high adjustment is low + q = low - q_lo + 2^big */ | |||||
(void) | |||||
sub_nr_ext_packed( | |||||
high_adjustment, | |||||
adjustment, SCALAR_WORDS, | |||||
curve_prime_order.p_lo, curve_prime_order.nwords_lo, | |||||
-1 | |||||
); | |||||
if (curve_prime_order.p_shift) { | |||||
high_adjustment[curve_prime_order.nwords_p - 1] += ((word_t)1)<<curve_prime_order.p_shift; | |||||
} | |||||
/* OK, now compute the tables */ | |||||
for (i=0; i<n; i++) { | |||||
/* doubling phase */ | |||||
for (j=0; j<t; j++) { | |||||
if (j) { | |||||
convert_tw_extensible_to_tw_pniels(pn_tmp, working); | |||||
add_tw_pniels_to_tw_extensible(start, pn_tmp); | |||||
} else { | |||||
copy_tw_extensible(start, working); | |||||
} | |||||
if (j==t-1 && i==n-1) { | |||||
break; | |||||
} | |||||
double_tw_extensible(working); | |||||
if (j<t-1) { | |||||
convert_tw_extensible_to_tw_pniels(doubles[j], working); | |||||
} | |||||
for (k=0; k<s-1; k++) { | |||||
double_tw_extensible(working); | |||||
} | |||||
} | |||||
/* Gray-code phase */ | |||||
for (j=0;; j++) { | |||||
int gray = j ^ (j>>1); | |||||
int idx = (((i+1)<<(t-1))-1) ^ gray; | |||||
convert_tw_extensible_to_tw_pniels(pn_tmp, start); | |||||
copy_tw_niels(table[idx], pn_tmp->n); | |||||
field_copy(zs[idx], pn_tmp->z); | |||||
if (j >= (1u<<(t-1)) - 1) break; | |||||
int delta = (j+1) ^ ((j+1)>>1) ^ gray; | |||||
for (k=0; delta>1; k++) | |||||
delta >>=1; | |||||
if (gray & (1<<k)) { | |||||
/* start += doubles[k] */ | |||||
add_tw_pniels_to_tw_extensible(start, doubles[k]); | |||||
} else { | |||||
/* start -= doubles[k] */ | |||||
sub_tw_pniels_from_tw_extensible(start, doubles[k]); | |||||
} | |||||
} | |||||
} | |||||
field_simultaneous_invert(zis, (const field_a_t*)zs, n<<(t-1)); | |||||
field_a_t product; | |||||
for (i=0; i<n<<(t-1); i++) { | |||||
field_mul(product, table[i]->a, zis[i]); | |||||
field_strong_reduce(product); | |||||
field_copy(table[i]->a, product); | |||||
field_mul(product, table[i]->b, zis[i]); | |||||
field_strong_reduce(product); | |||||
field_copy(table[i]->b, product); | |||||
field_mul(product, table[i]->c, zis[i]); | |||||
field_strong_reduce(product); | |||||
field_copy(table[i]->c, product); | |||||
} | |||||
mask_t ret = ~field_is_zero(zis[0]); | |||||
free(doubles); | |||||
free(zs); | |||||
free(zis); | |||||
if (unlikely(!ret)) { | |||||
really_memset(table, 0, sizeof(*table) * (n<<(t-1))); | |||||
if (!prealloc) free(table); | |||||
really_memset(out, 0, sizeof(*out)); | |||||
return 0; | |||||
} | |||||
return ret; | |||||
} | |||||
void | |||||
destroy_fixed_base ( | |||||
struct fixed_base_table_t* table | |||||
) { | |||||
if (table->table) { | |||||
really_memset(table->table,0,sizeof(*table->table)*(table->n<<(table->t-1))); | |||||
} | |||||
if (table->own_table) { | |||||
free(table->table); | |||||
} | |||||
really_memset(table,0,sizeof(*table)); | |||||
} | |||||
mask_t | |||||
precompute_fixed_base_wnaf ( | |||||
tw_niels_a_t *out, | |||||
const tw_extensible_a_t const_base, | |||||
unsigned int tbits | |||||
) { | |||||
int i; | |||||
field_a_t *zs = (field_a_t *) malloc_vector(sizeof(*zs)<<tbits); | |||||
field_a_t *zis = (field_a_t *) malloc_vector(sizeof(*zis)<<tbits); | |||||
if (!zs || !zis) { | |||||
free(zs); | |||||
free(zis); | |||||
return 0; | |||||
} | |||||
tw_extensible_a_t base; | |||||
copy_tw_extensible(base,const_base); | |||||
tw_pniels_a_t twop, tmp; | |||||
convert_tw_extensible_to_tw_pniels(tmp, base); | |||||
field_copy(zs[0], tmp->z); | |||||
copy_tw_niels(out[0], tmp->n); | |||||
if (tbits > 0) { | |||||
double_tw_extensible(base); | |||||
convert_tw_extensible_to_tw_pniels(twop, base); | |||||
add_tw_pniels_to_tw_extensible(base, tmp); | |||||
convert_tw_extensible_to_tw_pniels(tmp, base); | |||||
field_copy(zs[1], tmp->z); | |||||
copy_tw_niels(out[1], tmp->n); | |||||
for (i=2; i < 1<<tbits; i++) { | |||||
add_tw_pniels_to_tw_extensible(base, twop); | |||||
convert_tw_extensible_to_tw_pniels(tmp, base); | |||||
field_copy(zs[i], tmp->z); | |||||
copy_tw_niels(out[i], tmp->n); | |||||
} | |||||
} | |||||
field_simultaneous_invert(zis, (const field_a_t *)zs, 1<<tbits); | |||||
field_a_t product; | |||||
for (i=0; i<1<<tbits; i++) { | |||||
field_mul(product, out[i]->a, zis[i]); | |||||
field_strong_reduce(product); | |||||
field_copy(out[i]->a, product); | |||||
field_mul(product, out[i]->b, zis[i]); | |||||
field_strong_reduce(product); | |||||
field_copy(out[i]->b, product); | |||||
field_mul(product, out[i]->c, zis[i]); | |||||
field_strong_reduce(product); | |||||
field_copy(out[i]->c, product); | |||||
} | |||||
free(zs); | |||||
free(zis); | |||||
return -1; | |||||
} | |||||
/** | |||||
* @cond internal | |||||
* Control for variable-time scalar multiply algorithms. | |||||
*/ | |||||
struct smvt_control { | |||||
int power, addend; | |||||
}; | |||||
static int | |||||
recode_wnaf( | |||||
struct smvt_control *control, /* [nbits/(tableBits+1) + 3] */ | |||||
const word_t *scalar, | |||||
unsigned int nbits, | |||||
unsigned int tableBits) | |||||
{ | |||||
int current = 0, i, j; | |||||
unsigned int position = 0; | |||||
/* PERF: negate scalar if it's large | |||||
* PERF: this is a pretty simplistic algorithm. I'm sure there's a faster one... | |||||
*/ | |||||
for (i=nbits-1; i >= 0; i--) { | |||||
int bit = (scalar[i/WORD_BITS] >> (i%WORD_BITS)) & 1; | |||||
current = 2*current + bit; | |||||
/* | |||||
* Sizing: |current| >= 2^(tableBits+1) -> |current| = 2^0 | |||||
* So current loses (tableBits+1) bits every time. It otherwise gains | |||||
* 1 bit per iteration. The number of iterations is | |||||
* (nbits + 2 + tableBits), and an additional control word is added at | |||||
* the end. So the total number of control words is at most | |||||
* ceil((nbits+1) / (tableBits+1)) + 2 = floor((nbits)/(tableBits+1)) + 2. | |||||
* There's also the stopper with power -1, for a total of +3. | |||||
*/ | |||||
if (current >= (2<<tableBits) || current <= -1 - (2<<tableBits)) { | |||||
int delta = (current + 1) >> 1; /* |delta| < 2^tablebits */ | |||||
current = -(current & 1); | |||||
for (j=i; (delta & 1) == 0; j++) { | |||||
delta >>= 1; | |||||
} | |||||
control[position].power = j+1; | |||||
control[position].addend = delta; | |||||
position++; | |||||
assert(position <= nbits/(tableBits+1) + 2); | |||||
} | |||||
} | |||||
if (current) { | |||||
for (j=0; (current & 1) == 0; j++) { | |||||
current >>= 1; | |||||
} | |||||
control[position].power = j; | |||||
control[position].addend = current; | |||||
position++; | |||||
assert(position <= nbits/(tableBits+1) + 2); | |||||
} | |||||
control[position].power = -1; | |||||
control[position].addend = 0; | |||||
return position; | |||||
} | |||||
static void | |||||
prepare_wnaf_table( | |||||
tw_pniels_a_t *output, | |||||
tw_extensible_a_t working, | |||||
unsigned int tbits | |||||
) { | |||||
int i; | |||||
convert_tw_extensible_to_tw_pniels(output[0], working); | |||||
if (tbits == 0) return; | |||||
double_tw_extensible(working); | |||||
tw_pniels_a_t twop; | |||||
convert_tw_extensible_to_tw_pniels(twop, working); | |||||
add_tw_pniels_to_tw_extensible(working, output[0]); | |||||
convert_tw_extensible_to_tw_pniels(output[1], working); | |||||
for (i=2; i < 1<<tbits; i++) { | |||||
add_tw_pniels_to_tw_extensible(working, twop); | |||||
convert_tw_extensible_to_tw_pniels(output[i], working); | |||||
} | |||||
} | |||||
void | |||||
scalarmul_vt ( | |||||
tw_extensible_a_t working, | |||||
const word_t scalar[SCALAR_WORDS], | |||||
unsigned int nbits | |||||
) { | |||||
const int table_bits = SCALARMUL_WNAF_TABLE_BITS; | |||||
struct smvt_control control[nbits/(table_bits+1)+3]; | |||||
int control_bits = recode_wnaf(control, scalar, nbits, table_bits); | |||||
tw_pniels_a_t precmp[1<<table_bits]; | |||||
prepare_wnaf_table(precmp, working, table_bits); | |||||
if (control_bits > 0) { | |||||
assert(control[0].addend > 0); | |||||
assert(control[0].power >= 0); | |||||
convert_tw_pniels_to_tw_extensible(working, precmp[control[0].addend >> 1]); | |||||
} else { | |||||
set_identity_tw_extensible(working); | |||||
return; | |||||
} | |||||
int conti = 1, i; | |||||
for (i = control[0].power - 1; i >= 0; i--) { | |||||
double_tw_extensible(working); | |||||
if (i == control[conti].power) { | |||||
assert(control[conti].addend); | |||||
if (control[conti].addend > 0) { | |||||
add_tw_pniels_to_tw_extensible(working, precmp[control[conti].addend >> 1]); | |||||
} else { | |||||
sub_tw_pniels_from_tw_extensible(working, precmp[(-control[conti].addend) >> 1]); | |||||
} | |||||
conti++; | |||||
assert(conti <= control_bits); | |||||
} | |||||
} | |||||
} | |||||
void | |||||
scalarmul_fixed_base_wnaf_vt ( | |||||
tw_extensible_a_t working, | |||||
const word_t scalar[SCALAR_WORDS], | |||||
unsigned int nbits, | |||||
const tw_niels_a_t *precmp, | |||||
unsigned int table_bits | |||||
) { | |||||
struct smvt_control control[nbits/(table_bits+1)+3]; | |||||
int control_bits = recode_wnaf(control, scalar, nbits, table_bits); | |||||
if (control_bits > 0) { | |||||
assert(control[0].addend > 0); | |||||
assert(control[0].power >= 0); | |||||
convert_tw_niels_to_tw_extensible(working, precmp[control[0].addend >> 1]); | |||||
} else { | |||||
set_identity_tw_extensible(working); | |||||
return; | |||||
} | |||||
int conti = 1, i; | |||||
for (; control[conti].power >= 0; conti++) { | |||||
assert(conti <= control_bits); | |||||
for (i = control[conti-1].power - control[conti].power; i; i--) { | |||||
double_tw_extensible(working); | |||||
} | |||||
assert(control[conti].addend); | |||||
if (control[conti].addend > 0) { | |||||
add_tw_niels_to_tw_extensible(working, precmp[control[conti].addend >> 1]); | |||||
} else { | |||||
sub_tw_niels_from_tw_extensible(working, precmp[(-control[conti].addend) >> 1]); | |||||
} | |||||
} | |||||
for (i = control[conti-1].power; i; i--) { | |||||
double_tw_extensible(working); | |||||
} | |||||
} | |||||
void | |||||
linear_combo_var_fixed_vt( | |||||
tw_extensible_a_t working, | |||||
const word_t scalar_var[SCALAR_WORDS], | |||||
unsigned int nbits_var, | |||||
const word_t scalar_pre[SCALAR_WORDS], | |||||
unsigned int nbits_pre, | |||||
const tw_niels_a_t *precmp, | |||||
unsigned int table_bits_pre | |||||
) { | |||||
const int table_bits_var = SCALARMUL_WNAF_COMBO_TABLE_BITS; | |||||
struct smvt_control control_var[nbits_var/(table_bits_var+1)+3]; | |||||
struct smvt_control control_pre[nbits_pre/(table_bits_pre+1)+3]; | |||||
int ncb_var = recode_wnaf(control_var, scalar_var, nbits_var, table_bits_var); | |||||
int ncb_pre = recode_wnaf(control_pre, scalar_pre, nbits_pre, table_bits_pre); | |||||
(void)ncb_var; | |||||
(void)ncb_pre; | |||||
tw_pniels_a_t precmp_var[1<<table_bits_var]; | |||||
prepare_wnaf_table(precmp_var, working, table_bits_var); | |||||
int contp=0, contv=0, i; | |||||
i = control_var[0].power; | |||||
if (i > control_pre[0].power) { | |||||
convert_tw_pniels_to_tw_extensible(working, precmp_var[control_var[0].addend >> 1]); | |||||
contv++; | |||||
} else if (i == control_pre[0].power && i >=0 ) { | |||||
convert_tw_pniels_to_tw_extensible(working, precmp_var[control_var[0].addend >> 1]); | |||||
add_tw_niels_to_tw_extensible(working, precmp[control_pre[0].addend >> 1]); | |||||
contv++; contp++; | |||||
} else { | |||||
i = control_pre[0].power; | |||||
convert_tw_niels_to_tw_extensible(working, precmp[control_pre[0].addend >> 1]); | |||||
contp++; | |||||
} | |||||
if (i < 0) { | |||||
set_identity_tw_extensible(working); | |||||
return; | |||||
} | |||||
for (i--; i >= 0; i--) { | |||||
double_tw_extensible(working); | |||||
if (i == control_var[contv].power) { | |||||
assert(control_var[contv].addend); | |||||
if (control_var[contv].addend > 0) { | |||||
add_tw_pniels_to_tw_extensible(working, precmp_var[control_var[contv].addend >> 1]); | |||||
} else { | |||||
sub_tw_pniels_from_tw_extensible(working, precmp_var[(-control_var[contv].addend) >> 1]); | |||||
} | |||||
contv++; | |||||
} | |||||
if (i == control_pre[contp].power) { | |||||
assert(control_pre[contp].addend); | |||||
if (control_pre[contp].addend > 0) { | |||||
add_tw_niels_to_tw_extensible(working, precmp[control_pre[contp].addend >> 1]); | |||||
} else { | |||||
sub_tw_niels_from_tw_extensible(working, precmp[(-control_pre[contp].addend) >> 1]); | |||||
} | |||||
contp++; | |||||
} | |||||
} | |||||
assert(contv == ncb_var); | |||||
assert(contp == ncb_pre); | |||||
} | |||||
@@ -1,177 +0,0 @@ | |||||
/* Copyright (c) 2011 Stanford University. | |||||
* Copyright (c) 2014 Cryptography Research, Inc. | |||||
* Released under the MIT License. See LICENSE.txt for license information. | |||||
*/ | |||||
#include "word.h" | |||||
#include "sha512.h" | |||||
#include <string.h> | |||||
#include <assert.h> | |||||
static inline uint64_t | |||||
rotate_r ( | |||||
uint64_t x, | |||||
int d | |||||
) { | |||||
return (x >> d) | (x << (64-d)); | |||||
} | |||||
static const uint64_t | |||||
sha512_init_state[8] = { | |||||
0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, | |||||
0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179 | |||||
}; | |||||
static const uint64_t | |||||
sha512_k[80] = { | |||||
0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, | |||||
0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, | |||||
0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, | |||||
0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694, | |||||
0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, | |||||
0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, | |||||
0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, | |||||
0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70, | |||||
0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, | |||||
0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, | |||||
0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, | |||||
0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, | |||||
0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, | |||||
0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, | |||||
0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, | |||||
0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, | |||||
0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, | |||||
0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, | |||||
0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, | |||||
0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817 | |||||
}; | |||||
static inline uint64_t S0 (uint64_t h1) { | |||||
return rotate_r(h1, 28) ^ rotate_r(h1, 34) ^ rotate_r(h1, 39); | |||||
} | |||||
static inline uint64_t S1 (uint64_t h4) { | |||||
return rotate_r(h4,14) ^ rotate_r(h4,18) ^ rotate_r(h4,41); | |||||
} | |||||
static inline uint64_t s0 (uint64_t a) { | |||||
return rotate_r(a,1) ^ rotate_r(a,8) ^ a>>7; | |||||
} | |||||
static inline uint64_t s1 (uint64_t b) { | |||||
return rotate_r(b,19) ^ rotate_r(b,61) ^ b>>6; | |||||
} | |||||
static inline uint64_t ch (uint64_t h4, uint64_t h5, uint64_t h6) { | |||||
return h6^(h4 & (h6^h5)); | |||||
} | |||||
static inline uint64_t maj(uint64_t h1, uint64_t h2, uint64_t h3) { | |||||
return (h1&h2) ^ (h3&(h1^h2)); | |||||
} | |||||
static void | |||||
sha512_process_block ( | |||||
sha512_ctx_a_t ctx | |||||
) { | |||||
uint64_t i, tmp, a, b, | |||||
*w = (uint64_t *) ctx->block, | |||||
*state = ctx->chain, | |||||
h0 = state[0], h1 = state[1], h2 = state[2], h3 = state[3], | |||||
h4 = state[4], h5 = state[5], h6 = state[6], h7 = state[7]; | |||||
/* Clang doesn't unswitch this automatically */ | |||||
for (i=0; i<16; i++) { | |||||
/* load up the input word for this round */ | |||||
tmp = w[i] = htobe64(w[i]); | |||||
tmp = tmp + h7 + S1(h4) + ch(h4,h5,h6) + sha512_k[i]; | |||||
/* shift register */ | |||||
h7 = h6; h6 = h5; h5 = h4; | |||||
h4 = h3 + tmp; | |||||
h3 = h2; h2 = h1; h1 = h0; | |||||
h0 = tmp + maj(h1,h2,h3) + S0(h1); | |||||
} | |||||
for (; i<80; i++) { | |||||
/* load up the input word for this round */ | |||||
a = w[(i+1 ) & 15]; | |||||
b = w[(i+14) & 15]; | |||||
tmp = w[i&15] = s0(a) + s1(b) + w[i&15] + w[(i+9) & 15]; | |||||
tmp = tmp + h7 + S1(h4) + ch(h4,h5,h6) + sha512_k[i]; | |||||
/* shift register */ | |||||
h7 = h6; h6 = h5; h5 = h4; | |||||
h4 = h3 + tmp; | |||||
h3 = h2; h2 = h1; h1 = h0; | |||||
h0 = tmp + maj(h1,h2,h3) + S0(h1); | |||||
} | |||||
state[0] += h0; | |||||
state[1] += h1; | |||||
state[2] += h2; | |||||
state[3] += h3; | |||||
state[4] += h4; | |||||
state[5] += h5; | |||||
state[6] += h6; | |||||
state[7] += h7; | |||||
} | |||||
void | |||||
sha512_init ( | |||||
sha512_ctx_a_t ctx | |||||
) { | |||||
ctx->nbytes = 0; | |||||
memcpy(ctx->chain, sha512_init_state, sizeof(sha512_init_state)); | |||||
memset(ctx->block, 0, sizeof(ctx->block)); | |||||
} | |||||
void | |||||
sha512_update ( | |||||
sha512_ctx_a_t ctx, | |||||
const unsigned char *data, | |||||
uint64_t bytes | |||||
) { | |||||
assert(ctx->nbytes < 1ull<<56); | |||||
assert(bytes < 1ull<<56); | |||||
while (bytes) { | |||||
uint64_t fill = ctx->nbytes % 128, accept = 128 - fill; | |||||
if (accept > bytes) accept = bytes; | |||||
ctx->nbytes += accept; | |||||
memcpy(ctx->block + fill, data, accept); | |||||
if (fill+accept == 128) | |||||
sha512_process_block(ctx); | |||||
bytes -= accept; | |||||
data += accept; | |||||
} | |||||
assert(ctx->nbytes < 1ull<<56); | |||||
} | |||||
void | |||||
sha512_final ( | |||||
sha512_ctx_a_t ctx, | |||||
uint8_t result[64] | |||||
) { | |||||
uint64_t fill = ctx->nbytes % 128, i; | |||||
ctx->block[fill++] = 0x80; | |||||
if (fill > 112) { | |||||
memset(ctx->block + fill, 0, 128-fill); | |||||
sha512_process_block(ctx); | |||||
fill = 0; | |||||
} | |||||
memset(ctx->block + fill, 0, 112-fill); | |||||
uint64_t highCount = 0, lowCount = htobe64((ctx->nbytes * 8)); | |||||
memcpy(&ctx->block[112],&highCount,8); | |||||
memcpy(&ctx->block[120],&lowCount,8); | |||||
sha512_process_block(ctx); | |||||
for (i=0; i<8; i++) { | |||||
ctx->chain[i] = htobe64(ctx->chain[i]); | |||||
} | |||||
memcpy(result, ctx->chain, sizeof(ctx->chain)); | |||||
sha512_init(ctx); | |||||
} |
@@ -1,780 +0,0 @@ | |||||
/* Copyright (c) 2014 Cryptography Research, Inc. | |||||
* Released under the MIT License. See LICENSE.txt for license information. | |||||
*/ | |||||
#include "word.h" | |||||
#include <sys/time.h> | |||||
#include <sys/types.h> | |||||
#include <stdio.h> | |||||
#include <memory.h> | |||||
#include "field.h" | |||||
#include "ec_point.h" | |||||
#include "scalarmul.h" | |||||
#include "barrett_field.h" | |||||
#include "crandom.h" | |||||
#include "goldilocks.h" | |||||
#include "sha512.h" | |||||
#include "decaf.h" | |||||
#include "decaf_crypto.h" | |||||
#include "shake.h" | |||||
static __inline__ void | |||||
ignore_result ( int result ) { | |||||
(void)result; | |||||
} | |||||
static double now(void) { | |||||
struct timeval tv; | |||||
gettimeofday(&tv, NULL); | |||||
return tv.tv_sec + tv.tv_usec/1000000.0; | |||||
} | |||||
static void field_randomize( struct crandom_state_t *crand, field_a_t a ) { | |||||
crandom_generate(crand, (unsigned char *)a, sizeof(*a)); | |||||
field_strong_reduce(a); | |||||
} | |||||
static void q448_randomize( struct crandom_state_t *crand, word_t sk[SCALAR_WORDS] ) { | |||||
crandom_generate(crand, (unsigned char *)sk, SCALAR_BYTES); | |||||
} | |||||
static void field_print( const char *descr, const field_a_t a ) { | |||||
int j; | |||||
unsigned char ser[FIELD_BYTES]; | |||||
field_serialize(ser,a); | |||||
printf("%s = 0x", descr); | |||||
for (j=FIELD_BYTES - 1; j>=0; j--) { | |||||
printf("%02x", ser[j]); | |||||
} | |||||
printf("\n"); | |||||
} | |||||
static void __attribute__((unused)) | |||||
field_print_full ( | |||||
const char *descr, | |||||
const field_a_t a | |||||
) { | |||||
int j; | |||||
printf("%s = 0x", descr); | |||||
for (j=15; j>=0; j--) { | |||||
printf("%02" PRIxWORD "_" PRIxWORD56 " ", | |||||
a->limb[j]>>28, a->limb[j]&((1<<28)-1)); | |||||
} | |||||
printf("\n"); | |||||
} | |||||
#ifndef N_TESTS_BASE | |||||
#define N_TESTS_BASE 10000 | |||||
#endif | |||||
int main(int argc, char **argv) { | |||||
(void)argc; | |||||
(void)argv; | |||||
struct tw_extensible_t ext; | |||||
struct extensible_t exta; | |||||
struct tw_niels_t niels; | |||||
struct tw_pniels_t pniels; | |||||
struct affine_t affine; | |||||
struct montgomery_t mb; | |||||
struct montgomery_aux_t mba; | |||||
field_a_t a,b,c,d; | |||||
double when; | |||||
int i; | |||||
int nbase = N_TESTS_BASE; | |||||
/* Bad randomness so we can debug. */ | |||||
char initial_seed[32]; | |||||
for (i=0; i<32; i++) initial_seed[i] = i; | |||||
struct crandom_state_t crand; | |||||
crandom_init_from_buffer(&crand, initial_seed); | |||||
/* For testing the performance drop from the crandom debuffering change. | |||||
ignore_result(crandom_init_from_file(&crand, "/dev/urandom", 10000, 1)); | |||||
*/ | |||||
word_t sk[SCALAR_WORDS],tk[SCALAR_WORDS]; | |||||
q448_randomize(&crand, sk); | |||||
memset(a,0,sizeof(a)); | |||||
memset(b,0,sizeof(b)); | |||||
memset(c,0,sizeof(c)); | |||||
memset(d,0,sizeof(d)); | |||||
when = now(); | |||||
for (i=0; i<nbase*5000; i++) { | |||||
field_mul(c, b, a); | |||||
} | |||||
when = now() - when; | |||||
printf("mul: %5.1fns\n", when * 1e9 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase*5000; i++) { | |||||
field_sqr(c, a); | |||||
} | |||||
when = now() - when; | |||||
printf("sqr: %5.1fns\n", when * 1e9 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase*5000; i++) { | |||||
field_mulw(c, b, 1234562); | |||||
} | |||||
when = now() - when; | |||||
printf("mulw: %5.1fns\n", when * 1e9 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase*500; i++) { | |||||
field_mul(c, b, a); | |||||
field_mul(a, b, c); | |||||
} | |||||
when = now() - when; | |||||
printf("mul dep: %5.1fns\n", when * 1e9 / i / 2); | |||||
when = now(); | |||||
for (i=0; i<nbase*10; i++) { | |||||
field_randomize(&crand, a); | |||||
} | |||||
when = now() - when; | |||||
printf("rand448: %5.1fns\n", when * 1e9 / i); | |||||
sha512_ctx_a_t sha; | |||||
uint8_t hashout[128]; | |||||
when = now(); | |||||
for (i=0; i<nbase; i++) { | |||||
sha512_init(sha); | |||||
sha512_final(sha, hashout); | |||||
} | |||||
when = now() - when; | |||||
printf("sha512 1blk: %5.1fns\n", when * 1e9 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase; i++) { | |||||
sha512_update(sha, hashout, 128); | |||||
} | |||||
when = now() - when; | |||||
printf("sha512 blk: %5.1fns (%0.2f MB/s)\n", when * 1e9 / i, 128*i/when/1e6); | |||||
when = now(); | |||||
for (i=0; i<nbase; i++) { | |||||
shake256_hash(hashout,128,hashout,128); | |||||
} | |||||
when = now() - when; | |||||
printf("shake 1blk: %5.1fns\n", when * 1e9 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase; i++) { | |||||
field_isr(c, a); | |||||
} | |||||
when = now() - when; | |||||
printf("isr auto: %5.1fµs\n", when * 1e6 / i); | |||||
for (i=0; i<100; i++) { | |||||
field_randomize(&crand, a); | |||||
field_isr(d,a); | |||||
field_sqr(b,d); | |||||
field_mul(c,b,a); | |||||
field_sqr(b,c); | |||||
field_subw(b,1); | |||||
if (!field_is_zero(b)) { | |||||
printf("ISR validation failure!\n"); | |||||
field_print("a", a); | |||||
field_print("s", d); | |||||
} | |||||
} | |||||
when = now(); | |||||
for (i=0; i<nbase; i++) { | |||||
elligator_2s_inject(&affine, a); | |||||
} | |||||
when = now() - when; | |||||
printf("elligator: %5.1fµs\n", when * 1e6 / i); | |||||
for (i=0; i<100; i++) { | |||||
field_randomize(&crand, a); | |||||
elligator_2s_inject(&affine, a); | |||||
if (!validate_affine(&affine)) { | |||||
printf("Elligator validation failure!\n"); | |||||
field_print("a", a); | |||||
field_print("x", affine.x); | |||||
field_print("y", affine.y); | |||||
} | |||||
} | |||||
when = now(); | |||||
for (i=0; i<nbase; i++) { | |||||
deserialize_affine(&affine, a); | |||||
} | |||||
when = now() - when; | |||||
printf("decompress: %5.1fµs\n", when * 1e6 / i); | |||||
convert_affine_to_extensible(&exta, &affine); | |||||
when = now(); | |||||
for (i=0; i<nbase; i++) { | |||||
serialize_extensible(a, &exta); | |||||
} | |||||
when = now() - when; | |||||
printf("compress: %5.1fµs\n", when * 1e6 / i); | |||||
int goods = 0; | |||||
for (i=0; i<100; i++) { | |||||
field_randomize(&crand, a); | |||||
mask_t good = deserialize_affine(&affine, a); | |||||
if (good & !validate_affine(&affine)) { | |||||
printf("Deserialize validation failure!\n"); | |||||
field_print("a", a); | |||||
field_print("x", affine.x); | |||||
field_print("y", affine.y); | |||||
} else if (good) { | |||||
goods++; | |||||
convert_affine_to_extensible(&exta,&affine); | |||||
serialize_extensible(b, &exta); | |||||
field_sub(c,b,a); | |||||
if (!field_is_zero(c)) { | |||||
printf("Reserialize validation failure!\n"); | |||||
field_print("a", a); | |||||
field_print("x", affine.x); | |||||
field_print("y", affine.y); | |||||
deserialize_affine(&affine, b); | |||||
field_print("b", b); | |||||
field_print("x", affine.x); | |||||
field_print("y", affine.y); | |||||
printf("\n"); | |||||
} | |||||
} | |||||
} | |||||
if (goods<i/3) { | |||||
printf("Deserialization validation failure! Deserialized %d/%d points\n", goods, i); | |||||
} | |||||
word_t lsk[768/WORD_BITS]; | |||||
crandom_generate(&crand, (unsigned char *)lsk, sizeof(lsk)); | |||||
when = now(); | |||||
for (i=0; i<nbase*100; i++) { | |||||
barrett_reduce(lsk,sizeof(lsk)/sizeof(word_t),0,&curve_prime_order); | |||||
} | |||||
when = now() - when; | |||||
printf("barrett red: %5.1fns\n", when * 1e9 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase*10; i++) { | |||||
barrett_mac(lsk,SCALAR_WORDS,lsk,SCALAR_WORDS,lsk,SCALAR_WORDS,&curve_prime_order); | |||||
} | |||||
when = now() - when; | |||||
printf("barrett mac: %5.1fns\n", when * 1e9 / i); | |||||
decaf_448_scalar_t asc,bsc,csc; | |||||
memset(asc,0,sizeof(asc)); | |||||
memset(bsc,0,sizeof(bsc)); | |||||
when = now(); | |||||
for (i=0; i<nbase*10; i++) { | |||||
decaf_448_scalar_mul(csc,asc,bsc); | |||||
} | |||||
when = now() - when; | |||||
printf("decaf mulsc: %5.1fns\n", when * 1e9 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
decaf_448_scalar_invert(csc,bsc); | |||||
} | |||||
when = now() - when; | |||||
printf("decaf invsc: %5.1fµs\n", when * 1e6 / i); | |||||
memset(&ext,0,sizeof(ext)); | |||||
memset(&niels,0,sizeof(niels)); /* avoid assertions in p521 even though this isn't a valid ext or niels */ | |||||
tw_extended_a_t ed; | |||||
convert_tw_extensible_to_tw_extended(ed,&ext); | |||||
when = now(); | |||||
for (i=0; i<nbase*100; i++) { | |||||
add_tw_niels_to_tw_extensible(&ext, &niels); | |||||
} | |||||
when = now() - when; | |||||
printf("exti+niels: %5.1fns\n", when * 1e9 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase*100; i++) { | |||||
add_tw_extended(ed,ed); | |||||
} | |||||
when = now() - when; | |||||
printf("txt + txt : %5.1fns\n", when * 1e9 / i); | |||||
decaf_448_point_t Da,Db,Dc; | |||||
memset(Da,0,sizeof(Da)); | |||||
memset(Db,0,sizeof(Db)); | |||||
memset(Dc,0,sizeof(Dc)); | |||||
when = now(); | |||||
for (i=0; i<nbase*100; i++) { | |||||
decaf_448_point_add(Da,Db,Dc); | |||||
} | |||||
when = now() - when; | |||||
printf("dec + dec: %5.1fns\n", when * 1e9 / i); | |||||
convert_tw_extensible_to_tw_pniels(&pniels, &ext); | |||||
when = now(); | |||||
for (i=0; i<nbase*100; i++) { | |||||
add_tw_pniels_to_tw_extensible(&ext, &pniels); | |||||
} | |||||
when = now() - when; | |||||
printf("exti+pniels: %5.1fns\n", when * 1e9 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase*100; i++) { | |||||
double_tw_extensible(&ext); | |||||
} | |||||
when = now() - when; | |||||
printf("exti dbl: %5.1fns\n", when * 1e9 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase*100; i++) { | |||||
untwist_and_double(&exta, &ext); | |||||
} | |||||
when = now() - when; | |||||
printf("i->a isog: %5.1fns\n", when * 1e9 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase*100; i++) { | |||||
twist_and_double(&ext, &exta); | |||||
} | |||||
when = now() - when; | |||||
printf("a->i isog: %5.1fns\n", when * 1e9 / i); | |||||
memset(&mb,0,sizeof(mb)); | |||||
when = now(); | |||||
for (i=0; i<nbase*100; i++) { | |||||
montgomery_step(&mb); | |||||
} | |||||
when = now() - when; | |||||
printf("monty step: %5.1fns\n", when * 1e9 / i); | |||||
memset(&mba,0,sizeof(mba)); | |||||
when = now(); | |||||
for (i=0; i<nbase*100; i++) { | |||||
montgomery_aux_step(&mba); | |||||
} | |||||
when = now() - when; | |||||
printf("monty aux: %5.1fns\n", when * 1e9 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
ignore_result(montgomery_ladder(a,b,sk,FIELD_BITS,0)); | |||||
} | |||||
when = now() - when; | |||||
printf("full ladder: %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
ignore_result(decaf_montgomery_ladder(a,b,sk,FIELD_BITS)); | |||||
} | |||||
when = now() - when; | |||||
printf("decafladder: %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
decaf_448_point_scalarmul(Da,Db,asc); | |||||
} | |||||
when = now() - when; | |||||
printf("decaf slow: %5.1fµs\n", when * 1e6 / i); | |||||
uint8_t enc[DECAF_448_SER_BYTES]; | |||||
memset(enc,4,sizeof(enc)); | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
ignore_result(decaf_448_direct_scalarmul(enc,enc,asc,-1,0)); | |||||
} | |||||
when = now() - when; | |||||
printf("decaf dir: %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
decaf_448_point_double_scalarmul(Da,Db,bsc,Dc,asc); | |||||
} | |||||
when = now() - when; | |||||
printf("decaf slo2: %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
decaf_448_precomputed_scalarmul(Da,decaf_448_precomputed_base,bsc); | |||||
} | |||||
when = now() - when; | |||||
printf("decaf pres: %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
scalarmul(&ext,sk); | |||||
} | |||||
when = now() - when; | |||||
printf("edwards smz: %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
scalarmul_vlook(&ext,sk); | |||||
} | |||||
when = now() - when; | |||||
printf("edwards svl: %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
scalarmul_ed(ed,sk); | |||||
} | |||||
when = now() - when; | |||||
printf("edwards txt: %5.1fµs\n", when * 1e6 / i); | |||||
field_set_ui(a,0); | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
ignore_result(decaf_deserialize_tw_extended(ed,a,-1)); | |||||
scalarmul_ed(ed,sk); | |||||
decaf_serialize_tw_extended(a,ed); | |||||
} | |||||
when = now() - when; | |||||
printf("simple ECDH: %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
scalarmul(&ext,sk); | |||||
untwist_and_double_and_serialize(a,&ext); | |||||
} | |||||
when = now() - when; | |||||
printf("edwards smc: %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
q448_randomize(&crand, sk); | |||||
scalarmul_vt(&ext,sk,SCALAR_BITS); | |||||
} | |||||
when = now() - when; | |||||
printf("edwards vtm: %5.1fµs\n", when * 1e6 / i); | |||||
tw_niels_a_t wnaft[1<<6]; | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
ignore_result(precompute_fixed_base_wnaf(wnaft,&ext,6)); | |||||
} | |||||
when = now() - when; | |||||
printf("wnaf6 pre: %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
q448_randomize(&crand, sk); | |||||
scalarmul_fixed_base_wnaf_vt(&ext,sk,SCALAR_BITS,(const tw_niels_a_t*)wnaft,6); | |||||
} | |||||
when = now() - when; | |||||
printf("edwards vt6: %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
ignore_result(precompute_fixed_base_wnaf(wnaft,&ext,4)); | |||||
} | |||||
when = now() - when; | |||||
printf("wnaf4 pre: %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
q448_randomize(&crand, sk); | |||||
scalarmul_fixed_base_wnaf_vt(&ext,sk,SCALAR_BITS,(const tw_niels_a_t*)wnaft,4); | |||||
} | |||||
when = now() - when; | |||||
printf("edwards vt4: %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
ignore_result(precompute_fixed_base_wnaf(wnaft,&ext,5)); | |||||
} | |||||
when = now() - when; | |||||
printf("wnaf5 pre: %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
q448_randomize(&crand, sk); | |||||
scalarmul_fixed_base_wnaf_vt(&ext,sk,SCALAR_BITS,(const tw_niels_a_t*)wnaft,5); | |||||
} | |||||
when = now() - when; | |||||
printf("edwards vt5: %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
q448_randomize(&crand, sk); | |||||
q448_randomize(&crand, tk); | |||||
linear_combo_var_fixed_vt(&ext,sk,FIELD_BITS,tk,FIELD_BITS,(const tw_niels_a_t*)wnaft,5); | |||||
} | |||||
when = now() - when; | |||||
printf("vt vf combo: %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
deserialize_affine(&affine, a); | |||||
convert_affine_to_extensible(&exta,&affine); | |||||
twist_and_double(&ext,&exta); | |||||
scalarmul(&ext,sk); | |||||
untwist_and_double(&exta,&ext); | |||||
serialize_extensible(b, &exta); | |||||
} | |||||
when = now() - when; | |||||
printf("edwards sm: %5.1fµs\n", when * 1e6 / i); | |||||
struct fixed_base_table_t t_5_5_18, t_3_5_30, t_8_4_14, t_5_3_30, t_15_3_10; | |||||
while (1) { | |||||
field_randomize(&crand, a); | |||||
if (deserialize_affine(&affine, a)) break; | |||||
} | |||||
convert_affine_to_extensible(&exta,&affine); | |||||
twist_and_double(&ext,&exta); | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
if (i) destroy_fixed_base(&t_5_5_18); | |||||
ignore_result(precompute_fixed_base(&t_5_5_18, &ext, 5, 5, 18, NULL)); | |||||
} | |||||
when = now() - when; | |||||
printf("pre(5,5,18): %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
if (i) destroy_fixed_base(&t_3_5_30); | |||||
ignore_result(precompute_fixed_base(&t_3_5_30, &ext, 3, 5, 30, NULL)); | |||||
} | |||||
when = now() - when; | |||||
printf("pre(3,5,30): %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
if (i) destroy_fixed_base(&t_5_3_30); | |||||
ignore_result(precompute_fixed_base(&t_5_3_30, &ext, 5, 3, 30, NULL)); | |||||
} | |||||
when = now() - when; | |||||
printf("pre(5,3,30): %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
if (i) destroy_fixed_base(&t_15_3_10); | |||||
ignore_result(precompute_fixed_base(&t_15_3_10, &ext, 15, 3, 10, NULL)); | |||||
} | |||||
when = now() - when; | |||||
printf("pre(15,3,10):%5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase/10; i++) { | |||||
if (i) destroy_fixed_base(&t_8_4_14); | |||||
ignore_result(precompute_fixed_base(&t_8_4_14, &ext, 8, 4, 14, NULL)); | |||||
} | |||||
when = now() - when; | |||||
printf("pre(8,4,14): %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase; i++) { | |||||
scalarmul_fixed_base(&ext, sk, FIELD_BITS, &t_5_5_18); | |||||
} | |||||
when = now() - when; | |||||
printf("com(5,5,18): %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase; i++) { | |||||
scalarmul_fixed_base(&ext, sk, FIELD_BITS, &t_3_5_30); | |||||
} | |||||
when = now() - when; | |||||
printf("com(3,5,30): %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase; i++) { | |||||
scalarmul_fixed_base(&ext, sk, FIELD_BITS, &t_8_4_14); | |||||
} | |||||
when = now() - when; | |||||
printf("com(8,4,14): %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase; i++) { | |||||
scalarmul_fixed_base(&ext, sk, FIELD_BITS, &t_5_3_30); | |||||
} | |||||
when = now() - when; | |||||
printf("com(5,3,30): %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase; i++) { | |||||
scalarmul_fixed_base(&ext, sk, FIELD_BITS, &t_15_3_10); | |||||
} | |||||
when = now() - when; | |||||
printf("com(15,3,10):%5.1fµs\n", when * 1e6 / i); | |||||
printf("\nGoldilocks:\n"); | |||||
int res = goldilocks_init(); | |||||
assert(!res); | |||||
struct goldilocks_public_key_t gpk,hpk; | |||||
struct goldilocks_private_key_t gsk,hsk; | |||||
when = now(); | |||||
for (i=0; i<nbase; i++) { | |||||
if (i&1) { | |||||
res = goldilocks_keygen(&gsk,&gpk); | |||||
} else { | |||||
res = goldilocks_keygen(&hsk,&hpk); | |||||
} | |||||
assert(!res); | |||||
} | |||||
when = now() - when; | |||||
printf("keygen: %5.1fµs\n", when * 1e6 / i); | |||||
uint8_t ss1[64],ss2[64]; | |||||
int gres1=0,gres2=0; | |||||
when = now(); | |||||
for (i=0; i<nbase; i++) { | |||||
if (i&1) { | |||||
gres1 = goldilocks_shared_secret(ss1,&gsk,&hpk); | |||||
} else { | |||||
gres2 = goldilocks_shared_secret(ss2,&hsk,&gpk); | |||||
} | |||||
} | |||||
when = now() - when; | |||||
printf("ecdh: %5.1fµs\n", when * 1e6 / i); | |||||
if (gres1 || gres2 || memcmp(ss1,ss2,64)) { | |||||
printf("[FAIL] %d %d\n",gres1,gres2); | |||||
printf("sk1 = "); | |||||
for (i=0; i<SCALAR_BYTES; i++) { | |||||
printf("%02x", gsk.opaque[i]); | |||||
} | |||||
printf("\nsk2 = "); | |||||
for (i=0; i<SCALAR_BYTES; i++) { | |||||
printf("%02x", hsk.opaque[i]); | |||||
} | |||||
printf("\nss1 = "); | |||||
for (i=0; i<64; i++) { | |||||
printf("%02x", ss1[i]); | |||||
} | |||||
printf("\nss2 = "); | |||||
for (i=0; i<64; i++) { | |||||
printf("%02x", ss2[i]); | |||||
} | |||||
printf("\n"); | |||||
} | |||||
uint8_t sout[FIELD_BYTES*2]; | |||||
const char *message = "hello world"; | |||||
size_t message_len = strlen(message); | |||||
when = now(); | |||||
for (i=0; i<nbase; i++) { | |||||
res = goldilocks_sign(sout,(const unsigned char *)message,message_len,&gsk); | |||||
(void)res; | |||||
assert(!res); | |||||
} | |||||
when = now() - when; | |||||
printf("sign: %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase; i++) { | |||||
int ver = goldilocks_verify(sout,(const unsigned char *)message,message_len,&gpk); | |||||
(void)ver; | |||||
assert(!ver); | |||||
} | |||||
when = now() - when; | |||||
printf("verify: %5.1fµs\n", when * 1e6 / i); | |||||
struct goldilocks_precomputed_public_key_t *pre = NULL; | |||||
when = now(); | |||||
for (i=0; i<nbase; i++) { | |||||
goldilocks_destroy_precomputed_public_key(pre); | |||||
pre = goldilocks_precompute_public_key(&gpk); | |||||
} | |||||
when = now() - when; | |||||
printf("precompute: %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase; i++) { | |||||
int ver = goldilocks_verify_precomputed(sout,(const unsigned char *)message,message_len,pre); | |||||
(void)ver; | |||||
assert(!ver); | |||||
} | |||||
when = now() - when; | |||||
printf("verify pre: %5.1fµs\n", when * 1e6 / i); | |||||
when = now(); | |||||
for (i=0; i<nbase; i++) { | |||||
int ret = goldilocks_shared_secret_precomputed(ss1,&gsk,pre); | |||||
(void)ret; | |||||
assert(!ret); | |||||
} | |||||
when = now() - when; | |||||
printf("ecdh pre: %5.1fµs\n", when * 1e6 / i); | |||||
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]; | |||||
unsigned char dshared[2][32]; | |||||
when = now(); | |||||
for (i=0; i<nbase; i++) { | |||||
decaf_448_derive_private_key(dpriv[i&1], sym[i&1]); | |||||
} | |||||
when = now() - when; | |||||
printf("derive priv: %5.1fµs\n", when * 1e6 / i); | |||||
decaf_448_private_to_public(dpub[0], dpriv[0]); | |||||
decaf_448_private_to_public(dpub[1], dpriv[1]); | |||||
when = now(); | |||||
for (i=0; i<nbase; i++) { | |||||
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; | |||||
} | |||||
} | |||||
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"); | |||||
} | |||||
decaf_448_signature_t dsig; | |||||
const char *dmessage = "hello world"; | |||||
const char *dnessage = "Jello world"; | |||||
when = now(); | |||||
for (i=0; i<nbase; i++) { | |||||
decaf_448_sign(dsig, dpriv[0], (const unsigned char *)dmessage, 11); | |||||
} | |||||
when = now() - when; | |||||
printf("sign: %5.1fµs\n", when * 1e6 / i); | |||||
if (memcmp(dshared[0], dshared[1], 32)) { | |||||
printf("BUG: mismatched shared secrets\n"); | |||||
} | |||||
when = now(); | |||||
for (i=0; i<nbase; i++) { | |||||
decaf_bool_t ret = decaf_448_verify(dsig, dpub[0], | |||||
(const unsigned char *)((i&1) ? dmessage : dnessage), 11); | |||||
if ((i&1) && ~ret) { | |||||
printf("BUG: verify failed\n"); | |||||
break; | |||||
} else if (!(i&1) && ret) { | |||||
printf("BUG: unverify succeeded\n"); | |||||
break; | |||||
} | |||||
} | |||||
when = now() - when; | |||||
printf("verify: %5.1fµs\n", when * 1e6 / i); | |||||
decaf_448_precomputed_s *dpre; | |||||
ignore_result(posix_memalign((void**)&dpre, | |||||
alignof_decaf_448_precomputed_s, sizeof_decaf_448_precomputed_s)); | |||||
assert(dpre); | |||||
when = now(); | |||||
for (i=0; i<nbase; i++) { | |||||
decaf_448_precompute(dpre, Da); | |||||
} | |||||
when = now() - when; | |||||
printf("pre: %5.1fµs\n", when * 1e6 / i); | |||||
free(dpre); | |||||
return 0; | |||||
} |
@@ -1,152 +0,0 @@ | |||||
#include "test.h" | |||||
#include <stdio.h> | |||||
#include <string.h> | |||||
#ifndef LIMBPERM | |||||
#define LIMBPERM(x) (x) | |||||
#endif | |||||
int failed_tests, n_tests, failed_this_test, running_a_test; | |||||
static void end_test(void) { | |||||
if (!failed_this_test) { | |||||
printf("[PASS]\n"); | |||||
} | |||||
n_tests ++; | |||||
running_a_test = 0; | |||||
} | |||||
static void begin_test(const char *name) { | |||||
if (running_a_test) end_test(); | |||||
printf("%s...%*s",name,(int)(30-strlen(name)),""); | |||||
fflush(stdout); | |||||
failed_this_test = 0; | |||||
running_a_test = 1; | |||||
} | |||||
void youfail(void) { | |||||
if (failed_this_test) return; | |||||
failed_this_test = 1; | |||||
failed_tests ++; | |||||
printf("[FAIL]\n"); | |||||
} | |||||
static int | |||||
hexchar (char c) { | |||||
if (c >= '0' && c <= '9') { | |||||
return c - '0'; | |||||
} else if (c >= 'a' && c <= 'f') { | |||||
return 10 + c - 'a'; | |||||
} else if (c >= 'A' && c <= 'F') { | |||||
return 10 + c - 'A'; | |||||
} else { | |||||
return -1; | |||||
} | |||||
} | |||||
int | |||||
hexdecode ( | |||||
unsigned char *bytes, | |||||
const char *hex, | |||||
unsigned int nbytes | |||||
) { | |||||
if (strlen(hex) != nbytes*2) { | |||||
return -1; | |||||
} | |||||
unsigned int i; | |||||
for (i=0; i<nbytes; i++) { | |||||
int hi = hexchar(hex[2*i]), | |||||
lo = hexchar(hex[2*i+1]); | |||||
if (hi<0 || lo<0) return -1; | |||||
bytes[i] = hi*16 + lo; | |||||
} | |||||
return 0; | |||||
} | |||||
void | |||||
hexprint ( | |||||
const char *descr, | |||||
const unsigned char *bytes, | |||||
unsigned int nbytes | |||||
) { | |||||
if (descr) printf("%s = ", descr); | |||||
unsigned int i; | |||||
for (i=0; i<nbytes; i++) { | |||||
printf("%02x", bytes[i]); | |||||
} | |||||
printf("\n"); | |||||
} | |||||
void field_print ( | |||||
const char *descr, | |||||
const field_a_t a | |||||
) { | |||||
int j; | |||||
unsigned char ser[FIELD_BYTES]; | |||||
field_serialize(ser,a); | |||||
printf("%s = 0x", descr); | |||||
for (j=FIELD_BYTES - 1; j>=0; j--) { | |||||
printf("%02x", ser[j]); | |||||
} | |||||
printf("\n"); | |||||
} | |||||
void scalar_print ( | |||||
const char *descr, | |||||
const word_t *scalar, | |||||
int nwords | |||||
) { | |||||
int j; | |||||
printf("%s = 0x", descr); | |||||
for (j=nwords-1; j>=0; j--) { | |||||
printf(PRIxWORDfull, scalar[j]); | |||||
} | |||||
printf("\n"); | |||||
} | |||||
int main(int argc, char **argv) { | |||||
(void) argc; | |||||
(void) argv; | |||||
n_tests = running_a_test = failed_tests = 0; | |||||
begin_test("Arithmetic"); | |||||
test_arithmetic(); | |||||
begin_test("EC point operations"); | |||||
test_pointops(); | |||||
begin_test("Decaf point encoding"); | |||||
test_decaf(); | |||||
begin_test("Decaf pathological cases"); | |||||
test_decaf_evil(); | |||||
begin_test("Scalarmul compatibility"); | |||||
test_scalarmul_compatibility(); | |||||
begin_test("Scalarmul commutativity"); | |||||
test_scalarmul_commutativity(); | |||||
begin_test("Linear combo"); | |||||
test_linear_combo(); | |||||
begin_test("SHA-512 NIST Monte Carlo"); | |||||
test_sha512_monte_carlo(); | |||||
begin_test("Goldilocks complete system"); | |||||
test_goldilocks(); | |||||
if (running_a_test) end_test(); | |||||
printf("\n"); | |||||
if (failed_tests) { | |||||
printf("Failed %d / %d tests.\n", failed_tests, n_tests); | |||||
} else { | |||||
printf("Passed all %d tests.\n", n_tests); | |||||
} | |||||
return failed_tests ? 1 : 0; | |||||
} |
@@ -1,51 +0,0 @@ | |||||
#ifndef __GOLDILOCKS_TEST_H__ | |||||
#define __GOLDILOCKS_TEST_H__ 1 | |||||
#include "word.h" | |||||
#include "field.h" | |||||
int | |||||
hexdecode ( | |||||
unsigned char *bytes, | |||||
const char *hex, | |||||
unsigned int nbytes | |||||
); | |||||
void | |||||
hexprint ( | |||||
const char *descr, | |||||
const unsigned char *bytes, | |||||
unsigned int nbytes | |||||
); | |||||
void field_print ( | |||||
const char *descr, | |||||
const field_a_t a | |||||
); | |||||
void scalar_print ( | |||||
const char *descr, | |||||
const word_t *scalar, | |||||
int nwords | |||||
); | |||||
void youfail(void); | |||||
int test_sha512_monte_carlo(void); | |||||
int test_linear_combo (void); | |||||
int test_scalarmul_compatibility (void); | |||||
int test_scalarmul_commutativity (void); | |||||
int test_arithmetic (void); | |||||
int test_goldilocks (void); | |||||
int test_pointops (void); | |||||
int test_decaf (void); | |||||
int test_decaf_evil (void); | |||||
#endif // __GOLDILOCKS_TEST_H__ |
@@ -1,392 +0,0 @@ | |||||
#include "field.h" | |||||
#include "test.h" | |||||
#include "decaf.h" | |||||
#include <gmp.h> | |||||
#include <string.h> | |||||
#include <stdio.h> | |||||
mpz_t mp_field; | |||||
mpz_t mp_scalar_field; | |||||
static void decaf_448_scalar_print ( | |||||
const char *descr, | |||||
const decaf_448_scalar_t scalar | |||||
) { | |||||
int j; | |||||
printf("%s = 0x", descr); | |||||
for (j=DECAF_448_SCALAR_LIMBS-1; j>=0; j--) { | |||||
printf(PRIxWORDfull, scalar->limb[j]); | |||||
} | |||||
printf("\n"); | |||||
} | |||||
static mask_t mpz_to_field ( | |||||
field_a_t out, | |||||
const mpz_t in | |||||
) { | |||||
uint8_t ser[FIELD_BYTES]; | |||||
mpz_t modded; | |||||
memset(ser,0,sizeof(ser)); | |||||
mpz_init(modded); | |||||
mpz_mod(modded, in, mp_field); | |||||
mpz_export(ser, NULL, -1, 1, -1, 0, modded); | |||||
mask_t succ = field_deserialize(out, ser); | |||||
return succ; | |||||
} | |||||
static mask_t mpz_to_scalar ( | |||||
decaf_448_scalar_t out, | |||||
const mpz_t in | |||||
) { | |||||
uint8_t ser[DECAF_448_SCALAR_BYTES]; | |||||
mpz_t modded; | |||||
memset(ser,0,sizeof(ser)); | |||||
mpz_init(modded); | |||||
mpz_mod(modded, in, mp_scalar_field); | |||||
mpz_export(ser, NULL, -1, 1, -1, 0, modded); | |||||
mask_t succ = decaf_448_scalar_decode(out, ser); | |||||
return succ; | |||||
} | |||||
static mask_t scalar_assert_eq_gmp( | |||||
const char *descr, | |||||
const decaf_448_scalar_t a, | |||||
const decaf_448_scalar_t b, | |||||
const decaf_448_scalar_t x, | |||||
const mpz_t ma, | |||||
const mpz_t mb, | |||||
const mpz_t y | |||||
) { | |||||
uint8_t xser[FIELD_BYTES], yser[FIELD_BYTES]; | |||||
mpz_t modded; | |||||
memset(yser,0,sizeof(yser)); | |||||
decaf_448_scalar_encode(xser, x); | |||||
mpz_init(modded); | |||||
mpz_mod(modded, y, mp_scalar_field); | |||||
mpz_export(yser, NULL, -1, 1, -1, 0, modded); | |||||
if (memcmp(xser,yser,FIELD_BYTES)) { | |||||
youfail(); | |||||
printf(" Failed arithmetic test %s\n", descr); | |||||
decaf_448_scalar_print(" a", a); | |||||
decaf_448_scalar_print(" b", b); | |||||
decaf_448_scalar_print(" decaf_448", x); | |||||
// printf(" gmpa = 0x"); | |||||
int j; | |||||
// mpz_export(yser, NULL, -1, 1, -1, 0, ma); | |||||
// for (j=FIELD_BYTES-1; j>=0; j--) { | |||||
// printf("%02x", yser[j]); | |||||
// } | |||||
// printf("\n"); | |||||
// printf(" gmpb = 0x"); | |||||
// | |||||
// | |||||
// mpz_export(yser, NULL, -1, 1, -1, 0, mb); | |||||
// for (j=FIELD_BYTES-1; j>=0; j--) { | |||||
// printf("%02x", yser[j]); | |||||
// } | |||||
// printf("\n"); | |||||
(void)ma; (void)mb; | |||||
printf(" gmpy = 0x"); | |||||
mpz_export(yser, NULL, -1, 1, -1, 0, modded); | |||||
for (j=FIELD_BYTES-1; j>=0; j--) { | |||||
printf("%02x", yser[j]); | |||||
} | |||||
printf("\n"); | |||||
return MASK_FAILURE; | |||||
} | |||||
mpz_clear(modded); | |||||
return MASK_SUCCESS; | |||||
} | |||||
static inline int BRANCH_ON_CONSTANT(int x) { | |||||
__asm__ ("" : "+r"(x)); | |||||
return x; | |||||
} | |||||
static mask_t field_assert_eq_gmp( | |||||
const char *descr, | |||||
const field_a_t a, | |||||
const field_a_t b, | |||||
const field_a_t x, | |||||
const mpz_t y, | |||||
float lowBound, | |||||
float highBound | |||||
) { | |||||
uint8_t xser[FIELD_BYTES], yser[FIELD_BYTES]; | |||||
mpz_t modded; | |||||
memset(yser,0,sizeof(yser)); | |||||
field_serialize(xser, x); | |||||
mpz_init(modded); | |||||
mpz_mod(modded, y, mp_field); | |||||
mpz_export(yser, NULL, -1, 1, -1, 0, modded); | |||||
unsigned int i; | |||||
for (i=0; i<sizeof(*x)/sizeof(x->limb[0]); i++) { | |||||
int radix_bits = 1 + (sizeof(x->limb[0]) * FIELD_BITS - 1) / sizeof(*x); | |||||
word_t yardstick; | |||||
if (BRANCH_ON_CONSTANT(FIELD_BITS == 521) && BRANCH_ON_CONSTANT(sizeof(*x)==12*8)) { | |||||
radix_bits = 58; | |||||
} | |||||
yardstick = (1ull<<radix_bits) - 1; | |||||
if (x->limb[i] < yardstick * lowBound || x->limb[i] > yardstick * highBound) { | |||||
youfail(); | |||||
printf(" Limb %d -> " PRIxWORDfull " is out of bounds (%0.2f, %0.2f) for test %s (yardstick = " PRIxWORDfull ")\n", | |||||
i, x->limb[i], lowBound, highBound, descr, yardstick); | |||||
break; | |||||
} | |||||
} | |||||
if (memcmp(xser,yser,FIELD_BYTES)) { | |||||
youfail(); | |||||
printf(" Failed arithmetic test %s\n", descr); | |||||
field_print(" a", a); | |||||
field_print(" b", b); | |||||
field_print(" goldi", x); | |||||
printf(" gmp = 0x"); | |||||
int j; | |||||
for (j=FIELD_BYTES-1; j>=0; j--) { | |||||
printf("%02x", yser[j]); | |||||
} | |||||
printf("\n"); | |||||
return MASK_FAILURE; | |||||
} | |||||
mpz_clear(modded); | |||||
return MASK_SUCCESS; | |||||
} | |||||
static mask_t test_add_sub_RAW ( | |||||
const mpz_t x, | |||||
const mpz_t y, | |||||
word_t word | |||||
) { | |||||
field_a_t xx,yy,tt; | |||||
mpz_t t; | |||||
mask_t succ = MASK_SUCCESS; | |||||
succ = mpz_to_field(xx,x); | |||||
succ &= mpz_to_field(yy,y); | |||||
mpz_init(t); | |||||
field_add_RAW(tt,xx,yy); | |||||
mpz_add(t,x,y); | |||||
succ &= field_assert_eq_gmp("add",xx,yy,tt,t,0,2.1); | |||||
field_sub_RAW(tt,xx,yy); | |||||
field_bias(tt,2); | |||||
mpz_sub(t,x,y); | |||||
succ &= field_assert_eq_gmp("sub",xx,yy,tt,t,0,3.1); | |||||
field_copy(tt,xx); | |||||
field_addw(tt,word); | |||||
mpz_add_ui(t,x,word); | |||||
succ &= field_assert_eq_gmp("addw",xx,yy,tt,t,0,2.1); | |||||
field_copy(tt,xx); | |||||
field_subw(tt,word); | |||||
field_bias(tt,1); | |||||
mpz_sub_ui(t,x,word); | |||||
succ &= field_assert_eq_gmp("subw",xx,yy,tt,t,0,2.1); | |||||
/* | |||||
if (!succ) { | |||||
field_print(" x", &xx); | |||||
field_print(" y", &yy); | |||||
} | |||||
*/ | |||||
mpz_clear(t); | |||||
return succ; | |||||
} | |||||
static mask_t test_scalar ( | |||||
const mpz_t x, | |||||
const mpz_t y, | |||||
int inv | |||||
) { | |||||
decaf_448_scalar_t xx,yy,tt; | |||||
mpz_t t; | |||||
mask_t succ = MASK_SUCCESS; | |||||
succ = mpz_to_scalar(xx,x); | |||||
succ &= mpz_to_scalar(yy,y); | |||||
mpz_init(t); | |||||
decaf_448_scalar_add(tt,xx,yy); | |||||
mpz_add(t,x,y); | |||||
succ &= scalar_assert_eq_gmp("scalar add",xx,yy,tt,x,y,t); | |||||
decaf_448_scalar_sub(tt,xx,yy); | |||||
mpz_sub(t,x,y); | |||||
succ &= scalar_assert_eq_gmp("scalar sub",xx,yy,tt,x,y,t); | |||||
decaf_448_scalar_mul(tt,xx,yy); | |||||
mpz_mul(t,x,y); | |||||
succ &= scalar_assert_eq_gmp("scalar mul",xx,yy,tt,x,y,t); | |||||
if (inv) { | |||||
decaf_bool_t ret = decaf_448_scalar_invert(tt,xx); | |||||
if (!mpz_cmp_ui(x,0)) { | |||||
mpz_set_ui(t,0); | |||||
succ &= (ret == 0) ? MASK_SUCCESS : MASK_FAILURE; | |||||
} else { | |||||
mpz_invert(t,x,mp_scalar_field); | |||||
succ &= (ret == MASK_SUCCESS) ? MASK_SUCCESS : MASK_FAILURE; | |||||
} | |||||
succ &= scalar_assert_eq_gmp("scalar inv",xx,yy,tt,x,y,t); | |||||
} | |||||
mpz_clear(t); | |||||
return succ; | |||||
} | |||||
static mask_t test_mul_sqr ( | |||||
const mpz_t x, | |||||
const mpz_t y, | |||||
word_t word | |||||
) { | |||||
ANALYZE_THIS_ROUTINE_CAREFULLY; | |||||
field_a_t xx,yy,tt,zz; | |||||
mpz_t t, z; | |||||
mask_t succ = MASK_SUCCESS; | |||||
succ = mpz_to_field(xx,x); | |||||
succ &= mpz_to_field(yy,y); | |||||
mpz_init(t); | |||||
mpz_init(z); | |||||
field_mul(tt,xx,yy); | |||||
mpz_mul(t,x,y); | |||||
succ &= field_assert_eq_gmp("mul",xx,yy,tt,t,0,1.1); | |||||
field_mulw(tt,xx,word); | |||||
mpz_mul_ui(t,x,word); | |||||
succ &= field_assert_eq_gmp("mulw",xx,yy,tt,t,0,1.1); | |||||
field_sqr(tt,xx); | |||||
mpz_mul(t,x,x); | |||||
succ &= field_assert_eq_gmp("sqrx",xx,yy,tt,t,0,1.1); | |||||
field_sqr(tt,yy); | |||||
mpz_mul(t,y,y); | |||||
succ &= field_assert_eq_gmp("sqy",xx,yy,tt,t,0,1.1); | |||||
field_add_nr(zz,xx,xx); | |||||
mpz_add(z,x,x); | |||||
mpz_mul(t,z,z); | |||||
field_mul(tt,zz,zz); | |||||
succ &= field_assert_eq_gmp("msr4",xx,yy,tt,t,0,1.1); | |||||
field_sqr(tt,zz); | |||||
succ &= field_assert_eq_gmp("sqr4",xx,yy,tt,t,0,1.1); | |||||
if (!succ) { | |||||
field_print(" x", xx); | |||||
field_print(" y", yy); | |||||
} | |||||
mpz_clear(t); | |||||
mpz_clear(z); | |||||
return succ; | |||||
} | |||||
static mask_t test_isr ( | |||||
const mpz_t x | |||||
) { | |||||
field_a_t xx,yy,ss,tt; | |||||
mask_t succ = 0; | |||||
succ = mpz_to_field(xx,x); | |||||
field_isr(ss,xx); | |||||
field_sqr(tt,ss); | |||||
field_mul(yy,xx,tt); | |||||
field_addw(tt,1); | |||||
succ |= field_is_zero(tt); | |||||
field_subw(tt,2); | |||||
field_bias(tt,1); | |||||
succ |= field_is_zero(tt); | |||||
field_addw(tt,1); | |||||
if (~succ) { | |||||
youfail(); | |||||
printf("ISR failure.\n"); | |||||
field_print(" x", xx); | |||||
field_print(" s", ss); | |||||
field_print(" t", tt); | |||||
} | |||||
return succ; | |||||
} | |||||
void dbg_gmp_printf(const mpz_t x); | |||||
void dbg_gmp_printf(const mpz_t x) { | |||||
gmp_printf("DEBUG: 0x%Zx\n", x); | |||||
} | |||||
int test_arithmetic (void) { | |||||
int j, ntests = 100000; | |||||
gmp_randstate_t state; | |||||
gmp_randinit_mt(state); | |||||
mpz_init(mp_field); | |||||
mpz_import(mp_field, FIELD_BYTES, -1, 1, -1, 0, FIELD_MODULUS); | |||||
mpz_import(mp_scalar_field, DECAF_448_SCALAR_LIMBS, -1, sizeof(decaf_word_t), -1, 0, decaf_448_scalar_p); | |||||
mpz_t x,y; | |||||
mpz_init(x); | |||||
mpz_init(y); | |||||
mask_t succ = MASK_SUCCESS; | |||||
int radix_bits = sizeof(word_t) * FIELD_BITS / sizeof(field_a_t); | |||||
for (j=0; j<ntests; j++) { | |||||
if (j<256) { | |||||
mpz_set_ui(x,0); | |||||
mpz_set_ui(y,0); | |||||
mpz_setbit(x,(j%16)*28); | |||||
mpz_setbit(y,(j/16)*28); | |||||
} else if (j&1) { | |||||
mpz_rrandomb(x, state, FIELD_BITS); | |||||
mpz_rrandomb(y, state, FIELD_BITS); | |||||
} else { | |||||
mpz_urandomb(x, state, FIELD_BITS); | |||||
mpz_urandomb(y, state, FIELD_BITS); | |||||
} | |||||
word_t word = gmp_urandomm_ui (state, 1ull<<radix_bits); | |||||
succ &= test_add_sub_RAW(x,y,word); | |||||
succ &= test_mul_sqr(x,y,word); | |||||
succ &= test_scalar(x,y,(j%20==0)); | |||||
if (j < 1000) | |||||
succ &= test_isr(x); | |||||
// TODO: test neg, cond_neg_RAW, set_ui, wrd, srd, inv, ...? | |||||
} | |||||
mpz_clear(x); | |||||
mpz_clear(y); | |||||
mpz_clear(mp_field); | |||||
gmp_randclear(state); | |||||
return succ ? 0 : 1; | |||||
} | |||||
@@ -1,195 +0,0 @@ | |||||
#include "test.h" | |||||
#include "goldilocks.h" | |||||
#include <stdio.h> | |||||
#include <stdlib.h> | |||||
#include <string.h> | |||||
int test_goldilocks (void) { | |||||
const char *message1 = "hello world"; | |||||
const char *message2 = "Jello world"; | |||||
unsigned char signature[GOLDI_SIGNATURE_BYTES]; | |||||
unsigned char | |||||
ss12[GOLDI_SHARED_SECRET_BYTES], | |||||
ss21[GOLDI_SHARED_SECRET_BYTES], | |||||
ss21p[GOLDI_SHARED_SECRET_BYTES], | |||||
proto[GOLDI_SYMKEY_BYTES]; | |||||
struct goldilocks_public_key_t pub, pub2; | |||||
struct goldilocks_private_key_t priv, priv2; | |||||
struct goldilocks_precomputed_public_key_t *pre = NULL; | |||||
int i, ret, good = 1; | |||||
ret = goldilocks_init(); | |||||
if (ret) { | |||||
youfail(); | |||||
printf(" Failed init.\n"); | |||||
} | |||||
for (i=0; i<1000 && good; i++) { | |||||
ret = goldilocks_keygen(&priv, &pub); | |||||
if (ret) { | |||||
youfail(); | |||||
printf(" Failed keygen trial %d.\n", i); | |||||
good = 0; | |||||
} | |||||
goldilocks_destroy_precomputed_public_key( pre ); | |||||
pre = goldilocks_precompute_public_key ( &pub ); | |||||
if (!pre) { | |||||
youfail(); | |||||
printf(" Failed precomp-public trial %d.\n", i); | |||||
return -1; | |||||
} | |||||
ret = goldilocks_sign( | |||||
signature, | |||||
(const unsigned char *)message1, | |||||
strlen(message1), | |||||
&priv | |||||
); | |||||
if (ret) { | |||||
youfail(); | |||||
printf(" Failed sign trial %d.\n", i); | |||||
good = 0; | |||||
} | |||||
ret = goldilocks_verify( | |||||
signature, | |||||
(const unsigned char *)message1, | |||||
strlen(message1), | |||||
&pub | |||||
); | |||||
if (ret) { | |||||
youfail(); | |||||
printf(" Failed verify trial %d.\n", i); | |||||
good = 0; | |||||
} | |||||
ret = goldilocks_verify_precomputed ( | |||||
signature, | |||||
(const unsigned char *)message1, | |||||
strlen(message1), | |||||
pre | |||||
); | |||||
if (ret) { | |||||
youfail(); | |||||
printf(" Failed verify-pre trial %d.\n", i); | |||||
good = 0; | |||||
} | |||||
/* terrible negative test */ | |||||
ret = goldilocks_verify( | |||||
signature, | |||||
(const unsigned char *)message2, | |||||
strlen(message1), | |||||
&pub | |||||
); | |||||
if (ret != GOLDI_EINVAL) { | |||||
youfail(); | |||||
printf(" Failed nega-verify trial %d.\n", i); | |||||
good = 0; | |||||
} | |||||
ret = goldilocks_verify_precomputed( | |||||
signature, | |||||
(const unsigned char *)message2, | |||||
strlen(message1), | |||||
pre | |||||
); | |||||
if (ret != GOLDI_EINVAL) { | |||||
youfail(); | |||||
printf(" Failed nega-verify-pre trial %d.\n", i); | |||||
good = 0; | |||||
} | |||||
/* honestly a slightly better negative test */ | |||||
memset(signature,0,sizeof(signature)); | |||||
ret = goldilocks_verify( | |||||
signature, | |||||
(const unsigned char *)message1, | |||||
strlen(message1), | |||||
&pub | |||||
); | |||||
if (ret != GOLDI_EINVAL) { | |||||
youfail(); | |||||
printf(" Failed nega-verify-0 trial %d.\n", i); | |||||
good = 0; | |||||
} | |||||
ret = goldilocks_verify_precomputed( | |||||
signature, | |||||
(const unsigned char *)message1, | |||||
strlen(message1), | |||||
pre | |||||
); | |||||
if (ret != GOLDI_EINVAL) { | |||||
youfail(); | |||||
printf(" Failed nega-verify-pre-0 trial %d.\n", i); | |||||
good = 0; | |||||
} | |||||
/* ecdh */ | |||||
ret = goldilocks_keygen(&priv2, &pub2); | |||||
if (ret) { | |||||
youfail(); | |||||
printf(" Failed keygen2 trial %d.\n", i); | |||||
good = 0; | |||||
} | |||||
ret = goldilocks_shared_secret ( ss12, &priv, &pub2 ); | |||||
if (ret) { | |||||
youfail(); | |||||
printf(" Failed ss12 trial %d.\n", i); | |||||
good = 0; | |||||
} | |||||
ret = goldilocks_shared_secret ( ss21, &priv2, &pub ); | |||||
if (ret) { | |||||
youfail(); | |||||
printf(" Failed ss21 trial %d.\n", i); | |||||
good = 0; | |||||
} | |||||
ret = goldilocks_shared_secret_precomputed ( ss21p, &priv2, pre ); | |||||
if (ret) { | |||||
youfail(); | |||||
printf(" Failed ss21p trial %d.\n", i); | |||||
good = 0; | |||||
} | |||||
if (memcmp(ss12,ss21,sizeof(ss12))) { | |||||
youfail(); | |||||
printf(" Failed shared-secret trial %d.\n", i); | |||||
good = 0; | |||||
} | |||||
if (memcmp(ss21,ss21p,sizeof(ss21))) { | |||||
youfail(); | |||||
printf(" Failed shared-secret precomp trial %d.\n", i); | |||||
good = 0; | |||||
} | |||||
/* test derive / underive / priv to pub */ | |||||
goldilocks_underive_private_key ( proto, &priv ); | |||||
ret = goldilocks_derive_private_key ( &priv2, proto ); | |||||
if (ret || memcmp(&priv,&priv2,sizeof(priv))) { | |||||
youfail(); | |||||
printf(" Failed derive round-trip trial %d.\n", i); | |||||
good = 0; | |||||
} | |||||
ret = goldilocks_private_to_public ( &pub2, &priv ); | |||||
if (ret || memcmp(&pub,&pub2,sizeof(pub))) { | |||||
youfail(); | |||||
printf(" Failed private-to-public trial %d.\n", i); | |||||
good = 0; | |||||
} | |||||
} | |||||
goldilocks_destroy_precomputed_public_key( pre ); | |||||
return good ? 0 : -1; | |||||
} |
@@ -1,648 +0,0 @@ | |||||
#include "test.h" | |||||
#include <stdio.h> | |||||
#include "ec_point.h" | |||||
#include "decaf.h" | |||||
#include "scalarmul.h" | |||||
#include "magic.h" | |||||
#include "field.h" | |||||
#include "crandom.h" | |||||
static void | |||||
failprint_ext ( | |||||
const struct extensible_t *a | |||||
) { | |||||
field_a_t zi, scaled; | |||||
field_print(" x", a->x); | |||||
field_print(" y", a->y); | |||||
field_print(" z", a->z); | |||||
field_inverse(zi, a->z); | |||||
field_mul(scaled, zi, a->x); | |||||
field_print(" X", scaled); | |||||
field_mul(scaled, zi, a->y); | |||||
field_print(" Y", scaled); | |||||
printf("\n"); | |||||
} | |||||
static void | |||||
failprint_tw_ext ( | |||||
const struct tw_extensible_t *a | |||||
) { | |||||
failprint_ext((const struct extensible_t *)a); | |||||
} | |||||
static mask_t | |||||
fail_if_different ( | |||||
const struct extensible_t *a, | |||||
const struct extensible_t *b, | |||||
const char *faildescr, | |||||
const char *adescr, | |||||
const char *bdescr | |||||
) { | |||||
mask_t succ = eq_extensible(a, b); | |||||
if (!succ) { | |||||
youfail(); | |||||
printf(" %s\n", faildescr); | |||||
printf("\n %s:\n", adescr); | |||||
failprint_ext(a); | |||||
printf("\n %s:\n", bdescr); | |||||
failprint_ext(b); | |||||
} | |||||
return succ; | |||||
} | |||||
static mask_t | |||||
validate_ext( | |||||
const struct extensible_t *ext, | |||||
int evenness, | |||||
const char *description | |||||
) { | |||||
mask_t succ = validate_extensible(ext), succ2; | |||||
const char *error = "Point isn't on the curve."; | |||||
if (evenness > 0) { | |||||
succ2 = is_even_pt(ext); | |||||
if (succ &~ succ2) error = "Point isn't even."; | |||||
succ &= succ2; | |||||
} else if (evenness < 0) { | |||||
succ2 = is_even_pt(ext); | |||||
if (succ &~ succ2) error = "Point is even but shouldn't be."; | |||||
succ &= succ2; | |||||
} /* FUTURE: quadness */ | |||||
if (~succ) { | |||||
youfail(); | |||||
printf(" %s\n", error); | |||||
printf(" %s\n", description); | |||||
failprint_ext(ext); | |||||
} | |||||
return succ; | |||||
} | |||||
static mask_t | |||||
validate_tw_ext( | |||||
const struct tw_extensible_t *ext, | |||||
int evenness, | |||||
const char *description | |||||
) { | |||||
mask_t succ = validate_tw_extensible(ext), succ2; | |||||
const char *error = "Point isn't on the twisted curve."; | |||||
if (evenness > 0) { | |||||
succ2 = is_even_tw(ext); | |||||
if (succ &~ succ2) error = "Point isn't even."; | |||||
succ &= succ2; | |||||
} else if (evenness < 0) { | |||||
succ2 = is_even_tw(ext); | |||||
if (succ &~ succ2) error = "Point is even but shouldn't be."; | |||||
succ &= succ2; | |||||
} /* FUTURE: quadness */ | |||||
if (~succ) { | |||||
youfail(); | |||||
printf(" %s\n", error); | |||||
printf(" %s\n", description); | |||||
failprint_tw_ext(ext); | |||||
} | |||||
return succ; | |||||
} | |||||
static mask_t | |||||
fail_if_different_tw ( | |||||
const struct tw_extensible_t *a, | |||||
const struct tw_extensible_t *b, | |||||
const char *faildescr, | |||||
const char *adescr, | |||||
const char *bdescr | |||||
) { | |||||
return fail_if_different( | |||||
(const struct extensible_t *)a, (const struct extensible_t *)b, | |||||
faildescr,adescr,bdescr | |||||
); | |||||
} | |||||
static int | |||||
add_double_test ( | |||||
const struct affine_t *base1, | |||||
const struct affine_t *base2 | |||||
) { | |||||
mask_t succ = MASK_SUCCESS; | |||||
struct extensible_t exb; | |||||
struct tw_extensible_t text1, text2, texta, textb; | |||||
struct tw_extended_t ted1, ted2; | |||||
struct tw_pniels_t pn; | |||||
/* Convert to ext */ | |||||
convert_affine_to_extensible(&exb, base1); | |||||
succ &= validate_ext(&exb,0,"base1"); | |||||
twist_and_double(&text1, &exb); | |||||
succ &= validate_tw_ext(&text1,2,"iso1"); | |||||
convert_affine_to_extensible(&exb, base2); | |||||
succ &= validate_ext(&exb,0,"base2"); | |||||
twist_and_double(&text2, &exb); | |||||
succ &= validate_tw_ext(&text2,2,"iso2"); | |||||
/* a + b == b + a? */ | |||||
convert_tw_extensible_to_tw_pniels(&pn, &text1); | |||||
copy_tw_extensible(&texta, &text2); | |||||
add_tw_pniels_to_tw_extensible(&texta, &pn); | |||||
convert_tw_extensible_to_tw_pniels(&pn, &text2); | |||||
copy_tw_extensible(&textb, &text1); | |||||
add_tw_pniels_to_tw_extensible(&textb, &pn); | |||||
decaf_448_point_t ted3; | |||||
convert_tw_extensible_to_tw_extended(&ted1, &text1); | |||||
convert_tw_extensible_to_tw_extended(&ted2, &text2); | |||||
decaf_448_point_add(ted3, (struct decaf_448_point_s*)&ted1, (struct decaf_448_point_s*)&ted2); | |||||
add_tw_extended(&ted1, &ted2); | |||||
convert_tw_extensible_to_tw_extended(&ted2, &textb); | |||||
if (~decaf_eq_tw_extended(&ted1, &ted2) | ~decaf_448_point_eq((struct decaf_448_point_s*)&ted1, ted3)) { | |||||
youfail(); | |||||
succ = 0; | |||||
printf(" Tw extended simple compat:\n"); | |||||
field_print(" x1",ted1.x); | |||||
field_print(" y1",ted1.y); | |||||
field_print(" z1",ted1.z); | |||||
field_print(" t1",ted1.t); | |||||
field_print(" x2",ted2.x); | |||||
field_print(" y2",ted2.y); | |||||
field_print(" z2",ted2.z); | |||||
field_print(" t2",ted2.t); | |||||
struct tw_extended_t *t3 = (struct tw_extended_t *)&ted3; | |||||
field_print(" x3",t3->x); | |||||
field_print(" y3",t3->y); | |||||
field_print(" z3",t3->z); | |||||
field_print(" t3",t3->t); | |||||
} | |||||
succ &= fail_if_different_tw(&texta,&textb,"Addition commutativity","a+b","b+a"); | |||||
copy_tw_extensible(&textb, &text2); | |||||
add_tw_pniels_to_tw_extensible(&textb, &pn); | |||||
copy_tw_extensible(&texta, &text2); | |||||
double_tw_extensible(&texta); | |||||
succ &= fail_if_different_tw(&texta,&textb,"Doubling test","2b","b+b"); | |||||
if (~succ) { | |||||
printf(" Bases were:\n"); | |||||
field_print(" x1", base1->x); | |||||
field_print(" y1", base1->y); | |||||
field_print(" x2", base2->x); | |||||
field_print(" y2", base2->y); | |||||
} | |||||
return succ ? 0 : -1; | |||||
} | |||||
static int | |||||
single_twisting_test ( | |||||
const struct affine_t *base | |||||
) { | |||||
struct extensible_t exb, ext, tmpext; | |||||
struct tw_extensible_t text, text2; | |||||
mask_t succ = MASK_SUCCESS; | |||||
convert_affine_to_extensible(&exb, base); | |||||
succ &= validate_ext(&exb,0,"base"); | |||||
/* check: dual . iso = 4 */ | |||||
twist_and_double(&text, &exb); | |||||
succ &= validate_tw_ext(&text,2,"iso"); | |||||
untwist_and_double(&ext, &text); | |||||
succ &= validate_ext(&ext,2,"dual.iso"); | |||||
copy_extensible(&tmpext,&exb); | |||||
double_extensible(&tmpext); | |||||
succ &= validate_ext(&tmpext,1,"2*base"); | |||||
double_extensible(&tmpext); | |||||
succ &= validate_ext(&tmpext,2,"4*base"); | |||||
succ &= fail_if_different(&ext,&tmpext,"Isogeny and dual","Dual . iso","4*base"); | |||||
/* check: twist and serialize */ | |||||
test_only_twist(&text, &exb); | |||||
succ &= validate_tw_ext(&text,0,"tot"); | |||||
mask_t evt = is_even_tw(&text), evb = is_even_pt(&exb); | |||||
if (evt != evb) { | |||||
youfail(); | |||||
printf(" Different evenness from twist base: %d, twist: %d\n", (int)-evt, (int)-evb); | |||||
succ = 0; | |||||
} /* FUTURE: quadness */ | |||||
field_a_t sera,serb; | |||||
untwist_and_double_and_serialize(sera,&text); | |||||
copy_extensible(&tmpext,&exb); | |||||
double_extensible(&tmpext); | |||||
serialize_extensible(serb,&tmpext); | |||||
/* check that their (doubled; FUTURE?) serializations are equal */ | |||||
if (~field_eq(sera,serb)) { | |||||
youfail(); | |||||
printf(" Different serialization from twist + double ()\n"); | |||||
field_print(" t", sera); | |||||
field_print(" b", serb); | |||||
succ = 0; | |||||
} | |||||
untwist_and_double(&ext, &text); | |||||
succ &= validate_ext(&tmpext,1,"dual.tot"); | |||||
twist_and_double(&text2, &ext); | |||||
succ &= validate_tw_ext(&text2,2,"iso.dual.tot"); | |||||
double_tw_extensible(&text); | |||||
succ &= validate_tw_ext(&text,1,"2*tot"); | |||||
double_tw_extensible(&text); | |||||
succ &= validate_tw_ext(&text,2,"4*tot"); | |||||
succ &= fail_if_different_tw(&text,&text2,"Dual and isogeny","4*tot","iso.dual.tot"); | |||||
if (~succ) { | |||||
printf(" Base was:\n"); | |||||
field_print(" x", base->x); | |||||
field_print(" y", base->y); | |||||
} | |||||
return succ ? 0 : -1; | |||||
} | |||||
int test_decaf_evil (void) { | |||||
#if FIELD_BITS != 448 | |||||
printf(" [ UNIMP ] "); | |||||
return 0; | |||||
#else | |||||
#if WORD_BITS==64 | |||||
#define SC_WORD(x) x##ull | |||||
#elif WORD_BITS==32 | |||||
#define SC_WORD(x) (uint32_t)(x##ull), (x##ull)>>32 | |||||
#endif | |||||
word_t evil_scalars[5][448/WORD_BITS] = { | |||||
{0}, | |||||
{SC_WORD(0x2378c292ab5844f3),SC_WORD(0x216cc2728dc58f55),SC_WORD(0xc44edb49aed63690),SC_WORD(0xffffffff7cca23e9), | |||||
SC_WORD(0xffffffffffffffff),SC_WORD(0xffffffffffffffff),SC_WORD(0x3fffffffffffffff)}, /* q */ | |||||
{SC_WORD(0xdc873d6d54a7bb0d),SC_WORD(0xde933d8d723a70aa),SC_WORD(0x3bb124b65129c96f), | |||||
SC_WORD(0x335dc16),SC_WORD(0x0),SC_WORD(0x0),SC_WORD(0x4000000000000000)}, /* qtwist */ | |||||
{SC_WORD(0x46f1852556b089e6),SC_WORD(0x42d984e51b8b1eaa),SC_WORD(0x889db6935dac6d20),SC_WORD(0xfffffffef99447d3), | |||||
SC_WORD(0xffffffffffffffff),SC_WORD(0xffffffffffffffff),SC_WORD(0x7fffffffffffffff)}, /* 2q */ | |||||
{SC_WORD(0xb90e7adaa94f761a),SC_WORD(0xbd267b1ae474e155),SC_WORD(0x7762496ca25392df),SC_WORD(0x66bb82c), | |||||
SC_WORD(0x0),SC_WORD(0x0),SC_WORD(0x8000000000000000)} /* 2*qtwist */ | |||||
}; | |||||
word_t random_scalar[448/WORD_BITS]; | |||||
unsigned char evil_inputs[3][56]; | |||||
memset(evil_inputs[0],0,56); | |||||
memset(evil_inputs[1],0,56); | |||||
memset(evil_inputs[2],0xff,56); | |||||
evil_inputs[1][0] = 1; | |||||
evil_inputs[2][0] = evil_inputs[2][28] = 0xFE; | |||||
unsigned char random_input[56]; | |||||
crandom_state_a_t crand; | |||||
crandom_init_from_buffer(crand, "my evil_decaf random initializer"); | |||||
int i,j,fails=0; | |||||
int ret = 0; | |||||
for (i=0; i<100; i++) { | |||||
crandom_generate(crand, (unsigned char *)random_scalar, sizeof(random_scalar)); | |||||
if (i<15) { | |||||
memcpy(random_scalar, evil_scalars[i%5], sizeof(random_scalar)); | |||||
if (i%3 == 1) random_scalar[0] ++; | |||||
if (i%3 == 2) random_scalar[0] --; | |||||
} | |||||
for (j=0; j<100; j++) { | |||||
crandom_generate(crand, random_input, sizeof(random_input)); | |||||
mask_t should = 0, care_should = 0; | |||||
if (j<3) { | |||||
memcpy(random_input, evil_inputs[j], sizeof(random_input)); | |||||
care_should = -1; | |||||
should = (j==0) ? -1 : 0; | |||||
} else { | |||||
random_input[55] &= 0x7F; | |||||
} | |||||
field_a_t base, out_m, out_e, out_ed; | |||||
mask_t s_base = field_deserialize(base,random_input); | |||||
affine_a_t pt_e; | |||||
tw_affine_a_t pt_te; | |||||
tw_extended_a_t pt_ed; | |||||
// TODO: test don't allow identity | |||||
mask_t s_e = decaf_deserialize_affine(pt_e,base,-1); | |||||
mask_t s_te = decaf_deserialize_tw_affine(pt_te,base,-1); | |||||
mask_t s_ed = decaf_deserialize_tw_extended(pt_ed,base,-1); | |||||
mask_t s_m = decaf_montgomery_ladder(out_m, base, random_scalar, 448); | |||||
uint8_t ser_di[56]; | |||||
mask_t s_di = decaf_448_direct_scalarmul(ser_di,random_input,(struct decaf_448_scalar_s *)random_scalar,-1,-1); | |||||
tw_extensible_a_t work; | |||||
convert_tw_affine_to_tw_extensible(work,pt_te); | |||||
scalarmul(work, random_scalar); | |||||
decaf_serialize_tw_extensible(out_e, work); | |||||
scalarmul_ed(pt_ed, random_scalar); | |||||
decaf_serialize_tw_extended(out_ed, pt_ed); | |||||
uint8_t ser_de[56], ser_ed[56]; | |||||
decaf_448_point_t pt_dec, pt_dec2; | |||||
memcpy(pt_dec, pt_ed, sizeof(pt_dec)); | |||||
decaf_448_point_encode(ser_de, pt_dec); | |||||
mask_t succ_dec = decaf_448_point_decode(pt_dec2, ser_de, -1); | |||||
field_serialize(ser_ed, out_ed); | |||||
decaf_448_point_t p,q,m; | |||||
uint8_t oo_base_ser[56], n_base_ser[56]; | |||||
field_a_t oo_base,tmp,tmp2; | |||||
field_isr(tmp,base); | |||||
field_sqr(tmp2,tmp); // 1/+-s_base | |||||
field_sqr(tmp,tmp2); // = 1/s_base^2 | |||||
field_mul(oo_base,tmp,base); // = 1/s_base | |||||
field_serialize(oo_base_ser,oo_base); | |||||
field_neg(tmp,base); | |||||
field_serialize(n_base_ser,tmp); // = -base | |||||
decaf_448_point_from_hash_nonuniform (p,random_input); | |||||
decaf_448_point_from_hash_nonuniform (q,oo_base_ser); | |||||
decaf_448_point_from_hash_nonuniform (m,n_base_ser); | |||||
mask_t succ_nur = decaf_448_point_valid(p); | |||||
succ_nur &= decaf_448_point_valid(q); | |||||
succ_nur &= decaf_448_point_valid(m); | |||||
mask_t eq_neg, eq_pos; | |||||
eq_neg = decaf_448_point_eq(m,p); | |||||
decaf_448_point_add(m,p,q); | |||||
eq_pos = decaf_448_point_eq(m,decaf_448_point_identity); | |||||
if ((care_should && should != s_m) | |||||
|| ~s_base || s_e != s_te || s_m != s_te || s_ed != s_te || s_di != s_te | |||||
|| (s_te && ~field_eq(out_e,out_m)) | |||||
|| (s_ed && ~field_eq(out_e,out_ed)) | |||||
|| memcmp(ser_de, ser_ed, 56) | |||||
|| (s_te && memcmp(ser_di, ser_ed, 56)) | |||||
|| (s_e & ~succ_dec) | |||||
|| (s_e & ~decaf_448_point_eq(pt_dec, pt_dec2) | |||||
|| (s_e & ~decaf_448_point_valid(pt_dec)) | |||||
|| (succ_dec & ~decaf_448_point_valid(pt_dec2)) | |||||
|| ~succ_nur | |||||
|| ~eq_neg | |||||
|| ~eq_pos) | |||||
) { | |||||
youfail(); | |||||
field_print(" base", base); | |||||
scalar_print(" scal", random_scalar, (448+WORD_BITS-1)/WORD_BITS); | |||||
field_print(" oute", out_e); | |||||
field_print(" outE", out_ed); | |||||
field_print(" outm", out_m); | |||||
printf(" succ: m=%d, e=%d, t=%d, di=%d, b=%d, T=%d, D=%d, nur=%d, e+=%d, e-=%d, should=%d[%d]\n", | |||||
-(int)s_m,-(int)s_e,-(int)s_te,-(int)s_di,-(int)s_base,-(int)s_ed,-(int)succ_dec, | |||||
-(int)succ_nur, -(int)eq_neg, -(int)eq_pos, | |||||
-(int)should,-(int)care_should | |||||
); | |||||
ret = -1; | |||||
fails++; | |||||
} | |||||
} | |||||
} | |||||
if (fails) { | |||||
printf(" Failed %d trials\n", fails); | |||||
} | |||||
return ret; | |||||
#endif | |||||
} | |||||
int test_decaf (void) { | |||||
struct affine_t base; | |||||
struct tw_affine_t tw_base; | |||||
field_a_t serf; | |||||
struct crandom_state_t crand; | |||||
crandom_init_from_buffer(&crand, "my test_decaf random initializer"); | |||||
int i, hits = 0, fails = 0; | |||||
if (~decaf_448_point_valid(decaf_448_point_base)) { | |||||
youfail(); | |||||
printf(" Decaf base point invalid\n"); | |||||
fails++; | |||||
} | |||||
if (~decaf_448_point_valid(decaf_448_point_identity)) { | |||||
youfail(); | |||||
printf(" Decaf identity point invalid\n"); | |||||
fails++; | |||||
} | |||||
for (i=0; i<1000; i++) { | |||||
uint8_t ser[FIELD_BYTES]; | |||||
int j; | |||||
mask_t succ = 0; | |||||
for (j=0; j<128 && !succ; j++) { | |||||
crandom_generate(&crand, ser, sizeof(ser)); | |||||
ser[FIELD_BYTES-1] &= (1<<((FIELD_BITS-1)%8)) - 1; | |||||
succ = field_deserialize(serf, ser); | |||||
if (!succ) { | |||||
youfail(); | |||||
printf(" Unlikely: fail at field_deserialize\n"); | |||||
return -1; | |||||
} | |||||
succ &= decaf_deserialize_affine(&base, serf, 0); | |||||
} | |||||
if (!succ) { | |||||
youfail(); | |||||
printf("Unlikely: fail 128 desers\n"); | |||||
return -1; | |||||
} | |||||
hits++; | |||||
field_a_t serf2; | |||||
struct extensible_t ext; | |||||
convert_affine_to_extensible(&ext, &base); | |||||
decaf_serialize_extensible(serf2, &ext); | |||||
if (~validate_affine(&base)) { | |||||
youfail(); | |||||
printf("Invalid decaf deser:\n"); | |||||
field_print(" s", serf); | |||||
field_print(" x", base.x); | |||||
field_print(" y", base.y); | |||||
fails ++; | |||||
} else if (~field_eq(serf, serf2)) { | |||||
youfail(); | |||||
printf("Fail round-trip through decaf ser:\n"); | |||||
field_print(" s", serf); | |||||
field_print(" x", base.x); | |||||
field_print(" y", base.y); | |||||
printf(" deser is %s\n", validate_affine(&base) ? "valid" : "invalid"); | |||||
field_print(" S", serf2); | |||||
fails ++; | |||||
} else if (~is_even_pt(&ext)) { | |||||
youfail(); | |||||
printf("Decaf deser isn't even:\n"); | |||||
field_print(" s", serf); | |||||
field_print(" x", base.x); | |||||
field_print(" y", base.y); | |||||
fails ++; | |||||
} | |||||
succ = decaf_deserialize_tw_affine(&tw_base, serf, 0); | |||||
struct tw_extensible_t tw_ext, tw_ext2; | |||||
convert_tw_affine_to_tw_extensible(&tw_ext, &tw_base); | |||||
decaf_serialize_tw_extensible(serf2, &tw_ext); | |||||
twist_even(&tw_ext2, &ext); | |||||
if (~succ | ~validate_tw_extensible(&tw_ext)) { | |||||
youfail(); | |||||
printf("Invalid decaf tw deser:\n"); | |||||
field_print(" s", serf); | |||||
field_print(" x", tw_base.x); | |||||
field_print(" y", tw_base.y); | |||||
fails ++; | |||||
} else if (~field_eq(serf, serf2)) { | |||||
youfail(); | |||||
printf("Fail round-trip through decaf ser:\n"); | |||||
field_print(" s", serf); | |||||
field_print(" x", tw_base.x); | |||||
field_print(" y", tw_base.y); | |||||
printf(" tw deser is %s\n", validate_tw_extensible(&tw_ext) ? "valid" : "invalid"); | |||||
field_print(" S", serf2); | |||||
fails ++; | |||||
} else if (~is_even_tw(&tw_ext)) { | |||||
youfail(); | |||||
printf("Decaf tw deser isn't even:\n"); | |||||
field_print(" s", serf); | |||||
field_print(" x", tw_base.x); | |||||
field_print(" y", tw_base.y); | |||||
fails ++; | |||||
} else if (~decaf_eq_tw_extensible(&tw_ext,&tw_ext2)) { | |||||
youfail(); | |||||
printf("Decaf tw doesn't equal ext:\n"); | |||||
field_print(" s", serf); | |||||
field_print(" x1", base.x); | |||||
field_print(" y1", base.y); | |||||
field_print(" x2", tw_base.x); | |||||
field_print(" y2", tw_base.y); | |||||
field_print(" X2", tw_ext2.x); | |||||
field_print(" Y2", tw_ext2.y); | |||||
fails ++; | |||||
} | |||||
tw_extended_a_t ed; | |||||
succ = decaf_deserialize_tw_extended(ed, serf, 0); | |||||
decaf_serialize_tw_extended(serf2, ed); | |||||
if (~succ) { | |||||
youfail(); | |||||
printf("Invalid decaf ed deser:\n"); | |||||
field_print(" s", serf); | |||||
fails ++; | |||||
} else if (~field_eq(serf, serf2)) { | |||||
youfail(); | |||||
printf("Fail round-trip through decaf ser:\n"); | |||||
field_print(" s", serf); | |||||
field_print(" x", ed->x); | |||||
field_print(" y", ed->y); | |||||
field_print(" z", ed->z); | |||||
field_print(" t", ed->t); | |||||
printf(" tw deser is %s\n", validate_tw_extensible(&tw_ext) ? "valid" : "invalid"); | |||||
field_print(" S", serf2); | |||||
fails ++; | |||||
} | |||||
word_t scalar = 1; | |||||
mask_t res = decaf_montgomery_ladder(serf2,serf,&scalar,1+(i%31)); | |||||
if (~res | ~field_eq(serf2,serf)) { | |||||
youfail(); | |||||
printf("Decaf Montgomery ladder i=%d res=%d\n", 1+(i%31), (int)res); | |||||
field_print(" s", serf); | |||||
field_print(" o", serf2); | |||||
printf("\n"); | |||||
} | |||||
} | |||||
if (hits < 1000) { | |||||
youfail(); | |||||
printf(" Fail: only %d successes in decaf_deser\n", hits); | |||||
return -1; | |||||
} else if (fails) { | |||||
printf(" %d fails\n", fails); | |||||
return -1; | |||||
} else { | |||||
return 0; | |||||
} | |||||
} | |||||
int test_pointops (void) { | |||||
struct affine_t base, pbase; | |||||
field_a_t serf; | |||||
struct crandom_state_t crand; | |||||
crandom_init_from_buffer(&crand, "test_pointops random initializer"); | |||||
struct extensible_t ext_base; | |||||
if (!validate_affine(goldilocks_base_point)) { | |||||
youfail(); | |||||
printf(" Base point isn't on the curve.\n"); | |||||
return -1; | |||||
} | |||||
convert_affine_to_extensible(&ext_base, goldilocks_base_point); | |||||
if (!validate_ext(&ext_base, 2, "base")) return -1; | |||||
int i, ret; | |||||
for (i=0; i<1000; i++) { | |||||
uint8_t ser[FIELD_BYTES]; | |||||
crandom_generate(&crand, ser, sizeof(ser)); | |||||
#if (FIELD_BITS % 8) | |||||
ser[FIELD_BYTES-1] &= (1<<(FIELD_BITS%8)) - 1; | |||||
#endif | |||||
/* TODO: we need a field generate, which can return random or pathological. */ | |||||
mask_t succ = field_deserialize(serf, ser); | |||||
if (!succ) { | |||||
youfail(); | |||||
printf(" Unlikely: fail at field_deserialize\n"); | |||||
return -1; | |||||
} | |||||
if (i) { | |||||
copy_affine(&pbase, &base); | |||||
} | |||||
elligator_2s_inject(&base, serf); | |||||
if (i) { | |||||
ret = add_double_test(&base, &pbase); | |||||
if (ret) return ret; | |||||
} | |||||
ret = single_twisting_test(&base); | |||||
if (ret) return ret; | |||||
} | |||||
return 0; | |||||
} |
@@ -1,480 +0,0 @@ | |||||
#include "test.h" | |||||
#include <stdio.h> | |||||
#include "scalarmul.h" | |||||
#include "decaf.h" | |||||
#include "ec_point.h" | |||||
#include "field.h" | |||||
#include "crandom.h" | |||||
#define STRIDE 7 | |||||
/* 0 = succeed, 1 = inval, -1 = fail */ | |||||
static int | |||||
single_scalarmul_compatibility_test ( | |||||
const field_a_t base, | |||||
const word_t *scalar, | |||||
int nbits | |||||
) { | |||||
struct tw_extensible_t text, work; | |||||
field_a_t mont, ct, vl, vt, sced, decaf_s, decaf_m, decaf_te; | |||||
int ret = 0, i; | |||||
mask_t succ, succm; | |||||
succ = deserialize_and_twist_approx(&text, base); | |||||
succm = montgomery_ladder(mont,base,scalar,nbits,1); | |||||
if (succ != succm) { | |||||
youfail(); | |||||
printf(" Deserialize_and_twist_approx succ=%d, montgomery_ladder succ=%d\n", | |||||
(int)-succ, (int)-succm); | |||||
printf(" nbits = %d\n", nbits); | |||||
field_print(" base", base); | |||||
scalar_print(" scal", scalar, (nbits+WORD_BITS-1)/WORD_BITS); | |||||
return -1; | |||||
} | |||||
if (!succ) { | |||||
return 1; | |||||
} | |||||
#if FIELD_BITS == 448 | |||||
struct { int n,t,s; } params[] = {{5,5,18},{3,5,30},{4,4,28},{1,2,224}}; | |||||
#elif FIELD_BITS == 480 | |||||
struct { int n,t,s; } params[] = {{5,6,16},{6,5,16},{4,5,24},{4,4,30},{1,2,240}}; | |||||
#elif FIELD_BITS == 521 | |||||
struct { int n,t,s; } params[] = {{5,8,13},{4,5,26},{1,2,(SCALAR_BITS+1)/2}}; | |||||
#else | |||||
struct { int n,t,s; } params[] = {{5,5,(SCALAR_BITS+24)/25},{1,2,(SCALAR_BITS+1)/2}}; | |||||
#endif | |||||
const int nparams = sizeof(params)/sizeof(params[0]); | |||||
struct fixed_base_table_t fbt; | |||||
const int nsizes = 6; | |||||
field_a_t fbout[nparams], wout[nsizes]; | |||||
memset(&fbt, 0, sizeof(fbt)); | |||||
memset(&fbout, 0, sizeof(fbout)); | |||||
memset(&wout, 0, sizeof(wout)); | |||||
/* compute using combs */ | |||||
for (i=0; i<nparams; i++) { | |||||
int n=params[i].n, t=params[i].t, s=params[i].s; | |||||
succ = precompute_fixed_base(&fbt, &text, n, t, s, NULL); | |||||
if (!succ) { | |||||
youfail(); | |||||
printf(" Failed to precompute_fixed_base(%d,%d,%d)\n", n, t, s); | |||||
continue; | |||||
} | |||||
succ = scalarmul_fixed_base(&work, scalar, nbits, &fbt); | |||||
destroy_fixed_base(&fbt); | |||||
if (!succ) { | |||||
youfail(); | |||||
printf(" Failed to scalarmul_fixed_base(%d,%d,%d)\n", n, t, s); | |||||
continue; | |||||
} | |||||
untwist_and_double_and_serialize(fbout[i], &work); | |||||
} | |||||
/* compute using precomp wNAF */ | |||||
for (i=0; i<nsizes; i++) { | |||||
tw_niels_a_t pre[1<<i]; | |||||
succ = precompute_fixed_base_wnaf(pre, &text, i); | |||||
if (!succ) { | |||||
youfail(); | |||||
printf(" Failed to precompute_fixed_base_wnaf(%d)\n", i); | |||||
continue; | |||||
} | |||||
scalarmul_fixed_base_wnaf_vt(&work, scalar, nbits, (const tw_niels_a_t*)pre, i); | |||||
untwist_and_double_and_serialize(wout[i], &work); | |||||
} | |||||
mask_t consistent = MASK_SUCCESS; | |||||
if (nbits == FIELD_BITS) { | |||||
/* window methods currently only work on FIELD_BITS bits. */ | |||||
copy_tw_extensible(&work, &text); | |||||
scalarmul(&work, scalar); | |||||
untwist_and_double_and_serialize(ct, &work); | |||||
copy_tw_extensible(&work, &text); | |||||
scalarmul_vlook(&work, scalar); | |||||
untwist_and_double_and_serialize(vl, &work); | |||||
copy_tw_extensible(&work, &text); | |||||
scalarmul_vt(&work, scalar, nbits); | |||||
untwist_and_double_and_serialize(vt, &work); | |||||
decaf_448_point_t ed2, ed3; | |||||
struct decaf_448_precomputed_s *dpre; | |||||
int pmret = posix_memalign( | |||||
(void**)&dpre, | |||||
alignof_decaf_448_precomputed_s, | |||||
sizeof_decaf_448_precomputed_s | |||||
); | |||||
if (pmret) return 1; | |||||
tw_extended_a_t ed; | |||||
convert_tw_extensible_to_tw_extended(ed, &text); | |||||
uint8_t ser4[DECAF_448_SER_BYTES]; | |||||
decaf_448_point_encode(ser4, (struct decaf_448_point_s *)ed); | |||||
decaf_448_point_scalarmul( | |||||
ed2, | |||||
(struct decaf_448_point_s *)ed, | |||||
(struct decaf_448_scalar_s *)scalar | |||||
); | |||||
decaf_448_precompute(dpre, (struct decaf_448_point_s *)ed); | |||||
decaf_448_precomputed_scalarmul( | |||||
ed3, | |||||
dpre, | |||||
(struct decaf_448_scalar_s *)scalar | |||||
); | |||||
free(dpre); | |||||
scalarmul_ed(ed, scalar); | |||||
field_copy(work.x, ed->x); | |||||
field_copy(work.y, ed->y); | |||||
field_copy(work.z, ed->z); | |||||
field_copy(work.t, ed->t); | |||||
field_set_ui(work.u, 1); | |||||
untwist_and_double_and_serialize(sced, &work); | |||||
uint8_t ser1[DECAF_448_SER_BYTES], ser2[DECAF_448_SER_BYTES], | |||||
ser3[DECAF_448_SER_BYTES]; | |||||
decaf_448_point_encode(ser1, (struct decaf_448_point_s *)ed); | |||||
decaf_448_point_encode(ser2, ed2); | |||||
decaf_448_point_encode(ser3, ed3); | |||||
consistent &= decaf_448_direct_scalarmul(ser4, ser4, (struct decaf_448_scalar_s *)scalar, -1, -1); | |||||
/* check consistency mont vs window */ | |||||
consistent &= field_eq(mont, ct); | |||||
consistent &= field_eq(mont, vl); | |||||
consistent &= field_eq(mont, vt); | |||||
consistent &= field_eq(mont, sced); | |||||
consistent &= memcmp(ser1,ser2,sizeof(ser1)) ? 0 : -1; | |||||
consistent &= memcmp(ser1,ser3,sizeof(ser1)) ? 0 : -1; | |||||
consistent &= memcmp(ser1,ser4,sizeof(ser1)) ? 0 : -1; | |||||
} | |||||
/* check consistency mont vs combs */ | |||||
for (i=0; i<nparams; i++) { | |||||
consistent &= field_eq(mont,fbout[i]); | |||||
} | |||||
/* check consistency mont vs wNAF */ | |||||
for (i=0; i<nsizes; i++) { | |||||
consistent &= field_eq(mont,wout[i]); | |||||
} | |||||
/* Do decaf */ | |||||
copy_tw_extensible(&work,&text); | |||||
double_tw_extensible(&work); | |||||
decaf_serialize_tw_extensible(decaf_s, &work); | |||||
mask_t succ_dm, succ_dta; | |||||
succ_dm = decaf_montgomery_ladder(decaf_m, decaf_s, scalar, nbits); | |||||
succ_dta = deserialize_and_twist_approx(&work, mont); | |||||
decaf_serialize_tw_extensible(decaf_te, &work); | |||||
consistent &= field_eq(decaf_m, decaf_te); | |||||
consistent &= succ_dm & succ_dta; | |||||
/* If inconsistent, complain. */ | |||||
if (!consistent) { | |||||
youfail(); | |||||
printf(" Failed scalarmul consistency test with nbits=%d.\n",nbits); | |||||
field_print(" base", base); | |||||
scalar_print(" scal", scalar, (nbits+WORD_BITS-1)/WORD_BITS); | |||||
field_print(" mont", mont); | |||||
for (i=0; i<nparams; i++) { | |||||
printf(" With n=%d, t=%d, s=%d:\n", params[i].n, params[i].t, params[i].s); | |||||
field_print(" out ", fbout[i]); | |||||
} | |||||
for (i=0; i<nsizes; i++) { | |||||
printf(" With w=%d:\n",i); | |||||
field_print(" wNAF", wout[i]); | |||||
} | |||||
if (nbits == FIELD_BITS) { | |||||
field_print(" ct ", ct); | |||||
field_print(" vl ", vl); | |||||
field_print(" vt ", vt); | |||||
field_print(" ed ", sced); | |||||
} | |||||
printf("decaf: succ = %d, %d\n", (int)succ_dm, (int)succ_dta); | |||||
field_print(" s0", decaf_s); | |||||
field_print(" dm", decaf_m); | |||||
field_print(" dt", decaf_te); | |||||
ret = -1; | |||||
} | |||||
return ret; | |||||
} | |||||
static int | |||||
single_linear_combo_test ( | |||||
const field_a_t base1, | |||||
const word_t *scalar1, | |||||
int nbits1, | |||||
const field_a_t base2, | |||||
const word_t *scalar2, | |||||
int nbits2 | |||||
) { | |||||
struct tw_extensible_t text1, text2, working; | |||||
struct tw_pniels_t pn; | |||||
field_a_t result_comb, result_combo, result_wnaf; | |||||
mask_t succ = | |||||
deserialize_and_twist_approx(&text1, base1) | |||||
& deserialize_and_twist_approx(&text2, base2); | |||||
if (!succ) return 1; | |||||
struct fixed_base_table_t t1, t2; | |||||
tw_niels_a_t wnaf[32]; | |||||
memset(&t1,0,sizeof(t1)); | |||||
memset(&t2,0,sizeof(t2)); | |||||
succ = precompute_fixed_base(&t1, &text1, 5, 5, 18, NULL); // FIELD_MAGIC | |||||
succ &= precompute_fixed_base(&t2, &text2, 6, 3, 25, NULL); // FIELD_MAGIC | |||||
succ &= precompute_fixed_base_wnaf(wnaf, &text2, 5); | |||||
if (!succ) { | |||||
destroy_fixed_base(&t1); | |||||
destroy_fixed_base(&t2); | |||||
return -1; | |||||
} | |||||
/* use the dedicated wNAF linear combo algorithm */ | |||||
copy_tw_extensible(&working, &text1); | |||||
linear_combo_var_fixed_vt(&working, scalar1, nbits1, scalar2, nbits2, (const tw_niels_a_t*)wnaf, 5); | |||||
untwist_and_double_and_serialize(result_wnaf, &working); | |||||
/* use the dedicated combs algorithm */ | |||||
succ &= linear_combo_combs_vt(&working, scalar1, nbits1, &t1, scalar2, nbits2, &t2); | |||||
untwist_and_double_and_serialize(result_combo, &working); | |||||
/* use two combs */ | |||||
succ &= scalarmul_fixed_base(&working, scalar1, nbits1, &t1); | |||||
convert_tw_extensible_to_tw_pniels(&pn, &working); | |||||
succ &= scalarmul_fixed_base(&working, scalar2, nbits2, &t2); | |||||
add_tw_pniels_to_tw_extensible(&working, &pn); | |||||
untwist_and_double_and_serialize(result_comb, &working); | |||||
mask_t consistent = MASK_SUCCESS; | |||||
consistent &= field_eq(result_combo, result_wnaf); | |||||
consistent &= field_eq(result_comb, result_wnaf); | |||||
if (!succ || !consistent) { | |||||
youfail(); | |||||
printf(" Failed linear combo consistency test with nbits=%d,%d.\n",nbits1,nbits2); | |||||
field_print(" base1", base1); | |||||
scalar_print(" scal1", scalar1, (nbits1+WORD_BITS-1)/WORD_BITS); | |||||
field_print(" base2", base2); | |||||
scalar_print(" scal2", scalar2, (nbits1+WORD_BITS-1)/WORD_BITS); | |||||
field_print(" combs", result_comb); | |||||
field_print(" combo", result_combo); | |||||
field_print(" wNAFs", result_wnaf); | |||||
return -1; | |||||
} | |||||
destroy_fixed_base(&t1); | |||||
destroy_fixed_base(&t2); | |||||
return 0; | |||||
} | |||||
/* 0 = succeed, 1 = inval, -1 = fail */ | |||||
static int | |||||
single_scalarmul_commutativity_test ( | |||||
const field_a_t base, | |||||
const word_t *scalar1, | |||||
int nbits1, | |||||
int ned1, | |||||
const word_t *scalar2, | |||||
int nbits2, | |||||
int ned2 | |||||
) { | |||||
field_a_t m12, m21, tmp1, tmp2; | |||||
mask_t succ12a = montgomery_ladder(tmp1,base,scalar1,nbits1,ned1); | |||||
mask_t succ12b = montgomery_ladder(m12,tmp1,scalar2,nbits2,ned2); | |||||
mask_t succ21a = montgomery_ladder(tmp2,base,scalar2,nbits2,ned2); | |||||
mask_t succ21b = montgomery_ladder(m21,tmp2,scalar1,nbits1,ned1); | |||||
mask_t succ12 = succ12a & succ12b, succ21 = succ21a & succ21b; | |||||
if (succ12 != succ21) { | |||||
youfail(); | |||||
printf(" Failed scalarmul commutativity test with (nbits,ned) = (%d,%d), (%d,%d).\n", | |||||
nbits1,ned1,nbits2,ned2); | |||||
field_print(" base", base); | |||||
field_print(" tmp1", tmp1); | |||||
field_print(" tmp2", tmp2); | |||||
scalar_print(" sca1", scalar1, (nbits1+WORD_BITS-1)/WORD_BITS); | |||||
scalar_print(" sca2", scalar2, (nbits1+WORD_BITS-1)/WORD_BITS); | |||||
printf(" good = ((%d,%d),(%d,%d))\n", (int)-succ12a, | |||||
(int)-succ12b, (int)-succ21a, (int)-succ21b); | |||||
return -1; | |||||
} else if (!succ12) { | |||||
// printf(" (nbits,ned) = (%d,%d), (%d,%d).\n", nbits1,ned1,nbits2,ned2); | |||||
// printf(" succ = (%d,%d), (%d,%d).\n", (int)-succ12a, (int)-succ12b, (int)-succ21a, (int)-succ21b); | |||||
return 1; | |||||
} | |||||
mask_t consistent = field_eq(m12,m21); | |||||
if (consistent) { | |||||
return 0; | |||||
} else { | |||||
youfail(); | |||||
printf(" Failed scalarmul commutativity test with (nbits,ned) = (%d,%d), (%d,%d).\n", | |||||
nbits1,ned1,nbits2,ned2); | |||||
field_print(" base", base); | |||||
scalar_print(" sca1", scalar1, (nbits1+WORD_BITS-1)/WORD_BITS); | |||||
scalar_print(" sca2", scalar2, (nbits1+WORD_BITS-1)/WORD_BITS); | |||||
field_print(" m12 ", m12); | |||||
field_print(" m21 ", m21); | |||||
return -1; | |||||
} | |||||
} | |||||
static void crandom_generate_f(struct crandom_state_t *crand, uint8_t *scalar, int n) { | |||||
crandom_generate(crand, scalar, n); | |||||
int i; | |||||
for (i = FIELD_BYTES; i<n; i++) { | |||||
scalar[i] = 0; | |||||
} | |||||
#if (FIELD_BITS % 8) | |||||
if (n >= FIELD_BYTES) { | |||||
scalar[FIELD_BYTES-1] &= (1<<(FIELD_BITS%8)) - 1; | |||||
} | |||||
#endif | |||||
} | |||||
int test_scalarmul_commutativity (void) { | |||||
int i,j,k,got; | |||||
struct crandom_state_t crand; | |||||
crandom_init_from_buffer(&crand, "scalarmul_commutativity_test RNG"); | |||||
for (i=0; i<=FIELD_BITS; i+=STRIDE) { | |||||
for (j=0; j<=FIELD_BITS; j+=STRIDE) { | |||||
got = 0; | |||||
for (k=0; k<128 && !got; k++) { | |||||
uint8_t ser[FIELD_BYTES]; | |||||
word_t scalar1[SCALAR_WORDS], scalar2[SCALAR_WORDS]; | |||||
crandom_generate_f(&crand, ser, sizeof(ser)); | |||||
crandom_generate(&crand, (uint8_t *)scalar1, sizeof(scalar1)); | |||||
crandom_generate(&crand, (uint8_t *)scalar2, sizeof(scalar2)); | |||||
field_t base; | |||||
mask_t succ = field_deserialize(&base, ser); | |||||
if (!succ) continue; | |||||
int ret = single_scalarmul_commutativity_test (&base, scalar1, i, i%3, scalar2, j, j%3); | |||||
got = !ret; | |||||
if (ret == -1) return -1; | |||||
} | |||||
if (!got) { | |||||
youfail(); | |||||
printf(" Unlikely: rejected 128 scalars in a row.\n"); | |||||
return -1; | |||||
} | |||||
} | |||||
} | |||||
return 0; | |||||
} | |||||
int test_linear_combo (void) { | |||||
int i,j,k,got; | |||||
struct crandom_state_t crand; | |||||
crandom_init_from_buffer(&crand, "scalarmul_linear_combos_test RNG"); | |||||
for (i=0; i<=FIELD_BITS; i+=STRIDE) { | |||||
for (j=0; j<=FIELD_BITS; j+=STRIDE) { | |||||
got = 0; | |||||
for (k=0; k<128 && !got; k++) { | |||||
uint8_t ser[FIELD_BYTES]; | |||||
word_t scalar1[SCALAR_WORDS], scalar2[SCALAR_WORDS]; | |||||
crandom_generate(&crand, (uint8_t *)scalar1, sizeof(scalar1)); | |||||
crandom_generate(&crand, (uint8_t *)scalar2, sizeof(scalar2)); | |||||
field_t base1; | |||||
crandom_generate_f(&crand, ser, sizeof(ser)); | |||||
mask_t succ = field_deserialize(&base1, ser); | |||||
if (!succ) continue; | |||||
field_t base2; | |||||
crandom_generate(&crand, ser, sizeof(ser)); | |||||
succ = field_deserialize(&base2, ser); | |||||
if (!succ) continue; | |||||
int ret = single_linear_combo_test (&base1, scalar1, i, &base2, scalar2, j); | |||||
got = !ret; | |||||
if (ret == -1) return -1; | |||||
} | |||||
if (!got) { | |||||
youfail(); | |||||
printf(" Unlikely: rejected 128 scalars in a row.\n"); | |||||
return -1; | |||||
} | |||||
} | |||||
} | |||||
return 0; | |||||
} | |||||
int test_scalarmul_compatibility (void) { | |||||
int i,j,k,got; | |||||
struct crandom_state_t crand; | |||||
crandom_init_from_buffer(&crand, "scalarmul_compatibility_test RNG"); | |||||
for (i=0; i<=FIELD_BITS; i+=STRIDE) { | |||||
for (j=0; j<=20; j++) { | |||||
got = 0; | |||||
for (k=0; k<128 && !got; k++) { | |||||
uint8_t ser[FIELD_BYTES]; | |||||
word_t scalar[SCALAR_WORDS]; | |||||
crandom_generate_f(&crand, ser, sizeof(ser)); | |||||
crandom_generate(&crand, (uint8_t *)scalar, sizeof(scalar)); | |||||
field_t base; | |||||
mask_t succ = field_deserialize(&base, ser); | |||||
if (!succ) continue; | |||||
int ret = single_scalarmul_compatibility_test (&base, scalar, i); | |||||
got = !ret; | |||||
if (ret == -1) return -1; | |||||
} | |||||
if (!got) { | |||||
youfail(); | |||||
printf(" Unlikely: rejected 128 scalars in a row.\n"); | |||||
return -1; | |||||
} | |||||
} | |||||
} | |||||
return 0; | |||||
} |
@@ -1,270 +0,0 @@ | |||||
#include "test.h" | |||||
#include <stdio.h> | |||||
#include <string.h> | |||||
#include "sha512.h" | |||||
static int sha512_monte_carlo_core ( | |||||
const char *seed, | |||||
const char *checks[100] | |||||
) { | |||||
sha512_ctx_a_t sha; | |||||
sha512_init(sha); | |||||
unsigned char md0[64],md1[64],md2[64]; | |||||
int ret = hexdecode(md0,seed,64); | |||||
if (ret) { | |||||
youfail(); | |||||
printf(" SHA-512 NIST Monte Carlo validation seed hex decode failure.\n"); | |||||
return -1; | |||||
} | |||||
int i,j; | |||||
memcpy(md1,md0,sizeof(md1)); | |||||
memcpy(md2,md0,sizeof(md1)); | |||||
for (j=0; j<100; j++) { | |||||
for (i=3; i<1003; i++) { | |||||
sha512_update(sha,md0,sizeof(md0)); | |||||
sha512_update(sha,md1,sizeof(md1)); | |||||
sha512_update(sha,md2,sizeof(md2)); | |||||
memcpy(md0,md1,sizeof(md1)); | |||||
memcpy(md1,md2,sizeof(md1)); | |||||
sha512_final(sha,md2); | |||||
} | |||||
ret = hexdecode(md0,checks[j],64); | |||||
if (ret) { | |||||
youfail(); | |||||
printf(" SHA-512 NIST Monte Carlo validation hex decode failure at iteration %d\n", j); | |||||
return -1; | |||||
} else if (memcmp(md0,md2,sizeof(md2))) { | |||||
youfail(); | |||||
printf(" SHA-512 NIST Monte Carlo validation failure at iteration %d\n", j); | |||||
hexprint(" Expected", md0, 64); | |||||
hexprint(" But got ", md2, 64); | |||||
return j+1; | |||||
} | |||||
memcpy(md0,md2,sizeof(md1)); | |||||
memcpy(md1,md2,sizeof(md1)); | |||||
} | |||||
return 0; | |||||
} | |||||
int test_sha512_monte_carlo(void) { | |||||
const char *seed = | |||||
"5c337de5caf35d18ed90b5cddfce001ca1b8ee8602f367e7c24ccca6f893802f" | |||||
"b1aca7a3dae32dcd60800a59959bc540d63237876b799229ae71a2526fbc52cd"; | |||||
const char *checks[100] = { | |||||
"ada69add0071b794463c8806a177326735fa624b68ab7bcab2388b9276c036e4" | |||||
"eaaff87333e83c81c0bca0359d4aeebcbcfd314c0630e0c2af68c1fb19cc470e", | |||||
"ef219b37c24ae507a2b2b26d1add51b31fb5327eb8c3b19b882fe38049433dbe" | |||||
"ccd63b3d5b99ba2398920bcefb8aca98cd28a1ee5d2aaf139ce58a15d71b06b4", | |||||
"c3d5087a62db0e5c6f5755c417f69037308cbce0e54519ea5be8171496cc6d18" | |||||
"023ba15768153cfd74c7e7dc103227e9eed4b0f82233362b2a7b1a2cbcda9daf", | |||||
"bb3a58f71148116e377505461d65d6c89906481fedfbcfe481b7aa8ceb977d25" | |||||
"2b3fe21bfff6e7fbf7575ceecf5936bd635e1cf52698c36ef6908ddbd5b6ae05", | |||||
"b68f0cd2d63566b3934a50666dec6d62ca1db98e49d7733084c1f86d91a8a08c" | |||||
"756fa7ece815e20930dd7cb66351bad8c087c2f94e8757cb98e7f4b86b21a8a8", | |||||
"937d7856a82a84c163c79417d0540c47daaf9ffe662c843737dbbcbe5f865bf6" | |||||
"f47a9d2bd10129a4f498073094653c324a2519a1c71ac1279b1623ff7d24647a", | |||||
"f8fbc058c2b9f84131c9decfa543a35ade41581f670398efd61b3abfced9c1cf" | |||||
"cb5324f2370487f9c59a65bc668ea596c8d22ce8a33014dfad28357fa7d05f04", | |||||
"4ab0c9484ff5c30fa64ae6e81510c5fea566eafb88f175f8bc19109f40fe8001" | |||||
"4c8b77fff10b8750778429bf3c5497e4cb92d9b30014f4cb975dff2a45244c28", | |||||
"685179397554d276513d630234a03419808c698abf2600d7490aabb8e455c6ab" | |||||
"6ea412c7729dc140a79dff66533c6946cbe90f9da9ed16e2e629db1651bea870", | |||||
"335e6e941ab7dadfecdb74ea6cb4e8584b6e3408841a33a6cf7fd6a63294b193" | |||||
"0a60983240311672acac3840a90e64cc366ce75081b2252627e9c31197ebad03", | |||||
"e3217f6af6e279e9445dc3738cbf9ba0e9edba0455844a73648139777afdea2c" | |||||
"4d8032e214f541bf92675fb23f24df8e4fe98e0003aadfb6d8f9cc2cd799bbf7", | |||||
"ee2fdfb3ae630613b7d890977cf2515deac272a37f27e4a01961ecf103d4ff5b" | |||||
"45cc8aef53b635dd75aa51aabf71c0642555ccd3281e0388f8ca09d83258cf30", | |||||
"6a30d97cc98af6a25b673dce7aeab8d762bf2e55ea0c6dc899179281f84dd02a" | |||||
"2896f77e9c106b472f55f7adbef7b1157be567ee1236ebdac2a3c5d8cb133eb5", | |||||
"ac1176abdc5f71170183d92ae55856221b0d95590af11d9d72ba605ec026bbec" | |||||
"52d6974bc43a1efb125ff2b161fbdc616fda00f04193a0bc26aacdfa052a5741", | |||||
"59fa909480620ecc08d34531a6da1b55158b74fc93ddf68e1d242615b6f3843a" | |||||
"7952e63e798c6445cde1b07e0be09d0d711cb7b42a0e7760a593b08acfceb63d", | |||||
"9eb253319efa61b864f27bd334d7dd78b38d3265fb544e0c8edee950a547e1d8" | |||||
"db921a285774ab94d66beae933298d20f2a5aa87c62fe1e383cc3b18e7af18ac", | |||||
"81735324005671f7bdad9e685ee8257f5e0622b9fcb5d38dbdfb2df27258c3e1" | |||||
"d46d76e24c0c92c744e1b50a2b4b0d31525b3af83cc80a75722d921bdeef59c4", | |||||
"17498cdff4323bb8021e44eca6559e05d8ff9a0ef2ee9d4ba0ac6e73f83972a0" | |||||
"dfbb6d47728fa70311d7c82e154966e1b7678263b0f65133e9116969193d429b", | |||||
"228c4574d7c45eb9ba9240722133fce74abe00c7328ab30b4bde373dc79afdd6" | |||||
"e0569d36268cd5eaa2f27205fc00512577bcbb6699e1d66ed85eafaba7548afb", | |||||
"3d40ccd9cc445bbecca9227c67fe455d89e0b7c1c858d32f30e2b544ca9a5a60" | |||||
"6535aea2e59fec6ec4d1ba898cc4338c6eadef9c0884bcf56aca2f481a2d7d3e", | |||||
"e1e577aeac92e3a2b7f8a262bf2ac9c037d2274ca6618fbe4cc21db7c699e994" | |||||
"6b6671ae45ea433a1e392a5bc9eec96fd641ba8f4a047f022a04a337227004df", | |||||
"5e4424c0bcb2f0f7a2428821a9d5840a82401f4440ae6bed25c53cd9e71cf9d3" | |||||
"9904d6a375bd721f4332ab0202529c91feb9c094c3e6d34ca4f66649ee6fa212", | |||||
"56b199d63ca37189d5ca0d40006ac7bcb9f39cbdc00ef7b8a5697caa7d81d05b" | |||||
"645a146995b1151d01958f1589337e14afc6e7dd10a815170e527a398e6ce8c3", | |||||
"d2d498ff93fb03013a64f295b5bc68e57d2fb5600da578aa011d43ff432eae3e" | |||||
"0c800f9e2a53155e56fdbf5e068fe2b4beb3e42b2585531b8b16c4d8ca3356c6", | |||||
"3d3875489903710f17cf4247b5842ace6f017b1a3b99e9ee5fbc04fc7898e78b" | |||||
"12693879878028ca40c63cd0f6925fb7d0ca0412e4f06619e3ace223690f03b8", | |||||
"a013e21cd1234483c95c2ea2757be949bc79401ba39b09c316a1612d594642be" | |||||
"65ca106e12695ac3808c57c6f2980e895fd1fe188946562afc238414e1e43649", | |||||
"c5f6367d7195489e16242f912fbe0d8002e947de3a7e9c53f77b1e5e90e05bd7" | |||||
"ca395e787e34cb5f500c02da59c9d83de35601de7ae80dae74a0d6b4a292d43b", | |||||
"7c28c44c6aaba83c122f24d68273e28a5afd65b4071d02b7ea3300478d511897" | |||||
"1e1356ae57cbc70d2a177ea464a1c2c50d4297b933e789c63b1481797ae8f08c", | |||||
"af7cb42b1c70a85ac1ae1c2991b25b657c19f4fcf83af7f7dc0ae1028c1452a6" | |||||
"a17dc98929634fe6ed3855b70b96bc2caa93d82037b94ebeddc77e4c1a7cc563", | |||||
"bd56ad4c0cbd162706053da929d667253aadcf417affb483fff4f2699bf406d1" | |||||
"28cfdf5196dfbb05bb89ccbf04c5147bd2ebb3156b0bc1768ca6faa171c91c01", | |||||
"004d7b0fff9bcddf4b3913ae190a76728705a3d23874d92a8b7ff246c8fcad46" | |||||
"623cb04723c8aded0cba4968d1a8cc1375b99005786c1bcb7ae4bf13325c3ae0", | |||||
"8299a5bf5ed64f525c4eebbeca969fc1b91a81adb58c584bdd2d7676386a31fa" | |||||
"546643a3cf505007584f02fb712d708cab645bf078a1b9339f5a76aee985d017", | |||||
"ce7100f3455db1a9776a9f40d562ea998afca1f9fee7e0d81c8db34cf68ad23a" | |||||
"8bfa6fc04774703e1e56d5196b66966158fcf2a8335a58c6ba7ba1af756ba1dc", | |||||
"90aaabcb655ee921b8350229efe6064a60051cf0cac858fa3d43afd5b97cc823" | |||||
"01bd1b8cc1f874022e5af948185638783a13ca1bbd5049ace7fbf4f6d90c201f", | |||||
"3cf0a25b33ded3e0806dfe603b9987f1d6f2b3fdcb1ec7f8566828c00e17e8f5" | |||||
"9e38b3bca302396c7525ca194e6cc8501369059e2e34ae21e3141215876847c4", | |||||
"bdc5266aee339a1ff13fcf5229773cd3d14b47101e83076927c160bb71bf7445" | |||||
"590525a2012d52af008e118e16df1b6bfcaf8f22b4e45f9e749f3c20625a2bc8", | |||||
"ef8d2ba885381ab97756d59dbbbf53a1ea35d152b2d8f82c3518430aa34e7083" | |||||
"59194ea43950d032e151f576d343a5c3cfe6b71d4ed0ead9d3a107402589bad0", | |||||
"194ea5324c4179998dd7057755f255fdea04dadf533f7851e3e9718b610948e3" | |||||
"2fd28323077d9421142ac808978adfa325b668c8599a2e01c757a5a14ed2dd37", | |||||
"106984d2f0087e621dae760552bc6279072267883c204079481af6034354f1a2" | |||||
"b77c17e6c039a1063e479342aa3ccd90330dd3fb5a7d5e976619497e2d3326cd", | |||||
"a1347216f1a6db47b90c4ded3c5c75440f54c22c87d538314d1340f86f88acba" | |||||
"01378acb933ddad0adc6b75d55bfb7e8efc9c4a531b2a410610b7515b6dac66a", | |||||
"b76e4db147e0eaa4f04880654088b9d0fce518c8c377d92c846345604dc6b2b1" | |||||
"8d377fdb8e30f06d9bcfe6d7dacc07d6adff73d98d49f8f132b80f3084390830", | |||||
"acd4e527763dfd4513f0def0b1edf8ea12dc78d336b7b796f3dcc32e10687254" | |||||
"43a2f55ab4f666b27d6bf2ab39669c98293f0a9108051fd3144d31a1ed171ddd", | |||||
"10128c15494bc87a87374f676ef9fe2df20b36ffcca41a80bd40b216637b3de7" | |||||
"10efd070e277827820a7bba3cceb7b21f8fe7f9775d6c4df4d3da5349434ec49", | |||||
"2632dd5c188c6ed3a4610405fdda704add752f5424d9de65a51400fe478e26cd" | |||||
"0412e5f91ca4b744c34f4954f40a3a4254431d21954623208b527b7b4daa687e", | |||||
"45707f5b6fc5ccd1f78d77f177d10fb8b462c74cc821518cd5cfa4b5d6b40b41" | |||||
"8044900693c37abbb82367d340fec67f800d74072935da1706b4d90ae26099c7", | |||||
"56c37f31220b5b3040373d91b2c5e42fe9e601a12f7f8dc4534459bf28e484b8" | |||||
"713db243c5782c031e674003a3c14c42fd152e7188789065e82795e10f87d54b", | |||||
"5da94c899d48bd8299fee3d81662f8d6c5f8f8bc54d18cb0368b13cebaee7ad7" | |||||
"1e74ea80f34974ad166f04f9a0602809166fe4085a475a8ca86cade12b6754c4", | |||||
"0664363f97ba910760b0922e31ca880ca97469506cb007e3108c36c3ce3ce180" | |||||
"1fb4197609479339e8820632b6a38bffffee05a9adc11cc544b9aa6f5b95cc6f", | |||||
"732c41a1edaa727c04f627ff158aaff67c18efd667216132b99ab84d108996a1" | |||||
"0bb008b5d803b22ed1aa78bb0d10f8a762fd34777d7dccce8e84827ba88d4193", | |||||
"fc9c21d67e393a2b05a23a17d8db630cbaebaa3def211181749f1bcad1815606" | |||||
"27fb60ee20fae2e5980cbf50fce0a19dce807e7fb75c4da0ef008bc75d413a65", | |||||
"0453b765afc1edffa595efe345177f5805ed3abc1297ceab757ae7161723a614" | |||||
"4cb543299f418049276d16b7896662631634fab9549127c10f27505b7dee8665", | |||||
"3853f3bf024e0668e8d1ea53733a97537f97d9307c5f3a19864ab4eeb1654710" | |||||
"693bb961a344dec8a758f5e64b26fcb6dd423419c4a114fa749211a9de06c281", | |||||
"240137f0dd57beb3f7fc283bb3ead423c67883fd46f4e27471d7be57ad469a49" | |||||
"bad03a3658418bd55614678f3a463bceff85291314b90ef43ccbcb028f0a7a07", | |||||
"f9050a5271edbe4cfdb9520ec05bbdc3cbcb9bce36fd212338d3e7028a39b9ab" | |||||
"30793e561d75a2e424193264c7f0775e65599ef0c94e0ad24dbfe18252364267", | |||||
"47caa7a5862fad837aaa409a4a9df2575e645528c35159115911b7c4e2f08ae4" | |||||
"9d68de97249b31b83ce2c163f649cad4559dc6e6a7191f2922d79a5fd6af167b", | |||||
"13f5825c41fa49edf6104e3e35c9c224eba93e37374f730004c39c54e7391e4a" | |||||
"847fd61865235a3fe32224c96fbe86f7e14c3d5df496e83ec989a71b4f293a44", | |||||
"e5b55e05efe1ca6b9a96a57e3a1523d610d70f837e93b31fa98c2736d3e114d2" | |||||
"38d46ec6b6e3d19e774b253f6b0c7a2ebe69b7e60fc0874444806b2a2278df45", | |||||
"f14a586ac30f0af255f597a9aef9abba5e99c04d17b01f24427c4ee2c196b52a" | |||||
"cb1ceefc9b15cb822b3ecffdc2f7c49e11d3fc0769acee33361537d379c62e0c", | |||||
"7e2d3398807195c48e6ec52d20710bbf8b21ea8de4d1abc197897ccc58aeff40" | |||||
"259edc67270cdae0edcc686c0d0dccc5760c1495ab1cf48482dc2000ae2d42ad", | |||||
"2f3d5c5f990bf615d5e8b396ccbd0337da39fad09b059f955a431db76a9dc720" | |||||
"dffc4e02c0be397c7e0463799cd75fd6ab7c52bec66c8df5ef0d47e14a4c5927", | |||||
"483a1764d308cc494a2b543d29ba616483aefdf91c7769fd084eedaac1add189" | |||||
"1df95d317a47430b2bf73e4081f86597020e28afe2d34a22b77ea62b6112d09a", | |||||
"bfa88691ec951511651c6f14af100eeb26d87729e18ac3ef49a80d73ffeaeea5" | |||||
"3e97c4a7277a7ee9f2fba070b1c9720d6cdba407dd82267019e3f0f5662b2f2b", | |||||
"4c17c8e2e7132dbf82afebc40efc77926d16f4d2c082d846dac28733aa767e28" | |||||
"40ebf04f2563df75933466a36e11968d342e4157827605d04d9627ce9b5216c8", | |||||
"70bbfc29a2a765220af84e7bb10d759a3152ad4b5643ef6b89966950ec7ef950" | |||||
"3d57bc0a28c4ee789a60bf9dcac59139e15241d73b990410cf92eff213da9eca", | |||||
"8d1d56f37fc19b84984a6fa33aa9c2dbdbf79a29c04ad0b4cf20333e6bec9434" | |||||
"47be2416242f8cd2f9732e79bb925cc5a61a80c5fc9c079961243fd1c1f5900e", | |||||
"492fd0171f4dcd5d20ea6c0d34b5576c8894664ae5955e6737f5e3b711c2804d" | |||||
"99ccca065b7ec18c82da98b18a3029b765c51ebc7c433b36492e0ed6b8511bb6", | |||||
"7f49e8e54db7e5b4323cae2db71f3e8b8eba172dcad3602e9b7b058007a55893" | |||||
"58732d5afffa56072a46e89b1ea27ef8d556deb86b569c635d394f15d99d8a15", | |||||
"56884a6a9210d5f371e25823efb2511a9c410c26a441e07c1bdffe8605084267" | |||||
"d49c315baf6a692d7d97844b2714b4930877a5d7f52cf6fa151700fcb6980546", | |||||
"6aaef8284eef221ecb17ea3c9596f075b5155fe7b925d737ed3c6543c761c28c" | |||||
"7cd9d9d4b5e2a37b2f183a2a367bbd34b633497bc7a1737d61c8c1f3ef295062", | |||||
"38ef178f5688e59d47c375252db7b39f40c0c84169878ee7ba5086e4b25fea81" | |||||
"076b9c37847e9e6bf24ae0b343689c265ec5ca7469e619acd61b0276721efb1b", | |||||
"e3fe1aabad120777cf24eaae289b486632ca46ceb89afae73dbae5fa87c76787" | |||||
"9369355a9cc5c21ca604ed91d0f2f58c466573f3e6d88e52c62c0d3cb188e141", | |||||
"82f5bd920457bb2763a0da031a7fed47b236951b1ea420c20fd2b6de1dbfbb9c" | |||||
"4600ea7092788493e2d4be6ee24b6dba04e57af3e8f2f14d9837295420ac7631", | |||||
"6d0b26208ba9b1615067bb3ff97b292fe67e4c02d240d649c32370e0a4cd22d0" | |||||
"3bdf864be4d24a3f5f51aeccfd1afd5191e590edeb5f7bec323b0506c3104b89", | |||||
"d081083158054d08371ec84f4d3aa5aa761734ac6091a30330a861fda056f835" | |||||
"c750bf4f7981af1693ff28545366bd05cec47bccd77a7d237befb0135c534138", | |||||
"6ba8b52780b8a07a2a2015dd8f0c5e7437b8e024c4ee428f7ba91dfea118cb72" | |||||
"a939872550983317132b841b7cbc29a22b8f1cfea0c55203cafc69b55ed6244a", | |||||
"312692b0a51f002b7f06d05b39d15a5637dbddd2f4f1a73e6c88a4c841cdba5c" | |||||
"d8e69c0939ab39bb1a9c54fa35402143c97edb9704a0e9e1a98701710f6a5dad", | |||||
"aaee960de201a8dcccff95b834fccf0dafc03fe6cffc0429162bf4aff01165ab" | |||||
"07a0c9435e9cb412121b7ba010657ccc3152118602b665072136317d92fd4262", | |||||
"21fdff552e08c86c07f080cefacaaaf31846eb893bfe2e4f88c3c3cd8cbf592a" | |||||
"84500942695a5e5ae971ab343ce2695dd1baeb1f94dd4b53d678e14265e421ae", | |||||
"ca8f1a5b2172f6adb474da53b35e3f73ffd88263d3eecde72e48b16e1a065801" | |||||
"5b555ee319005a1d82802e91431ee777610f9b1028d819921e1044ad426b0270", | |||||
"ce5ab25eff9c1ddc569a1eaaa66b689109ee269db7066e0b02d39b3564fd14ca" | |||||
"6249987b7791e203d3d7c2ebf18558d2f23f94c03dd1d03aa63849e4d2889a76", | |||||
"a6f8b0561000dd4ae8b828c5f676e8c1a6474c4a042a645f1815bd52e9ff53c9" | |||||
"7dc36d5d8997f8ce332185feead76267f5b2e63f597fb3345ca0046e58fc0f24", | |||||
"fec86794bad4106c5ad1c1a2d9a1b7aae480396ec231eb5cac21c4077d17a0b6" | |||||
"52da0037363399a5a1dababa4a40e4c54b9124167580dee9108c4dbb24c57512", | |||||
"594f5dd3f4c87bdc0d81309386e9163a9718e34c7b0dcb4613f8487aa786f9d2" | |||||
"11cfb61bb247fa9f5ecef042e710f192850f5571807294bfd8a54397850e5773", | |||||
"d81ad866f25ef6a0a6431d267114da564513e5ebdcf48db7e95db8cf32a89f0a" | |||||
"b107874d796035db97420ffcf1db5f04dc1a52ddbbb960fc63b7f3f835cc8be6", | |||||
"431d537e098e9949f6a68108d55d20952e3bfcdeb7273bac3917e37790a84fa5" | |||||
"db04c33a79c113a06cf333e831d7702a00853a93fd0aa5146d934f4f71242a6a", | |||||
"4ed95636c6885ae4e63d042e82f4da830c702dbf3b9746d64770a64dd666b332" | |||||
"08315f3a947c4dff790771ef283788a9c74da83e22b97f750286a820ee46698c", | |||||
"a9bcb60b4d7724cdddddbc232b4ac70b94d0d7e9f0724b1222d918930cbb9bdb" | |||||
"b04b3ad43e3c8caf3bf8b004ee4aec6bd527ff8eb6189b44827f7ba7057f6a90", | |||||
"d6d5e44d5bb07fc4144ab6ab309f048968f73f7992beb326047e9e2cd7af6240" | |||||
"bc8abf46703c32fdb58fb2a8672594a660ef855be74f24cec09d4fb00219de82", | |||||
"dfda9ac0c7147530da97715ccf47814182255f2f2cf40287db97a4c63b43fcd3" | |||||
"9e6d41e560921492badb253a7dea0aba863c7c33b912bb59d1ff4de03a4f03bb", | |||||
"0395faaaf2e907f27779d6f1cc9c9db68ec390a38fbb0702c6475b46f7a39949" | |||||
"8d46fd8014f834b131e1e83abba0359b1f16d8fc0a393580615def2ad0caba73", | |||||
"41cb98f09029abe85d24a0f131f116c7f69f54f7e91c250642606512bf3da4ca" | |||||
"89ba70a4714a5f66d9ae81ff09317dadaff12a02057074c970f0f02a52bfafd2", | |||||
"8e8f161d48e306c5533ed614b8ef3a1979df6db7e13d0780a73c4a3980ddf0a9" | |||||
"5f93941d412c93683e39915a660c3fbec0dbb1bb6beea2e2099cd968011535c0", | |||||
"789593f0b8fb83ef9b3ec50ab8f6e1e47344f763d4f7ceab5600989e7b6fd5fe" | |||||
"f6ee5e487975f64474af6cd71ae4d9ecce8f009edea0227c7ebe73080b8f961b", | |||||
"f37e1449e0b313d9537a6177f7a31158d353e5b79c781facf02526ec94e0c6cf" | |||||
"da37105bac67098b194ea82efb307c2929a9ab8aca0e76c53e829e3f901cd245", | |||||
"2e74e745caaf2d449ab3b031dd214b48616853a512cf2e95c40cb8e7594fe5e4" | |||||
"879ac8a26d02eb35b3b96a5c9e7dcae3e15fd050a0bcc1fb3b9cb9c4df0fad3e", | |||||
"6eac7069c26082e52574ca6a58abb9b1b9faf452e8cca9f1c7023679ce192ca5" | |||||
"54892f30e38104d39088a24df35612444a0fc90084af7535fd9344fa51dded84", | |||||
"ada6caf30c4f6e3644d952366e01519af6771b406e2c447552f0c597b8dd10e9" | |||||
"e9b4e699c9a835de03f422be8980538d9786172dfd2fe511db272a1543d5aa35", | |||||
"4d4b0086b2cb05d713f2805caa7e6605c8f7dbbb2e0f92aa159aebdcd6306030" | |||||
"5f47b748f1bca6e0b6e11cf8f9697fcccb6584b878c4b54a699290728a40aa1b", | |||||
"97420b8a0ad102aeb92139da2c052d2748dd7d2dbb93a9ea79dc15b520d0ca7c" | |||||
"ab8cb7a00f5b5aebcb49d7e7f52a27180935ce617aeecdecba04064c668edd37", | |||||
"4aa7dad74eb51d09a6ae7735c4b795b078f51c314f14f42a0d63071e13bdc5fd" | |||||
"9f51612e77b36d44567502a3b5eb66c609ec017e51d8df93e58d1a44f3c1e375" | |||||
}; | |||||
return sha512_monte_carlo_core(seed, checks); | |||||
} |