-rw-r--r-- 31134 lib25519-20220426/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; }