-rw-r--r-- 31134 lib25519-20220726/command/lib25519-test.c raw
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <assert.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/resource.h>
#include "crypto_uint8.h"
#include "crypto_uint32.h"
#include "crypto_uint64.h"
#include "lib25519.h" /* -l25519 */
#include "randombytes.h"
static const char *targeto = 0;
static const char *targeti = 0;
static int ok = 1;
#define fail ((ok = 0),printf)
/* ----- kernelrandombytes */
static int kernelrandombytes_fd = -1;
static void kernelrandombytes_setup(void)
{
kernelrandombytes_fd = open("/dev/urandom",O_RDONLY);
if (kernelrandombytes_fd == -1) {
fprintf(stderr,"lib25519-test: fatal: unable to open /dev/urandom: %s",strerror(errno));
exit(111);
}
}
static void kernelrandombytes(unsigned char *x,long long xlen)
{
int i;
while (xlen > 0) {
if (xlen < 1048576) i = xlen; else i = 1048576;
i = read(kernelrandombytes_fd,x,i);
if (i < 1) {
sleep(1);
continue;
}
x += i;
xlen -= i;
}
}
/* ----- rng and hash, from supercop/try-anything.c */
typedef crypto_uint8 u8;
typedef crypto_uint32 u32;
typedef crypto_uint64 u64;
#define FOR(i,n) for (i = 0;i < n;++i)
static u32 L32(u32 x,int c) { return (x << c) | ((x&0xffffffff) >> (32 - c)); }
static u32 ld32(const u8 *x)
{
u32 u = x[3];
u = (u<<8)|x[2];
u = (u<<8)|x[1];
return (u<<8)|x[0];
}
static void st32(u8 *x,u32 u)
{
int i;
FOR(i,4) { x[i] = u; u >>= 8; }
}
static const u8 sigma[17] = "expand 32-byte k";
static void core_salsa(u8 *out,const u8 *in,const u8 *k)
{
u32 w[16],x[16],y[16],t[4];
int i,j,m;
FOR(i,4) {
x[5*i] = ld32(sigma+4*i);
x[1+i] = ld32(k+4*i);
x[6+i] = ld32(in+4*i);
x[11+i] = ld32(k+16+4*i);
}
FOR(i,16) y[i] = x[i];
FOR(i,20) {
FOR(j,4) {
FOR(m,4) t[m] = x[(5*j+4*m)%16];
t[1] ^= L32(t[0]+t[3], 7);
t[2] ^= L32(t[1]+t[0], 9);
t[3] ^= L32(t[2]+t[1],13);
t[0] ^= L32(t[3]+t[2],18);
FOR(m,4) w[4*j+(j+m)%4] = t[m];
}
FOR(m,16) x[m] = w[m];
}
FOR(i,16) st32(out + 4 * i,x[i] + y[i]);
}
static void salsa20(u8 *c,u64 b,const u8 *n,const u8 *k)
{
u8 z[16],x[64];
u32 u,i;
if (!b) return;
FOR(i,16) z[i] = 0;
FOR(i,8) z[i] = n[i];
while (b >= 64) {
core_salsa(x,z,k);
FOR(i,64) c[i] = x[i];
u = 1;
for (i = 8;i < 16;++i) {
u += (u32) z[i];
z[i] = u;
u >>= 8;
}
b -= 64;
c += 64;
}
if (b) {
core_salsa(x,z,k);
FOR(i,b) c[i] = x[i];
}
}
static void increment(u8 *n)
{
if (!++n[0])
if (!++n[1])
if (!++n[2])
if (!++n[3])
if (!++n[4])
if (!++n[5])
if (!++n[6])
if (!++n[7])
;
}
static unsigned char testvector_n[8];
static void testvector_clear(void)
{
memset(testvector_n,0,sizeof testvector_n);
}
static void testvector(unsigned char *x,unsigned long long xlen)
{
const static unsigned char testvector_k[33] = "generate inputs for test vectors";
salsa20(x,xlen,testvector_n,testvector_k);
increment(testvector_n);
}
static unsigned long long myrandom(void)
{
unsigned char x[8];
unsigned long long result;
testvector(x,8);
result = x[7];
result = (result<<8)|x[6];
result = (result<<8)|x[5];
result = (result<<8)|x[4];
result = (result<<8)|x[3];
result = (result<<8)|x[2];
result = (result<<8)|x[1];
result = (result<<8)|x[0];
return result;
}
static unsigned char canary_n[8];
static void canary(unsigned char *x,unsigned long long xlen)
{
const static unsigned char canary_k[33] = "generate pad to catch overwrites";
salsa20(x,xlen,canary_n,canary_k);
increment(canary_n);
}
static void double_canary(unsigned char *x2,unsigned char *x,unsigned long long xlen)
{
canary(x - 16,16);
canary(x + xlen,16);
memcpy(x2 - 16,x - 16,16);
memcpy(x2 + xlen,x + xlen,16);
}
static void input_prepare(unsigned char *x2,unsigned char *x,unsigned long long xlen)
{
testvector(x,xlen);
canary(x - 16,16);
canary(x + xlen,16);
memcpy(x2 - 16,x - 16,xlen + 32);
}
static void input_compare(const unsigned char *x2,const unsigned char *x,unsigned long long xlen,const char *fun)
{
if (memcmp(x2 - 16,x - 16,xlen + 32)) {
fail("failure: %s overwrites input\n",fun);
}
}
static void output_prepare(unsigned char *x2,unsigned char *x,unsigned long long xlen)
{
canary(x - 16,xlen + 32);
memcpy(x2 - 16,x - 16,xlen + 32);
}
static void output_compare(const unsigned char *x2,const unsigned char *x,unsigned long long xlen,const char *fun)
{
if (memcmp(x2 - 16,x - 16,16)) {
fail("failure: %s writes before output\n",fun);
}
if (memcmp(x2 + xlen,x + xlen,16)) {
fail("failure: %s writes after output\n",fun);
}
}
/* ----- knownrandombytes */
static const int knownrandombytes_is_only_for_testing_not_for_cryptographic_use = 1;
#define knownrandombytes randombytes
#define QUARTERROUND(a,b,c,d) \
a += b; d = L32(d^a,16); \
c += d; b = L32(b^c,12); \
a += b; d = L32(d^a, 8); \
c += d; b = L32(b^c, 7);
static void core_chacha(u8 *out,const u8 *in,const u8 *k)
{
u32 x[16],y[16];
int i,j;
FOR(i,4) {
x[i] = ld32(sigma+4*i);
x[12+i] = ld32(in+4*i);
}
FOR(i,8) x[4+i] = ld32(k+4*i);
FOR(i,16) y[i] = x[i];
FOR(i,10) {
FOR(j,4) { QUARTERROUND(x[j],x[j+4],x[j+8],x[j+12]) }
FOR(j,4) { QUARTERROUND(x[j],x[((j+1)&3)+4],x[((j+2)&3)+8],x[((j+3)&3)+12]) }
}
FOR(i,16) st32(out+4*i,x[i]+y[i]);
}
static void chacha20(u8 *c,u64 b,const u8 *n,const u8 *k)
{
u8 z[16],x[64];
u32 u,i;
if (!b) return;
FOR(i,16) z[i] = 0;
FOR(i,8) z[i+8] = n[i];
while (b >= 64) {
core_chacha(x,z,k);
FOR(i,64) c[i] = x[i];
u = 1;
FOR(i,8) {
u += (u32) z[i];
z[i] = u;
u >>= 8;
}
b -= 64;
c += 64;
}
if (b) {
core_chacha(x,z,k);
FOR(i,b) c[i] = x[i];
}
}
#define crypto_rng_OUTPUTBYTES 736
static int crypto_rng(
unsigned char *r, /* random output */
unsigned char *n, /* new key */
const unsigned char *g /* old key */
)
{
static const unsigned char nonce[8] = {0};
unsigned char x[32+crypto_rng_OUTPUTBYTES];
chacha20(x,sizeof x,nonce,g);
memcpy(n,x,32);
memcpy(r,x+32,crypto_rng_OUTPUTBYTES);
return 0;
}
static unsigned char knownrandombytes_g[32];
static unsigned char knownrandombytes_r[crypto_rng_OUTPUTBYTES];
static unsigned long long knownrandombytes_pos = crypto_rng_OUTPUTBYTES;
static void knownrandombytes_clear(void)
{
memset(knownrandombytes_g,0,sizeof knownrandombytes_g);
memset(knownrandombytes_r,0,sizeof knownrandombytes_r);
knownrandombytes_pos = crypto_rng_OUTPUTBYTES;
}
void knownrandombytes(unsigned char *x,long long xlen)
{
assert(knownrandombytes_is_only_for_testing_not_for_cryptographic_use);
while (xlen > 0) {
if (knownrandombytes_pos == crypto_rng_OUTPUTBYTES) {
crypto_rng(knownrandombytes_r,knownrandombytes_g,knownrandombytes_g);
knownrandombytes_pos = 0;
}
*x++ = knownrandombytes_r[knownrandombytes_pos]; xlen -= 1;
knownrandombytes_r[knownrandombytes_pos++] = 0;
}
}
/* ----- checksums */
static unsigned char checksum_state[64];
static char checksum_hex[65];
static void checksum_expected(const char *expected)
{
long long i;
for (i = 0;i < 32;++i) {
checksum_hex[2 * i] = "0123456789abcdef"[15 & (checksum_state[i] >> 4)];
checksum_hex[2 * i + 1] = "0123456789abcdef"[15 & checksum_state[i]];
}
checksum_hex[2 * i] = 0;
if (strcmp(checksum_hex,expected))
fail("failure: checksum mismatch: %s expected %s\n",checksum_hex,expected);
}
static void checksum_clear(void)
{
memset(checksum_state,0,sizeof checksum_state);
knownrandombytes_clear();
testvector_clear();
// not necessary to clear canary
}
static void checksum(const unsigned char *x,unsigned long long xlen)
{
u8 block[16];
int i;
while (xlen >= 16) {
core_salsa(checksum_state,x,checksum_state);
x += 16;
xlen -= 16;
}
FOR(i,16) block[i] = 0;
FOR(i,xlen) block[i] = x[i];
block[xlen] = 1;
checksum_state[0] ^= 1;
core_salsa(checksum_state,block,checksum_state);
}
#include "limits.inc"
static unsigned char *alignedcalloc(unsigned long long len)
{
unsigned char *x = (unsigned char *) calloc(1,len + 256);
long long i;
if (!x) abort();
/* will never deallocate so shifting is ok */
for (i = 0;i < len + 256;++i) x[i] = random();
x += 64;
x += 63 & (-(unsigned long) x);
for (i = 0;i < len;++i) x[i] = 0;
return x;
}
/* ----- catching SIGILL, SIGBUS, SIGSEGV, etc. */
static void forked(void (*test)(long long),long long impl)
{
fflush(stdout);
pid_t child = fork();
int childstatus = -1;
if (child == -1) {
fprintf(stderr,"fatal: fork failed: %s",strerror(errno));
exit(111);
}
if (child == 0) {
ok = 1;
limits();
test(impl);
if (!ok) exit(100);
exit(0);
}
if (waitpid(child,&childstatus,0) != child) {
fprintf(stderr,"fatal: wait failed: %s",strerror(errno));
exit(111);
}
if (childstatus)
fail("failure: process failed, status %d\n",childstatus);
fflush(stdout);
}
/* ----- verify, derived from supercop/crypto_verify/try.c */
static int (*crypto_verify)(const unsigned char *,const unsigned char *);
#define crypto_verify_BYTES lib25519_verify_BYTES
static unsigned char *test_verify_x;
static unsigned char *test_verify_y;
static void test_verify_check(void)
{
unsigned char *x = test_verify_x;
unsigned char *y = test_verify_y;
int r = crypto_verify(x,y);
if (r == 0) {
if (memcmp(x,y,crypto_verify_BYTES))
fail("failure: different strings pass verify\n");
} else if (r == -1) {
if (!memcmp(x,y,crypto_verify_BYTES))
fail("failure: equal strings fail verify\n");
} else {
fail("failure: weird return value\n");
}
}
void test_verify_impl(long long impl)
{
unsigned char *x = test_verify_x;
unsigned char *y = test_verify_y;
if (targeti && strcmp(targeti,lib25519_dispatch_verify_implementation(impl))) return;
if (impl >= 0) {
crypto_verify = lib25519_dispatch_verify(impl);
printf("verify %lld implementation %s compiler %s\n",impl,lib25519_dispatch_verify_implementation(impl),lib25519_dispatch_verify_compiler(impl));
} else {
crypto_verify = lib25519_verify;
printf("verify default implementation %s compiler %s\n",lib25519_verify_implementation(),lib25519_verify_compiler());
}
kernelrandombytes(x,crypto_verify_BYTES);
kernelrandombytes(y,crypto_verify_BYTES);
test_verify_check();
memcpy(y,x,crypto_verify_BYTES);
test_verify_check();
y[myrandom() % crypto_verify_BYTES] = myrandom();
test_verify_check();
y[myrandom() % crypto_verify_BYTES] = myrandom();
test_verify_check();
y[myrandom() % crypto_verify_BYTES] = myrandom();
test_verify_check();
}
static void test_verify(void)
{
if (targeto && strcmp(targeto,"verify")) return;
test_verify_x = alignedcalloc(crypto_verify_BYTES);
test_verify_y = alignedcalloc(crypto_verify_BYTES);
for (long long offset = 0;offset < 2;++offset) {
printf("verify offset %lld\n",offset);
for (long long impl = -1;impl < lib25519_numimpl_verify();++impl)
forked(test_verify_impl,impl);
++test_verify_x;
++test_verify_y;
}
}
/* ----- hashblocks, derived from supercop/crypto_hashblocks/try.c */
static const char *hashblocks_checksums[] = {
"f0bc623a9033f9f648336540e11e85be21aeb60905c7d8808d10ea20b39d58d1",
"f1a2c46c9ce7fa4cd22f180907d77b6f7189badef4b9a1b5284d6fb9db859b76",
} ;
static int (*crypto_hashblocks)(unsigned char *,const unsigned char *,long long);
#define crypto_hashblocks_STATEBYTES lib25519_hashblocks_STATEBYTES
#define crypto_hashblocks_BLOCKBYTES lib25519_hashblocks_BLOCKBYTES
static unsigned char *test_hashblocks_h;
static unsigned char *test_hashblocks_m;
static unsigned char *test_hashblocks_h2;
static unsigned char *test_hashblocks_m2;
static void test_hashblocks_impl(long long impl)
{
unsigned char *h = test_hashblocks_h;
unsigned char *m = test_hashblocks_m;
unsigned char *h2 = test_hashblocks_h2;
unsigned char *m2 = test_hashblocks_m2;
long long hlen = crypto_hashblocks_STATEBYTES;
if (targeti && strcmp(targeti,lib25519_dispatch_hashblocks_implementation(impl))) return;
if (impl >= 0) {
crypto_hashblocks = lib25519_dispatch_hashblocks(impl);
printf("hashblocks %lld implementation %s compiler %s\n",impl,lib25519_dispatch_hashblocks_implementation(impl),lib25519_dispatch_hashblocks_compiler(impl));
} else {
crypto_hashblocks = lib25519_hashblocks;
printf("hashblocks default implementation %s compiler %s\n",lib25519_hashblocks_implementation(),lib25519_hashblocks_compiler());
}
for (long long checksumbig = 0;checksumbig < 2;++checksumbig) {
long long loops = checksumbig ? 32768 : 4096;
long long maxtest = checksumbig ? 4096 : 128;
checksum_clear();
for (long long loop = 0;loop < loops;++loop) {
long long mlen = myrandom() % (maxtest + 1);
int result;
input_prepare(m2,m,mlen);
input_prepare(h2,h,hlen);
result = crypto_hashblocks(h,m,mlen);
if (result != mlen % crypto_hashblocks_BLOCKBYTES)
fail("failure: crypto_hashblocks returns unexpected value\n");
checksum(h,hlen);
output_compare(h2,h,hlen,"crypto_hashblocks");
input_compare(m2,m,mlen,"crypto_hashblocks");
double_canary(h2,h,hlen);
double_canary(m2,m,mlen);
result = crypto_hashblocks(h2,m2,mlen);
if (result != mlen % crypto_hashblocks_BLOCKBYTES)
fail("failure: crypto_hashblocks returns unexpected value");
if (memcmp(h2,h,hlen) != 0)
fail("failure: crypto_hashblocks is nondeterministic");
}
checksum_expected(hashblocks_checksums[checksumbig]);
}
}
static void test_hashblocks(void)
{
if (targeto && strcmp(targeto,"hashblocks")) return;
test_hashblocks_h = alignedcalloc(crypto_hashblocks_STATEBYTES);
test_hashblocks_m = alignedcalloc(4096);
test_hashblocks_h2 = alignedcalloc(crypto_hashblocks_STATEBYTES);
test_hashblocks_m2 = alignedcalloc(4096);
for (long long offset = 0;offset < 2;++offset) {
printf("hashblocks offset %lld\n",offset);
for (long long impl = -1;impl < lib25519_numimpl_hashblocks();++impl)
forked(test_hashblocks_impl,impl);
++test_hashblocks_h;
++test_hashblocks_m;
++test_hashblocks_h2;
++test_hashblocks_m2;
}
}
/* ----- hash, derived from supercop/crypto_hash/try.c */
static const char *hash_checksums[] = {
"8220572f58bd4730be165c9739d8d4b0fd2e0229dbe01e25b4aed23f00f23b70",
"c1e322b7cbfc941260c5508967ba05bce22eeee94d425e708b7c3301ea1d5e2e",
} ;
static void (*crypto_hash)(unsigned char *,const unsigned char *,long long);
#define crypto_hash_BYTES lib25519_hash_BYTES
static unsigned char *test_hash_h;
static unsigned char *test_hash_m;
static unsigned char *test_hash_h2;
static unsigned char *test_hash_m2;
static void test_hash_impl(long long impl)
{
unsigned char *h = test_hash_h;
unsigned char *m = test_hash_m;
unsigned char *h2 = test_hash_h2;
unsigned char *m2 = test_hash_m2;
long long hlen = crypto_hash_BYTES;
if (targeti && strcmp(targeti,lib25519_dispatch_hash_implementation(impl))) return;
if (impl >= 0) {
crypto_hash = lib25519_dispatch_hash(impl);
printf("hash %lld implementation %s compiler %s\n",impl,lib25519_dispatch_hash_implementation(impl),lib25519_dispatch_hash_compiler(impl));
} else {
crypto_hash = lib25519_hash;
printf("hash default implementation %s compiler %s\n",lib25519_hash_implementation(),lib25519_hash_compiler());
}
for (long long checksumbig = 0;checksumbig < 2;++checksumbig) {
long long loops = checksumbig ? 512 : 64;
long long maxtest = checksumbig ? 4096 : 128;
checksum_clear();
for (long long loop = 0;loop < loops;++loop) {
long long mlen = myrandom() % (maxtest + 1);
output_prepare(h2,h,hlen);
input_prepare(m2,m,mlen);
crypto_hash(h,m,mlen);
checksum(h,hlen);
output_compare(h2,h,hlen,"crypto_hash");
input_compare(m2,m,mlen,"crypto_hash");
double_canary(h2,h,hlen);
double_canary(m2,m,mlen);
crypto_hash(h2,m2,mlen);
if (memcmp(h2,h,hlen) != 0) fail("failure: crypto_hash is nondeterministic\n");
double_canary(h2,h,hlen);
double_canary(m2,m,mlen);
crypto_hash(m2,m2,mlen);
if (memcmp(m2,h,hlen) != 0) fail("failure: crypto_hash does not handle m=h overlap\n");
memcpy(m2,m,mlen);
}
checksum_expected(hash_checksums[checksumbig]);
}
}
static void test_hash(void)
{
if (targeto && strcmp(targeto,"hash")) return;
test_hash_h = alignedcalloc(crypto_hash_BYTES);
test_hash_m = alignedcalloc(4096);
test_hash_h2 = alignedcalloc(crypto_hash_BYTES);
test_hash_m2 = alignedcalloc(4096);
for (long long offset = 0;offset < 2;++offset) {
printf("hash offset %lld\n",offset);
for (long long impl = -1;impl < lib25519_numimpl_hash();++impl)
forked(test_hash_impl,impl);
++test_hash_h;
++test_hash_m;
++test_hash_h2;
++test_hash_m2;
}
}
/* ----- dh, derived from supercop/crypto_dh/try.c */
static const char *dh_checksums[] = {
"2c8a73ec86d5d4c4bc838f49cfd78c87b60b534ae6fff59ce3bea0c32cdc1450",
"b09016b3a1371786b46a183085133338159e623c5eb9cbc5eaa4f8b62d6c5aea",
} ;
void (*crypto_dh_keypair)(unsigned char *,unsigned char *);
void (*crypto_dh)(unsigned char *,const unsigned char *,const unsigned char *);
#define crypto_dh_PUBLICKEYBYTES lib25519_dh_PUBLICKEYBYTES
#define crypto_dh_SECRETKEYBYTES lib25519_dh_SECRETKEYBYTES
#define crypto_dh_BYTES lib25519_dh_BYTES
static unsigned char *test_dh_a;
static unsigned char *test_dh_b;
static unsigned char *test_dh_c;
static unsigned char *test_dh_d;
static unsigned char *test_dh_e;
static unsigned char *test_dh_f;
static unsigned char *test_dh_a2;
static unsigned char *test_dh_b2;
static unsigned char *test_dh_c2;
static unsigned char *test_dh_d2;
static unsigned char *test_dh_e2;
static unsigned char *test_dh_f2;
static void test_dh_impl(long long impl)
{
unsigned char *a = test_dh_a;
unsigned char *b = test_dh_b;
unsigned char *c = test_dh_c;
unsigned char *d = test_dh_d;
unsigned char *e = test_dh_e;
unsigned char *f = test_dh_f;
unsigned char *a2 = test_dh_a2;
unsigned char *b2 = test_dh_b2;
unsigned char *c2 = test_dh_c2;
unsigned char *d2 = test_dh_d2;
unsigned char *e2 = test_dh_e2;
unsigned char *f2 = test_dh_f2;
long long alen = crypto_dh_SECRETKEYBYTES;
long long blen = crypto_dh_SECRETKEYBYTES;
long long clen = crypto_dh_PUBLICKEYBYTES;
long long dlen = crypto_dh_PUBLICKEYBYTES;
long long elen = crypto_dh_BYTES;
long long flen = crypto_dh_BYTES;
if (targeti && strcmp(targeti,lib25519_dispatch_dh_implementation(impl))) return;
if (impl >= 0) {
crypto_dh_keypair = lib25519_dispatch_dh_keypair(impl);
crypto_dh = lib25519_dispatch_dh(impl);
printf("dh %lld implementation %s compiler %s\n",impl,lib25519_dispatch_dh_implementation(impl),lib25519_dispatch_dh_compiler(impl));
} else {
crypto_dh_keypair = lib25519_dh_keypair;
crypto_dh = lib25519_dh;
printf("dh default implementation %s compiler %s\n",lib25519_dh_implementation(),lib25519_dh_compiler());
}
for (long long checksumbig = 0;checksumbig < 2;++checksumbig) {
long long loops = checksumbig ? 512 : 64;
checksum_clear();
for (long long loop = 0;loop < loops;++loop) {
output_prepare(c2,c,clen);
output_prepare(a2,a,alen);
crypto_dh_keypair(c,a);
checksum(c,clen);
checksum(a,alen);
output_compare(c2,c,clen,"crypto_dh_keypair");
output_compare(a2,a,alen,"crypto_dh_keypair");
output_prepare(d2,d,dlen);
output_prepare(b2,b,blen);
crypto_dh_keypair(d,b);
checksum(d,dlen);
checksum(b,blen);
output_compare(d2,d,dlen,"crypto_dh_keypair");
output_compare(b2,b,blen,"crypto_dh_keypair");
output_prepare(e2,e,elen);
memcpy(d2,d,dlen);
double_canary(d2,d,dlen);
memcpy(a2,a,alen);
double_canary(a2,a,alen);
crypto_dh(e,d,a);
checksum(e,elen);
output_compare(e2,e,elen,"crypto_dh");
input_compare(d2,d,dlen,"crypto_dh");
input_compare(a2,a,alen,"crypto_dh");
double_canary(e2,e,elen);
double_canary(d2,d,dlen);
double_canary(a2,a,alen);
crypto_dh(e2,d2,a2);
if (memcmp(e2,e,elen) != 0) fail("failure: crypto_dh is nondeterministic\n");
double_canary(e2,e,elen);
double_canary(d2,d,dlen);
double_canary(a2,a,alen);
crypto_dh(d2,d2,a);
if (memcmp(d2,e,elen) != 0) fail("failure: crypto_dh does not handle d=e overlap\n");
memcpy(d2,d,dlen);
crypto_dh(a2,d,a2);
if (memcmp(a2,e,elen) != 0) fail("failure: crypto_dh does not handle a=e overlap\n");
memcpy(a2,a,alen);
output_prepare(f2,f,flen);
memcpy(c2,c,clen);
double_canary(c2,c,clen);
memcpy(b2,b,blen);
double_canary(b2,b,blen);
crypto_dh(f,c,b);
checksum(f,flen);
output_compare(f2,f,flen,"crypto_dh");
input_compare(c2,c,clen,"crypto_dh");
input_compare(b2,b,blen,"crypto_dh");
double_canary(f2,f,flen);
double_canary(c2,c,clen);
double_canary(b2,b,blen);
crypto_dh(f2,c2,b2);
if (memcmp(f2,f,flen) != 0) fail("failure: crypto_dh is nondeterministic\n");
double_canary(f2,f,flen);
double_canary(c2,c,clen);
double_canary(b2,b,blen);
crypto_dh(c2,c2,b);
if (memcmp(c2,f,flen) != 0) fail("failure: crypto_dh does not handle c=f overlap\n");
memcpy(c2,c,clen);
crypto_dh(b2,c,b2);
if (memcmp(b2,f,flen) != 0) fail("failure: crypto_dh does not handle b=f overlap\n");
memcpy(b2,b,blen);
if (memcmp(f,e,elen) != 0) fail("failure: crypto_dh not associative\n");
}
checksum_expected(dh_checksums[checksumbig]);
}
}
static void test_dh(void)
{
long long alloclen = crypto_dh_BYTES+crypto_dh_PUBLICKEYBYTES+crypto_dh_SECRETKEYBYTES;
test_dh_a = alignedcalloc(alloclen);
test_dh_b = alignedcalloc(alloclen);
test_dh_c = alignedcalloc(alloclen);
test_dh_d = alignedcalloc(alloclen);
test_dh_e = alignedcalloc(alloclen);
test_dh_f = alignedcalloc(alloclen);
test_dh_a2 = alignedcalloc(alloclen);
test_dh_b2 = alignedcalloc(alloclen);
test_dh_c2 = alignedcalloc(alloclen);
test_dh_d2 = alignedcalloc(alloclen);
test_dh_e2 = alignedcalloc(alloclen);
test_dh_f2 = alignedcalloc(alloclen);
if (targeto && strcmp(targeto,"dh")) return;
for (long long offset = 0;offset < 2;++offset) {
printf("dh offset %lld\n",offset);
for (long long impl = -1;impl < lib25519_numimpl_dh();++impl)
forked(test_dh_impl,impl);
++test_dh_a;
++test_dh_b;
++test_dh_c;
++test_dh_d;
++test_dh_e;
++test_dh_f;
++test_dh_a2;
++test_dh_b2;
++test_dh_c2;
++test_dh_d2;
++test_dh_e2;
++test_dh_f2;
}
}
/* ----- sign, derived from supercop/crypto_sign/try.c */
static const char *sign_checksums[] = {
"6d6cae511aa24af47411243ba5bc2a84f8e827dfe80aca92ec3769061471952a",
"6dacbe42d112348ae7abf32ff69ac95041f2e6cd9fe91eeab9ca10dedf318812",
} ;
void (*crypto_sign_keypair)(unsigned char *,unsigned char *);
void (*crypto_sign)(unsigned char *,long long *,const unsigned char *,long long,const unsigned char *);
int (*crypto_sign_open)(unsigned char *,long long *,const unsigned char *,long long,const unsigned char *);
#define crypto_sign_PUBLICKEYBYTES lib25519_sign_PUBLICKEYBYTES
#define crypto_sign_SECRETKEYBYTES lib25519_sign_SECRETKEYBYTES
#define crypto_sign_BYTES lib25519_sign_BYTES
static unsigned char *test_sign_p;
static unsigned char *test_sign_s;
static unsigned char *test_sign_m;
static unsigned char *test_sign_c;
static unsigned char *test_sign_t;
static unsigned char *test_sign_p2;
static unsigned char *test_sign_s2;
static unsigned char *test_sign_m2;
static unsigned char *test_sign_c2;
static unsigned char *test_sign_t2;
static void test_sign_impl(long long impl)
{
unsigned char *p = test_sign_p;
unsigned char *s = test_sign_s;
unsigned char *m = test_sign_m;
unsigned char *c = test_sign_c;
unsigned char *t = test_sign_t;
unsigned char *p2 = test_sign_p2;
unsigned char *s2 = test_sign_s2;
unsigned char *m2 = test_sign_m2;
unsigned char *c2 = test_sign_c2;
unsigned char *t2 = test_sign_t2;
long long clen;
long long tlen;
long long plen = crypto_sign_PUBLICKEYBYTES;
long long slen = crypto_sign_SECRETKEYBYTES;
if (targeti && strcmp(targeti,lib25519_dispatch_sign_implementation(impl))) return;
if (impl >= 0) {
crypto_sign_keypair = lib25519_dispatch_sign_keypair(impl);
crypto_sign = lib25519_dispatch_sign(impl);
crypto_sign_open = lib25519_dispatch_sign_open(impl);
printf("sign %lld implementation %s compiler %s\n",impl,lib25519_dispatch_sign_implementation(impl),lib25519_dispatch_sign_compiler(impl));
} else {
crypto_sign_keypair = lib25519_sign_keypair;
crypto_sign = lib25519_sign;
crypto_sign_open = lib25519_sign_open;
printf("sign default implementation %s compiler %s\n",lib25519_sign_implementation(),lib25519_sign_compiler());
}
for (long long checksumbig = 0;checksumbig < 2;++checksumbig) {
long long loops = checksumbig ? 64 : 8;
long long maxtest = checksumbig ? 4096 : 128;
checksum_clear();
for (long long loop = 0;loop < loops;++loop) {
long long mlen = myrandom() % (maxtest + 1);
int result;
output_prepare(p2,p,plen);
output_prepare(s2,s,slen);
crypto_sign_keypair(p,s);
checksum(p,plen);
checksum(s,slen);
output_compare(p2,p,plen,"crypto_sign_keypair");
output_compare(s2,s,slen,"crypto_sign_keypair");
clen = mlen + crypto_sign_BYTES;
output_prepare(c2,c,clen);
input_prepare(m2,m,mlen);
memcpy(s2,s,slen);
double_canary(s2,s,slen);
crypto_sign(c,&clen,m,mlen,s);
if (clen < mlen) fail("failure: crypto_sign returns smaller output than input\n");
if (clen > mlen + crypto_sign_BYTES) fail("failure: crypto_sign returns more than crypto_sign_BYTES extra bytes\n");
checksum(c,clen);
output_compare(c2,c,clen,"crypto_sign");
input_compare(m2,m,mlen,"crypto_sign");
input_compare(s2,s,slen,"crypto_sign");
double_canary(c2,c,clen);
double_canary(m2,m,mlen);
double_canary(s2,s,slen);
crypto_sign(c2,&clen,m2,mlen,s2);
if (memcmp(c2,c,clen) != 0) fail("failure: crypto_sign is nondeterministic\n");
double_canary(c2,c,clen);
double_canary(m2,m,mlen);
double_canary(s2,s,slen);
crypto_sign(m2,&clen,m2,mlen,s);
if (memcmp(m2,c,clen) != 0) fail("failure: crypto_sign does not handle m=c overlap\n");
memcpy(m2,m,mlen);
crypto_sign(s2,&clen,m,mlen,s2);
if (memcmp(s2,c,clen) != 0) fail("failure: crypto_sign does not handle s=c overlap\n");
memcpy(s2,s,slen);
tlen = clen;
output_prepare(t2,t,tlen);
memcpy(c2,c,clen);
double_canary(c2,c,clen);
memcpy(p2,p,plen);
double_canary(p2,p,plen);
result = crypto_sign_open(t,&tlen,c,clen,p);
if (result != 0) fail("failure: crypto_sign_open returns nonzero\n");
if (tlen != mlen) fail("failure: crypto_sign_open does not match mlen\n");
if (memcmp(t,m,mlen) != 0) fail("failure: crypto_sign_open does not match m\n");
checksum(t,tlen);
output_compare(t2,t,clen,"crypto_sign_open");
input_compare(c2,c,clen,"crypto_sign_open");
input_compare(p2,p,plen,"crypto_sign_open");
double_canary(t2,t,tlen);
double_canary(c2,c,clen);
double_canary(p2,p,plen);
result = crypto_sign_open(t2,&tlen,c2,clen,p2);
if (result != 0) fail("failure: crypto_sign_open returns nonzero\n");
if (memcmp(t2,t,tlen) != 0) fail("failure: crypto_sign_open is nondeterministic\n");
double_canary(t2,t,tlen);
double_canary(c2,c,clen);
double_canary(p2,p,plen);
result = crypto_sign_open(c2,&tlen,c2,clen,p);
if (result != 0) fail("failure: crypto_sign_open with c=t overlap returns nonzero\n");
if (memcmp(c2,t,tlen) != 0) fail("failure: crypto_sign_open does not handle c=t overlap\n");
memcpy(c2,c,clen);
result = crypto_sign_open(p2,&tlen,c,clen,p2);
if (result != 0) fail("failure: crypto_sign_open with p=t overlap returns nonzero\n");
if (memcmp(p2,t,tlen) != 0) fail("failure: crypto_sign_open does not handle p=t overlap\n");
memcpy(p2,p,plen);
c[myrandom() % clen] += 1 + (myrandom() % 255);
if (crypto_sign_open(t,&tlen,c,clen,p) == 0)
if ((tlen != mlen) || (memcmp(t,m,mlen) != 0))
fail("failure: crypto_sign_open allows trivial forgeries\n");
c[myrandom() % clen] += 1 + (myrandom() % 255);
if (crypto_sign_open(t,&tlen,c,clen,p) == 0)
if ((tlen != mlen) || (memcmp(t,m,mlen) != 0))
fail("failure: crypto_sign_open allows trivial forgeries\n");
c[myrandom() % clen] += 1 + (myrandom() % 255);
if (crypto_sign_open(t,&tlen,c,clen,p) == 0)
if ((tlen != mlen) || (memcmp(t,m,mlen) != 0))
fail("failure: crypto_sign_open allows trivial forgeries\n");
}
checksum_expected(sign_checksums[checksumbig]);
}
}
static void test_sign(void)
{
long long alloclen = 4096+crypto_sign_BYTES+crypto_sign_PUBLICKEYBYTES+crypto_sign_SECRETKEYBYTES;
test_sign_p = alignedcalloc(alloclen);
test_sign_s = alignedcalloc(alloclen);
test_sign_m = alignedcalloc(alloclen);
test_sign_c = alignedcalloc(alloclen);
test_sign_t = alignedcalloc(alloclen);
test_sign_p2 = alignedcalloc(alloclen);
test_sign_s2 = alignedcalloc(alloclen);
test_sign_m2 = alignedcalloc(alloclen);
test_sign_c2 = alignedcalloc(alloclen);
test_sign_t2 = alignedcalloc(alloclen);
if (targeto && strcmp(targeto,"sign")) return;
for (long long offset = 0;offset < 2;++offset) {
printf("sign offset %lld\n",offset);
for (long long impl = -1;impl < lib25519_numimpl_sign();++impl)
forked(test_sign_impl,impl);
++test_sign_p;
++test_sign_s;
++test_sign_m;
++test_sign_c;
++test_sign_t;
++test_sign_p2;
++test_sign_s2;
++test_sign_m2;
++test_sign_c2;
++test_sign_t2;
}
}
/* ----- top level */
#include "print_cpuid.inc"
int main(int argc,char **argv)
{
kernelrandombytes_setup();
printf("lib25519 version %s\n",lib25519_version);
printf("lib25519 arch %s\n",lib25519_arch);
print_cpuid();
if (*argv) ++argv;
if (*argv) {
targeto = *argv++;
if (*argv) {
targeti = *argv++;
}
}
test_verify();
test_hashblocks();
test_hash();
test_dh();
test_sign();
if (!ok) {
printf("some tests failed\n");
return 100;
}
printf("all tests succeeded\n");
return 0;
}