#!/bin/sh -e supercop=supercop-20240107 mkdir -p kpqc-supercop-build cd kpqc-supercop-build # ===== download supercop (if not already downloaded) [ -f done-"$supercop".tar.bz2 ] || ( echo "downloading $supercop..." curl -s -o "$supercop".tar.bz2 https://bench.cr.yp.to/supercop/"$supercop".tar.bz2 bunzip2 < "$supercop".tar.bz2 | tar -xf - "$supercop" mv "$supercop".tar.bz2 done-"$supercop".tar.bz2 ) # ===== download kpqc submissions (if not already downloaded) ( for x in AIMer HAETAE MQ-Sign NCC-Sign NTRU+ Paloma REDOG SMAUG-T do [ -f done-"$x".zip ] || ( echo "downloading $x..." if [ "$x" = Paloma ] || [ "$x" = REDOG ] then curl -s -o partial-"$x".zip https://kpqc.or.kr/images/zip/"$x"_Implementation_package.zip else curl -s -o partial-"$x".zip https://kpqc.or.kr/images/zip/"$x"_Implementation_package_v2.zip fi rm -rf "$x" mv partial-"$x".zip "$x".zip mkdir -p "$x" ( cd "$x" unzip -q ../"$x".zip ) mv "$x".zip done-"$x".zip ) done ) # ===== AIMer integration ( sourcetop='AIMer/240402_AIMer' for p in 128f 128s 192f 192s 256f 256s do targettop="$supercop/crypto_sign/aimer$p" # rm -rf "$targettop" mkdir -p "$targettop" ( echo ref "$sourcetop"/Reference_Implementation echo opt "$sourcetop"/Optimized_Implementation echo aarch64 "$sourcetop"/Additional_Implementation/aarch64 echo avx2 "$sourcetop"/Additional_Implementation/avx2 ) | while read target source do x="$targettop/$target" [ -d "$x" ] && continue mkdir -p "$x" echo "integrating $x..." cp -pr "$source"/aimer$p/* "$x" cp -pr "$source"/aimer$p/shake/* "$x" echo '#include "randombytes.h"' > "$x/rng.h" rm "$x/rng.c" rm "$x/PQCgenKAT_sign.c" [ "$target" = "aarch64" ] && echo aarch64 > "$x/architectures" [ "$target" = "avx2" ] && echo amd64 > "$x/architectures" sed -i '1a#include "crypto_sign.h"' "$x/api.c" sed -i '1a#define CRYPTO_BYTES crypto_sign_BYTES' "$x/api.c" sed -i 's_shake/KeccakHash.h_KeccakHash.h_' "$x/hash.h" touch "$x/goal-constbranch" touch "$x/goal-constindex" done done ) # ===== HAETAE integration # XXX: original HAETAE code has different API using size_t etc. ( sourcetop='HAETAE/HAETAE_Implementation_package/Implementation package/' for p in 2 3 5 do targettop="$supercop/crypto_sign/haetae$p" # rm -rf "$targettop" mkdir -p "$targettop" ( echo ref "$sourcetop"/reference_implementation echo opt "$sourcetop"/optimized_implementation ) | while read target source do x="$targettop/$target" [ -d "$x" ] && continue mkdir -p "$x" echo "integrating $x..." cp -pr "$source"/include/* "$x" cp -pr "$source"/src/* "$x" cp -pr "$source"/kat/api.h "$x" rm "$x/randombytes.c" rm "$x/randombytes.h" sed -i '2a#define HAETAE_MODE '$p "$x/config.h" sed -i '2a#include "crypto_sign.h"' "$x/sign.h" sed -i 's/#define crypto_sign_sign HAETAE_NAMESPACE(sign)/#define crypto_sign_sign crypto_sign/' "$x/sign.h" sed -i 's/#define crypto_sign_open HAETAE_NAMESPACE(open)//' "$x/sign.h" sed -i 's/#define crypto_sign_keypair HAETAE_NAMESPACE(keypair)//' "$x/sign.h" sed -i 's/uint8_t/unsigned char/g' "$x/sign.h" sed -i 's/uint8_t/unsigned char/g' "$x/sign.c" sed -i 's/uint8_t/unsigned char/g' "$x/api.h" sed -i 's/size_t/unsigned long long/g' "$x/sign.h" sed -i 's/size_t/unsigned long long/g' "$x/sign.c" sed -i 's/size_t/unsigned long long/g' "$x/api.h" sed -i 's/CRYPTO_BYTES/crypto_BYTES/g' "$x"/* sed -i 's/CRYPTO_SECRETKEYBYTES/crypto_SECRETKEYBYTES/g' "$x"/* sed -i 's/CRYPTO_PUBLICKEYBYTES/crypto_PUBLICKEYBYTES/g' "$x"/* sed -i '/#include "params.h"/ a#define CRYPTO_BYTES crypto_BYTES' "$x/api.h" sed -i '/#include "params.h"/ a#define CRYPTO_SECRETKEYBYTES crypto_SECRETKEYBYTES' "$x/api.h" sed -i '/#include "params.h"/ a#define CRYPTO_PUBLICKEYBYTES crypto_PUBLICKEYBYTES' "$x/api.h" touch "$x/goal-constbranch" touch "$x/goal-constindex" done done ) # ===== MQ-Sign integration # XXX: MQ-Sign's original crypto_sign_open() code doesn't allow sm overlapping m # XXX: MQ-Sign's original crypto_sign_keypair() and crypto_sign() require seeds as input # XXX: the original MQLR code does not work unless (pk,sk) is 0-initialized; the integration makes it work # XXX: the original and integrated code will produce incorrect results for message lengths beyond 32 bits ( sourcetop='MQ-Sign/MQ-Sign_Implementation package_v2' ( echo mqsignlr MQLR echo mqsignrr MQRR ) | while read mq MQ do ( echo 2567246 _MQS256_72_46 echo 25611272 _MQS256_112_72 echo 25614896 _MQS256_148_96 ) | while read p P do targettop="$supercop/crypto_sign/$mq$p" # rm -rf "$targettop" mkdir -p "$targettop" ( echo opt "$sourcetop"/"$MQ"/optimized_implementation/MQSALG echo ref "$sourcetop"/"$MQ"/reference_implementation/MQSALG ) | while read target source do x="$targettop/$target" [ -d "$x" ] && continue mkdir -p "$x" echo "integrating $x..." cp -pr "$source"/* "$x" sed -i 's/#define _MQS256_72_46/#define '$P/ "$x/mqs_config.h" sed -i 's/\/\/#define _MQS256_112_72//' "$x/mqs_config.h" sed -i 's/\/\/#define _MQS256_148_96//' "$x/mqs_config.h" sed -i 's/randombytes(/unused_randombytes(/' "$x/rng.c" sed -i 's/crypto_sign_keypair/seeded_sign_keypair/' "$x"/api.h sed -i 's/crypto_sign_keypair/seeded_sign_keypair/' "$x"/sign.c sed -i 's/crypto_sign(/seeded_sign(/' "$x"/api.h "$x"/sign.c sed -i 's/crypto_sign_open(/unused_sign_open(/' "$x"/sign.c # labels followed by declarations are rejected by some compilers sed -i 's/rej:/rej: ;/' "$x"/mqs*.c sed -i 's/rej_out:/rej_out: ;/' "$x"/mqs*.c [ "$MQ" = "MQLR" ] && sed -i '/generate_keypair_mqlr/ i memset(pk,0,_PUB_KEY_LEN);' "$x"/sign.c [ "$MQ" = "MQLR" ] && sed -i '/generate_keypair_mqlr/ i memset(sk,0,_SEC_KEY_LEN);' "$x"/sign.c ( verify=mqsc_verify [ "$target" = "opt" ] && verify=mqrr_verify [ "$MQ" = "MQLR" ] && verify=mqlr_verify echo '#include "crypto_sign.h"' echo '#include "randombytes.h"' echo '#include "api.h"' echo '#include "mqs.h"' echo '#include ' echo '' echo 'int crypto_sign_keypair(unsigned char *pk,unsigned char *sk) {' echo ' unsigned char sk_seed[LEN_SKSEED];' echo ' randombytes(sk_seed,sizeof sk_seed);' echo ' return seeded_sign_keypair(pk,sk,sk_seed);' echo '}' echo '' echo 'int crypto_sign(unsigned char *sm,unsigned long long *smlen,const unsigned char *m,unsigned long long mlen,const unsigned char *sk) {' echo ' unsigned char sign_seed[LEN_SKSEED];' echo ' unsigned char sign_salt[_SALT_SOURCE_LEN];' echo ' randombytes(sign_seed,sizeof sign_seed);' echo ' randombytes(sign_salt,sizeof sign_salt);' echo ' return seeded_sign(sm,smlen,m,mlen,sk,sign_seed,sign_salt);' echo '}' echo '' echo 'int crypto_sign_open(unsigned char *m,unsigned long long *mlen,const unsigned char *sm,unsigned long long smlen,const unsigned char *pk) {' echo ' if( _SIGNATURE_BYTE > smlen ) return -1;' echo ' mlen[0] = smlen-_SIGNATURE_BYTE;' echo ' if ('"$verify"'(sm, (uint32_t) mlen[0], sm + smlen - _SIGNATURE_BYTE, pk)) return -1;' echo ' memmove( m , sm , smlen-_SIGNATURE_BYTE );' echo ' return 0;' echo '}' ) > "$x"/wrapper.c touch "$x/goal-constbranch" touch "$x/goal-constindex" done done done ) # ===== NCC-Sign integration # XXX: secret-key sizes are different from documentation # XXX: integration is specifically for NIMS_TRI_NTT_MODE and NIMS_TRI_USE_AES # XXX: documentation shows other options; are those in the original software? # XXX: supercop checksums show variations, so code is reading something it shouldn't # XXX: original NCC-Sign code has different API using size_t etc. ( sourcetop='NCC-Sign/NCC-Sign_Implementation package_v2' for p in 1 3 5 do targettop="$supercop/crypto_sign/nccsign$p" # rm -rf "$targettop" mkdir -p "$targettop" ( echo ref "$sourcetop"/reference_implementation echo opt "$sourcetop"/optimized_implementation ) | while read target source do x="$targettop/$target" [ -d "$x" ] && continue mkdir -p "$x" echo "integrating $x..." cp -pr "$source"/* "$x" rm -rf "$x"/Keccak rm -r "$x"/test rm "$x/randombytes.c" rm "$x/randombytes.h" rm "$x/rng.c" rm "$x/rng.h" rm "$x/PQCgenKAT_sign.c" sed -i '2a#define NIMS_TRI_NTT_MODE '$p "$x/config.h" sed -i '2a#define NIMS_TRI_USE_AES' "$x/config.h" sed -i '2a#include "crypto_sign.h"' "$x/sign.h" sed -i 's/uint8_t/unsigned char/g' "$x/sign.h" sed -i 's/uint8_t/unsigned char/g' "$x/sign.c" sed -i 's/uint8_t/unsigned char/g' "$x/api.h" sed -i 's/size_t/unsigned long long/g' "$x/sign.h" sed -i 's/size_t/unsigned long long/g' "$x/sign.c" sed -i 's/size_t/unsigned long long/g' "$x/api.h" sed -i 's/CRYPTO_BYTES/crypto_BYTES/g' "$x"/* sed -i 's/CRYPTO_SECRETKEYBYTES/crypto_SECRETKEYBYTES/g' "$x"/* sed -i 's/CRYPTO_PUBLICKEYBYTES/crypto_PUBLICKEYBYTES/g' "$x"/* sed -i '/#include "params.h"/ a#define CRYPTO_BYTES crypto_BYTES' "$x/api.h" sed -i '/#include "params.h"/ a#define CRYPTO_SECRETKEYBYTES crypto_SECRETKEYBYTES' "$x/api.h" sed -i '/#include "params.h"/ a#define CRYPTO_PUBLICKEYBYTES crypto_PUBLICKEYBYTES' "$x/api.h" sed -i 's_Keccak/_libkeccak.a.headers/_' "$x/fips202.c" sed -i '/test.cpucycles.h/ d' "$x/sign.c" touch "$x/goal-constbranch" touch "$x/goal-constindex" done done ) # ===== NTRU+ integration # XXX: this integration is including only KEM, not PKE ( sourcetop='NTRU+/NTRU+_Implementation package_v2' for p in 576 768 864 1152 do targettop="$supercop/crypto_kem/ntruplus$p" # rm -rf "$targettop" mkdir -p "$targettop" ( echo ref "$sourcetop"/Reference_Implementation/crypto_kem/NTRU+KEM"$p" echo opt "$sourcetop"/Optimized_Implementation/crypto_kem/NTRU+KEM"$p" echo avx2 "$sourcetop"/Additional_Implementation/avx2/crypto_kem/NTRU+KEM"$p" ) | while read target source do x="$targettop/$target" [ -d "$x" ] && continue mkdir -p "$x" echo "integrating $x..." cp -pr "$source"/* "$x" [ "$target" = avx2 ] && cp -pr "$source"/asm/* "$x" rm -f "$x"/PQCgenKAT_kem.c rm -f "$x"/cpucycles.c rm -f "$x"/cpucycles.h rm -f "$x"/rng.c rm -f "$x"/rng.h rm -f "$x"/randombytes.c rm -f "$x"/randombytes.h rm -f "$x"/test.c sed -i '1a#include "crypto_kem.h"' "$x/kem.c" [ "$target" = "avx2" ] && echo amd64 > "$x/architectures" touch "$x/goal-constbranch" touch "$x/goal-constindex" done done ) # ===== Paloma integration # XXX: taking only w_openssl implementation # XXX: original code has uninitialized hash output buffers in utility.c; integration fixes this # XXX: original code fails on (many) invalid ciphertexts; integration removes the weight test # XXX: original code has different API for tables; integration handles this as a constructor ( sourcetop='Paloma/Implementation package' for p in 128 192 256 do targettop="$supercop/crypto_kem/paloma$p" # rm -rf "$targettop" ( echo ref "$sourcetop"/reference_implementation/2r_paloma_opt_w_openssl ) | while read target source do x="$targettop/$target" [ -d "$x" ] && continue mkdir -p "$x" echo "integrating $x..." cp -p "$source"/api.h "$x" cp -p "$source"/config.h "$x" cp -p "$source"/gf_tab_gen.h "$x" cp -p "$source"/utility/*.h "$x" cp -p "$source"/utility/*.c "$x" cp -p "$source"/utility/include/*.h "$x" sed -i '/#ifndef CONFIG/ a#define PALOMA_MODE '$p "$x"/config.h sed -i '/#ifndef CONFIG/ a#define WORD 64' "$x"/config.h sed -i 's,\.\./config.h,config.h,' "$x"/* sed -i 's,\.\./api.h,api.h,' "$x"/* sed -i 's,\.\./gf_tab_gen\.h,gf_tab_gen.h,' "$x"/* sed -i 's_include/__' "$x"/* sed -i 's_utility/__' "$x"/* sed -i 's_\./rng\.h_randombytes.h_' "$x"/* rm -r "$x"/rng.c rm -r "$x"/rng.h sed -i '/lsh_digest/a for (int i = 0;i < 32;++i) seed[i / WORD_BYTES] = 0;' "$x"/utility.c sed -i '1i#include "crypto_kem.h"' "$x/kem.c" sed -i '1i#include "config.h"' "$x"/*.c sed -i 's/crypto_kem_keypair/crypto_kem_keypair_usetables/g' "$x"/* sed -i 's/crypto_kem_dec/crypto_kem_dec_usetables/g' "$x"/* sed -i 's/!check_err_vec(e_hat)/0/' "$x"/decap.c echo ' static gf2m_tab gf2m_tables; __attribute__((constructor)) static void precompute(void) { gen_precomputation_tab(&gf2m_tables); } int crypto_kem_keypair(unsigned char *pk,unsigned char *sk) { return crypto_kem_keypair_usetables(pk,sk,&gf2m_tables); } int crypto_kem_dec(unsigned char *ss,const unsigned char *c,const unsigned char *sk) { return crypto_kem_dec_usetables(ss,c,sk,&gf2m_tables); } ' >> "$x"/kem.c touch "$x/goal-constbranch" touch "$x/goal-constindex" done done ) # ===== REDOG integration # XXX: original code seems to be in progress # XXX: this is a preliminary integration, not working ( sourcetop='REDOG/Implementation package_REDOG' for p in 1 2 3 do targettop="$supercop/crypto_kem/redog$p" # rm -rf "$targettop" ( echo ref "$sourcetop"/reference_implementation/REDOG_C ) | while read target source do x="$targettop/$target" [ -d "$x" ] && continue mkdir -p "$x" echo "integrating $x..." for s in "$source"/*.[ch] do t=`echo "$s" | sed 's_.*/__' | tr ' ' '_'` sed 's/\xef\xbb\xbf//' < "$s" | tr -d '\015' > "$x/$t" done cp "$source"/ref/api.h "$x"/api.h rm -r "$x"/2* cp "$x"/finiteFIeld.h "$x"/finiteField.h sed -i 's///' "$x"/rbc_lr.h touch "$x/goal-constbranch" touch "$x/goal-constindex" done done ) # ===== SMAUG-T integration # XXX: documented sk sizes are missing necessary pk copy in sk # XXX: is additional_implementation also usable? documentation mentions TiMER ( sourcetop='SMAUG-T/SMAUG-T_Implementation package_v2' for p in 1 3 5 do targettop="$supercop/crypto_kem/smaugt$p" # rm -rf "$targettop" ( echo ref "$sourcetop"/reference_implementation echo opt "$sourcetop"/optimized_implementation/kem ) | while read target source do x="$targettop/$target" [ -d "$x" ] && continue mkdir -p "$x" echo "integrating $x..." cp "$source"/src/*.c "$x" [ "$target" = opt ] && cp "$source"/src/keccak/* "$x" cp "$source"/include/*.h "$x" [ "$target" = opt ] && cp "$source"/include/keccak/* "$x" rm "$x"/randombytes.c rm "$x"/randombytes.h rm "$x"/rng.c rm "$x"/rng.h sed -i '/#define SMAUG_PARAMETERS_H/ a#define SMAUG_MODE '$p "$x"/parameters.h sed -i 's/CRYPTO_BYTES/crypto_BYTES/g' "$x"/* sed -i 's/crypto_kem_keypair/crypto_kem_keypair_partial/g' "$x"/* sed -i 's/int crypto_kem_keypair/void crypto_kem_keypair/g' "$x"/* sed -i 's_#include "\.\./_#include "_' "$x"/* sed -i 's/int cryptolab_smaug1_crypto_kem_keypair_partial/void cryptolab_smaug1_crypto_kem_keypair_partial/g' "$x"/* sed -i 's/int cryptolab_smaug3_crypto_kem_keypair_partial/void cryptolab_smaug3_crypto_kem_keypair_partial/g' "$x"/* sed -i 's/int cryptolab_smaug5_crypto_kem_keypair_partial/void cryptolab_smaug5_crypto_kem_keypair_partial/g' "$x"/* ( echo '#include "parameters.h"' echo '#define CRYPTO_BYTES crypto_BYTES' echo '#define CRYPTO_PUBLICKEYBYTES PUBLICKEY_BYTES' echo '#define CRYPTO_SECRETKEYBYTES (KEM_SECRETKEY_BYTES+PUBLICKEY_BYTES)' echo '#define CRYPTO_CIPHERTEXTBYTES CIPHERTEXT_BYTES' ) >> "$x"/api.h ( echo '#include #include "kem.h" #include "crypto_kem.h" int crypto_kem_keypair( unsigned char *pk, unsigned char *sk ) { crypto_kem_keypair_partial(pk,sk); memcpy(sk+KEM_SECRETKEY_BYTES,pk,PUBLICKEY_BYTES); return 0; } int crypto_kem_enc( unsigned char *c, unsigned char *k, const unsigned char *pk ) { return crypto_kem_encap(c,k,pk); } int crypto_kem_dec( unsigned char *k, const unsigned char *c, const unsigned char *sk ) { return crypto_kem_decap(k,sk,sk+KEM_SECRETKEY_BYTES,c); } ' ) >> "$x"/wrapper.c touch "$x/goal-constbranch" touch "$x/goal-constindex" done done ) # ===== running supercop ( [ -d "$supercop"/bench ] || ( cd "$supercop" chmod +t crypto_*/*/cryptopp chmod +t crypto_*/*/rust* ./do-part init || : ./do-part keccak || : ./do-part crypto_hashblocks sha256 || : ./do-part crypto_hashblocks sha512 || : ./do-part crypto_hash sha256 || : ./do-part crypto_hash sha384 || : ./do-part crypto_hash sha512 || : ./do-part crypto_hash sha3512 || : ./do-part crypto_stream chacha20 || : ./do-part crypto_rng chacha20 || : ) ( echo crypto_sign aimer128f echo crypto_sign aimer128s echo crypto_sign aimer192f echo crypto_sign aimer192s echo crypto_sign aimer256f echo crypto_sign aimer256s echo crypto_sign haetae2 echo crypto_sign haetae3 echo crypto_sign haetae5 echo crypto_sign mqsignlr2567246 echo crypto_sign mqsignlr25611272 echo crypto_sign mqsignlr25614896 echo crypto_sign mqsignrr2567246 echo crypto_sign mqsignrr25611272 echo crypto_sign mqsignrr25614896 echo crypto_sign nccsign1 echo crypto_sign nccsign3 echo crypto_sign nccsign5 echo crypto_kem ntruplus576 echo crypto_kem ntruplus768 echo crypto_kem ntruplus864 echo crypto_kem ntruplus1152 echo crypto_kem paloma128 echo crypto_kem paloma192 echo crypto_kem paloma256 echo crypto_kem redog1 echo crypto_kem redog2 echo crypto_kem redog3 echo crypto_kem smaugt1 echo crypto_kem smaugt3 echo crypto_kem smaugt5 ) | while read o p do [ -f bench-"$p" ] || ( cd "$supercop" ./do-part "$o" "$p" || : cp bench/*/data ../bench-"$p" ) [ -f timecop-"$p" ] || ( cd "$supercop" env TIMECOP=1 ./do-part "$o" "$p" || : cp bench/*/data ../timecop-"$p" ) python3 -c ' import sys o = sys.argv[1] p = sys.argv[2] pkbytes = None skbytes = None outputbytes = None ctbytes = None sigbytes = [] keypair_cycles = [] cycles = [] open_cycles = [] enc_cycles = [] dec_cycles = [] checksums = [] tries = [] for line in sys.stdin: line = line.split() if len(line) < 8: continue if line[6] == "publickeybytes": pkbytes = line[7] if line[6] == "secretkeybytes": skbytes = line[7] if line[6] == "outputbytes": outputbytes = line[7] if line[6] == "ciphertextbytes": ctbytes = line[7] if line[6] == "bytes": sigbytes += [int(x)-int(line[7]) for x in line[9:]] if line[6] == "keypair_cycles": keypair_cycles += [int(x) for x in line[9:]] if line[6] == "cycles": cycles += [int(x) for x in line[9:]] if line[6] == "open_cycles": open_cycles += [int(x) for x in line[9:]] if line[6] == "enc_cycles": enc_cycles += [int(x) for x in line[9:]] if line[6] == "dec_cycles": dec_cycles += [int(x) for x in line[9:]] if line[6] == "try": checksums += [line[7]] tries += [(int(line[9]),line[12],line[13])] def statistics(x): x = sorted(x) if x == []: return None if x[0] == x[-1]: return x[0] median = x[len(x)//2] # XXX: handle even cases q1 = x[len(x)//4] # XXX: handle other cases q3 = x[(3*len(x))//4] # XXX: handle other cases return f"{q1}...{median}...{q3}" if o == "crypto_kem": print(p,"bytes","pk",pkbytes,"sk",skbytes,"ct",ctbytes,"shared",outputbytes) else: print(p,"bytes","pk",pkbytes,"sk",skbytes,"sigbuf",outputbytes,"sig",statistics(sigbytes)) print(p,"keypair",statistics(keypair_cycles)) if o == "crypto_kem": print(p,"enc",statistics(enc_cycles)) print(p,"dec",statistics(dec_cycles)) else: print(p,"sign",statistics(cycles)) print(p,"open",statistics(open_cycles)) print(p,"checksums",statistics(checksums)) for c,opi,compiler in sorted(tries): print(p,"try",c,opi,compiler) ' "$o" "$p" < bench-"$p" > report-"$p" done )