From 323d2f586acda2935bead592daeeb500686e39c7 Mon Sep 17 00:00:00 2001 From: Ray Neiheiser Date: Fri, 19 Jun 2020 15:45:09 +0100 Subject: [PATCH 01/11] Initial setup of BLS --- .gitignore | 2 + CMakeLists.txt | 11 +- bls/build/contrib/relic/include/relic_conf.h | 722 + bls/contrib/catch/catch.hpp | 13286 ++++++++++++++++ bls/contrib/relic/include/low/relic_bn_low.h | 306 + bls/contrib/relic/include/low/relic_dv_low.h | 82 + bls/contrib/relic/include/low/relic_fb_low.h | 290 + bls/contrib/relic/include/low/relic_fp_low.h | 346 + bls/contrib/relic/include/low/relic_fpx_low.h | 390 + bls/contrib/relic/include/relic.h | 112 + bls/contrib/relic/include/relic_alloc.h | 87 + bls/contrib/relic/include/relic_arch.h | 106 + bls/contrib/relic/include/relic_bc.h | 84 + bls/contrib/relic/include/relic_bench.h | 202 + bls/contrib/relic/include/relic_bn.h | 1377 ++ bls/contrib/relic/include/relic_conf.h.in | 722 + bls/contrib/relic/include/relic_core.h | 464 + bls/contrib/relic/include/relic_cp.h | 1751 ++ bls/contrib/relic/include/relic_dv.h | 262 + bls/contrib/relic/include/relic_eb.h | 967 ++ bls/contrib/relic/include/relic_ec.h | 455 + bls/contrib/relic/include/relic_ed.h | 894 ++ bls/contrib/relic/include/relic_ep.h | 1185 ++ bls/contrib/relic/include/relic_epx.h | 1022 ++ bls/contrib/relic/include/relic_err.h | 340 + bls/contrib/relic/include/relic_fb.h | 995 ++ bls/contrib/relic/include/relic_fbx.h | 204 + bls/contrib/relic/include/relic_fp.h | 1088 ++ bls/contrib/relic/include/relic_fpx.h | 4497 ++++++ bls/contrib/relic/include/relic_label.h | 2667 ++++ bls/contrib/relic/include/relic_md.h | 274 + bls/contrib/relic/include/relic_pc.h | 895 ++ bls/contrib/relic/include/relic_pp.h | 911 ++ bls/contrib/relic/include/relic_rand.h | 118 + bls/contrib/relic/include/relic_test.h | 104 + bls/contrib/relic/include/relic_types.h | 166 + bls/contrib/relic/include/relic_util.h | 248 + bls/src/CMakeLists.txt | 76 + bls/src/aggregationinfo.cpp | 410 + bls/src/aggregationinfo.hpp | 109 + bls/src/bls.cpp | 135 + bls/src/bls.hpp | 70 + bls/src/chaincode.cpp | 57 + bls/src/chaincode.hpp | 58 + bls/src/extendedprivatekey.cpp | 203 + bls/src/extendedprivatekey.hpp | 109 + bls/src/extendedpublickey.cpp | 136 + bls/src/extendedpublickey.hpp | 100 + bls/src/privatekey.cpp | 261 + bls/src/privatekey.hpp | 103 + bls/src/publickey.cpp | 158 + bls/src/publickey.hpp | 80 + bls/src/signature.cpp | 773 + bls/src/signature.hpp | 242 + bls/src/test-bench.cpp | 199 + bls/src/test-utils.hpp | 50 + bls/src/test.cpp | 1659 ++ bls/src/threshold.cpp | 227 + bls/src/threshold.hpp | 118 + bls/src/util.hpp | 112 + examples/CMakeLists.txt | 11 +- examples/hotstuff_app.cpp | 2 +- hotstuff-sec0.conf | 2 +- hotstuff-sec1.conf | 2 +- hotstuff-sec2.conf | 2 +- hotstuff-sec3.conf | 2 +- hotstuff.conf | 8 +- include/hotstuff/crypto.h | 317 +- include/hotstuff/entity.h | 4 +- include/hotstuff/hotstuff.h | 2 + src/consensus.cpp | 3 +- src/crypto.cpp | 101 +- 72 files changed, 43477 insertions(+), 56 deletions(-) create mode 100644 bls/build/contrib/relic/include/relic_conf.h create mode 100644 bls/contrib/catch/catch.hpp create mode 100644 bls/contrib/relic/include/low/relic_bn_low.h create mode 100644 bls/contrib/relic/include/low/relic_dv_low.h create mode 100644 bls/contrib/relic/include/low/relic_fb_low.h create mode 100644 bls/contrib/relic/include/low/relic_fp_low.h create mode 100644 bls/contrib/relic/include/low/relic_fpx_low.h create mode 100644 bls/contrib/relic/include/relic.h create mode 100644 bls/contrib/relic/include/relic_alloc.h create mode 100644 bls/contrib/relic/include/relic_arch.h create mode 100644 bls/contrib/relic/include/relic_bc.h create mode 100644 bls/contrib/relic/include/relic_bench.h create mode 100644 bls/contrib/relic/include/relic_bn.h create mode 100644 bls/contrib/relic/include/relic_conf.h.in create mode 100644 bls/contrib/relic/include/relic_core.h create mode 100644 bls/contrib/relic/include/relic_cp.h create mode 100644 bls/contrib/relic/include/relic_dv.h create mode 100644 bls/contrib/relic/include/relic_eb.h create mode 100644 bls/contrib/relic/include/relic_ec.h create mode 100644 bls/contrib/relic/include/relic_ed.h create mode 100644 bls/contrib/relic/include/relic_ep.h create mode 100644 bls/contrib/relic/include/relic_epx.h create mode 100644 bls/contrib/relic/include/relic_err.h create mode 100644 bls/contrib/relic/include/relic_fb.h create mode 100644 bls/contrib/relic/include/relic_fbx.h create mode 100644 bls/contrib/relic/include/relic_fp.h create mode 100644 bls/contrib/relic/include/relic_fpx.h create mode 100644 bls/contrib/relic/include/relic_label.h create mode 100644 bls/contrib/relic/include/relic_md.h create mode 100644 bls/contrib/relic/include/relic_pc.h create mode 100644 bls/contrib/relic/include/relic_pp.h create mode 100644 bls/contrib/relic/include/relic_rand.h create mode 100644 bls/contrib/relic/include/relic_test.h create mode 100644 bls/contrib/relic/include/relic_types.h create mode 100644 bls/contrib/relic/include/relic_util.h create mode 100644 bls/src/CMakeLists.txt create mode 100644 bls/src/aggregationinfo.cpp create mode 100644 bls/src/aggregationinfo.hpp create mode 100644 bls/src/bls.cpp create mode 100644 bls/src/bls.hpp create mode 100644 bls/src/chaincode.cpp create mode 100644 bls/src/chaincode.hpp create mode 100644 bls/src/extendedprivatekey.cpp create mode 100644 bls/src/extendedprivatekey.hpp create mode 100644 bls/src/extendedpublickey.cpp create mode 100644 bls/src/extendedpublickey.hpp create mode 100644 bls/src/privatekey.cpp create mode 100644 bls/src/privatekey.hpp create mode 100644 bls/src/publickey.cpp create mode 100644 bls/src/publickey.hpp create mode 100644 bls/src/signature.cpp create mode 100644 bls/src/signature.hpp create mode 100644 bls/src/test-bench.cpp create mode 100644 bls/src/test-utils.hpp create mode 100644 bls/src/test.cpp create mode 100644 bls/src/threshold.cpp create mode 100644 bls/src/threshold.hpp create mode 100644 bls/src/util.hpp diff --git a/.gitignore b/.gitignore index 4de281a3..74fcf304 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,5 @@ include/hotstuff/config.h /test/test_secp256k1 /test/test_concurrent_queue core + +.idea/ diff --git a/CMakeLists.txt b/CMakeLists.txt index c6af4bd5..c13e44dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,13 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/salticidae/cmake add_subdirectory(salticidae) include_directories(salticidae/include) +INCLUDE_DIRECTORIES(bls/src) +LINK_DIRECTORIES(bls/build/src) + +LINK_DIRECTORIES(bls/build/contrib/relic/lib) +INCLUDE_DIRECTORIES(bls/build/contrib/relic/include) +INCLUDE_DIRECTORIES(bls/contrib/relic/include) + find_package(OpenSSL REQUIRED) find_package(Threads REQUIRED) @@ -91,11 +98,11 @@ endif() # build tools add_executable(hotstuff-keygen src/hotstuff_keygen.cpp) -target_link_libraries(hotstuff-keygen hotstuff_static) +target_link_libraries(hotstuff-keygen hotstuff_static blstmp relic_s) add_executable(hotstuff-tls-keygen src/hotstuff_tls_keygen.cpp) -target_link_libraries(hotstuff-tls-keygen hotstuff_static) +target_link_libraries(hotstuff-tls-keygen hotstuff_static blstmp relic_s) find_package(Doxygen) if (DOXYGEN_FOUND) diff --git a/bls/build/contrib/relic/include/relic_conf.h b/bls/build/contrib/relic/include/relic_conf.h new file mode 100644 index 00000000..9930e104 --- /dev/null +++ b/bls/build/contrib/relic/include/relic_conf.h @@ -0,0 +1,722 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @file + * + * Project configuration. + * + * @version $Id: relic_conf.h.in 45 2009-07-04 23:45:48Z dfaranha $ + * @ingroup relic + */ + +#ifndef RLC_CONF_H +#define RLC_CONF_H + +/** Project version. */ +#define RLC_VERSION "0.5.0" + +/** Debugging support. */ +/* #undef DEBUG */ +/** Profiling support. */ +/* #undef PROFL */ +/** Error handling support. */ +/* #undef CHECK */ +/** Verbose error messages. */ +/* #undef VERBS */ +/** Build with overhead estimation. */ +/* #undef OVERH */ +/** Build documentation. */ +#define DOCUM +/** Build only the selected algorithms. */ +/* #undef STRIP */ +/** Build with printing disabled. */ +#define QUIET +/** Build with colored output. */ +#define COLOR +/** Build with big-endian support. */ +/* #undef BIGED */ +/** Build shared library. */ +/* #undef SHLIB */ +/** Build static library. */ +#define STLIB + +/** Number of times each test is ran. */ +#define TESTS 0 +/** Number of times each benchmark is ran. */ +#define BENCH 0 + +/** Number of available cores. */ +#define CORES 1 + +/** Atmel AVR ATMega128 8-bit architecture. */ +#define AVR 1 +/** MSP430 16-bit architecture. */ +#define MSP 2 +/** ARM 32-bit architecture. */ +#define ARM 3 +/** Intel x86-compatible 32-bit architecture. */ +#define X86 4 +/** AMD64-compatible 64-bit architecture. */ +#define X64 5 +/** Architecture. */ +#define ARCH X64 + +/** Size of word in this architecture. */ +#define WSIZE 64 + +/** Byte boundary to align digit vectors. */ +#define ALIGN 1 + +/** Build multiple precision integer module. */ +#define WITH_BN +/** Build prime field module. */ +#define WITH_FP +/** Build prime field extension module. */ +#define WITH_FPX +/** Build binary field module. */ +#define WITH_FB +/** Build prime elliptic curve module. */ +#define WITH_EP +/** Build prime field extension elliptic curve module. */ +#define WITH_EPX +/** Build binary elliptic curve module. */ +#define WITH_EB +/** Build elliptic Edwards curve module. */ +#define WITH_ED +/** Build elliptic curve cryptography module. */ +#define WITH_EC +/** Build pairings over prime curves module. */ +#define WITH_PP +/** Build pairing-based cryptography module. */ +#define WITH_PC +/** Build block ciphers. */ +#define WITH_BC +/** Build hash functions. */ +#define WITH_MD +/** Build cryptographic protocols. */ +#define WITH_CP + +/** Easy C-only backend. */ +#define EASY 1 +/** GMP backend. */ +#define GMP 2 +/** Arithmetic backend. */ +#define ARITH EASY + +/** Required precision in bits. */ +#define BN_PRECI 1024 +/** A multiple precision integer can store w words. */ +#define SINGLE 0 +/** A multiple precision integer can store the result of an addition. */ +#define CARRY 1 +/** A multiple precision integer can store the result of a multiplication. */ +#define DOUBLE 2 +/** Effective size of a multiple precision integer. */ +#define BN_MAGNI DOUBLE +/** Number of Karatsuba steps. */ +#define BN_KARAT 0 + +/** Schoolbook multiplication. */ +#define BASIC 1 +/** Comba multiplication. */ +#define COMBA 2 +/** Chosen multiple precision multiplication method. */ +#define BN_MUL COMBA + +/** Schoolbook squaring. */ +#define BASIC 1 +/** Comba squaring. */ +#define COMBA 2 +/** Reuse multiplication for squaring. */ +#define MULTP 4 +/** Chosen multiple precision multiplication method. */ +#define BN_SQR COMBA + +/** Division modular reduction. */ +#define BASIC 1 +/** Barrett modular reduction. */ +#define BARRT 2 +/** Montgomery modular reduction. */ +#define MONTY 3 +/** Pseudo-Mersenne modular reduction. */ +#define PMERS 4 +/** Chosen multiple precision modular reduction method. */ +#define BN_MOD MONTY + +/** Binary modular exponentiation. */ +#define BASIC 1 +/** Sliding window modular exponentiation. */ +#define SLIDE 2 +/** Montgomery powering ladder. */ +#define MONTY 3 +/** Chosen multiple precision modular exponentiation method. */ +#define BN_MXP SLIDE + +/** Basic Euclidean GCD Algorithm. */ +#define BASIC 1 +/** Lehmer's fast GCD Algorithm. */ +#define LEHME 2 +/** Stein's binary GCD Algorithm. */ +#define STEIN 3 +/** Chosen multiple precision greatest common divisor method. */ +#define BN_GCD BASIC + +/** Basic prime generation. */ +#define BASIC 1 +/** Safe prime generation. */ +#define SAFEP 2 +/** Strong prime generation. */ +#define STRON 3 +/** Chosen prime generation algorithm. */ +#define BN_GEN BASIC + +/** Multiple precision arithmetic method */ +#define BN_METHD "COMBA;COMBA;MONTY;SLIDE;BASIC;BASIC" + +/** Prime field size in bits. */ +#define FP_PRIME 381 +/** Number of Karatsuba steps. */ +#define FP_KARAT 0 +/** Prefer Pseudo-Mersenne primes over random primes. */ +/* #undef FP_PMERS */ +/** Use -1 as quadratic non-residue. */ +#define FP_QNRES +/** Width of window processing for exponentiation methods. */ +#define FP_WIDTH 4 + +/** Schoolbook addition. */ +#define BASIC 1 +/** Integrated modular addtion. */ +#define INTEG 3 +/** Chosen prime field multiplication method. */ +#define FP_ADD INTEG + +/** Schoolbook multiplication. */ +#define BASIC 1 +/** Comba multiplication. */ +#define COMBA 2 +/** Integrated modular multiplication. */ +#define INTEG 3 +/** Chosen prime field multiplication method. */ +#define FP_MUL INTEG + +/** Schoolbook squaring. */ +#define BASIC 1 +/** Comba squaring. */ +#define COMBA 2 +/** Integrated modular squaring. */ +#define INTEG 3 +/** Reuse multiplication for squaring. */ +#define MULTP 4 +/** Chosen prime field multiplication method. */ +#define FP_SQR INTEG + +/** Division-based reduction. */ +#define BASIC 1 +/** Fast reduction modulo special form prime. */ +#define QUICK 2 +/** Montgomery modular reduction. */ +#define MONTY 3 +/** Chosen prime field reduction method. */ +#define FP_RDC MONTY + +/** Inversion by Fermat's Little Theorem. */ +#define BASIC 1 +/** Binary inversion. */ +#define BINAR 2 +/** Integrated modular multiplication. */ +#define MONTY 3 +/** Extended Euclidean algorithm. */ +#define EXGCD 4 +/** Constant-time inversion by Bernstein-Yang division steps. */ +#define DIVST 5 +/** Use implementation provided by the lower layer. */ +#define LOWER 8 +/** Chosen prime field inversion method. */ +#define FP_INV LOWER + +/** Binary modular exponentiation. */ +#define BASIC 1 +/** Sliding window modular exponentiation. */ +#define SLIDE 2 +/** Constant-time Montgomery powering ladder. */ +#define MONTY 3 +/** Chosen multiple precision modular exponentiation method. */ +#define FP_EXP SLIDE + +/** Prime field arithmetic method */ +#define FP_METHD "INTEG;INTEG;INTEG;MONTY;LOWER;SLIDE" + +/** Basic quadratic extension field arithmetic. */ +#define BASIC 1 +/** Integrated extension field arithmetic. */ +#define INTEG 3 +/* Chosen extension field arithmetic method. */ +#define FPX_QDR INTEG + +/** Basic cubic extension field arithmetic. */ +#define BASIC 1 +/** Integrated extension field arithmetic. */ +#define INTEG 3 +/* Chosen extension field arithmetic method. */ +#define FPX_CBC INTEG + +/** Basic quadratic extension field arithmetic. */ +#define BASIC 1 +/** Lazy-reduced extension field arithmetic. */ +#define LAZYR 2 +/* Chosen extension field arithmetic method. */ +#define FPX_RDC LAZYR + +/** Prime extension field arithmetic method */ +#define FPX_METHD "INTEG;INTEG;LAZYR" + +/** Irreducible polynomial size in bits. */ +#define FB_POLYN 283 +/** Number of Karatsuba steps. */ +#define FB_KARAT 0 +/** Prefer trinomials over pentanomials. */ +#define FB_TRINO +/** Prefer square-root friendly polynomials. */ +/* #undef FB_SQRTF */ +/** Precompute multiplication table for sqrt(z). */ +#define FB_PRECO +/** Width of window processing for exponentiation methods. */ +#define FB_WIDTH 4 + +/** Shift-and-add multiplication. */ +#define BASIC 1 +/** Lopez-Dahab multiplication. */ +#define LODAH 2 +/** Integrated modular multiplication. */ +#define INTEG 3 +/** Chosen binary field multiplication method. */ +#define FB_MUL LODAH + +/** Basic squaring. */ +#define BASIC 1 +/** Table-based squaring. */ +#define QUICK 2 +/** Integrated modular squaring. */ +#define INTEG 3 +/** Chosen binary field squaring method. */ +#define FB_SQR QUICK + +/** Shift-and-add modular reduction. */ +#define BASIC 1 +/** Fast reduction modulo a trinomial or pentanomial. */ +#define QUICK 2 +/** Chosen binary field modular reduction method. */ +#define FB_RDC QUICK + +/** Square root by repeated squaring. */ +#define BASIC 1 +/** Fast square root extraction. */ +#define QUICK 2 +/** Chosen binary field modular reduction method. */ +#define FB_SRT QUICK + +/** Trace by repeated squaring. */ +#define BASIC 1 +/** Fast trace computation. */ +#define QUICK 2 +/** Chosen trace computation method. */ +#define FB_TRC QUICK + +/** Solve by half-trace computation. */ +#define BASIC 1 +/** Solve with precomputed half-traces. */ +#define QUICK 2 +/** Chosen method to solve a quadratic equation. */ +#define FB_SLV QUICK + +/** Inversion by Fermat's Little Theorem. */ +#define BASIC 1 +/** Binary inversion. */ +#define BINAR 2 +/** Almost inverse algorithm. */ +#define ALMOS 3 +/** Extended Euclidean algorithm. */ +#define EXGCD 4 +/** Itoh-Tsuji inversion. */ +#define ITOHT 5 +/** Hardware-friendly inversion by Brunner-Curiger-Hofstetter.*/ +#define BRUCH 6 +/** Constant-time version of almost inverse. */ +#define CTAIA 7 +/** Use implementation provided by the lower layer. */ +#define LOWER 8 +/** Chosen binary field inversion method. */ +#define FB_INV EXGCD + +/** Binary modular exponentiation. */ +#define BASIC 1 +/** Sliding window modular exponentiation. */ +#define SLIDE 2 +/** Constant-time Montgomery powering ladder. */ +#define MONTY 3 +/** Chosen multiple precision modular exponentiation method. */ +#define FB_EXP SLIDE + +/** Iterated squaring/square-root by consecutive squaring/square-root. */ +#define BASIC 1 +/** Iterated squaring/square-root by table-based method. */ +#define QUICK 2 +/** Chosen method to solve a quadratic equation. */ +#define FB_ITR QUICK + +/** Binary field arithmetic method */ +#define FB_METHD "LODAH;QUICK;QUICK;QUICK;QUICK;QUICK;EXGCD;SLIDE;QUICK" + +/** Support for ordinary curves. */ +/* #undef EP_PLAIN */ +/** Support for supersingular curves. */ +/* #undef EP_SUPER */ +/** Support for prime curves with efficient endormorphisms. */ +#define EP_ENDOM +/** Use mixed coordinates. */ +#define EP_MIXED +/** Build precomputation table for generator. */ +#define EP_PRECO +/** Enable isogeny map for SSWU map-to-curve. */ +#define EP_CTMAP +/** Width of precomputation table for fixed point methods. */ +#define EP_DEPTH 4 +/** Width of window processing for unknown point methods. */ +#define EP_WIDTH 4 + +/** Affine coordinates. */ +#define BASIC 1 +/** Projective coordinates. */ +#define PROJC 2 +/** Chosen prime elliptic curve coordinate method. */ +#define EP_ADD PROJC + +/** Binary point multiplication. */ +#define BASIC 1 +/** Sliding window. */ +#define SLIDE 2 +/** Montgomery powering ladder. */ +#define MONTY 3 +/** Left-to-right Width-w NAF. */ +#define LWNAF 4 +/** Left-to-right Width-w NAF. */ +#define LWREG 5 +/** Chosen prime elliptic curve point multiplication method. */ +#define EP_MUL LWNAF + +/** Binary point multiplication. */ +#define BASIC 1 +/** Single-table comb method. */ +#define COMBS 2 +/** Double-table comb method. */ +#define COMBD 3 +/** Left-to-right Width-w NAF. */ +#define LWNAF 4 +/** Chosen prime elliptic curve point multiplication method. */ +#define EP_FIX COMBS + +/** Basic simultaneouns point multiplication. */ +#define BASIC 1 +/** Shamir's trick. */ +#define TRICK 2 +/** Interleaving of w-(T)NAFs. */ +#define INTER 3 +/** Joint sparse form. */ +#define JOINT 4 +/** Chosen prime elliptic curve simulteanous point multiplication method. */ +#define EP_SIM INTER + +/** Prime elliptic curve arithmetic method. */ +#define EP_METHD "PROJC;LWNAF;COMBS;INTER" + +/** Support for ordinary curves without endormorphisms. */ +#define EB_PLAIN +/** Support for Koblitz anomalous binary curves. */ +#define EB_KBLTZ +/** Use mixed coordinates. */ +#define EB_MIXED +/** Build precomputation table for generator. */ +#define EB_PRECO +/** Width of precomputation table for fixed point methods. */ +#define EB_DEPTH 4 +/** Width of window processing for unknown point methods. */ +#define EB_WIDTH 4 + +/** Binary elliptic curve arithmetic method. */ +#define EB_METHD "PROJC;LWNAF;COMBS;INTER" + +/** Affine coordinates. */ +#define BASIC 1 +/** López-Dahab Projective coordinates. */ +#define PROJC 2 +/** Chosen binary elliptic curve coordinate method. */ +#define EB_ADD PROJC + +/** Binary point multiplication. */ +#define BASIC 1 +/** López-Dahab point multiplication. */ +#define LODAH 2 +/** Halving. */ +#define HALVE 3 +/** Left-to-right width-w (T)NAF. */ +#define LWNAF 4 +/** Right-to-left width-w (T)NAF. */ +#define RWNAF 5 +/** Chosen binary elliptic curve point multiplication method. */ +#define EB_MUL LWNAF + +/** Binary point multiplication. */ +#define BASIC 1 +/** Single-table comb method. */ +#define COMBS 2 +/** Double-table comb method. */ +#define COMBD 3 +/** Left-to-right Width-w NAF. */ +#define LWNAF 4 +/** Chosen binary elliptic curve point multiplication method. */ +#define EB_FIX COMBS + +/** Basic simultaneouns point multiplication. */ +#define BASIC 1 +/** Shamir's trick. */ +#define TRICK 2 +/** Interleaving of w-(T)NAFs. */ +#define INTER 3 +/** Joint sparse form. */ +#define JOINT 4 +/** Chosen binary elliptic curve simulteanous point multiplication method. */ +#define EB_SIM INTER + +/** Build precomputation table for generator. */ +#define ED_PRECO +/** Width of precomputation table for fixed point methods. */ +#define ED_DEPTH 4 +/** Width of window processing for unknown point methods. */ +#define ED_WIDTH 4 + +/** Edwards elliptic curve arithmetic method. */ +#define ED_METHD "PROJC;LWNAF;COMBS;INTER" + +/** Affine coordinates. */ +#define BASIC 1 +/** Simple projective twisted Edwards coordinates */ +#define PROJC 2 +/** Extended projective twisted Edwards coordinates */ +#define EXTND 3 +/** Chosen binary elliptic curve coordinate method. */ +#define ED_ADD PROJC + +/** Binary point multiplication. */ +#define BASIC 1 +/** Sliding window. */ +#define SLIDE 2 +/** Montgomery powering ladder. */ +#define MONTY 3 +/** Left-to-right Width-w NAF. */ +#define LWNAF 4 +/** Left-to-right Width-w NAF. */ +#define LWREG 5 +/** Chosen prime elliptic twisted Edwards curve point multiplication method. */ +#define ED_MUL LWNAF + +/** Binary point multiplication. */ +#define BASIC 1 +/** Single-table comb method. */ +#define COMBS 2 +/** Double-table comb method. */ +#define COMBD 3 +/** Left-to-right Width-w NAF. */ +#define LWNAF 4 +/** Chosen prime elliptic twisted Edwards curve point multiplication method. */ +#define ED_FIX COMBS + +/** Basic simultaneouns point multiplication. */ +#define BASIC 1 +/** Shamir's trick. */ +#define TRICK 2 +/** Interleaving of w-(T)NAFs. */ +#define INTER 3 +/** Joint sparse form. */ +#define JOINT 4 +/** Chosen prime elliptic curve simulteanous point multiplication method. */ +#define ED_SIM INTER + +/** Prime curves. */ +#define PRIME 1 +/** Binary curves. */ +#define CHAR2 2 +/** Edwards curves */ +#define EDDIE 3 +/** Chosen elliptic curve type. */ +#define EC_CUR PRIME + +/** Chosen elliptic curve cryptography method. */ +#define EC_METHD "PRIME" +/** Prefer curves with efficient endomorphisms. */ +/* #undef EC_ENDOM */ + +/** Basic quadratic extension field arithmetic. */ +#define BASIC 1 +/** Lazy-reduced extension field arithmetic. */ +#define LAZYR 2 +/* Chosen extension field arithmetic method. */ +#define PP_EXT LAZYR + +/** Bilinear pairing method. */ +#define PP_METHD "LAZYR;OATEP" + +/** Tate pairing. */ +#define TATEP 1 +/** Weil pairing. */ +#define WEILP 2 +/** Optimal ate pairing. */ +#define OATEP 3 +/** Chosen pairing method over prime elliptic curves. */ +#define PP_MAP OATEP + +/** SHA-224 hash function. */ +#define SH224 2 +/** SHA-256 hash function. */ +#define SH256 3 +/** SHA-384 hash function. */ +#define SH384 4 +/** SHA-512 hash function. */ +#define SH512 5 +/** BLAKE2s-160 hash function. */ +#define B2S160 6 +/** BLAKE2s-256 hash function. */ +#define B2S256 7 +/** Chosen hash function. */ +#define MD_MAP SH256 + +/** Choice of hash function. */ +#define MD_METHD "SH256" + +/** RSA without padding. */ +#define BASIC 1 +/** RSA PKCS#1 v1.5 padding. */ +#define PKCS1 2 +/** RSA PKCS#1 v2.1 padding. */ +#define PKCS2 3 +/** Chosen RSA padding method. */ +#define CP_RSAPD PKCS1 + +/** Slow RSA decryption/signature. */ +#define BASIC 1 +/** Fast RSA decryption/signature with CRT. */ +#define QUICK 2 +/** Chosen RSA method. */ +#define CP_RSA QUICK + +/** Standard ECDSA. */ +#define BASIC 1 +/** ECDSA with fast verification. */ +#define QUICK 2 +/** Chosen ECDSA method. */ +#define CP_ECDSA + +/** Automatic memory allocation. */ +#define AUTO 1 +/** Dynamic memory allocation. */ +#define DYNAMIC 2 +/** Stack memory allocation. */ +#define STACK 3 +/** Chosen memory allocation policy. */ +#define ALLOC AUTO + +/** NIST HASH-DRBG generator. */ +#define HASHD 1 +/** Intel RdRand instruction. */ +#define RDRND 2 +/** Operating system underlying generator. */ +#define UDEV 3 +/** Override library generator with the callback. */ +#define CALL 4 +/** Chosen random generator. */ +#define RAND HASHD + +/** Standard C library generator. */ +#define LIBC 1 +/** Intel RdRand instruction. */ +#define RDRND 2 +/** Device node generator. */ +#define UDEV 3 +/** Use Windows' CryptGenRandom. */ +#define WCGR 4 +/** Chosen random generator seeder. */ +#define SEED UDEV + +/** GNU/Linux operating system. */ +#define LINUX 1 +/** FreeBSD operating system. */ +#define FREEBSD 2 +/** Windows operating system. */ +#define MACOSX 3 +/** Windows operating system. */ +#define WINDOWS 4 +/** Android operating system. */ +#define DROID 5 +/* Arduino platform. */ +#define DUINO 6 +/** Detected operation system. */ +#define OPSYS LINUX + +/** OpenMP multithreading support. */ +#define OPENMP 1 +/** POSIX multithreading support. */ +#define PTHREAD 2 +/** Chosen multithreading API. */ +#define MULTI PTHREAD + +/** Per-process high-resolution timer. */ +#define HREAL 1 +/** Per-process high-resolution timer. */ +#define HPROC 2 +/** Per-thread high-resolution timer. */ +#define HTHRD 3 +/** POSIX-compatible timer. */ +#define POSIX 4 +/** ANSI-compatible timer. */ +#define ANSI 5 +/** Cycle-counting timer. */ +#define CYCLE 6 +/** Chosen timer. */ +#define TIMER CYCLE + +/** Prefix to identity this build of the library. */ +/* #undef LABEL */ + +#ifndef ASM + +#include "relic_label.h" + +/** + * Prints the project options selected at build time. + */ +void conf_print(void); + +#endif /* ASM */ + +#endif /* !RLC_CONF_H */ diff --git a/bls/contrib/catch/catch.hpp b/bls/contrib/catch/catch.hpp new file mode 100644 index 00000000..aacc5601 --- /dev/null +++ b/bls/contrib/catch/catch.hpp @@ -0,0 +1,13286 @@ +/* + * Catch v2.2.3 + * Generated: 2018-06-06 23:11:57.601416 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * Copyright (c) 2018 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +// start catch.hpp + + +#define CATCH_VERSION_MAJOR 2 +#define CATCH_VERSION_MINOR 2 +#define CATCH_VERSION_PATCH 3 + +#ifdef __clang__ +# pragma clang system_header +#elif defined __GNUC__ +# pragma GCC system_header +#endif + +// start catch_suppress_warnings.h + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(push) +# pragma warning(disable: 161 1682) +# else // __ICC +# pragma clang diagnostic ignored "-Wunused-variable" +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic ignored "-Wparentheses" +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic ignored "-Wpadded" +#endif +// end catch_suppress_warnings.h +#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) +# define CATCH_IMPL +# define CATCH_CONFIG_ALL_PARTS +#endif + +// In the impl file, we want to have access to all parts of the headers +// Can also be used to sanely support PCHs +#if defined(CATCH_CONFIG_ALL_PARTS) +# define CATCH_CONFIG_EXTERNAL_INTERFACES +# if defined(CATCH_CONFIG_DISABLE_MATCHERS) +# undef CATCH_CONFIG_DISABLE_MATCHERS +# endif +# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +#endif + +#if !defined(CATCH_CONFIG_IMPL_ONLY) +// start catch_platform.h + +#ifdef __APPLE__ +# include +# if TARGET_OS_OSX == 1 +# define CATCH_PLATFORM_MAC +# elif TARGET_OS_IPHONE == 1 +# define CATCH_PLATFORM_IPHONE +# endif + +#elif defined(linux) || defined(__linux) || defined(__linux__) +# define CATCH_PLATFORM_LINUX + +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) +# define CATCH_PLATFORM_WINDOWS +#endif + +// end catch_platform.h + +#ifdef CATCH_IMPL +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// start catch_user_interfaces.h + +namespace Catch { + unsigned int rngSeed(); +} + +// end catch_user_interfaces.h +// start catch_tag_alias_autoregistrar.h + +// start catch_common.h + +// start catch_compiler_capabilities.h + +// Detect a number of compiler features - by compiler +// The following features are defined: +// +// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? +// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? +// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** + +// In general each macro has a _NO_ form +// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +#ifdef __cplusplus + +# if __cplusplus >= 201402L +# define CATCH_CPP14_OR_GREATER +# endif + +# if __cplusplus >= 201703L +# define CATCH_CPP17_OR_GREATER +# endif + +#endif + +#if defined(CATCH_CPP17_OR_GREATER) +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +#ifdef __clang__ + +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic push" ) \ + _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ + _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") +# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic pop" ) + +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic push" ) \ + _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) +# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic pop" ) + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Assume that non-Windows platforms support posix signals by default +#if !defined(CATCH_PLATFORM_WINDOWS) + #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS +#endif + +//////////////////////////////////////////////////////////////////////////////// +// We know some environments not to support full POSIX signals +#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) + #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +#endif + +#ifdef __OS400__ +# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +# define CATCH_CONFIG_COLOUR_NONE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Android somehow still does not support std::to_string +#if defined(__ANDROID__) +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Not all Windows environments support SEH properly +#if defined(__MINGW32__) +# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Cygwin +#ifdef __CYGWIN__ + +// Required for some versions of Cygwin to declare gettimeofday +// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin +# define _BSD_SOURCE + +#endif // __CYGWIN__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +# if _MSC_VER >= 1900 // Visual Studio 2015 or newer +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +# endif + +// Universal Windows platform does not support SEH +// Or console colours (or console at all...) +# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +# define CATCH_CONFIG_COLOUR_NONE +# else +# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH +# endif + +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// + +// DJGPP +#ifdef __DJGPP__ +# define CATCH_INTERNAL_CONFIG_NO_WCHAR +#endif // __DJGPP__ + +//////////////////////////////////////////////////////////////////////////////// + +// Use of __COUNTER__ is suppressed during code analysis in +// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly +// handled by it. +// Otherwise all supported compilers support COUNTER macro, +// but user still might want to turn it off +#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) + #define CATCH_INTERNAL_CONFIG_COUNTER +#endif + +#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) +# define CATCH_CONFIG_COUNTER +#endif +#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) +# define CATCH_CONFIG_WINDOWS_SEH +#endif +// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. +#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) +# define CATCH_CONFIG_POSIX_SIGNALS +#endif +// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. +#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) +# define CATCH_CONFIG_WCHAR +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) +# define CATCH_CONFIG_CPP11_TO_STRING +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) +# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS +# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS +# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS +#endif + +// end catch_compiler_capabilities.h +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#ifdef CATCH_CONFIG_COUNTER +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) +#else +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) +#endif + +#include +#include +#include + +namespace Catch { + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + + class NonCopyable { + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; + + protected: + NonCopyable(); + virtual ~NonCopyable(); + }; + + struct SourceLineInfo { + + SourceLineInfo() = delete; + SourceLineInfo( char const* _file, std::size_t _line ) noexcept + : file( _file ), + line( _line ) + {} + + SourceLineInfo( SourceLineInfo const& other ) = default; + SourceLineInfo( SourceLineInfo && ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo& operator = ( SourceLineInfo && ) = default; + + bool empty() const noexcept; + bool operator == ( SourceLineInfo const& other ) const noexcept; + bool operator < ( SourceLineInfo const& other ) const noexcept; + + char const* file; + std::size_t line; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() const; + }; + template + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO \ + ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) + +// end catch_common.h +namespace Catch { + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS + +// end catch_tag_alias_autoregistrar.h +// start catch_test_registry.h + +// start catch_interfaces_testcase.h + +#include +#include + +namespace Catch { + + class TestSpec; + + struct ITestInvoker { + virtual void invoke () const = 0; + virtual ~ITestInvoker(); + }; + + using ITestCasePtr = std::shared_ptr; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector const& getAllTests() const = 0; + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; + }; + + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + +} + +// end catch_interfaces_testcase.h +// start catch_stringref.h + +#include +#include +#include + +namespace Catch { + + class StringData; + + /// A non-owning string class (similar to the forthcoming std::string_view) + /// Note that, because a StringRef may be a substring of another string, + /// it may not be null terminated. c_str() must return a null terminated + /// string, however, and so the StringRef will internally take ownership + /// (taking a copy), if necessary. In theory this ownership is not externally + /// visible - but it does mean (substring) StringRefs should not be shared between + /// threads. + class StringRef { + public: + using size_type = std::size_t; + + private: + friend struct StringRefTestAccess; + + char const* m_start; + size_type m_size; + + char* m_data = nullptr; + + void takeOwnership(); + + static constexpr char const* const s_empty = ""; + + public: // construction/ assignment + StringRef() noexcept + : StringRef( s_empty, 0 ) + {} + + StringRef( StringRef const& other ) noexcept + : m_start( other.m_start ), + m_size( other.m_size ) + {} + + StringRef( StringRef&& other ) noexcept + : m_start( other.m_start ), + m_size( other.m_size ), + m_data( other.m_data ) + { + other.m_data = nullptr; + } + + StringRef( char const* rawChars ) noexcept; + + StringRef( char const* rawChars, size_type size ) noexcept + : m_start( rawChars ), + m_size( size ) + {} + + StringRef( std::string const& stdString ) noexcept + : m_start( stdString.c_str() ), + m_size( stdString.size() ) + {} + + ~StringRef() noexcept { + delete[] m_data; + } + + auto operator = ( StringRef const &other ) noexcept -> StringRef& { + delete[] m_data; + m_data = nullptr; + m_start = other.m_start; + m_size = other.m_size; + return *this; + } + + operator std::string() const; + + void swap( StringRef& other ) noexcept; + + public: // operators + auto operator == ( StringRef const& other ) const noexcept -> bool; + auto operator != ( StringRef const& other ) const noexcept -> bool; + + auto operator[] ( size_type index ) const noexcept -> char; + + public: // named queries + auto empty() const noexcept -> bool { + return m_size == 0; + } + auto size() const noexcept -> size_type { + return m_size; + } + + auto numberOfCharacters() const noexcept -> size_type; + auto c_str() const -> char const*; + + public: // substrings and searches + auto substr( size_type start, size_type size ) const noexcept -> StringRef; + + // Returns the current start pointer. + // Note that the pointer can change when if the StringRef is a substring + auto currentData() const noexcept -> char const*; + + private: // ownership queries - may not be consistent between calls + auto isOwned() const noexcept -> bool; + auto isSubstring() const noexcept -> bool; + }; + + auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string; + auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string; + auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string; + + auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; + auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; + + inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { + return StringRef( rawChars, size ); + } + +} // namespace Catch + +// end catch_stringref.h +namespace Catch { + +template +class TestInvokerAsMethod : public ITestInvoker { + void (C::*m_testAsMethod)(); +public: + TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {} + + void invoke() const override { + C obj; + (obj.*m_testAsMethod)(); + } +}; + +auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker*; + +template +auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* { + return new(std::nothrow) TestInvokerAsMethod( testAsMethod ); +} + +struct NameAndTags { + NameAndTags( StringRef const& name_ = StringRef(), StringRef const& tags_ = StringRef() ) noexcept; + StringRef name; + StringRef tags; +}; + +struct AutoReg : NonCopyable { + AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept; + ~AutoReg(); +}; + +} // end namespace Catch + +#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) +#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ +#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ +#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF + +#if defined(CATCH_CONFIG_DISABLE) + #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \ + static void TestName() + #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \ + namespace{ \ + struct TestName : INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF ClassName) { \ + void test(); \ + }; \ + } \ + void TestName::test() + +#endif + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ + static void TestName(); \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, "", Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ + static void TestName() + #define INTERNAL_CATCH_TESTCASE( ... ) \ + INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ ) + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ \ + struct TestName : INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF ClassName) { \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ + } \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ + void TestName::test() + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ + INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ ) + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, "", Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS + +// end catch_test_registry.h +// start catch_capture.hpp + +// start catch_assertionhandler.h + +// start catch_assertioninfo.h + +// start catch_result_type.h + +namespace Catch { + + // ResultWas::OfType enum + struct ResultWas { enum OfType { + Unknown = -1, + Ok = 0, + Info = 1, + Warning = 2, + + FailureBit = 0x10, + + ExpressionFailed = FailureBit | 1, + ExplicitFailure = FailureBit | 2, + + Exception = 0x100 | FailureBit, + + ThrewException = Exception | 1, + DidntThrowException = Exception | 2, + + FatalErrorCondition = 0x200 | FailureBit + + }; }; + + bool isOk( ResultWas::OfType resultType ); + bool isJustInfo( int flags ); + + // ResultDisposition::Flags enum + struct ResultDisposition { enum Flags { + Normal = 0x01, + + ContinueOnFailure = 0x02, // Failures fail test, but execution continues + FalseTest = 0x04, // Prefix expression with ! + SuppressFail = 0x08 // Failures are reported but do not fail the test + }; }; + + ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ); + + bool shouldContinueOnFailure( int flags ); + inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } + bool shouldSuppressFailure( int flags ); + +} // end namespace Catch + +// end catch_result_type.h +namespace Catch { + + struct AssertionInfo + { + StringRef macroName; + SourceLineInfo lineInfo; + StringRef capturedExpression; + ResultDisposition::Flags resultDisposition; + + // We want to delete this constructor but a compiler bug in 4.8 means + // the struct is then treated as non-aggregate + //AssertionInfo() = delete; + }; + +} // end namespace Catch + +// end catch_assertioninfo.h +// start catch_decomposer.h + +// start catch_tostring.h + +#include +#include +#include +#include +// start catch_stream.h + +#include +#include +#include + +namespace Catch { + + std::ostream& cout(); + std::ostream& cerr(); + std::ostream& clog(); + + class StringRef; + + struct IStream { + virtual ~IStream(); + virtual std::ostream& stream() const = 0; + }; + + auto makeStream( StringRef const &filename ) -> IStream const*; + + class ReusableStringStream { + std::size_t m_index; + std::ostream* m_oss; + public: + ReusableStringStream(); + ~ReusableStringStream(); + + auto str() const -> std::string; + + template + auto operator << ( T const& value ) -> ReusableStringStream& { + *m_oss << value; + return *this; + } + auto get() -> std::ostream& { return *m_oss; } + + static void cleanup(); + }; +} + +// end catch_stream.h + +#ifdef __OBJC__ +// start catch_objc_arc.hpp + +#import + +#ifdef __has_feature +#define CATCH_ARC_ENABLED __has_feature(objc_arc) +#else +#define CATCH_ARC_ENABLED 0 +#endif + +void arcSafeRelease( NSObject* obj ); +id performOptionalSelector( id obj, SEL sel ); + +#if !CATCH_ARC_ENABLED +inline void arcSafeRelease( NSObject* obj ) { + [obj release]; +} +inline id performOptionalSelector( id obj, SEL sel ) { + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; + return nil; +} +#define CATCH_UNSAFE_UNRETAINED +#define CATCH_ARC_STRONG +#else +inline void arcSafeRelease( NSObject* ){} +inline id performOptionalSelector( id obj, SEL sel ) { +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" +#endif + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + return nil; +} +#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained +#define CATCH_ARC_STRONG __strong +#endif + +// end catch_objc_arc.hpp +#endif + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless +#endif + +// We need a dummy global operator<< so we can bring it into Catch namespace later +struct Catch_global_namespace_dummy {}; +std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); + +namespace Catch { + // Bring in operator<< from global namespace into Catch namespace + using ::operator<<; + + namespace Detail { + + extern const std::string unprintableString; + + std::string rawMemoryToString( const void *object, std::size_t size ); + + template + std::string rawMemoryToString( const T& object ) { + return rawMemoryToString( &object, sizeof(object) ); + } + + template + class IsStreamInsertable { + template + static auto test(int) + -> decltype(std::declval() << std::declval(), std::true_type()); + + template + static auto test(...)->std::false_type; + + public: + static const bool value = decltype(test(0))::value; + }; + + template + std::string convertUnknownEnumToString( E e ); + + template + typename std::enable_if< + !std::is_enum::value && !std::is_base_of::value, + std::string>::type convertUnstreamable( T const& ) { + return Detail::unprintableString; + } + template + typename std::enable_if< + !std::is_enum::value && std::is_base_of::value, + std::string>::type convertUnstreamable(T const& ex) { + return ex.what(); + } + + template + typename std::enable_if< + std::is_enum::value + , std::string>::type convertUnstreamable( T const& value ) { + return convertUnknownEnumToString( value ); + } + +#if defined(_MANAGED) + //! Convert a CLR string to a utf8 std::string + template + std::string clrReferenceToString( T^ ref ) { + if (ref == nullptr) + return std::string("null"); + auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString()); + cli::pin_ptr p = &bytes[0]; + return std::string(reinterpret_cast(p), bytes->Length); + } +#endif + + } // namespace Detail + + // If we decide for C++14, change these to enable_if_ts + template + struct StringMaker { + template + static + typename std::enable_if<::Catch::Detail::IsStreamInsertable::value, std::string>::type + convert(const Fake& value) { + ReusableStringStream rss; + // NB: call using the function-like syntax to avoid ambiguity with + // user-defined templated operator<< under clang. + rss.operator<<(value); + return rss.str(); + } + + template + static + typename std::enable_if::value, std::string>::type + convert( const Fake& value ) { +#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER) + return Detail::convertUnstreamable(value); +#else + return CATCH_CONFIG_FALLBACK_STRINGIFIER(value); +#endif + } + }; + + namespace Detail { + + // This function dispatches all stringification requests inside of Catch. + // Should be preferably called fully qualified, like ::Catch::Detail::stringify + template + std::string stringify(const T& e) { + return ::Catch::StringMaker::type>::type>::convert(e); + } + + template + std::string convertUnknownEnumToString( E e ) { + return ::Catch::Detail::stringify(static_cast::type>(e)); + } + +#if defined(_MANAGED) + template + std::string stringify( T^ e ) { + return ::Catch::StringMaker::convert(e); + } +#endif + + } // namespace Detail + + // Some predefined specializations + + template<> + struct StringMaker { + static std::string convert(const std::string& str); + }; +#ifdef CATCH_CONFIG_WCHAR + template<> + struct StringMaker { + static std::string convert(const std::wstring& wstr); + }; +#endif + + template<> + struct StringMaker { + static std::string convert(char const * str); + }; + template<> + struct StringMaker { + static std::string convert(char * str); + }; + +#ifdef CATCH_CONFIG_WCHAR + template<> + struct StringMaker { + static std::string convert(wchar_t const * str); + }; + template<> + struct StringMaker { + static std::string convert(wchar_t * str); + }; +#endif + + // TBD: Should we use `strnlen` to ensure that we don't go out of the buffer, + // while keeping string semantics? + template + struct StringMaker { + static std::string convert(char const* str) { + return ::Catch::Detail::stringify(std::string{ str }); + } + }; + template + struct StringMaker { + static std::string convert(signed char const* str) { + return ::Catch::Detail::stringify(std::string{ reinterpret_cast(str) }); + } + }; + template + struct StringMaker { + static std::string convert(unsigned char const* str) { + return ::Catch::Detail::stringify(std::string{ reinterpret_cast(str) }); + } + }; + + template<> + struct StringMaker { + static std::string convert(int value); + }; + template<> + struct StringMaker { + static std::string convert(long value); + }; + template<> + struct StringMaker { + static std::string convert(long long value); + }; + template<> + struct StringMaker { + static std::string convert(unsigned int value); + }; + template<> + struct StringMaker { + static std::string convert(unsigned long value); + }; + template<> + struct StringMaker { + static std::string convert(unsigned long long value); + }; + + template<> + struct StringMaker { + static std::string convert(bool b); + }; + + template<> + struct StringMaker { + static std::string convert(char c); + }; + template<> + struct StringMaker { + static std::string convert(signed char c); + }; + template<> + struct StringMaker { + static std::string convert(unsigned char c); + }; + + template<> + struct StringMaker { + static std::string convert(std::nullptr_t); + }; + + template<> + struct StringMaker { + static std::string convert(float value); + }; + template<> + struct StringMaker { + static std::string convert(double value); + }; + + template + struct StringMaker { + template + static std::string convert(U* p) { + if (p) { + return ::Catch::Detail::rawMemoryToString(p); + } else { + return "nullptr"; + } + } + }; + + template + struct StringMaker { + static std::string convert(R C::* p) { + if (p) { + return ::Catch::Detail::rawMemoryToString(p); + } else { + return "nullptr"; + } + } + }; + +#if defined(_MANAGED) + template + struct StringMaker { + static std::string convert( T^ ref ) { + return ::Catch::Detail::clrReferenceToString(ref); + } + }; +#endif + + namespace Detail { + template + std::string rangeToString(InputIterator first, InputIterator last) { + ReusableStringStream rss; + rss << "{ "; + if (first != last) { + rss << ::Catch::Detail::stringify(*first); + for (++first; first != last; ++first) + rss << ", " << ::Catch::Detail::stringify(*first); + } + rss << " }"; + return rss.str(); + } + } + +#ifdef __OBJC__ + template<> + struct StringMaker { + static std::string convert(NSString * nsstring) { + if (!nsstring) + return "nil"; + return std::string("@") + [nsstring UTF8String]; + } + }; + template<> + struct StringMaker { + static std::string convert(NSObject* nsObject) { + return ::Catch::Detail::stringify([nsObject description]); + } + + }; + namespace Detail { + inline std::string stringify( NSString* nsstring ) { + return StringMaker::convert( nsstring ); + } + + } // namespace Detail +#endif // __OBJC__ + +} // namespace Catch + +////////////////////////////////////////////////////// +// Separate std-lib types stringification, so it can be selectively enabled +// This means that we do not bring in + +#if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS) +# define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER +# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER +# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +#endif + +// Separate std::pair specialization +#if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER) +#include +namespace Catch { + template + struct StringMaker > { + static std::string convert(const std::pair& pair) { + ReusableStringStream rss; + rss << "{ " + << ::Catch::Detail::stringify(pair.first) + << ", " + << ::Catch::Detail::stringify(pair.second) + << " }"; + return rss.str(); + } + }; +} +#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER + +// Separate std::tuple specialization +#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER) +#include +namespace Catch { + namespace Detail { + template< + typename Tuple, + std::size_t N = 0, + bool = (N < std::tuple_size::value) + > + struct TupleElementPrinter { + static void print(const Tuple& tuple, std::ostream& os) { + os << (N ? ", " : " ") + << ::Catch::Detail::stringify(std::get(tuple)); + TupleElementPrinter::print(tuple, os); + } + }; + + template< + typename Tuple, + std::size_t N + > + struct TupleElementPrinter { + static void print(const Tuple&, std::ostream&) {} + }; + + } + + template + struct StringMaker> { + static std::string convert(const std::tuple& tuple) { + ReusableStringStream rss; + rss << '{'; + Detail::TupleElementPrinter>::print(tuple, rss.get()); + rss << " }"; + return rss.str(); + } + }; +} +#endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER + +namespace Catch { + struct not_this_one {}; // Tag type for detecting which begin/ end are being selected + + // Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace + using std::begin; + using std::end; + + not_this_one begin( ... ); + not_this_one end( ... ); + + template + struct is_range { + static const bool value = + !std::is_same())), not_this_one>::value && + !std::is_same())), not_this_one>::value; + }; + +#if defined(_MANAGED) // Managed types are never ranges + template + struct is_range { + static const bool value = false; + }; +#endif + + template + std::string rangeToString( Range const& range ) { + return ::Catch::Detail::rangeToString( begin( range ), end( range ) ); + } + + // Handle vector specially + template + std::string rangeToString( std::vector const& v ) { + ReusableStringStream rss; + rss << "{ "; + bool first = true; + for( bool b : v ) { + if( first ) + first = false; + else + rss << ", "; + rss << ::Catch::Detail::stringify( b ); + } + rss << " }"; + return rss.str(); + } + + template + struct StringMaker::value && !::Catch::Detail::IsStreamInsertable::value>::type> { + static std::string convert( R const& range ) { + return rangeToString( range ); + } + }; + + template + struct StringMaker { + static std::string convert(T const(&arr)[SZ]) { + return rangeToString(arr); + } + }; + +} // namespace Catch + +// Separate std::chrono::duration specialization +#if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +#include +#include +#include + +namespace Catch { + +template +struct ratio_string { + static std::string symbol(); +}; + +template +std::string ratio_string::symbol() { + Catch::ReusableStringStream rss; + rss << '[' << Ratio::num << '/' + << Ratio::den << ']'; + return rss.str(); +} +template <> +struct ratio_string { + static std::string symbol(); +}; +template <> +struct ratio_string { + static std::string symbol(); +}; +template <> +struct ratio_string { + static std::string symbol(); +}; +template <> +struct ratio_string { + static std::string symbol(); +}; +template <> +struct ratio_string { + static std::string symbol(); +}; +template <> +struct ratio_string { + static std::string symbol(); +}; + + //////////// + // std::chrono::duration specializations + template + struct StringMaker> { + static std::string convert(std::chrono::duration const& duration) { + ReusableStringStream rss; + rss << duration.count() << ' ' << ratio_string::symbol() << 's'; + return rss.str(); + } + }; + template + struct StringMaker>> { + static std::string convert(std::chrono::duration> const& duration) { + ReusableStringStream rss; + rss << duration.count() << " s"; + return rss.str(); + } + }; + template + struct StringMaker>> { + static std::string convert(std::chrono::duration> const& duration) { + ReusableStringStream rss; + rss << duration.count() << " m"; + return rss.str(); + } + }; + template + struct StringMaker>> { + static std::string convert(std::chrono::duration> const& duration) { + ReusableStringStream rss; + rss << duration.count() << " h"; + return rss.str(); + } + }; + + //////////// + // std::chrono::time_point specialization + // Generic time_point cannot be specialized, only std::chrono::time_point + template + struct StringMaker> { + static std::string convert(std::chrono::time_point const& time_point) { + return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch"; + } + }; + // std::chrono::time_point specialization + template + struct StringMaker> { + static std::string convert(std::chrono::time_point const& time_point) { + auto converted = std::chrono::system_clock::to_time_t(time_point); + +#ifdef _MSC_VER + std::tm timeInfo = {}; + gmtime_s(&timeInfo, &converted); +#else + std::tm* timeInfo = std::gmtime(&converted); +#endif + + auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); + char timeStamp[timeStampSize]; + const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; + +#ifdef _MSC_VER + std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); +#else + std::strftime(timeStamp, timeStampSize, fmt, timeInfo); +#endif + return std::string(timeStamp); + } + }; +} +#endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// end catch_tostring.h +#include + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4389) // '==' : signed/unsigned mismatch +#pragma warning(disable:4018) // more "signed/unsigned mismatch" +#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) +#pragma warning(disable:4180) // qualifier applied to function type has no meaning +#endif + +namespace Catch { + + struct ITransientExpression { + auto isBinaryExpression() const -> bool { return m_isBinaryExpression; } + auto getResult() const -> bool { return m_result; } + virtual void streamReconstructedExpression( std::ostream &os ) const = 0; + + ITransientExpression( bool isBinaryExpression, bool result ) + : m_isBinaryExpression( isBinaryExpression ), + m_result( result ) + {} + + // We don't actually need a virtual destructor, but many static analysers + // complain if it's not here :-( + virtual ~ITransientExpression(); + + bool m_isBinaryExpression; + bool m_result; + + }; + + void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ); + + template + class BinaryExpr : public ITransientExpression { + LhsT m_lhs; + StringRef m_op; + RhsT m_rhs; + + void streamReconstructedExpression( std::ostream &os ) const override { + formatReconstructedExpression + ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) ); + } + + public: + BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs ) + : ITransientExpression{ true, comparisonResult }, + m_lhs( lhs ), + m_op( op ), + m_rhs( rhs ) + {} + }; + + template + class UnaryExpr : public ITransientExpression { + LhsT m_lhs; + + void streamReconstructedExpression( std::ostream &os ) const override { + os << Catch::Detail::stringify( m_lhs ); + } + + public: + explicit UnaryExpr( LhsT lhs ) + : ITransientExpression{ false, lhs ? true : false }, + m_lhs( lhs ) + {} + }; + + // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int) + template + auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast(lhs == rhs); } + template + auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast( rhs ); } + template + auto compareEqual( T* const& lhs, long rhs ) -> bool { return lhs == reinterpret_cast( rhs ); } + template + auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) == rhs; } + template + auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) == rhs; } + + template + auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast(lhs != rhs); } + template + auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast( rhs ); } + template + auto compareNotEqual( T* const& lhs, long rhs ) -> bool { return lhs != reinterpret_cast( rhs ); } + template + auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) != rhs; } + template + auto compareNotEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) != rhs; } + + template + class ExprLhs { + LhsT m_lhs; + public: + explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} + + template + auto operator == ( RhsT const& rhs ) -> BinaryExpr const { + return { compareEqual( m_lhs, rhs ), m_lhs, "==", rhs }; + } + auto operator == ( bool rhs ) -> BinaryExpr const { + return { m_lhs == rhs, m_lhs, "==", rhs }; + } + + template + auto operator != ( RhsT const& rhs ) -> BinaryExpr const { + return { compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs }; + } + auto operator != ( bool rhs ) -> BinaryExpr const { + return { m_lhs != rhs, m_lhs, "!=", rhs }; + } + + template + auto operator > ( RhsT const& rhs ) -> BinaryExpr const { + return { static_cast(m_lhs > rhs), m_lhs, ">", rhs }; + } + template + auto operator < ( RhsT const& rhs ) -> BinaryExpr const { + return { static_cast(m_lhs < rhs), m_lhs, "<", rhs }; + } + template + auto operator >= ( RhsT const& rhs ) -> BinaryExpr const { + return { static_cast(m_lhs >= rhs), m_lhs, ">=", rhs }; + } + template + auto operator <= ( RhsT const& rhs ) -> BinaryExpr const { + return { static_cast(m_lhs <= rhs), m_lhs, "<=", rhs }; + } + + auto makeUnaryExpr() const -> UnaryExpr { + return UnaryExpr{ m_lhs }; + } + }; + + void handleExpression( ITransientExpression const& expr ); + + template + void handleExpression( ExprLhs const& expr ) { + handleExpression( expr.makeUnaryExpr() ); + } + + struct Decomposer { + template + auto operator <= ( T const& lhs ) -> ExprLhs { + return ExprLhs{ lhs }; + } + + auto operator <=( bool value ) -> ExprLhs { + return ExprLhs{ value }; + } + }; + +} // end namespace Catch + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// end catch_decomposer.h +// start catch_interfaces_capture.h + +#include + +namespace Catch { + + class AssertionResult; + struct AssertionInfo; + struct SectionInfo; + struct SectionEndInfo; + struct MessageInfo; + struct Counts; + struct BenchmarkInfo; + struct BenchmarkStats; + struct AssertionReaction; + + struct ITransientExpression; + + struct IResultCapture { + + virtual ~IResultCapture(); + + virtual bool sectionStarted( SectionInfo const& sectionInfo, + Counts& assertions ) = 0; + virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; + + virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0; + virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0; + + virtual void pushScopedMessage( MessageInfo const& message ) = 0; + virtual void popScopedMessage( MessageInfo const& message ) = 0; + + virtual void handleFatalErrorCondition( StringRef message ) = 0; + + virtual void handleExpr + ( AssertionInfo const& info, + ITransientExpression const& expr, + AssertionReaction& reaction ) = 0; + virtual void handleMessage + ( AssertionInfo const& info, + ResultWas::OfType resultType, + StringRef const& message, + AssertionReaction& reaction ) = 0; + virtual void handleUnexpectedExceptionNotThrown + ( AssertionInfo const& info, + AssertionReaction& reaction ) = 0; + virtual void handleUnexpectedInflightException + ( AssertionInfo const& info, + std::string const& message, + AssertionReaction& reaction ) = 0; + virtual void handleIncomplete + ( AssertionInfo const& info ) = 0; + virtual void handleNonExpr + ( AssertionInfo const &info, + ResultWas::OfType resultType, + AssertionReaction &reaction ) = 0; + + virtual bool lastAssertionPassed() = 0; + virtual void assertionPassed() = 0; + + // Deprecated, do not use: + virtual std::string getCurrentTestName() const = 0; + virtual const AssertionResult* getLastResult() const = 0; + virtual void exceptionEarlyReported() = 0; + }; + + IResultCapture& getResultCapture(); +} + +// end catch_interfaces_capture.h +namespace Catch { + + struct TestFailureException{}; + struct AssertionResultData; + struct IResultCapture; + class RunContext; + + class LazyExpression { + friend class AssertionHandler; + friend struct AssertionStats; + friend class RunContext; + + ITransientExpression const* m_transientExpression = nullptr; + bool m_isNegated; + public: + LazyExpression( bool isNegated ); + LazyExpression( LazyExpression const& other ); + LazyExpression& operator = ( LazyExpression const& ) = delete; + + explicit operator bool() const; + + friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; + }; + + struct AssertionReaction { + bool shouldDebugBreak = false; + bool shouldThrow = false; + }; + + class AssertionHandler { + AssertionInfo m_assertionInfo; + AssertionReaction m_reaction; + bool m_completed = false; + IResultCapture& m_resultCapture; + + public: + AssertionHandler + ( StringRef macroName, + SourceLineInfo const& lineInfo, + StringRef capturedExpression, + ResultDisposition::Flags resultDisposition ); + ~AssertionHandler() { + if ( !m_completed ) { + m_resultCapture.handleIncomplete( m_assertionInfo ); + } + } + + template + void handleExpr( ExprLhs const& expr ) { + handleExpr( expr.makeUnaryExpr() ); + } + void handleExpr( ITransientExpression const& expr ); + + void handleMessage(ResultWas::OfType resultType, StringRef const& message); + + void handleExceptionThrownAsExpected(); + void handleUnexpectedExceptionNotThrown(); + void handleExceptionNotThrownAsExpected(); + void handleThrowingCallSkipped(); + void handleUnexpectedInflightException(); + + void complete(); + void setCompleted(); + + // query + auto allowThrows() const -> bool; + }; + + void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ); + +} // namespace Catch + +// end catch_assertionhandler.h +// start catch_message.h + +#include + +namespace Catch { + + struct MessageInfo { + MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ); + + std::string macroName; + std::string message; + SourceLineInfo lineInfo; + ResultWas::OfType type; + unsigned int sequence; + + bool operator == ( MessageInfo const& other ) const; + bool operator < ( MessageInfo const& other ) const; + private: + static unsigned int globalCount; + }; + + struct MessageStream { + + template + MessageStream& operator << ( T const& value ) { + m_stream << value; + return *this; + } + + ReusableStringStream m_stream; + }; + + struct MessageBuilder : MessageStream { + MessageBuilder( std::string const& macroName, + SourceLineInfo const& lineInfo, + ResultWas::OfType type ); + + template + MessageBuilder& operator << ( T const& value ) { + m_stream << value; + return *this; + } + + MessageInfo m_info; + }; + + class ScopedMessage { + public: + explicit ScopedMessage( MessageBuilder const& builder ); + ~ScopedMessage(); + + MessageInfo m_info; + }; + +} // end namespace Catch + +// end catch_message.h +#if !defined(CATCH_CONFIG_DISABLE) + +#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) + #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__ +#else + #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION" +#endif + +#if defined(CATCH_CONFIG_FAST_COMPILE) + +/////////////////////////////////////////////////////////////////////////////// +// Another way to speed-up compilation is to omit local try-catch for REQUIRE* +// macros. +#define INTERNAL_CATCH_TRY +#define INTERNAL_CATCH_CATCH( capturer ) + +#else // CATCH_CONFIG_FAST_COMPILE + +#define INTERNAL_CATCH_TRY try +#define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); } + +#endif + +#define INTERNAL_CATCH_REACT( handler ) handler.complete(); + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ + INTERNAL_CATCH_TRY { \ + CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \ + CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ + } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( (void)0, false && static_cast( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look + // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \ + INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ + if( Catch::getResultCapture().lastAssertionPassed() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \ + INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ + if( !Catch::getResultCapture().lastAssertionPassed() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ + try { \ + static_cast(__VA_ARGS__); \ + catchAssertionHandler.handleExceptionNotThrownAsExpected(); \ + } \ + catch( ... ) { \ + catchAssertionHandler.handleUnexpectedInflightException(); \ + } \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \ + if( catchAssertionHandler.allowThrows() ) \ + try { \ + static_cast(__VA_ARGS__); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ + } \ + catch( ... ) { \ + catchAssertionHandler.handleExceptionThrownAsExpected(); \ + } \ + else \ + catchAssertionHandler.handleThrowingCallSkipped(); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \ + if( catchAssertionHandler.allowThrows() ) \ + try { \ + static_cast(expr); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ + } \ + catch( exceptionType const& ) { \ + catchAssertionHandler.handleExceptionThrownAsExpected(); \ + } \ + catch( ... ) { \ + catchAssertionHandler.handleUnexpectedInflightException(); \ + } \ + else \ + catchAssertionHandler.handleThrowingCallSkipped(); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_INFO( macroName, log ) \ + Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ); + +/////////////////////////////////////////////////////////////////////////////// +// Although this is matcher-based, it can be used with just a string +#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ + if( catchAssertionHandler.allowThrows() ) \ + try { \ + static_cast(__VA_ARGS__); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ + } \ + catch( ... ) { \ + Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \ + } \ + else \ + catchAssertionHandler.handleThrowingCallSkipped(); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) + +#endif // CATCH_CONFIG_DISABLE + +// end catch_capture.hpp +// start catch_section.h + +// start catch_section_info.h + +// start catch_totals.h + +#include + +namespace Catch { + + struct Counts { + Counts operator - ( Counts const& other ) const; + Counts& operator += ( Counts const& other ); + + std::size_t total() const; + bool allPassed() const; + bool allOk() const; + + std::size_t passed = 0; + std::size_t failed = 0; + std::size_t failedButOk = 0; + }; + + struct Totals { + + Totals operator - ( Totals const& other ) const; + Totals& operator += ( Totals const& other ); + + Totals delta( Totals const& prevTotals ) const; + + int error = 0; + Counts assertions; + Counts testCases; + }; +} + +// end catch_totals.h +#include + +namespace Catch { + + struct SectionInfo { + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description = std::string() ); + + std::string name; + std::string description; + SourceLineInfo lineInfo; + }; + + struct SectionEndInfo { + SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ); + + SectionInfo sectionInfo; + Counts prevAssertions; + double durationInSeconds; + }; + +} // end namespace Catch + +// end catch_section_info.h +// start catch_timer.h + +#include + +namespace Catch { + + auto getCurrentNanosecondsSinceEpoch() -> uint64_t; + auto getEstimatedClockResolution() -> uint64_t; + + class Timer { + uint64_t m_nanoseconds = 0; + public: + void start(); + auto getElapsedNanoseconds() const -> uint64_t; + auto getElapsedMicroseconds() const -> uint64_t; + auto getElapsedMilliseconds() const -> unsigned int; + auto getElapsedSeconds() const -> double; + }; + +} // namespace Catch + +// end catch_timer.h +#include + +namespace Catch { + + class Section : NonCopyable { + public: + Section( SectionInfo const& info ); + ~Section(); + + // This indicates whether the section should be executed or not + explicit operator bool() const; + + private: + SectionInfo m_info; + + std::string m_name; + Counts m_assertions; + bool m_sectionIncluded; + Timer m_timer; + }; + +} // end namespace Catch + + #define INTERNAL_CATCH_SECTION( ... ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) + +// end catch_section.h +// start catch_benchmark.h + +#include +#include + +namespace Catch { + + class BenchmarkLooper { + + std::string m_name; + std::size_t m_count = 0; + std::size_t m_iterationsToRun = 1; + uint64_t m_resolution; + Timer m_timer; + + static auto getResolution() -> uint64_t; + public: + // Keep most of this inline as it's on the code path that is being timed + BenchmarkLooper( StringRef name ) + : m_name( name ), + m_resolution( getResolution() ) + { + reportStart(); + m_timer.start(); + } + + explicit operator bool() { + if( m_count < m_iterationsToRun ) + return true; + return needsMoreIterations(); + } + + void increment() { + ++m_count; + } + + void reportStart(); + auto needsMoreIterations() -> bool; + }; + +} // end namespace Catch + +#define BENCHMARK( name ) \ + for( Catch::BenchmarkLooper looper( name ); looper; looper.increment() ) + +// end catch_benchmark.h +// start catch_interfaces_exception.h + +// start catch_interfaces_registry_hub.h + +#include +#include + +namespace Catch { + + class TestCase; + struct ITestCaseRegistry; + struct IExceptionTranslatorRegistry; + struct IExceptionTranslator; + struct IReporterRegistry; + struct IReporterFactory; + struct ITagAliasRegistry; + class StartupExceptionRegistry; + + using IReporterFactoryPtr = std::shared_ptr; + + struct IRegistryHub { + virtual ~IRegistryHub(); + + virtual IReporterRegistry const& getReporterRegistry() const = 0; + virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; + virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; + + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; + + virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0; + }; + + struct IMutableRegistryHub { + virtual ~IMutableRegistryHub(); + virtual void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) = 0; + virtual void registerListener( IReporterFactoryPtr const& factory ) = 0; + virtual void registerTest( TestCase const& testInfo ) = 0; + virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; + virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; + virtual void registerStartupException() noexcept = 0; + }; + + IRegistryHub& getRegistryHub(); + IMutableRegistryHub& getMutableRegistryHub(); + void cleanUp(); + std::string translateActiveException(); + +} + +// end catch_interfaces_registry_hub.h +#if defined(CATCH_CONFIG_DISABLE) + #define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \ + static std::string translatorName( signature ) +#endif + +#include +#include +#include + +namespace Catch { + using exceptionTranslateFunction = std::string(*)(); + + struct IExceptionTranslator; + using ExceptionTranslators = std::vector>; + + struct IExceptionTranslator { + virtual ~IExceptionTranslator(); + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; + }; + + struct IExceptionTranslatorRegistry { + virtual ~IExceptionTranslatorRegistry(); + + virtual std::string translateActiveException() const = 0; + }; + + class ExceptionTranslatorRegistrar { + template + class ExceptionTranslator : public IExceptionTranslator { + public: + + ExceptionTranslator( std::string(*translateFunction)( T& ) ) + : m_translateFunction( translateFunction ) + {} + + std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override { + try { + if( it == itEnd ) + std::rethrow_exception(std::current_exception()); + else + return (*it)->translate( it+1, itEnd ); + } + catch( T& ex ) { + return m_translateFunction( ex ); + } + } + + protected: + std::string(*m_translateFunction)( T& ); + }; + + public: + template + ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { + getMutableRegistryHub().registerTranslator + ( new ExceptionTranslator( translateFunction ) ); + } + }; +} + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \ + static std::string translatorName( signature ); \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ + static std::string translatorName( signature ) + +#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) + +// end catch_interfaces_exception.h +// start catch_approx.h + +#include +#include + +namespace Catch { +namespace Detail { + + class Approx { + private: + bool equalityComparisonImpl(double other) const; + + public: + explicit Approx ( double value ); + + static Approx custom(); + + template ::value>::type> + Approx operator()( T const& value ) { + Approx approx( static_cast(value) ); + approx.epsilon( m_epsilon ); + approx.margin( m_margin ); + approx.scale( m_scale ); + return approx; + } + + template ::value>::type> + explicit Approx( T const& value ): Approx(static_cast(value)) + {} + + template ::value>::type> + friend bool operator == ( const T& lhs, Approx const& rhs ) { + auto lhs_v = static_cast(lhs); + return rhs.equalityComparisonImpl(lhs_v); + } + + template ::value>::type> + friend bool operator == ( Approx const& lhs, const T& rhs ) { + return operator==( rhs, lhs ); + } + + template ::value>::type> + friend bool operator != ( T const& lhs, Approx const& rhs ) { + return !operator==( lhs, rhs ); + } + + template ::value>::type> + friend bool operator != ( Approx const& lhs, T const& rhs ) { + return !operator==( rhs, lhs ); + } + + template ::value>::type> + friend bool operator <= ( T const& lhs, Approx const& rhs ) { + return static_cast(lhs) < rhs.m_value || lhs == rhs; + } + + template ::value>::type> + friend bool operator <= ( Approx const& lhs, T const& rhs ) { + return lhs.m_value < static_cast(rhs) || lhs == rhs; + } + + template ::value>::type> + friend bool operator >= ( T const& lhs, Approx const& rhs ) { + return static_cast(lhs) > rhs.m_value || lhs == rhs; + } + + template ::value>::type> + friend bool operator >= ( Approx const& lhs, T const& rhs ) { + return lhs.m_value > static_cast(rhs) || lhs == rhs; + } + + template ::value>::type> + Approx& epsilon( T const& newEpsilon ) { + double epsilonAsDouble = static_cast(newEpsilon); + if( epsilonAsDouble < 0 || epsilonAsDouble > 1.0 ) { + throw std::domain_error + ( "Invalid Approx::epsilon: " + + Catch::Detail::stringify( epsilonAsDouble ) + + ", Approx::epsilon has to be between 0 and 1" ); + } + m_epsilon = epsilonAsDouble; + return *this; + } + + template ::value>::type> + Approx& margin( T const& newMargin ) { + double marginAsDouble = static_cast(newMargin); + if( marginAsDouble < 0 ) { + throw std::domain_error + ( "Invalid Approx::margin: " + + Catch::Detail::stringify( marginAsDouble ) + + ", Approx::Margin has to be non-negative." ); + + } + m_margin = marginAsDouble; + return *this; + } + + template ::value>::type> + Approx& scale( T const& newScale ) { + m_scale = static_cast(newScale); + return *this; + } + + std::string toString() const; + + private: + double m_epsilon; + double m_margin; + double m_scale; + double m_value; + }; +} + +template<> +struct StringMaker { + static std::string convert(Catch::Detail::Approx const& value); +}; + +} // end namespace Catch + +// end catch_approx.h +// start catch_string_manip.h + +#include +#include + +namespace Catch { + + bool startsWith( std::string const& s, std::string const& prefix ); + bool startsWith( std::string const& s, char prefix ); + bool endsWith( std::string const& s, std::string const& suffix ); + bool endsWith( std::string const& s, char suffix ); + bool contains( std::string const& s, std::string const& infix ); + void toLowerInPlace( std::string& s ); + std::string toLower( std::string const& s ); + std::string trim( std::string const& str ); + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); + + struct pluralise { + pluralise( std::size_t count, std::string const& label ); + + friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); + + std::size_t m_count; + std::string m_label; + }; +} + +// end catch_string_manip.h +#ifndef CATCH_CONFIG_DISABLE_MATCHERS +// start catch_capture_matchers.h + +// start catch_matchers.h + +#include +#include + +namespace Catch { +namespace Matchers { + namespace Impl { + + template struct MatchAllOf; + template struct MatchAnyOf; + template struct MatchNotOf; + + class MatcherUntypedBase { + public: + MatcherUntypedBase() = default; + MatcherUntypedBase ( MatcherUntypedBase const& ) = default; + MatcherUntypedBase& operator = ( MatcherUntypedBase const& ) = delete; + std::string toString() const; + + protected: + virtual ~MatcherUntypedBase(); + virtual std::string describe() const = 0; + mutable std::string m_cachedToString; + }; + + template + struct MatcherMethod { + virtual bool match( ObjectT const& arg ) const = 0; + }; + template + struct MatcherMethod { + virtual bool match( PtrT* arg ) const = 0; + }; + + template + struct MatcherBase : MatcherUntypedBase, MatcherMethod { + + MatchAllOf operator && ( MatcherBase const& other ) const; + MatchAnyOf operator || ( MatcherBase const& other ) const; + MatchNotOf operator ! () const; + }; + + template + struct MatchAllOf : MatcherBase { + bool match( ArgT const& arg ) const override { + for( auto matcher : m_matchers ) { + if (!matcher->match(arg)) + return false; + } + return true; + } + std::string describe() const override { + std::string description; + description.reserve( 4 + m_matchers.size()*32 ); + description += "( "; + bool first = true; + for( auto matcher : m_matchers ) { + if( first ) + first = false; + else + description += " and "; + description += matcher->toString(); + } + description += " )"; + return description; + } + + MatchAllOf& operator && ( MatcherBase const& other ) { + m_matchers.push_back( &other ); + return *this; + } + + std::vector const*> m_matchers; + }; + template + struct MatchAnyOf : MatcherBase { + + bool match( ArgT const& arg ) const override { + for( auto matcher : m_matchers ) { + if (matcher->match(arg)) + return true; + } + return false; + } + std::string describe() const override { + std::string description; + description.reserve( 4 + m_matchers.size()*32 ); + description += "( "; + bool first = true; + for( auto matcher : m_matchers ) { + if( first ) + first = false; + else + description += " or "; + description += matcher->toString(); + } + description += " )"; + return description; + } + + MatchAnyOf& operator || ( MatcherBase const& other ) { + m_matchers.push_back( &other ); + return *this; + } + + std::vector const*> m_matchers; + }; + + template + struct MatchNotOf : MatcherBase { + + MatchNotOf( MatcherBase const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} + + bool match( ArgT const& arg ) const override { + return !m_underlyingMatcher.match( arg ); + } + + std::string describe() const override { + return "not " + m_underlyingMatcher.toString(); + } + MatcherBase const& m_underlyingMatcher; + }; + + template + MatchAllOf MatcherBase::operator && ( MatcherBase const& other ) const { + return MatchAllOf() && *this && other; + } + template + MatchAnyOf MatcherBase::operator || ( MatcherBase const& other ) const { + return MatchAnyOf() || *this || other; + } + template + MatchNotOf MatcherBase::operator ! () const { + return MatchNotOf( *this ); + } + + } // namespace Impl + +} // namespace Matchers + +using namespace Matchers; +using Matchers::Impl::MatcherBase; + +} // namespace Catch + +// end catch_matchers.h +// start catch_matchers_floating.h + +#include +#include + +namespace Catch { +namespace Matchers { + + namespace Floating { + + enum class FloatingPointKind : uint8_t; + + struct WithinAbsMatcher : MatcherBase { + WithinAbsMatcher(double target, double margin); + bool match(double const& matchee) const override; + std::string describe() const override; + private: + double m_target; + double m_margin; + }; + + struct WithinUlpsMatcher : MatcherBase { + WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType); + bool match(double const& matchee) const override; + std::string describe() const override; + private: + double m_target; + int m_ulps; + FloatingPointKind m_type; + }; + + } // namespace Floating + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff); + Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff); + Floating::WithinAbsMatcher WithinAbs(double target, double margin); + +} // namespace Matchers +} // namespace Catch + +// end catch_matchers_floating.h +// start catch_matchers_generic.hpp + +#include +#include + +namespace Catch { +namespace Matchers { +namespace Generic { + +namespace Detail { + std::string finalizeDescription(const std::string& desc); +} + +template +class PredicateMatcher : public MatcherBase { + std::function m_predicate; + std::string m_description; +public: + + PredicateMatcher(std::function const& elem, std::string const& descr) + :m_predicate(std::move(elem)), + m_description(Detail::finalizeDescription(descr)) + {} + + bool match( T const& item ) const override { + return m_predicate(item); + } + + std::string describe() const override { + return m_description; + } +}; + +} // namespace Generic + + // The following functions create the actual matcher objects. + // The user has to explicitly specify type to the function, because + // infering std::function is hard (but possible) and + // requires a lot of TMP. + template + Generic::PredicateMatcher Predicate(std::function const& predicate, std::string const& description = "") { + return Generic::PredicateMatcher(predicate, description); + } + +} // namespace Matchers +} // namespace Catch + +// end catch_matchers_generic.hpp +// start catch_matchers_string.h + +#include + +namespace Catch { +namespace Matchers { + + namespace StdString { + + struct CasedString + { + CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ); + std::string adjustString( std::string const& str ) const; + std::string caseSensitivitySuffix() const; + + CaseSensitive::Choice m_caseSensitivity; + std::string m_str; + }; + + struct StringMatcherBase : MatcherBase { + StringMatcherBase( std::string const& operation, CasedString const& comparator ); + std::string describe() const override; + + CasedString m_comparator; + std::string m_operation; + }; + + struct EqualsMatcher : StringMatcherBase { + EqualsMatcher( CasedString const& comparator ); + bool match( std::string const& source ) const override; + }; + struct ContainsMatcher : StringMatcherBase { + ContainsMatcher( CasedString const& comparator ); + bool match( std::string const& source ) const override; + }; + struct StartsWithMatcher : StringMatcherBase { + StartsWithMatcher( CasedString const& comparator ); + bool match( std::string const& source ) const override; + }; + struct EndsWithMatcher : StringMatcherBase { + EndsWithMatcher( CasedString const& comparator ); + bool match( std::string const& source ) const override; + }; + + struct RegexMatcher : MatcherBase { + RegexMatcher( std::string regex, CaseSensitive::Choice caseSensitivity ); + bool match( std::string const& matchee ) const override; + std::string describe() const override; + + private: + std::string m_regex; + CaseSensitive::Choice m_caseSensitivity; + }; + + } // namespace StdString + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + + StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + StdString::RegexMatcher Matches( std::string const& regex, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); + +} // namespace Matchers +} // namespace Catch + +// end catch_matchers_string.h +// start catch_matchers_vector.h + +#include + +namespace Catch { +namespace Matchers { + + namespace Vector { + namespace Detail { + template + size_t count(InputIterator first, InputIterator last, T const& item) { + size_t cnt = 0; + for (; first != last; ++first) { + if (*first == item) { + ++cnt; + } + } + return cnt; + } + template + bool contains(InputIterator first, InputIterator last, T const& item) { + for (; first != last; ++first) { + if (*first == item) { + return true; + } + } + return false; + } + } + + template + struct ContainsElementMatcher : MatcherBase> { + + ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} + + bool match(std::vector const &v) const override { + for (auto const& el : v) { + if (el == m_comparator) { + return true; + } + } + return false; + } + + std::string describe() const override { + return "Contains: " + ::Catch::Detail::stringify( m_comparator ); + } + + T const& m_comparator; + }; + + template + struct ContainsMatcher : MatcherBase> { + + ContainsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} + + bool match(std::vector const &v) const override { + // !TBD: see note in EqualsMatcher + if (m_comparator.size() > v.size()) + return false; + for (auto const& comparator : m_comparator) { + auto present = false; + for (const auto& el : v) { + if (el == comparator) { + present = true; + break; + } + } + if (!present) { + return false; + } + } + return true; + } + std::string describe() const override { + return "Contains: " + ::Catch::Detail::stringify( m_comparator ); + } + + std::vector const& m_comparator; + }; + + template + struct EqualsMatcher : MatcherBase> { + + EqualsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} + + bool match(std::vector const &v) const override { + // !TBD: This currently works if all elements can be compared using != + // - a more general approach would be via a compare template that defaults + // to using !=. but could be specialised for, e.g. std::vector etc + // - then just call that directly + if (m_comparator.size() != v.size()) + return false; + for (std::size_t i = 0; i < v.size(); ++i) + if (m_comparator[i] != v[i]) + return false; + return true; + } + std::string describe() const override { + return "Equals: " + ::Catch::Detail::stringify( m_comparator ); + } + std::vector const& m_comparator; + }; + + template + struct UnorderedEqualsMatcher : MatcherBase> { + UnorderedEqualsMatcher(std::vector const& target) : m_target(target) {} + bool match(std::vector const& vec) const override { + // Note: This is a reimplementation of std::is_permutation, + // because I don't want to include inside the common path + if (m_target.size() != vec.size()) { + return false; + } + auto lfirst = m_target.begin(), llast = m_target.end(); + auto rfirst = vec.begin(), rlast = vec.end(); + // Cut common prefix to optimize checking of permuted parts + while (lfirst != llast && *lfirst != *rfirst) { + ++lfirst; ++rfirst; + } + if (lfirst == llast) { + return true; + } + + for (auto mid = lfirst; mid != llast; ++mid) { + // Skip already counted items + if (Detail::contains(lfirst, mid, *mid)) { + continue; + } + size_t num_vec = Detail::count(rfirst, rlast, *mid); + if (num_vec == 0 || Detail::count(lfirst, llast, *mid) != num_vec) { + return false; + } + } + + return true; + } + + std::string describe() const override { + return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target); + } + private: + std::vector const& m_target; + }; + + } // namespace Vector + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + + template + Vector::ContainsMatcher Contains( std::vector const& comparator ) { + return Vector::ContainsMatcher( comparator ); + } + + template + Vector::ContainsElementMatcher VectorContains( T const& comparator ) { + return Vector::ContainsElementMatcher( comparator ); + } + + template + Vector::EqualsMatcher Equals( std::vector const& comparator ) { + return Vector::EqualsMatcher( comparator ); + } + + template + Vector::UnorderedEqualsMatcher UnorderedEquals(std::vector const& target) { + return Vector::UnorderedEqualsMatcher(target); + } + +} // namespace Matchers +} // namespace Catch + +// end catch_matchers_vector.h +namespace Catch { + + template + class MatchExpr : public ITransientExpression { + ArgT const& m_arg; + MatcherT m_matcher; + StringRef m_matcherString; + public: + MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) + : ITransientExpression{ true, matcher.match( arg ) }, + m_arg( arg ), + m_matcher( matcher ), + m_matcherString( matcherString ) + {} + + void streamReconstructedExpression( std::ostream &os ) const override { + auto matcherAsString = m_matcher.toString(); + os << Catch::Detail::stringify( m_arg ) << ' '; + if( matcherAsString == Detail::unprintableString ) + os << m_matcherString; + else + os << matcherAsString; + } + }; + + using StringMatcher = Matchers::Impl::MatcherBase; + + void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ); + + template + auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) -> MatchExpr { + return MatchExpr( arg, matcher, matcherString ); + } + +} // namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ + INTERNAL_CATCH_TRY { \ + catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \ + } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \ + do { \ + Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ + if( catchAssertionHandler.allowThrows() ) \ + try { \ + static_cast(__VA_ARGS__ ); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ + } \ + catch( exceptionType const& ex ) { \ + catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \ + } \ + catch( ... ) { \ + catchAssertionHandler.handleUnexpectedInflightException(); \ + } \ + else \ + catchAssertionHandler.handleThrowingCallSkipped(); \ + INTERNAL_CATCH_REACT( catchAssertionHandler ) \ + } while( false ) + +// end catch_capture_matchers.h +#endif + +// These files are included here so the single_include script doesn't put them +// in the conditionally compiled sections +// start catch_test_case_info.h + +#include +#include +#include + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + struct ITestInvoker; + + struct TestCaseInfo { + enum SpecialProperties{ + None = 0, + IsHidden = 1 << 1, + ShouldFail = 1 << 2, + MayFail = 1 << 3, + Throws = 1 << 4, + NonPortable = 1 << 5, + Benchmark = 1 << 6 + }; + + TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::vector const& _tags, + SourceLineInfo const& _lineInfo ); + + friend void setTags( TestCaseInfo& testCaseInfo, std::vector tags ); + + bool isHidden() const; + bool throws() const; + bool okToFail() const; + bool expectedToFail() const; + + std::string tagsAsString() const; + + std::string name; + std::string className; + std::string description; + std::vector tags; + std::vector lcaseTags; + SourceLineInfo lineInfo; + SpecialProperties properties; + }; + + class TestCase : public TestCaseInfo { + public: + + TestCase( ITestInvoker* testCase, TestCaseInfo&& info ); + + TestCase withName( std::string const& _newName ) const; + + void invoke() const; + + TestCaseInfo const& getTestCaseInfo() const; + + bool operator == ( TestCase const& other ) const; + bool operator < ( TestCase const& other ) const; + + private: + std::shared_ptr test; + }; + + TestCase makeTestCase( ITestInvoker* testCase, + std::string const& className, + NameAndTags const& nameAndTags, + SourceLineInfo const& lineInfo ); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// end catch_test_case_info.h +// start catch_interfaces_runner.h + +namespace Catch { + + struct IRunner { + virtual ~IRunner(); + virtual bool aborting() const = 0; + }; +} + +// end catch_interfaces_runner.h + +#ifdef __OBJC__ +// start catch_objc.hpp + +#import + +#include + +// NB. Any general catch headers included here must be included +// in catch.hpp first to make sure they are included by the single +// header for non obj-usage + +/////////////////////////////////////////////////////////////////////////////// +// This protocol is really only here for (self) documenting purposes, since +// all its methods are optional. +@protocol OcFixture + +@optional + +-(void) setUp; +-(void) tearDown; + +@end + +namespace Catch { + + class OcMethod : public ITestInvoker { + + public: + OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} + + virtual void invoke() const { + id obj = [[m_cls alloc] init]; + + performOptionalSelector( obj, @selector(setUp) ); + performOptionalSelector( obj, m_sel ); + performOptionalSelector( obj, @selector(tearDown) ); + + arcSafeRelease( obj ); + } + private: + virtual ~OcMethod() {} + + Class m_cls; + SEL m_sel; + }; + + namespace Detail{ + + inline std::string getAnnotation( Class cls, + std::string const& annotationName, + std::string const& testCaseName ) { + NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; + SEL sel = NSSelectorFromString( selStr ); + arcSafeRelease( selStr ); + id value = performOptionalSelector( cls, sel ); + if( value ) + return [(NSString*)value UTF8String]; + return ""; + } + } + + inline std::size_t registerTestMethods() { + std::size_t noTestMethods = 0; + int noClasses = objc_getClassList( nullptr, 0 ); + + Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); + objc_getClassList( classes, noClasses ); + + for( int c = 0; c < noClasses; c++ ) { + Class cls = classes[c]; + { + u_int count; + Method* methods = class_copyMethodList( cls, &count ); + for( u_int m = 0; m < count ; m++ ) { + SEL selector = method_getName(methods[m]); + std::string methodName = sel_getName(selector); + if( startsWith( methodName, "Catch_TestCase_" ) ) { + std::string testCaseName = methodName.substr( 15 ); + std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); + std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); + const char* className = class_getName( cls ); + + getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo("",0) ) ); + noTestMethods++; + } + } + free(methods); + } + } + return noTestMethods; + } + +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) + + namespace Matchers { + namespace Impl { + namespace NSStringMatchers { + + struct StringHolder : MatcherBase{ + StringHolder( NSString* substr ) : m_substr( [substr copy] ){} + StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} + StringHolder() { + arcSafeRelease( m_substr ); + } + + bool match( NSString* arg ) const override { + return false; + } + + NSString* CATCH_ARC_STRONG m_substr; + }; + + struct Equals : StringHolder { + Equals( NSString* substr ) : StringHolder( substr ){} + + bool match( NSString* str ) const override { + return (str != nil || m_substr == nil ) && + [str isEqualToString:m_substr]; + } + + std::string describe() const override { + return "equals string: " + Catch::Detail::stringify( m_substr ); + } + }; + + struct Contains : StringHolder { + Contains( NSString* substr ) : StringHolder( substr ){} + + bool match( NSString* str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location != NSNotFound; + } + + std::string describe() const override { + return "contains string: " + Catch::Detail::stringify( m_substr ); + } + }; + + struct StartsWith : StringHolder { + StartsWith( NSString* substr ) : StringHolder( substr ){} + + bool match( NSString* str ) const override { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == 0; + } + + std::string describe() const override { + return "starts with: " + Catch::Detail::stringify( m_substr ); + } + }; + struct EndsWith : StringHolder { + EndsWith( NSString* substr ) : StringHolder( substr ){} + + bool match( NSString* str ) const override { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == [str length] - [m_substr length]; + } + + std::string describe() const override { + return "ends with: " + Catch::Detail::stringify( m_substr ); + } + }; + + } // namespace NSStringMatchers + } // namespace Impl + + inline Impl::NSStringMatchers::Equals + Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } + + inline Impl::NSStringMatchers::Contains + Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } + + inline Impl::NSStringMatchers::StartsWith + StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } + + inline Impl::NSStringMatchers::EndsWith + EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } + + } // namespace Matchers + + using namespace Matchers; + +#endif // CATCH_CONFIG_DISABLE_MATCHERS + +} // namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define OC_MAKE_UNIQUE_NAME( root, uniqueSuffix ) root##uniqueSuffix +#define OC_TEST_CASE2( name, desc, uniqueSuffix ) \ ++(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Name_test_, uniqueSuffix ) \ +{ \ +return @ name; \ +} \ ++(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Description_test_, uniqueSuffix ) \ +{ \ +return @ desc; \ +} \ +-(void) OC_MAKE_UNIQUE_NAME( Catch_TestCase_test_, uniqueSuffix ) + +#define OC_TEST_CASE( name, desc ) OC_TEST_CASE2( name, desc, __LINE__ ) + +// end catch_objc.hpp +#endif + +#ifdef CATCH_CONFIG_EXTERNAL_INTERFACES +// start catch_external_interfaces.h + +// start catch_reporter_bases.hpp + +// start catch_interfaces_reporter.h + +// start catch_config.hpp + +// start catch_test_spec_parser.h + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// start catch_test_spec.h + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// start catch_wildcard_pattern.h + +namespace Catch +{ + class WildcardPattern { + enum WildcardPosition { + NoWildcard = 0, + WildcardAtStart = 1, + WildcardAtEnd = 2, + WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd + }; + + public: + + WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ); + virtual ~WildcardPattern() = default; + virtual bool matches( std::string const& str ) const; + + private: + std::string adjustCase( std::string const& str ) const; + CaseSensitive::Choice m_caseSensitivity; + WildcardPosition m_wildcard = NoWildcard; + std::string m_pattern; + }; +} + +// end catch_wildcard_pattern.h +#include +#include +#include + +namespace Catch { + + class TestSpec { + struct Pattern { + virtual ~Pattern(); + virtual bool matches( TestCaseInfo const& testCase ) const = 0; + }; + using PatternPtr = std::shared_ptr; + + class NamePattern : public Pattern { + public: + NamePattern( std::string const& name ); + virtual ~NamePattern(); + virtual bool matches( TestCaseInfo const& testCase ) const override; + private: + WildcardPattern m_wildcardPattern; + }; + + class TagPattern : public Pattern { + public: + TagPattern( std::string const& tag ); + virtual ~TagPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const override; + private: + std::string m_tag; + }; + + class ExcludedPattern : public Pattern { + public: + ExcludedPattern( PatternPtr const& underlyingPattern ); + virtual ~ExcludedPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const override; + private: + PatternPtr m_underlyingPattern; + }; + + struct Filter { + std::vector m_patterns; + + bool matches( TestCaseInfo const& testCase ) const; + }; + + public: + bool hasFilters() const; + bool matches( TestCaseInfo const& testCase ) const; + + private: + std::vector m_filters; + + friend class TestSpecParser; + }; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// end catch_test_spec.h +// start catch_interfaces_tag_alias_registry.h + +#include + +namespace Catch { + + struct TagAlias; + + struct ITagAliasRegistry { + virtual ~ITagAliasRegistry(); + // Nullptr if not present + virtual TagAlias const* find( std::string const& alias ) const = 0; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; + + static ITagAliasRegistry const& get(); + }; + +} // end namespace Catch + +// end catch_interfaces_tag_alias_registry.h +namespace Catch { + + class TestSpecParser { + enum Mode{ None, Name, QuotedName, Tag, EscapedName }; + Mode m_mode = None; + bool m_exclusion = false; + std::size_t m_start = std::string::npos, m_pos = 0; + std::string m_arg; + std::vector m_escapeChars; + TestSpec::Filter m_currentFilter; + TestSpec m_testSpec; + ITagAliasRegistry const* m_tagAliases = nullptr; + + public: + TestSpecParser( ITagAliasRegistry const& tagAliases ); + + TestSpecParser& parse( std::string const& arg ); + TestSpec testSpec(); + + private: + void visitChar( char c ); + void startNewMode( Mode mode, std::size_t start ); + void escape(); + std::string subString() const; + + template + void addPattern() { + std::string token = subString(); + for( std::size_t i = 0; i < m_escapeChars.size(); ++i ) + token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 ); + m_escapeChars.clear(); + if( startsWith( token, "exclude:" ) ) { + m_exclusion = true; + token = token.substr( 8 ); + } + if( !token.empty() ) { + TestSpec::PatternPtr pattern = std::make_shared( token ); + if( m_exclusion ) + pattern = std::make_shared( pattern ); + m_currentFilter.m_patterns.push_back( pattern ); + } + m_exclusion = false; + m_mode = None; + } + + void addFilter(); + }; + TestSpec parseTestSpec( std::string const& arg ); + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// end catch_test_spec_parser.h +// start catch_interfaces_config.h + +#include +#include +#include +#include + +namespace Catch { + + enum class Verbosity { + Quiet = 0, + Normal, + High + }; + + struct WarnAbout { enum What { + Nothing = 0x00, + NoAssertions = 0x01, + NoTests = 0x02 + }; }; + + struct ShowDurations { enum OrNot { + DefaultForReporter, + Always, + Never + }; }; + struct RunTests { enum InWhatOrder { + InDeclarationOrder, + InLexicographicalOrder, + InRandomOrder + }; }; + struct UseColour { enum YesOrNo { + Auto, + Yes, + No + }; }; + struct WaitForKeypress { enum When { + Never, + BeforeStart = 1, + BeforeExit = 2, + BeforeStartAndExit = BeforeStart | BeforeExit + }; }; + + class TestSpec; + + struct IConfig : NonCopyable { + + virtual ~IConfig(); + + virtual bool allowThrows() const = 0; + virtual std::ostream& stream() const = 0; + virtual std::string name() const = 0; + virtual bool includeSuccessfulResults() const = 0; + virtual bool shouldDebugBreak() const = 0; + virtual bool warnAboutMissingAssertions() const = 0; + virtual bool warnAboutNoTests() const = 0; + virtual int abortAfter() const = 0; + virtual bool showInvisibles() const = 0; + virtual ShowDurations::OrNot showDurations() const = 0; + virtual TestSpec const& testSpec() const = 0; + virtual bool hasTestFilters() const = 0; + virtual RunTests::InWhatOrder runOrder() const = 0; + virtual unsigned int rngSeed() const = 0; + virtual int benchmarkResolutionMultiple() const = 0; + virtual UseColour::YesOrNo useColour() const = 0; + virtual std::vector const& getSectionsToRun() const = 0; + virtual Verbosity verbosity() const = 0; + }; + + using IConfigPtr = std::shared_ptr; +} + +// end catch_interfaces_config.h +// Libstdc++ doesn't like incomplete classes for unique_ptr + +#include +#include +#include + +#ifndef CATCH_CONFIG_CONSOLE_WIDTH +#define CATCH_CONFIG_CONSOLE_WIDTH 80 +#endif + +namespace Catch { + + struct IStream; + + struct ConfigData { + bool listTests = false; + bool listTags = false; + bool listReporters = false; + bool listTestNamesOnly = false; + + bool showSuccessfulTests = false; + bool shouldDebugBreak = false; + bool noThrow = false; + bool showHelp = false; + bool showInvisibles = false; + bool filenamesAsTags = false; + bool libIdentify = false; + + int abortAfter = -1; + unsigned int rngSeed = 0; + int benchmarkResolutionMultiple = 100; + + Verbosity verbosity = Verbosity::Normal; + WarnAbout::What warnings = WarnAbout::Nothing; + ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter; + RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder; + UseColour::YesOrNo useColour = UseColour::Auto; + WaitForKeypress::When waitForKeypress = WaitForKeypress::Never; + + std::string outputFilename; + std::string name; + std::string processName; +#ifndef CATCH_CONFIG_DEFAULT_REPORTER +#define CATCH_CONFIG_DEFAULT_REPORTER "console" +#endif + std::string reporterName = CATCH_CONFIG_DEFAULT_REPORTER; +#undef CATCH_CONFIG_DEFAULT_REPORTER + + std::vector testsOrTags; + std::vector sectionsToRun; + }; + + class Config : public IConfig { + public: + + Config() = default; + Config( ConfigData const& data ); + virtual ~Config() = default; + + std::string const& getFilename() const; + + bool listTests() const; + bool listTestNamesOnly() const; + bool listTags() const; + bool listReporters() const; + + std::string getProcessName() const; + std::string const& getReporterName() const; + + std::vector const& getTestsOrTags() const; + std::vector const& getSectionsToRun() const override; + + virtual TestSpec const& testSpec() const override; + bool hasTestFilters() const override; + + bool showHelp() const; + + // IConfig interface + bool allowThrows() const override; + std::ostream& stream() const override; + std::string name() const override; + bool includeSuccessfulResults() const override; + bool warnAboutMissingAssertions() const override; + bool warnAboutNoTests() const override; + ShowDurations::OrNot showDurations() const override; + RunTests::InWhatOrder runOrder() const override; + unsigned int rngSeed() const override; + int benchmarkResolutionMultiple() const override; + UseColour::YesOrNo useColour() const override; + bool shouldDebugBreak() const override; + int abortAfter() const override; + bool showInvisibles() const override; + Verbosity verbosity() const override; + + private: + + IStream const* openStream(); + ConfigData m_data; + + std::unique_ptr m_stream; + TestSpec m_testSpec; + bool m_hasTestFilters = false; + }; + +} // end namespace Catch + +// end catch_config.hpp +// start catch_assertionresult.h + +#include + +namespace Catch { + + struct AssertionResultData + { + AssertionResultData() = delete; + + AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression ); + + std::string message; + mutable std::string reconstructedExpression; + LazyExpression lazyExpression; + ResultWas::OfType resultType; + + std::string reconstructExpression() const; + }; + + class AssertionResult { + public: + AssertionResult() = delete; + AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); + + bool isOk() const; + bool succeeded() const; + ResultWas::OfType getResultType() const; + bool hasExpression() const; + bool hasMessage() const; + std::string getExpression() const; + std::string getExpressionInMacro() const; + bool hasExpandedExpression() const; + std::string getExpandedExpression() const; + std::string getMessage() const; + SourceLineInfo getSourceInfo() const; + StringRef getTestMacroName() const; + + //protected: + AssertionInfo m_info; + AssertionResultData m_resultData; + }; + +} // end namespace Catch + +// end catch_assertionresult.h +// start catch_option.hpp + +namespace Catch { + + // An optional type + template + class Option { + public: + Option() : nullableValue( nullptr ) {} + Option( T const& _value ) + : nullableValue( new( storage ) T( _value ) ) + {} + Option( Option const& _other ) + : nullableValue( _other ? new( storage ) T( *_other ) : nullptr ) + {} + + ~Option() { + reset(); + } + + Option& operator= ( Option const& _other ) { + if( &_other != this ) { + reset(); + if( _other ) + nullableValue = new( storage ) T( *_other ); + } + return *this; + } + Option& operator = ( T const& _value ) { + reset(); + nullableValue = new( storage ) T( _value ); + return *this; + } + + void reset() { + if( nullableValue ) + nullableValue->~T(); + nullableValue = nullptr; + } + + T& operator*() { return *nullableValue; } + T const& operator*() const { return *nullableValue; } + T* operator->() { return nullableValue; } + const T* operator->() const { return nullableValue; } + + T valueOr( T const& defaultValue ) const { + return nullableValue ? *nullableValue : defaultValue; + } + + bool some() const { return nullableValue != nullptr; } + bool none() const { return nullableValue == nullptr; } + + bool operator !() const { return nullableValue == nullptr; } + explicit operator bool() const { + return some(); + } + + private: + T *nullableValue; + alignas(alignof(T)) char storage[sizeof(T)]; + }; + +} // end namespace Catch + +// end catch_option.hpp +#include +#include +#include +#include +#include + +namespace Catch { + + struct ReporterConfig { + explicit ReporterConfig( IConfigPtr const& _fullConfig ); + + ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ); + + std::ostream& stream() const; + IConfigPtr fullConfig() const; + + private: + std::ostream* m_stream; + IConfigPtr m_fullConfig; + }; + + struct ReporterPreferences { + bool shouldRedirectStdOut = false; + }; + + template + struct LazyStat : Option { + LazyStat& operator=( T const& _value ) { + Option::operator=( _value ); + used = false; + return *this; + } + void reset() { + Option::reset(); + used = false; + } + bool used = false; + }; + + struct TestRunInfo { + TestRunInfo( std::string const& _name ); + std::string name; + }; + struct GroupInfo { + GroupInfo( std::string const& _name, + std::size_t _groupIndex, + std::size_t _groupsCount ); + + std::string name; + std::size_t groupIndex; + std::size_t groupsCounts; + }; + + struct AssertionStats { + AssertionStats( AssertionResult const& _assertionResult, + std::vector const& _infoMessages, + Totals const& _totals ); + + AssertionStats( AssertionStats const& ) = default; + AssertionStats( AssertionStats && ) = default; + AssertionStats& operator = ( AssertionStats const& ) = default; + AssertionStats& operator = ( AssertionStats && ) = default; + virtual ~AssertionStats(); + + AssertionResult assertionResult; + std::vector infoMessages; + Totals totals; + }; + + struct SectionStats { + SectionStats( SectionInfo const& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ); + SectionStats( SectionStats const& ) = default; + SectionStats( SectionStats && ) = default; + SectionStats& operator = ( SectionStats const& ) = default; + SectionStats& operator = ( SectionStats && ) = default; + virtual ~SectionStats(); + + SectionInfo sectionInfo; + Counts assertions; + double durationInSeconds; + bool missingAssertions; + }; + + struct TestCaseStats { + TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string const& _stdOut, + std::string const& _stdErr, + bool _aborting ); + + TestCaseStats( TestCaseStats const& ) = default; + TestCaseStats( TestCaseStats && ) = default; + TestCaseStats& operator = ( TestCaseStats const& ) = default; + TestCaseStats& operator = ( TestCaseStats && ) = default; + virtual ~TestCaseStats(); + + TestCaseInfo testInfo; + Totals totals; + std::string stdOut; + std::string stdErr; + bool aborting; + }; + + struct TestGroupStats { + TestGroupStats( GroupInfo const& _groupInfo, + Totals const& _totals, + bool _aborting ); + TestGroupStats( GroupInfo const& _groupInfo ); + + TestGroupStats( TestGroupStats const& ) = default; + TestGroupStats( TestGroupStats && ) = default; + TestGroupStats& operator = ( TestGroupStats const& ) = default; + TestGroupStats& operator = ( TestGroupStats && ) = default; + virtual ~TestGroupStats(); + + GroupInfo groupInfo; + Totals totals; + bool aborting; + }; + + struct TestRunStats { + TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ); + + TestRunStats( TestRunStats const& ) = default; + TestRunStats( TestRunStats && ) = default; + TestRunStats& operator = ( TestRunStats const& ) = default; + TestRunStats& operator = ( TestRunStats && ) = default; + virtual ~TestRunStats(); + + TestRunInfo runInfo; + Totals totals; + bool aborting; + }; + + struct BenchmarkInfo { + std::string name; + }; + struct BenchmarkStats { + BenchmarkInfo info; + std::size_t iterations; + uint64_t elapsedTimeInNanoseconds; + }; + + struct IStreamingReporter { + virtual ~IStreamingReporter() = default; + + // Implementing class must also provide the following static methods: + // static std::string getDescription(); + // static std::set getSupportedVerbosities() + + virtual ReporterPreferences getPreferences() const = 0; + + virtual void noMatchingTestCases( std::string const& spec ) = 0; + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; + virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; + virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; + + // *** experimental *** + virtual void benchmarkStarting( BenchmarkInfo const& ) {} + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; + + // *** experimental *** + virtual void benchmarkEnded( BenchmarkStats const& ) {} + + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; + virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; + + virtual void skipTest( TestCaseInfo const& testInfo ) = 0; + + // Default empty implementation provided + virtual void fatalErrorEncountered( StringRef name ); + + virtual bool isMulti() const; + }; + using IStreamingReporterPtr = std::unique_ptr; + + struct IReporterFactory { + virtual ~IReporterFactory(); + virtual IStreamingReporterPtr create( ReporterConfig const& config ) const = 0; + virtual std::string getDescription() const = 0; + }; + using IReporterFactoryPtr = std::shared_ptr; + + struct IReporterRegistry { + using FactoryMap = std::map; + using Listeners = std::vector; + + virtual ~IReporterRegistry(); + virtual IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const = 0; + virtual FactoryMap const& getFactories() const = 0; + virtual Listeners const& getListeners() const = 0; + }; + +} // end namespace Catch + +// end catch_interfaces_reporter.h +#include +#include +#include +#include +#include +#include +#include + +namespace Catch { + void prepareExpandedExpression(AssertionResult& result); + + // Returns double formatted as %.3f (format expected on output) + std::string getFormattedDuration( double duration ); + + template + struct StreamingReporterBase : IStreamingReporter { + + StreamingReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) + throw std::domain_error( "Verbosity level not supported by this reporter" ); + } + + ReporterPreferences getPreferences() const override { + return m_reporterPrefs; + } + + static std::set getSupportedVerbosities() { + return { Verbosity::Normal }; + } + + ~StreamingReporterBase() override = default; + + void noMatchingTestCases(std::string const&) override {} + + void testRunStarting(TestRunInfo const& _testRunInfo) override { + currentTestRunInfo = _testRunInfo; + } + void testGroupStarting(GroupInfo const& _groupInfo) override { + currentGroupInfo = _groupInfo; + } + + void testCaseStarting(TestCaseInfo const& _testInfo) override { + currentTestCaseInfo = _testInfo; + } + void sectionStarting(SectionInfo const& _sectionInfo) override { + m_sectionStack.push_back(_sectionInfo); + } + + void sectionEnded(SectionStats const& /* _sectionStats */) override { + m_sectionStack.pop_back(); + } + void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override { + currentTestCaseInfo.reset(); + } + void testGroupEnded(TestGroupStats const& /* _testGroupStats */) override { + currentGroupInfo.reset(); + } + void testRunEnded(TestRunStats const& /* _testRunStats */) override { + currentTestCaseInfo.reset(); + currentGroupInfo.reset(); + currentTestRunInfo.reset(); + } + + void skipTest(TestCaseInfo const&) override { + // Don't do anything with this by default. + // It can optionally be overridden in the derived class. + } + + IConfigPtr m_config; + std::ostream& stream; + + LazyStat currentTestRunInfo; + LazyStat currentGroupInfo; + LazyStat currentTestCaseInfo; + + std::vector m_sectionStack; + ReporterPreferences m_reporterPrefs; + }; + + template + struct CumulativeReporterBase : IStreamingReporter { + template + struct Node { + explicit Node( T const& _value ) : value( _value ) {} + virtual ~Node() {} + + using ChildNodes = std::vector>; + T value; + ChildNodes children; + }; + struct SectionNode { + explicit SectionNode(SectionStats const& _stats) : stats(_stats) {} + virtual ~SectionNode() = default; + + bool operator == (SectionNode const& other) const { + return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; + } + bool operator == (std::shared_ptr const& other) const { + return operator==(*other); + } + + SectionStats stats; + using ChildSections = std::vector>; + using Assertions = std::vector; + ChildSections childSections; + Assertions assertions; + std::string stdOut; + std::string stdErr; + }; + + struct BySectionInfo { + BySectionInfo( SectionInfo const& other ) : m_other( other ) {} + BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} + bool operator() (std::shared_ptr const& node) const { + return ((node->stats.sectionInfo.name == m_other.name) && + (node->stats.sectionInfo.lineInfo == m_other.lineInfo)); + } + void operator=(BySectionInfo const&) = delete; + + private: + SectionInfo const& m_other; + }; + + using TestCaseNode = Node; + using TestGroupNode = Node; + using TestRunNode = Node; + + CumulativeReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = false; + if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) + throw std::domain_error( "Verbosity level not supported by this reporter" ); + } + ~CumulativeReporterBase() override = default; + + ReporterPreferences getPreferences() const override { + return m_reporterPrefs; + } + + static std::set getSupportedVerbosities() { + return { Verbosity::Normal }; + } + + void testRunStarting( TestRunInfo const& ) override {} + void testGroupStarting( GroupInfo const& ) override {} + + void testCaseStarting( TestCaseInfo const& ) override {} + + void sectionStarting( SectionInfo const& sectionInfo ) override { + SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); + std::shared_ptr node; + if( m_sectionStack.empty() ) { + if( !m_rootSection ) + m_rootSection = std::make_shared( incompleteStats ); + node = m_rootSection; + } + else { + SectionNode& parentNode = *m_sectionStack.back(); + auto it = + std::find_if( parentNode.childSections.begin(), + parentNode.childSections.end(), + BySectionInfo( sectionInfo ) ); + if( it == parentNode.childSections.end() ) { + node = std::make_shared( incompleteStats ); + parentNode.childSections.push_back( node ); + } + else + node = *it; + } + m_sectionStack.push_back( node ); + m_deepestSection = std::move(node); + } + + void assertionStarting(AssertionInfo const&) override {} + + bool assertionEnded(AssertionStats const& assertionStats) override { + assert(!m_sectionStack.empty()); + // AssertionResult holds a pointer to a temporary DecomposedExpression, + // which getExpandedExpression() calls to build the expression string. + // Our section stack copy of the assertionResult will likely outlive the + // temporary, so it must be expanded or discarded now to avoid calling + // a destroyed object later. + prepareExpandedExpression(const_cast( assertionStats.assertionResult ) ); + SectionNode& sectionNode = *m_sectionStack.back(); + sectionNode.assertions.push_back(assertionStats); + return true; + } + void sectionEnded(SectionStats const& sectionStats) override { + assert(!m_sectionStack.empty()); + SectionNode& node = *m_sectionStack.back(); + node.stats = sectionStats; + m_sectionStack.pop_back(); + } + void testCaseEnded(TestCaseStats const& testCaseStats) override { + auto node = std::make_shared(testCaseStats); + assert(m_sectionStack.size() == 0); + node->children.push_back(m_rootSection); + m_testCases.push_back(node); + m_rootSection.reset(); + + assert(m_deepestSection); + m_deepestSection->stdOut = testCaseStats.stdOut; + m_deepestSection->stdErr = testCaseStats.stdErr; + } + void testGroupEnded(TestGroupStats const& testGroupStats) override { + auto node = std::make_shared(testGroupStats); + node->children.swap(m_testCases); + m_testGroups.push_back(node); + } + void testRunEnded(TestRunStats const& testRunStats) override { + auto node = std::make_shared(testRunStats); + node->children.swap(m_testGroups); + m_testRuns.push_back(node); + testRunEndedCumulative(); + } + virtual void testRunEndedCumulative() = 0; + + void skipTest(TestCaseInfo const&) override {} + + IConfigPtr m_config; + std::ostream& stream; + std::vector m_assertions; + std::vector>> m_sections; + std::vector> m_testCases; + std::vector> m_testGroups; + + std::vector> m_testRuns; + + std::shared_ptr m_rootSection; + std::shared_ptr m_deepestSection; + std::vector> m_sectionStack; + ReporterPreferences m_reporterPrefs; + }; + + template + char const* getLineOfChars() { + static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; + if( !*line ) { + std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); + line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; + } + return line; + } + + struct TestEventListenerBase : StreamingReporterBase { + TestEventListenerBase( ReporterConfig const& _config ); + + void assertionStarting(AssertionInfo const&) override; + bool assertionEnded(AssertionStats const&) override; + }; + +} // end namespace Catch + +// end catch_reporter_bases.hpp +// start catch_console_colour.h + +namespace Catch { + + struct Colour { + enum Code { + None = 0, + + White, + Red, + Green, + Blue, + Cyan, + Yellow, + Grey, + + Bright = 0x10, + + BrightRed = Bright | Red, + BrightGreen = Bright | Green, + LightGrey = Bright | Grey, + BrightWhite = Bright | White, + BrightYellow = Bright | Yellow, + + // By intention + FileName = LightGrey, + Warning = BrightYellow, + ResultError = BrightRed, + ResultSuccess = BrightGreen, + ResultExpectedFailure = Warning, + + Error = BrightRed, + Success = Green, + + OriginalExpression = Cyan, + ReconstructedExpression = BrightYellow, + + SecondaryText = LightGrey, + Headers = White + }; + + // Use constructed object for RAII guard + Colour( Code _colourCode ); + Colour( Colour&& other ) noexcept; + Colour& operator=( Colour&& other ) noexcept; + ~Colour(); + + // Use static method for one-shot changes + static void use( Code _colourCode ); + + private: + bool m_moved = false; + }; + + std::ostream& operator << ( std::ostream& os, Colour const& ); + +} // end namespace Catch + +// end catch_console_colour.h +// start catch_reporter_registrars.hpp + + +namespace Catch { + + template + class ReporterRegistrar { + + class ReporterFactory : public IReporterFactory { + + virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { + return std::unique_ptr( new T( config ) ); + } + + virtual std::string getDescription() const override { + return T::getDescription(); + } + }; + + public: + + explicit ReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, std::make_shared() ); + } + }; + + template + class ListenerRegistrar { + + class ListenerFactory : public IReporterFactory { + + virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { + return std::unique_ptr( new T( config ) ); + } + virtual std::string getDescription() const override { + return std::string(); + } + }; + + public: + + ListenerRegistrar() { + getMutableRegistryHub().registerListener( std::make_shared() ); + } + }; +} + +#if !defined(CATCH_CONFIG_DISABLE) + +#define CATCH_REGISTER_REPORTER( name, reporterType ) \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS + +#define CATCH_REGISTER_LISTENER( listenerType ) \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS +#else // CATCH_CONFIG_DISABLE + +#define CATCH_REGISTER_REPORTER(name, reporterType) +#define CATCH_REGISTER_LISTENER(listenerType) + +#endif // CATCH_CONFIG_DISABLE + +// end catch_reporter_registrars.hpp +// Allow users to base their work off existing reporters +// start catch_reporter_compact.h + +namespace Catch { + + struct CompactReporter : StreamingReporterBase { + + using StreamingReporterBase::StreamingReporterBase; + + ~CompactReporter() override; + + static std::string getDescription(); + + ReporterPreferences getPreferences() const override; + + void noMatchingTestCases(std::string const& spec) override; + + void assertionStarting(AssertionInfo const&) override; + + bool assertionEnded(AssertionStats const& _assertionStats) override; + + void sectionEnded(SectionStats const& _sectionStats) override; + + void testRunEnded(TestRunStats const& _testRunStats) override; + + }; + +} // end namespace Catch + +// end catch_reporter_compact.h +// start catch_reporter_console.h + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch + // Note that 4062 (not all labels are handled + // and default is missing) is enabled +#endif + +namespace Catch { + // Fwd decls + struct SummaryColumn; + class TablePrinter; + + struct ConsoleReporter : StreamingReporterBase { + std::unique_ptr m_tablePrinter; + + ConsoleReporter(ReporterConfig const& config); + ~ConsoleReporter() override; + static std::string getDescription(); + + void noMatchingTestCases(std::string const& spec) override; + + void assertionStarting(AssertionInfo const&) override; + + bool assertionEnded(AssertionStats const& _assertionStats) override; + + void sectionStarting(SectionInfo const& _sectionInfo) override; + void sectionEnded(SectionStats const& _sectionStats) override; + + void benchmarkStarting(BenchmarkInfo const& info) override; + void benchmarkEnded(BenchmarkStats const& stats) override; + + void testCaseEnded(TestCaseStats const& _testCaseStats) override; + void testGroupEnded(TestGroupStats const& _testGroupStats) override; + void testRunEnded(TestRunStats const& _testRunStats) override; + + private: + + void lazyPrint(); + + void lazyPrintWithoutClosingBenchmarkTable(); + void lazyPrintRunInfo(); + void lazyPrintGroupInfo(); + void printTestCaseAndSectionHeader(); + + void printClosedHeader(std::string const& _name); + void printOpenHeader(std::string const& _name); + + // if string has a : in first line will set indent to follow it on + // subsequent lines + void printHeaderString(std::string const& _string, std::size_t indent = 0); + + void printTotals(Totals const& totals); + void printSummaryRow(std::string const& label, std::vector const& cols, std::size_t row); + + void printTotalsDivider(Totals const& totals); + void printSummaryDivider(); + + private: + bool m_headerPrinted = false; + }; + +} // end namespace Catch + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +// end catch_reporter_console.h +// start catch_reporter_junit.h + +// start catch_xmlwriter.h + +#include + +namespace Catch { + + class XmlEncode { + public: + enum ForWhat { ForTextNodes, ForAttributes }; + + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ); + + void encodeTo( std::ostream& os ) const; + + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ); + + private: + std::string m_str; + ForWhat m_forWhat; + }; + + class XmlWriter { + public: + + class ScopedElement { + public: + ScopedElement( XmlWriter* writer ); + + ScopedElement( ScopedElement&& other ) noexcept; + ScopedElement& operator=( ScopedElement&& other ) noexcept; + + ~ScopedElement(); + + ScopedElement& writeText( std::string const& text, bool indent = true ); + + template + ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { + m_writer->writeAttribute( name, attribute ); + return *this; + } + + private: + mutable XmlWriter* m_writer = nullptr; + }; + + XmlWriter( std::ostream& os = Catch::cout() ); + ~XmlWriter(); + + XmlWriter( XmlWriter const& ) = delete; + XmlWriter& operator=( XmlWriter const& ) = delete; + + XmlWriter& startElement( std::string const& name ); + + ScopedElement scopedElement( std::string const& name ); + + XmlWriter& endElement(); + + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); + + XmlWriter& writeAttribute( std::string const& name, bool attribute ); + + template + XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { + ReusableStringStream rss; + rss << attribute; + return writeAttribute( name, rss.str() ); + } + + XmlWriter& writeText( std::string const& text, bool indent = true ); + + XmlWriter& writeComment( std::string const& text ); + + void writeStylesheetRef( std::string const& url ); + + XmlWriter& writeBlankLine(); + + void ensureTagClosed(); + + private: + + void writeDeclaration(); + + void newlineIfNecessary(); + + bool m_tagIsOpen = false; + bool m_needsNewline = false; + std::vector m_tags; + std::string m_indent; + std::ostream& m_os; + }; + +} + +// end catch_xmlwriter.h +namespace Catch { + + class JunitReporter : public CumulativeReporterBase { + public: + JunitReporter(ReporterConfig const& _config); + + ~JunitReporter() override; + + static std::string getDescription(); + + void noMatchingTestCases(std::string const& /*spec*/) override; + + void testRunStarting(TestRunInfo const& runInfo) override; + + void testGroupStarting(GroupInfo const& groupInfo) override; + + void testCaseStarting(TestCaseInfo const& testCaseInfo) override; + bool assertionEnded(AssertionStats const& assertionStats) override; + + void testCaseEnded(TestCaseStats const& testCaseStats) override; + + void testGroupEnded(TestGroupStats const& testGroupStats) override; + + void testRunEndedCumulative() override; + + void writeGroup(TestGroupNode const& groupNode, double suiteTime); + + void writeTestCase(TestCaseNode const& testCaseNode); + + void writeSection(std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode); + + void writeAssertions(SectionNode const& sectionNode); + void writeAssertion(AssertionStats const& stats); + + XmlWriter xml; + Timer suiteTimer; + std::string stdOutForSuite; + std::string stdErrForSuite; + unsigned int unexpectedExceptions = 0; + bool m_okToFail = false; + }; + +} // end namespace Catch + +// end catch_reporter_junit.h +// start catch_reporter_xml.h + +namespace Catch { + class XmlReporter : public StreamingReporterBase { + public: + XmlReporter(ReporterConfig const& _config); + + ~XmlReporter() override; + + static std::string getDescription(); + + virtual std::string getStylesheetRef() const; + + void writeSourceInfo(SourceLineInfo const& sourceInfo); + + public: // StreamingReporterBase + + void noMatchingTestCases(std::string const& s) override; + + void testRunStarting(TestRunInfo const& testInfo) override; + + void testGroupStarting(GroupInfo const& groupInfo) override; + + void testCaseStarting(TestCaseInfo const& testInfo) override; + + void sectionStarting(SectionInfo const& sectionInfo) override; + + void assertionStarting(AssertionInfo const&) override; + + bool assertionEnded(AssertionStats const& assertionStats) override; + + void sectionEnded(SectionStats const& sectionStats) override; + + void testCaseEnded(TestCaseStats const& testCaseStats) override; + + void testGroupEnded(TestGroupStats const& testGroupStats) override; + + void testRunEnded(TestRunStats const& testRunStats) override; + + private: + Timer m_testCaseTimer; + XmlWriter m_xml; + int m_sectionDepth = 0; + }; + +} // end namespace Catch + +// end catch_reporter_xml.h + +// end catch_external_interfaces.h +#endif + +#endif // ! CATCH_CONFIG_IMPL_ONLY + +#ifdef CATCH_IMPL +// start catch_impl.hpp + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +// Keep these here for external reporters +// start catch_test_case_tracker.h + +#include +#include +#include + +namespace Catch { +namespace TestCaseTracking { + + struct NameAndLocation { + std::string name; + SourceLineInfo location; + + NameAndLocation( std::string const& _name, SourceLineInfo const& _location ); + }; + + struct ITracker; + + using ITrackerPtr = std::shared_ptr; + + struct ITracker { + virtual ~ITracker(); + + // static queries + virtual NameAndLocation const& nameAndLocation() const = 0; + + // dynamic queries + virtual bool isComplete() const = 0; // Successfully completed or failed + virtual bool isSuccessfullyCompleted() const = 0; + virtual bool isOpen() const = 0; // Started but not complete + virtual bool hasChildren() const = 0; + + virtual ITracker& parent() = 0; + + // actions + virtual void close() = 0; // Successfully complete + virtual void fail() = 0; + virtual void markAsNeedingAnotherRun() = 0; + + virtual void addChild( ITrackerPtr const& child ) = 0; + virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) = 0; + virtual void openChild() = 0; + + // Debug/ checking + virtual bool isSectionTracker() const = 0; + virtual bool isIndexTracker() const = 0; + }; + + class TrackerContext { + + enum RunState { + NotStarted, + Executing, + CompletedCycle + }; + + ITrackerPtr m_rootTracker; + ITracker* m_currentTracker = nullptr; + RunState m_runState = NotStarted; + + public: + + static TrackerContext& instance(); + + ITracker& startRun(); + void endRun(); + + void startCycle(); + void completeCycle(); + + bool completedCycle() const; + ITracker& currentTracker(); + void setCurrentTracker( ITracker* tracker ); + }; + + class TrackerBase : public ITracker { + protected: + enum CycleState { + NotStarted, + Executing, + ExecutingChildren, + NeedsAnotherRun, + CompletedSuccessfully, + Failed + }; + + class TrackerHasName { + NameAndLocation m_nameAndLocation; + public: + TrackerHasName( NameAndLocation const& nameAndLocation ); + bool operator ()( ITrackerPtr const& tracker ) const; + }; + + using Children = std::vector; + NameAndLocation m_nameAndLocation; + TrackerContext& m_ctx; + ITracker* m_parent; + Children m_children; + CycleState m_runState = NotStarted; + + public: + TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); + + NameAndLocation const& nameAndLocation() const override; + bool isComplete() const override; + bool isSuccessfullyCompleted() const override; + bool isOpen() const override; + bool hasChildren() const override; + + void addChild( ITrackerPtr const& child ) override; + + ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override; + ITracker& parent() override; + + void openChild() override; + + bool isSectionTracker() const override; + bool isIndexTracker() const override; + + void open(); + + void close() override; + void fail() override; + void markAsNeedingAnotherRun() override; + + private: + void moveToParent(); + void moveToThis(); + }; + + class SectionTracker : public TrackerBase { + std::vector m_filters; + public: + SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); + + bool isSectionTracker() const override; + + static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ); + + void tryOpen(); + + void addInitialFilters( std::vector const& filters ); + void addNextFilters( std::vector const& filters ); + }; + + class IndexTracker : public TrackerBase { + int m_size; + int m_index = -1; + public: + IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ); + + bool isIndexTracker() const override; + void close() override; + + static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ); + + int index() const; + + void moveNext(); + }; + +} // namespace TestCaseTracking + +using TestCaseTracking::ITracker; +using TestCaseTracking::TrackerContext; +using TestCaseTracking::SectionTracker; +using TestCaseTracking::IndexTracker; + +} // namespace Catch + +// end catch_test_case_tracker.h + +// start catch_leak_detector.h + +namespace Catch { + + struct LeakDetector { + LeakDetector(); + }; + +} +// end catch_leak_detector.h +// Cpp files will be included in the single-header file here +// start catch_approx.cpp + +#include +#include + +namespace { + +// Performs equivalent check of std::fabs(lhs - rhs) <= margin +// But without the subtraction to allow for INFINITY in comparison +bool marginComparison(double lhs, double rhs, double margin) { + return (lhs + margin >= rhs) && (rhs + margin >= lhs); +} + +} + +namespace Catch { +namespace Detail { + + Approx::Approx ( double value ) + : m_epsilon( std::numeric_limits::epsilon()*100 ), + m_margin( 0.0 ), + m_scale( 0.0 ), + m_value( value ) + {} + + Approx Approx::custom() { + return Approx( 0 ); + } + + std::string Approx::toString() const { + ReusableStringStream rss; + rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )"; + return rss.str(); + } + + bool Approx::equalityComparisonImpl(const double other) const { + // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value + // Thanks to Richard Harris for his help refining the scaled margin value + return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value))); + } + +} // end namespace Detail + +std::string StringMaker::convert(Catch::Detail::Approx const& value) { + return value.toString(); +} + +} // end namespace Catch +// end catch_approx.cpp +// start catch_assertionhandler.cpp + +// start catch_context.h + +#include + +namespace Catch { + + struct IResultCapture; + struct IRunner; + struct IConfig; + struct IMutableContext; + + using IConfigPtr = std::shared_ptr; + + struct IContext + { + virtual ~IContext(); + + virtual IResultCapture* getResultCapture() = 0; + virtual IRunner* getRunner() = 0; + virtual IConfigPtr const& getConfig() const = 0; + }; + + struct IMutableContext : IContext + { + virtual ~IMutableContext(); + virtual void setResultCapture( IResultCapture* resultCapture ) = 0; + virtual void setRunner( IRunner* runner ) = 0; + virtual void setConfig( IConfigPtr const& config ) = 0; + + private: + static IMutableContext *currentContext; + friend IMutableContext& getCurrentMutableContext(); + friend void cleanUpContext(); + static void createContext(); + }; + + inline IMutableContext& getCurrentMutableContext() + { + if( !IMutableContext::currentContext ) + IMutableContext::createContext(); + return *IMutableContext::currentContext; + } + + inline IContext& getCurrentContext() + { + return getCurrentMutableContext(); + } + + void cleanUpContext(); +} + +// end catch_context.h +// start catch_debugger.h + +namespace Catch { + bool isDebuggerActive(); +} + +#ifdef CATCH_PLATFORM_MAC + + #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ + +#elif defined(CATCH_PLATFORM_LINUX) + // If we can use inline assembler, do it because this allows us to break + // directly at the location of the failing check instead of breaking inside + // raise() called from it, i.e. one stack frame below. + #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) + #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */ + #else // Fall back to the generic way. + #include + + #define CATCH_TRAP() raise(SIGTRAP) + #endif +#elif defined(_MSC_VER) + #define CATCH_TRAP() __debugbreak() +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) void __stdcall DebugBreak(); + #define CATCH_TRAP() DebugBreak() +#endif + +#ifdef CATCH_TRAP + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } +#else + namespace Catch { + inline void doNothing() {} + } + #define CATCH_BREAK_INTO_DEBUGGER() Catch::doNothing() +#endif + +// end catch_debugger.h +// start catch_run_context.h + +// start catch_fatal_condition.h + +// start catch_windows_h_proxy.h + + +#if defined(CATCH_PLATFORM_WINDOWS) + +#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) +# define CATCH_DEFINED_NOMINMAX +# define NOMINMAX +#endif +#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) +# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif + +#ifdef __AFXDLL +#include +#else +#include +#endif + +#ifdef CATCH_DEFINED_NOMINMAX +# undef NOMINMAX +#endif +#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN +# undef WIN32_LEAN_AND_MEAN +#endif + +#endif // defined(CATCH_PLATFORM_WINDOWS) + +// end catch_windows_h_proxy.h +#if defined( CATCH_CONFIG_WINDOWS_SEH ) + +namespace Catch { + + struct FatalConditionHandler { + + static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo); + FatalConditionHandler(); + static void reset(); + ~FatalConditionHandler(); + + private: + static bool isSet; + static ULONG guaranteeSize; + static PVOID exceptionHandlerHandle; + }; + +} // namespace Catch + +#elif defined ( CATCH_CONFIG_POSIX_SIGNALS ) + +#include + +namespace Catch { + + struct FatalConditionHandler { + + static bool isSet; + static struct sigaction oldSigActions[]; + static stack_t oldSigStack; + static char altStackMem[]; + + static void handleSignal( int sig ); + + FatalConditionHandler(); + ~FatalConditionHandler(); + static void reset(); + }; + +} // namespace Catch + +#else + +namespace Catch { + struct FatalConditionHandler { + void reset(); + }; +} + +#endif + +// end catch_fatal_condition.h +#include + +namespace Catch { + + struct IMutableContext; + + /////////////////////////////////////////////////////////////////////////// + + class RunContext : public IResultCapture, public IRunner { + + public: + RunContext( RunContext const& ) = delete; + RunContext& operator =( RunContext const& ) = delete; + + explicit RunContext( IConfigPtr const& _config, IStreamingReporterPtr&& reporter ); + + ~RunContext() override; + + void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ); + void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ); + + Totals runTest(TestCase const& testCase); + + IConfigPtr config() const; + IStreamingReporter& reporter() const; + + public: // IResultCapture + + // Assertion handlers + void handleExpr + ( AssertionInfo const& info, + ITransientExpression const& expr, + AssertionReaction& reaction ) override; + void handleMessage + ( AssertionInfo const& info, + ResultWas::OfType resultType, + StringRef const& message, + AssertionReaction& reaction ) override; + void handleUnexpectedExceptionNotThrown + ( AssertionInfo const& info, + AssertionReaction& reaction ) override; + void handleUnexpectedInflightException + ( AssertionInfo const& info, + std::string const& message, + AssertionReaction& reaction ) override; + void handleIncomplete + ( AssertionInfo const& info ) override; + void handleNonExpr + ( AssertionInfo const &info, + ResultWas::OfType resultType, + AssertionReaction &reaction ) override; + + bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override; + + void sectionEnded( SectionEndInfo const& endInfo ) override; + void sectionEndedEarly( SectionEndInfo const& endInfo ) override; + + void benchmarkStarting( BenchmarkInfo const& info ) override; + void benchmarkEnded( BenchmarkStats const& stats ) override; + + void pushScopedMessage( MessageInfo const& message ) override; + void popScopedMessage( MessageInfo const& message ) override; + + std::string getCurrentTestName() const override; + + const AssertionResult* getLastResult() const override; + + void exceptionEarlyReported() override; + + void handleFatalErrorCondition( StringRef message ) override; + + bool lastAssertionPassed() override; + + void assertionPassed() override; + + public: + // !TBD We need to do this another way! + bool aborting() const final; + + private: + + void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ); + void invokeActiveTestCase(); + + void resetAssertionInfo(); + bool testForMissingAssertions( Counts& assertions ); + + void assertionEnded( AssertionResult const& result ); + void reportExpr + ( AssertionInfo const &info, + ResultWas::OfType resultType, + ITransientExpression const *expr, + bool negated ); + + void populateReaction( AssertionReaction& reaction ); + + private: + + void handleUnfinishedSections(); + + TestRunInfo m_runInfo; + IMutableContext& m_context; + TestCase const* m_activeTestCase = nullptr; + ITracker* m_testCaseTracker; + Option m_lastResult; + + IConfigPtr m_config; + Totals m_totals; + IStreamingReporterPtr m_reporter; + std::vector m_messages; + AssertionInfo m_lastAssertionInfo; + std::vector m_unfinishedSections; + std::vector m_activeSections; + TrackerContext m_trackerContext; + bool m_lastAssertionPassed = false; + bool m_shouldReportUnexpected = true; + bool m_includeSuccessfulResults; + }; + +} // end namespace Catch + +// end catch_run_context.h +namespace Catch { + + auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& { + expr.streamReconstructedExpression( os ); + return os; + } + + LazyExpression::LazyExpression( bool isNegated ) + : m_isNegated( isNegated ) + {} + + LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {} + + LazyExpression::operator bool() const { + return m_transientExpression != nullptr; + } + + auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& { + if( lazyExpr.m_isNegated ) + os << "!"; + + if( lazyExpr ) { + if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() ) + os << "(" << *lazyExpr.m_transientExpression << ")"; + else + os << *lazyExpr.m_transientExpression; + } + else { + os << "{** error - unchecked empty expression requested **}"; + } + return os; + } + + AssertionHandler::AssertionHandler + ( StringRef macroName, + SourceLineInfo const& lineInfo, + StringRef capturedExpression, + ResultDisposition::Flags resultDisposition ) + : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, + m_resultCapture( getResultCapture() ) + {} + + void AssertionHandler::handleExpr( ITransientExpression const& expr ) { + m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction ); + } + void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const& message) { + m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction ); + } + + auto AssertionHandler::allowThrows() const -> bool { + return getCurrentContext().getConfig()->allowThrows(); + } + + void AssertionHandler::complete() { + setCompleted(); + if( m_reaction.shouldDebugBreak ) { + + // If you find your debugger stopping you here then go one level up on the + // call-stack for the code that caused it (typically a failed assertion) + + // (To go back to the test and change execution, jump over the throw, next) + CATCH_BREAK_INTO_DEBUGGER(); + } + if( m_reaction.shouldThrow ) + throw Catch::TestFailureException(); + } + void AssertionHandler::setCompleted() { + m_completed = true; + } + + void AssertionHandler::handleUnexpectedInflightException() { + m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction ); + } + + void AssertionHandler::handleExceptionThrownAsExpected() { + m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); + } + void AssertionHandler::handleExceptionNotThrownAsExpected() { + m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); + } + + void AssertionHandler::handleUnexpectedExceptionNotThrown() { + m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction ); + } + + void AssertionHandler::handleThrowingCallSkipped() { + m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); + } + + // This is the overload that takes a string and infers the Equals matcher from it + // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp + void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ) { + handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString ); + } + +} // namespace Catch +// end catch_assertionhandler.cpp +// start catch_assertionresult.cpp + +namespace Catch { + AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression): + lazyExpression(_lazyExpression), + resultType(_resultType) {} + + std::string AssertionResultData::reconstructExpression() const { + + if( reconstructedExpression.empty() ) { + if( lazyExpression ) { + ReusableStringStream rss; + rss << lazyExpression; + reconstructedExpression = rss.str(); + } + } + return reconstructedExpression; + } + + AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) + : m_info( info ), + m_resultData( data ) + {} + + // Result was a success + bool AssertionResult::succeeded() const { + return Catch::isOk( m_resultData.resultType ); + } + + // Result was a success, or failure is suppressed + bool AssertionResult::isOk() const { + return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); + } + + ResultWas::OfType AssertionResult::getResultType() const { + return m_resultData.resultType; + } + + bool AssertionResult::hasExpression() const { + return m_info.capturedExpression[0] != 0; + } + + bool AssertionResult::hasMessage() const { + return !m_resultData.message.empty(); + } + + std::string AssertionResult::getExpression() const { + if( isFalseTest( m_info.resultDisposition ) ) + return "!(" + m_info.capturedExpression + ")"; + else + return m_info.capturedExpression; + } + + std::string AssertionResult::getExpressionInMacro() const { + std::string expr; + if( m_info.macroName[0] == 0 ) + expr = m_info.capturedExpression; + else { + expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 ); + expr += m_info.macroName; + expr += "( "; + expr += m_info.capturedExpression; + expr += " )"; + } + return expr; + } + + bool AssertionResult::hasExpandedExpression() const { + return hasExpression() && getExpandedExpression() != getExpression(); + } + + std::string AssertionResult::getExpandedExpression() const { + std::string expr = m_resultData.reconstructExpression(); + return expr.empty() + ? getExpression() + : expr; + } + + std::string AssertionResult::getMessage() const { + return m_resultData.message; + } + SourceLineInfo AssertionResult::getSourceInfo() const { + return m_info.lineInfo; + } + + StringRef AssertionResult::getTestMacroName() const { + return m_info.macroName; + } + +} // end namespace Catch +// end catch_assertionresult.cpp +// start catch_benchmark.cpp + +namespace Catch { + + auto BenchmarkLooper::getResolution() -> uint64_t { + return getEstimatedClockResolution() * getCurrentContext().getConfig()->benchmarkResolutionMultiple(); + } + + void BenchmarkLooper::reportStart() { + getResultCapture().benchmarkStarting( { m_name } ); + } + auto BenchmarkLooper::needsMoreIterations() -> bool { + auto elapsed = m_timer.getElapsedNanoseconds(); + + // Exponentially increasing iterations until we're confident in our timer resolution + if( elapsed < m_resolution ) { + m_iterationsToRun *= 10; + return true; + } + + getResultCapture().benchmarkEnded( { { m_name }, m_count, elapsed } ); + return false; + } + +} // end namespace Catch +// end catch_benchmark.cpp +// start catch_capture_matchers.cpp + +namespace Catch { + + using StringMatcher = Matchers::Impl::MatcherBase; + + // This is the general overload that takes a any string matcher + // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers + // the Equals matcher (so the header does not mention matchers) + void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ) { + std::string exceptionMessage = Catch::translateActiveException(); + MatchExpr expr( exceptionMessage, matcher, matcherString ); + handler.handleExpr( expr ); + } + +} // namespace Catch +// end catch_capture_matchers.cpp +// start catch_commandline.cpp + +// start catch_commandline.h + +// start catch_clara.h + +// Use Catch's value for console width (store Clara's off to the side, if present) +#ifdef CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH +#undef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH +#endif +#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH-1 + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#pragma clang diagnostic ignored "-Wexit-time-destructors" +#pragma clang diagnostic ignored "-Wshadow" +#endif + +// start clara.hpp +// Copyright 2017 Two Blue Cubes Ltd. All rights reserved. +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See https://github.com/philsquared/Clara for more details + +// Clara v1.1.4 + + +#ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80 +#endif + +#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH +#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH +#endif + +#ifndef CLARA_CONFIG_OPTIONAL_TYPE +#ifdef __has_include +#if __has_include() && __cplusplus >= 201703L +#include +#define CLARA_CONFIG_OPTIONAL_TYPE std::optional +#endif +#endif +#endif + +// ----------- #included from clara_textflow.hpp ----------- + +// TextFlowCpp +// +// A single-header library for wrapping and laying out basic text, by Phil Nash +// +// This work is licensed under the BSD 2-Clause license. +// See the accompanying LICENSE file, or the one at https://opensource.org/licenses/BSD-2-Clause +// +// This project is hosted at https://github.com/philsquared/textflowcpp + + +#include +#include +#include +#include + +#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH +#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80 +#endif + +namespace Catch { namespace clara { namespace TextFlow { + + inline auto isWhitespace( char c ) -> bool { + static std::string chars = " \t\n\r"; + return chars.find( c ) != std::string::npos; + } + inline auto isBreakableBefore( char c ) -> bool { + static std::string chars = "[({<|"; + return chars.find( c ) != std::string::npos; + } + inline auto isBreakableAfter( char c ) -> bool { + static std::string chars = "])}>.,:;*+-=&/\\"; + return chars.find( c ) != std::string::npos; + } + + class Columns; + + class Column { + std::vector m_strings; + size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH; + size_t m_indent = 0; + size_t m_initialIndent = std::string::npos; + + public: + class iterator { + friend Column; + + Column const& m_column; + size_t m_stringIndex = 0; + size_t m_pos = 0; + + size_t m_len = 0; + size_t m_end = 0; + bool m_suffix = false; + + iterator( Column const& column, size_t stringIndex ) + : m_column( column ), + m_stringIndex( stringIndex ) + {} + + auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; } + + auto isBoundary( size_t at ) const -> bool { + assert( at > 0 ); + assert( at <= line().size() ); + + return at == line().size() || + ( isWhitespace( line()[at] ) && !isWhitespace( line()[at-1] ) ) || + isBreakableBefore( line()[at] ) || + isBreakableAfter( line()[at-1] ); + } + + void calcLength() { + assert( m_stringIndex < m_column.m_strings.size() ); + + m_suffix = false; + auto width = m_column.m_width-indent(); + m_end = m_pos; + while( m_end < line().size() && line()[m_end] != '\n' ) + ++m_end; + + if( m_end < m_pos + width ) { + m_len = m_end - m_pos; + } + else { + size_t len = width; + while (len > 0 && !isBoundary(m_pos + len)) + --len; + while (len > 0 && isWhitespace( line()[m_pos + len - 1] )) + --len; + + if (len > 0) { + m_len = len; + } else { + m_suffix = true; + m_len = width - 1; + } + } + } + + auto indent() const -> size_t { + auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos; + return initial == std::string::npos ? m_column.m_indent : initial; + } + + auto addIndentAndSuffix(std::string const &plain) const -> std::string { + return std::string( indent(), ' ' ) + (m_suffix ? plain + "-" : plain); + } + + public: + explicit iterator( Column const& column ) : m_column( column ) { + assert( m_column.m_width > m_column.m_indent ); + assert( m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent ); + calcLength(); + if( m_len == 0 ) + m_stringIndex++; // Empty string + } + + auto operator *() const -> std::string { + assert( m_stringIndex < m_column.m_strings.size() ); + assert( m_pos <= m_end ); + if( m_pos + m_column.m_width < m_end ) + return addIndentAndSuffix(line().substr(m_pos, m_len)); + else + return addIndentAndSuffix(line().substr(m_pos, m_end - m_pos)); + } + + auto operator ++() -> iterator& { + m_pos += m_len; + if( m_pos < line().size() && line()[m_pos] == '\n' ) + m_pos += 1; + else + while( m_pos < line().size() && isWhitespace( line()[m_pos] ) ) + ++m_pos; + + if( m_pos == line().size() ) { + m_pos = 0; + ++m_stringIndex; + } + if( m_stringIndex < m_column.m_strings.size() ) + calcLength(); + return *this; + } + auto operator ++(int) -> iterator { + iterator prev( *this ); + operator++(); + return prev; + } + + auto operator ==( iterator const& other ) const -> bool { + return + m_pos == other.m_pos && + m_stringIndex == other.m_stringIndex && + &m_column == &other.m_column; + } + auto operator !=( iterator const& other ) const -> bool { + return !operator==( other ); + } + }; + using const_iterator = iterator; + + explicit Column( std::string const& text ) { m_strings.push_back( text ); } + + auto width( size_t newWidth ) -> Column& { + assert( newWidth > 0 ); + m_width = newWidth; + return *this; + } + auto indent( size_t newIndent ) -> Column& { + m_indent = newIndent; + return *this; + } + auto initialIndent( size_t newIndent ) -> Column& { + m_initialIndent = newIndent; + return *this; + } + + auto width() const -> size_t { return m_width; } + auto begin() const -> iterator { return iterator( *this ); } + auto end() const -> iterator { return { *this, m_strings.size() }; } + + inline friend std::ostream& operator << ( std::ostream& os, Column const& col ) { + bool first = true; + for( auto line : col ) { + if( first ) + first = false; + else + os << "\n"; + os << line; + } + return os; + } + + auto operator + ( Column const& other ) -> Columns; + + auto toString() const -> std::string { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + }; + + class Spacer : public Column { + + public: + explicit Spacer( size_t spaceWidth ) : Column( "" ) { + width( spaceWidth ); + } + }; + + class Columns { + std::vector m_columns; + + public: + + class iterator { + friend Columns; + struct EndTag {}; + + std::vector const& m_columns; + std::vector m_iterators; + size_t m_activeIterators; + + iterator( Columns const& columns, EndTag ) + : m_columns( columns.m_columns ), + m_activeIterators( 0 ) + { + m_iterators.reserve( m_columns.size() ); + + for( auto const& col : m_columns ) + m_iterators.push_back( col.end() ); + } + + public: + explicit iterator( Columns const& columns ) + : m_columns( columns.m_columns ), + m_activeIterators( m_columns.size() ) + { + m_iterators.reserve( m_columns.size() ); + + for( auto const& col : m_columns ) + m_iterators.push_back( col.begin() ); + } + + auto operator ==( iterator const& other ) const -> bool { + return m_iterators == other.m_iterators; + } + auto operator !=( iterator const& other ) const -> bool { + return m_iterators != other.m_iterators; + } + auto operator *() const -> std::string { + std::string row, padding; + + for( size_t i = 0; i < m_columns.size(); ++i ) { + auto width = m_columns[i].width(); + if( m_iterators[i] != m_columns[i].end() ) { + std::string col = *m_iterators[i]; + row += padding + col; + if( col.size() < width ) + padding = std::string( width - col.size(), ' ' ); + else + padding = ""; + } + else { + padding += std::string( width, ' ' ); + } + } + return row; + } + auto operator ++() -> iterator& { + for( size_t i = 0; i < m_columns.size(); ++i ) { + if (m_iterators[i] != m_columns[i].end()) + ++m_iterators[i]; + } + return *this; + } + auto operator ++(int) -> iterator { + iterator prev( *this ); + operator++(); + return prev; + } + }; + using const_iterator = iterator; + + auto begin() const -> iterator { return iterator( *this ); } + auto end() const -> iterator { return { *this, iterator::EndTag() }; } + + auto operator += ( Column const& col ) -> Columns& { + m_columns.push_back( col ); + return *this; + } + auto operator + ( Column const& col ) -> Columns { + Columns combined = *this; + combined += col; + return combined; + } + + inline friend std::ostream& operator << ( std::ostream& os, Columns const& cols ) { + + bool first = true; + for( auto line : cols ) { + if( first ) + first = false; + else + os << "\n"; + os << line; + } + return os; + } + + auto toString() const -> std::string { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + }; + + inline auto Column::operator + ( Column const& other ) -> Columns { + Columns cols; + cols += *this; + cols += other; + return cols; + } +}}} // namespace Catch::clara::TextFlow + +// ----------- end of #include from clara_textflow.hpp ----------- +// ........... back in clara.hpp + +#include +#include +#include + +#if !defined(CATCH_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) ) +#define CATCH_PLATFORM_WINDOWS +#endif + +namespace Catch { namespace clara { +namespace detail { + + // Traits for extracting arg and return type of lambdas (for single argument lambdas) + template + struct UnaryLambdaTraits : UnaryLambdaTraits {}; + + template + struct UnaryLambdaTraits { + static const bool isValid = false; + }; + + template + struct UnaryLambdaTraits { + static const bool isValid = true; + using ArgType = typename std::remove_const::type>::type; + using ReturnType = ReturnT; + }; + + class TokenStream; + + // Transport for raw args (copied from main args, or supplied via init list for testing) + class Args { + friend TokenStream; + std::string m_exeName; + std::vector m_args; + + public: + Args( int argc, char const* const* argv ) + : m_exeName(argv[0]), + m_args(argv + 1, argv + argc) {} + + Args( std::initializer_list args ) + : m_exeName( *args.begin() ), + m_args( args.begin()+1, args.end() ) + {} + + auto exeName() const -> std::string { + return m_exeName; + } + }; + + // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string + // may encode an option + its argument if the : or = form is used + enum class TokenType { + Option, Argument + }; + struct Token { + TokenType type; + std::string token; + }; + + inline auto isOptPrefix( char c ) -> bool { + return c == '-' +#ifdef CATCH_PLATFORM_WINDOWS + || c == '/' +#endif + ; + } + + // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled + class TokenStream { + using Iterator = std::vector::const_iterator; + Iterator it; + Iterator itEnd; + std::vector m_tokenBuffer; + + void loadBuffer() { + m_tokenBuffer.resize( 0 ); + + // Skip any empty strings + while( it != itEnd && it->empty() ) + ++it; + + if( it != itEnd ) { + auto const &next = *it; + if( isOptPrefix( next[0] ) ) { + auto delimiterPos = next.find_first_of( " :=" ); + if( delimiterPos != std::string::npos ) { + m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } ); + m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } ); + } else { + if( next[1] != '-' && next.size() > 2 ) { + std::string opt = "- "; + for( size_t i = 1; i < next.size(); ++i ) { + opt[1] = next[i]; + m_tokenBuffer.push_back( { TokenType::Option, opt } ); + } + } else { + m_tokenBuffer.push_back( { TokenType::Option, next } ); + } + } + } else { + m_tokenBuffer.push_back( { TokenType::Argument, next } ); + } + } + } + + public: + explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {} + + TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) { + loadBuffer(); + } + + explicit operator bool() const { + return !m_tokenBuffer.empty() || it != itEnd; + } + + auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); } + + auto operator*() const -> Token { + assert( !m_tokenBuffer.empty() ); + return m_tokenBuffer.front(); + } + + auto operator->() const -> Token const * { + assert( !m_tokenBuffer.empty() ); + return &m_tokenBuffer.front(); + } + + auto operator++() -> TokenStream & { + if( m_tokenBuffer.size() >= 2 ) { + m_tokenBuffer.erase( m_tokenBuffer.begin() ); + } else { + if( it != itEnd ) + ++it; + loadBuffer(); + } + return *this; + } + }; + + class ResultBase { + public: + enum Type { + Ok, LogicError, RuntimeError + }; + + protected: + ResultBase( Type type ) : m_type( type ) {} + virtual ~ResultBase() = default; + + virtual void enforceOk() const = 0; + + Type m_type; + }; + + template + class ResultValueBase : public ResultBase { + public: + auto value() const -> T const & { + enforceOk(); + return m_value; + } + + protected: + ResultValueBase( Type type ) : ResultBase( type ) {} + + ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) { + if( m_type == ResultBase::Ok ) + new( &m_value ) T( other.m_value ); + } + + ResultValueBase( Type, T const &value ) : ResultBase( Ok ) { + new( &m_value ) T( value ); + } + + auto operator=( ResultValueBase const &other ) -> ResultValueBase & { + if( m_type == ResultBase::Ok ) + m_value.~T(); + ResultBase::operator=(other); + if( m_type == ResultBase::Ok ) + new( &m_value ) T( other.m_value ); + return *this; + } + + ~ResultValueBase() override { + if( m_type == Ok ) + m_value.~T(); + } + + union { + T m_value; + }; + }; + + template<> + class ResultValueBase : public ResultBase { + protected: + using ResultBase::ResultBase; + }; + + template + class BasicResult : public ResultValueBase { + public: + template + explicit BasicResult( BasicResult const &other ) + : ResultValueBase( other.type() ), + m_errorMessage( other.errorMessage() ) + { + assert( type() != ResultBase::Ok ); + } + + template + static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; } + static auto ok() -> BasicResult { return { ResultBase::Ok }; } + static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; } + static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; } + + explicit operator bool() const { return m_type == ResultBase::Ok; } + auto type() const -> ResultBase::Type { return m_type; } + auto errorMessage() const -> std::string { return m_errorMessage; } + + protected: + void enforceOk() const override { + + // Errors shouldn't reach this point, but if they do + // the actual error message will be in m_errorMessage + assert( m_type != ResultBase::LogicError ); + assert( m_type != ResultBase::RuntimeError ); + if( m_type != ResultBase::Ok ) + std::abort(); + } + + std::string m_errorMessage; // Only populated if resultType is an error + + BasicResult( ResultBase::Type type, std::string const &message ) + : ResultValueBase(type), + m_errorMessage(message) + { + assert( m_type != ResultBase::Ok ); + } + + using ResultValueBase::ResultValueBase; + using ResultBase::m_type; + }; + + enum class ParseResultType { + Matched, NoMatch, ShortCircuitAll, ShortCircuitSame + }; + + class ParseState { + public: + + ParseState( ParseResultType type, TokenStream const &remainingTokens ) + : m_type(type), + m_remainingTokens( remainingTokens ) + {} + + auto type() const -> ParseResultType { return m_type; } + auto remainingTokens() const -> TokenStream { return m_remainingTokens; } + + private: + ParseResultType m_type; + TokenStream m_remainingTokens; + }; + + using Result = BasicResult; + using ParserResult = BasicResult; + using InternalParseResult = BasicResult; + + struct HelpColumns { + std::string left; + std::string right; + }; + + template + inline auto convertInto( std::string const &source, T& target ) -> ParserResult { + std::stringstream ss; + ss << source; + ss >> target; + if( ss.fail() ) + return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" ); + else + return ParserResult::ok( ParseResultType::Matched ); + } + inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult { + target = source; + return ParserResult::ok( ParseResultType::Matched ); + } + inline auto convertInto( std::string const &source, bool &target ) -> ParserResult { + std::string srcLC = source; + std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast( ::tolower(c) ); } ); + if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on") + target = true; + else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off") + target = false; + else + return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" ); + return ParserResult::ok( ParseResultType::Matched ); + } +#ifdef CLARA_CONFIG_OPTIONAL_TYPE + template + inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE& target ) -> ParserResult { + T temp; + auto result = convertInto( source, temp ); + if( result ) + target = std::move(temp); + return result; + } +#endif // CLARA_CONFIG_OPTIONAL_TYPE + + struct NonCopyable { + NonCopyable() = default; + NonCopyable( NonCopyable const & ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable &operator=( NonCopyable const & ) = delete; + NonCopyable &operator=( NonCopyable && ) = delete; + }; + + struct BoundRef : NonCopyable { + virtual ~BoundRef() = default; + virtual auto isContainer() const -> bool { return false; } + virtual auto isFlag() const -> bool { return false; } + }; + struct BoundValueRefBase : BoundRef { + virtual auto setValue( std::string const &arg ) -> ParserResult = 0; + }; + struct BoundFlagRefBase : BoundRef { + virtual auto setFlag( bool flag ) -> ParserResult = 0; + virtual auto isFlag() const -> bool { return true; } + }; + + template + struct BoundValueRef : BoundValueRefBase { + T &m_ref; + + explicit BoundValueRef( T &ref ) : m_ref( ref ) {} + + auto setValue( std::string const &arg ) -> ParserResult override { + return convertInto( arg, m_ref ); + } + }; + + template + struct BoundValueRef> : BoundValueRefBase { + std::vector &m_ref; + + explicit BoundValueRef( std::vector &ref ) : m_ref( ref ) {} + + auto isContainer() const -> bool override { return true; } + + auto setValue( std::string const &arg ) -> ParserResult override { + T temp; + auto result = convertInto( arg, temp ); + if( result ) + m_ref.push_back( temp ); + return result; + } + }; + + struct BoundFlagRef : BoundFlagRefBase { + bool &m_ref; + + explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {} + + auto setFlag( bool flag ) -> ParserResult override { + m_ref = flag; + return ParserResult::ok( ParseResultType::Matched ); + } + }; + + template + struct LambdaInvoker { + static_assert( std::is_same::value, "Lambda must return void or clara::ParserResult" ); + + template + static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { + return lambda( arg ); + } + }; + + template<> + struct LambdaInvoker { + template + static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { + lambda( arg ); + return ParserResult::ok( ParseResultType::Matched ); + } + }; + + template + inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult { + ArgType temp{}; + auto result = convertInto( arg, temp ); + return !result + ? result + : LambdaInvoker::ReturnType>::invoke( lambda, temp ); + } + + template + struct BoundLambda : BoundValueRefBase { + L m_lambda; + + static_assert( UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument" ); + explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {} + + auto setValue( std::string const &arg ) -> ParserResult override { + return invokeLambda::ArgType>( m_lambda, arg ); + } + }; + + template + struct BoundFlagLambda : BoundFlagRefBase { + L m_lambda; + + static_assert( UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument" ); + static_assert( std::is_same::ArgType, bool>::value, "flags must be boolean" ); + + explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {} + + auto setFlag( bool flag ) -> ParserResult override { + return LambdaInvoker::ReturnType>::invoke( m_lambda, flag ); + } + }; + + enum class Optionality { Optional, Required }; + + struct Parser; + + class ParserBase { + public: + virtual ~ParserBase() = default; + virtual auto validate() const -> Result { return Result::ok(); } + virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0; + virtual auto cardinality() const -> size_t { return 1; } + + auto parse( Args const &args ) const -> InternalParseResult { + return parse( args.exeName(), TokenStream( args ) ); + } + }; + + template + class ComposableParserImpl : public ParserBase { + public: + template + auto operator|( T const &other ) const -> Parser; + + template + auto operator+( T const &other ) const -> Parser; + }; + + // Common code and state for Args and Opts + template + class ParserRefImpl : public ComposableParserImpl { + protected: + Optionality m_optionality = Optionality::Optional; + std::shared_ptr m_ref; + std::string m_hint; + std::string m_description; + + explicit ParserRefImpl( std::shared_ptr const &ref ) : m_ref( ref ) {} + + public: + template + ParserRefImpl( T &ref, std::string const &hint ) + : m_ref( std::make_shared>( ref ) ), + m_hint( hint ) + {} + + template + ParserRefImpl( LambdaT const &ref, std::string const &hint ) + : m_ref( std::make_shared>( ref ) ), + m_hint(hint) + {} + + auto operator()( std::string const &description ) -> DerivedT & { + m_description = description; + return static_cast( *this ); + } + + auto optional() -> DerivedT & { + m_optionality = Optionality::Optional; + return static_cast( *this ); + }; + + auto required() -> DerivedT & { + m_optionality = Optionality::Required; + return static_cast( *this ); + }; + + auto isOptional() const -> bool { + return m_optionality == Optionality::Optional; + } + + auto cardinality() const -> size_t override { + if( m_ref->isContainer() ) + return 0; + else + return 1; + } + + auto hint() const -> std::string { return m_hint; } + }; + + class ExeName : public ComposableParserImpl { + std::shared_ptr m_name; + std::shared_ptr m_ref; + + template + static auto makeRef(LambdaT const &lambda) -> std::shared_ptr { + return std::make_shared>( lambda) ; + } + + public: + ExeName() : m_name( std::make_shared( "" ) ) {} + + explicit ExeName( std::string &ref ) : ExeName() { + m_ref = std::make_shared>( ref ); + } + + template + explicit ExeName( LambdaT const& lambda ) : ExeName() { + m_ref = std::make_shared>( lambda ); + } + + // The exe name is not parsed out of the normal tokens, but is handled specially + auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { + return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); + } + + auto name() const -> std::string { return *m_name; } + auto set( std::string const& newName ) -> ParserResult { + + auto lastSlash = newName.find_last_of( "\\/" ); + auto filename = ( lastSlash == std::string::npos ) + ? newName + : newName.substr( lastSlash+1 ); + + *m_name = filename; + if( m_ref ) + return m_ref->setValue( filename ); + else + return ParserResult::ok( ParseResultType::Matched ); + } + }; + + class Arg : public ParserRefImpl { + public: + using ParserRefImpl::ParserRefImpl; + + auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override { + auto validationResult = validate(); + if( !validationResult ) + return InternalParseResult( validationResult ); + + auto remainingTokens = tokens; + auto const &token = *remainingTokens; + if( token.type != TokenType::Argument ) + return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); + + assert( !m_ref->isFlag() ); + auto valueRef = static_cast( m_ref.get() ); + + auto result = valueRef->setValue( remainingTokens->token ); + if( !result ) + return InternalParseResult( result ); + else + return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); + } + }; + + inline auto normaliseOpt( std::string const &optName ) -> std::string { +#ifdef CATCH_PLATFORM_WINDOWS + if( optName[0] == '/' ) + return "-" + optName.substr( 1 ); + else +#endif + return optName; + } + + class Opt : public ParserRefImpl { + protected: + std::vector m_optNames; + + public: + template + explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared>( ref ) ) {} + + explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared( ref ) ) {} + + template + Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} + + template + Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} + + auto operator[]( std::string const &optName ) -> Opt & { + m_optNames.push_back( optName ); + return *this; + } + + auto getHelpColumns() const -> std::vector { + std::ostringstream oss; + bool first = true; + for( auto const &opt : m_optNames ) { + if (first) + first = false; + else + oss << ", "; + oss << opt; + } + if( !m_hint.empty() ) + oss << " <" << m_hint << ">"; + return { { oss.str(), m_description } }; + } + + auto isMatch( std::string const &optToken ) const -> bool { + auto normalisedToken = normaliseOpt( optToken ); + for( auto const &name : m_optNames ) { + if( normaliseOpt( name ) == normalisedToken ) + return true; + } + return false; + } + + using ParserBase::parse; + + auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { + auto validationResult = validate(); + if( !validationResult ) + return InternalParseResult( validationResult ); + + auto remainingTokens = tokens; + if( remainingTokens && remainingTokens->type == TokenType::Option ) { + auto const &token = *remainingTokens; + if( isMatch(token.token ) ) { + if( m_ref->isFlag() ) { + auto flagRef = static_cast( m_ref.get() ); + auto result = flagRef->setFlag( true ); + if( !result ) + return InternalParseResult( result ); + if( result.value() == ParseResultType::ShortCircuitAll ) + return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); + } else { + auto valueRef = static_cast( m_ref.get() ); + ++remainingTokens; + if( !remainingTokens ) + return InternalParseResult::runtimeError( "Expected argument following " + token.token ); + auto const &argToken = *remainingTokens; + if( argToken.type != TokenType::Argument ) + return InternalParseResult::runtimeError( "Expected argument following " + token.token ); + auto result = valueRef->setValue( argToken.token ); + if( !result ) + return InternalParseResult( result ); + if( result.value() == ParseResultType::ShortCircuitAll ) + return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); + } + return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); + } + } + return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); + } + + auto validate() const -> Result override { + if( m_optNames.empty() ) + return Result::logicError( "No options supplied to Opt" ); + for( auto const &name : m_optNames ) { + if( name.empty() ) + return Result::logicError( "Option name cannot be empty" ); +#ifdef CATCH_PLATFORM_WINDOWS + if( name[0] != '-' && name[0] != '/' ) + return Result::logicError( "Option name must begin with '-' or '/'" ); +#else + if( name[0] != '-' ) + return Result::logicError( "Option name must begin with '-'" ); +#endif + } + return ParserRefImpl::validate(); + } + }; + + struct Help : Opt { + Help( bool &showHelpFlag ) + : Opt([&]( bool flag ) { + showHelpFlag = flag; + return ParserResult::ok( ParseResultType::ShortCircuitAll ); + }) + { + static_cast( *this ) + ("display usage information") + ["-?"]["-h"]["--help"] + .optional(); + } + }; + + struct Parser : ParserBase { + + mutable ExeName m_exeName; + std::vector m_options; + std::vector m_args; + + auto operator|=( ExeName const &exeName ) -> Parser & { + m_exeName = exeName; + return *this; + } + + auto operator|=( Arg const &arg ) -> Parser & { + m_args.push_back(arg); + return *this; + } + + auto operator|=( Opt const &opt ) -> Parser & { + m_options.push_back(opt); + return *this; + } + + auto operator|=( Parser const &other ) -> Parser & { + m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end()); + m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end()); + return *this; + } + + template + auto operator|( T const &other ) const -> Parser { + return Parser( *this ) |= other; + } + + // Forward deprecated interface with '+' instead of '|' + template + auto operator+=( T const &other ) -> Parser & { return operator|=( other ); } + template + auto operator+( T const &other ) const -> Parser { return operator|( other ); } + + auto getHelpColumns() const -> std::vector { + std::vector cols; + for (auto const &o : m_options) { + auto childCols = o.getHelpColumns(); + cols.insert( cols.end(), childCols.begin(), childCols.end() ); + } + return cols; + } + + void writeToStream( std::ostream &os ) const { + if (!m_exeName.name().empty()) { + os << "usage:\n" << " " << m_exeName.name() << " "; + bool required = true, first = true; + for( auto const &arg : m_args ) { + if (first) + first = false; + else + os << " "; + if( arg.isOptional() && required ) { + os << "["; + required = false; + } + os << "<" << arg.hint() << ">"; + if( arg.cardinality() == 0 ) + os << " ... "; + } + if( !required ) + os << "]"; + if( !m_options.empty() ) + os << " options"; + os << "\n\nwhere options are:" << std::endl; + } + + auto rows = getHelpColumns(); + size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH; + size_t optWidth = 0; + for( auto const &cols : rows ) + optWidth = (std::max)(optWidth, cols.left.size() + 2); + + optWidth = (std::min)(optWidth, consoleWidth/2); + + for( auto const &cols : rows ) { + auto row = + TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) + + TextFlow::Spacer(4) + + TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth ); + os << row << std::endl; + } + } + + friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& { + parser.writeToStream( os ); + return os; + } + + auto validate() const -> Result override { + for( auto const &opt : m_options ) { + auto result = opt.validate(); + if( !result ) + return result; + } + for( auto const &arg : m_args ) { + auto result = arg.validate(); + if( !result ) + return result; + } + return Result::ok(); + } + + using ParserBase::parse; + + auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override { + + struct ParserInfo { + ParserBase const* parser = nullptr; + size_t count = 0; + }; + const size_t totalParsers = m_options.size() + m_args.size(); + assert( totalParsers < 512 ); + // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do + ParserInfo parseInfos[512]; + + { + size_t i = 0; + for (auto const &opt : m_options) parseInfos[i++].parser = &opt; + for (auto const &arg : m_args) parseInfos[i++].parser = &arg; + } + + m_exeName.set( exeName ); + + auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); + while( result.value().remainingTokens() ) { + bool tokenParsed = false; + + for( size_t i = 0; i < totalParsers; ++i ) { + auto& parseInfo = parseInfos[i]; + if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) { + result = parseInfo.parser->parse(exeName, result.value().remainingTokens()); + if (!result) + return result; + if (result.value().type() != ParseResultType::NoMatch) { + tokenParsed = true; + ++parseInfo.count; + break; + } + } + } + + if( result.value().type() == ParseResultType::ShortCircuitAll ) + return result; + if( !tokenParsed ) + return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token ); + } + // !TBD Check missing required options + return result; + } + }; + + template + template + auto ComposableParserImpl::operator|( T const &other ) const -> Parser { + return Parser() | static_cast( *this ) | other; + } +} // namespace detail + +// A Combined parser +using detail::Parser; + +// A parser for options +using detail::Opt; + +// A parser for arguments +using detail::Arg; + +// Wrapper for argc, argv from main() +using detail::Args; + +// Specifies the name of the executable +using detail::ExeName; + +// Convenience wrapper for option parser that specifies the help option +using detail::Help; + +// enum of result types from a parse +using detail::ParseResultType; + +// Result type for parser operation +using detail::ParserResult; + +}} // namespace Catch::clara + +// end clara.hpp +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// Restore Clara's value for console width, if present +#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#endif + +// end catch_clara.h +namespace Catch { + + clara::Parser makeCommandLineParser( ConfigData& config ); + +} // end namespace Catch + +// end catch_commandline.h +#include +#include + +namespace Catch { + + clara::Parser makeCommandLineParser( ConfigData& config ) { + + using namespace clara; + + auto const setWarning = [&]( std::string const& warning ) { + auto warningSet = [&]() { + if( warning == "NoAssertions" ) + return WarnAbout::NoAssertions; + + if ( warning == "NoTests" ) + return WarnAbout::NoTests; + + return WarnAbout::Nothing; + }(); + + if (warningSet == WarnAbout::Nothing) + return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" ); + config.warnings = static_cast( config.warnings | warningSet ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const loadTestNamesFromFile = [&]( std::string const& filename ) { + std::ifstream f( filename.c_str() ); + if( !f.is_open() ) + return ParserResult::runtimeError( "Unable to load input file: '" + filename + "'" ); + + std::string line; + while( std::getline( f, line ) ) { + line = trim(line); + if( !line.empty() && !startsWith( line, '#' ) ) { + if( !startsWith( line, '"' ) ) + line = '"' + line + '"'; + config.testsOrTags.push_back( line + ',' ); + } + } + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setTestOrder = [&]( std::string const& order ) { + if( startsWith( "declared", order ) ) + config.runOrder = RunTests::InDeclarationOrder; + else if( startsWith( "lexical", order ) ) + config.runOrder = RunTests::InLexicographicalOrder; + else if( startsWith( "random", order ) ) + config.runOrder = RunTests::InRandomOrder; + else + return clara::ParserResult::runtimeError( "Unrecognised ordering: '" + order + "'" ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setRngSeed = [&]( std::string const& seed ) { + if( seed != "time" ) + return clara::detail::convertInto( seed, config.rngSeed ); + config.rngSeed = static_cast( std::time(nullptr) ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setColourUsage = [&]( std::string const& useColour ) { + auto mode = toLower( useColour ); + + if( mode == "yes" ) + config.useColour = UseColour::Yes; + else if( mode == "no" ) + config.useColour = UseColour::No; + else if( mode == "auto" ) + config.useColour = UseColour::Auto; + else + return ParserResult::runtimeError( "colour mode must be one of: auto, yes or no. '" + useColour + "' not recognised" ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setWaitForKeypress = [&]( std::string const& keypress ) { + auto keypressLc = toLower( keypress ); + if( keypressLc == "start" ) + config.waitForKeypress = WaitForKeypress::BeforeStart; + else if( keypressLc == "exit" ) + config.waitForKeypress = WaitForKeypress::BeforeExit; + else if( keypressLc == "both" ) + config.waitForKeypress = WaitForKeypress::BeforeStartAndExit; + else + return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" ); + return ParserResult::ok( ParseResultType::Matched ); + }; + auto const setVerbosity = [&]( std::string const& verbosity ) { + auto lcVerbosity = toLower( verbosity ); + if( lcVerbosity == "quiet" ) + config.verbosity = Verbosity::Quiet; + else if( lcVerbosity == "normal" ) + config.verbosity = Verbosity::Normal; + else if( lcVerbosity == "high" ) + config.verbosity = Verbosity::High; + else + return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" ); + return ParserResult::ok( ParseResultType::Matched ); + }; + + auto cli + = ExeName( config.processName ) + | Help( config.showHelp ) + | Opt( config.listTests ) + ["-l"]["--list-tests"] + ( "list all/matching test cases" ) + | Opt( config.listTags ) + ["-t"]["--list-tags"] + ( "list all/matching tags" ) + | Opt( config.showSuccessfulTests ) + ["-s"]["--success"] + ( "include successful tests in output" ) + | Opt( config.shouldDebugBreak ) + ["-b"]["--break"] + ( "break into debugger on failure" ) + | Opt( config.noThrow ) + ["-e"]["--nothrow"] + ( "skip exception tests" ) + | Opt( config.showInvisibles ) + ["-i"]["--invisibles"] + ( "show invisibles (tabs, newlines)" ) + | Opt( config.outputFilename, "filename" ) + ["-o"]["--out"] + ( "output filename" ) + | Opt( config.reporterName, "name" ) + ["-r"]["--reporter"] + ( "reporter to use (defaults to console)" ) + | Opt( config.name, "name" ) + ["-n"]["--name"] + ( "suite name" ) + | Opt( [&]( bool ){ config.abortAfter = 1; } ) + ["-a"]["--abort"] + ( "abort at first failure" ) + | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" ) + ["-x"]["--abortx"] + ( "abort after x failures" ) + | Opt( setWarning, "warning name" ) + ["-w"]["--warn"] + ( "enable warnings" ) + | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" ) + ["-d"]["--durations"] + ( "show test durations" ) + | Opt( loadTestNamesFromFile, "filename" ) + ["-f"]["--input-file"] + ( "load test names to run from a file" ) + | Opt( config.filenamesAsTags ) + ["-#"]["--filenames-as-tags"] + ( "adds a tag for the filename" ) + | Opt( config.sectionsToRun, "section name" ) + ["-c"]["--section"] + ( "specify section to run" ) + | Opt( setVerbosity, "quiet|normal|high" ) + ["-v"]["--verbosity"] + ( "set output verbosity" ) + | Opt( config.listTestNamesOnly ) + ["--list-test-names-only"] + ( "list all/matching test cases names only" ) + | Opt( config.listReporters ) + ["--list-reporters"] + ( "list all reporters" ) + | Opt( setTestOrder, "decl|lex|rand" ) + ["--order"] + ( "test case order (defaults to decl)" ) + | Opt( setRngSeed, "'time'|number" ) + ["--rng-seed"] + ( "set a specific seed for random numbers" ) + | Opt( setColourUsage, "yes|no" ) + ["--use-colour"] + ( "should output be colourised" ) + | Opt( config.libIdentify ) + ["--libidentify"] + ( "report name and version according to libidentify standard" ) + | Opt( setWaitForKeypress, "start|exit|both" ) + ["--wait-for-keypress"] + ( "waits for a keypress before exiting" ) + | Opt( config.benchmarkResolutionMultiple, "multiplier" ) + ["--benchmark-resolution-multiple"] + ( "multiple of clock resolution to run benchmarks" ) + + | Arg( config.testsOrTags, "test name|pattern|tags" ) + ( "which test or tests to use" ); + + return cli; + } + +} // end namespace Catch +// end catch_commandline.cpp +// start catch_common.cpp + +#include +#include + +namespace Catch { + + bool SourceLineInfo::empty() const noexcept { + return file[0] == '\0'; + } + bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept { + return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); + } + bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept { + return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0)); + } + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { +#ifndef __GNUG__ + os << info.file << '(' << info.line << ')'; +#else + os << info.file << ':' << info.line; +#endif + return os; + } + + std::string StreamEndStop::operator+() const { + return std::string(); + } + + NonCopyable::NonCopyable() = default; + NonCopyable::~NonCopyable() = default; + +} +// end catch_common.cpp +// start catch_config.cpp + +// start catch_enforce.h + +#include + +#define CATCH_PREPARE_EXCEPTION( type, msg ) \ + type( ( Catch::ReusableStringStream() << msg ).str() ) +#define CATCH_INTERNAL_ERROR( msg ) \ + throw CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg); +#define CATCH_ERROR( msg ) \ + throw CATCH_PREPARE_EXCEPTION( std::domain_error, msg ) +#define CATCH_ENFORCE( condition, msg ) \ + do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false) + +// end catch_enforce.h +namespace Catch { + + Config::Config( ConfigData const& data ) + : m_data( data ), + m_stream( openStream() ) + { + TestSpecParser parser(ITagAliasRegistry::get()); + if (data.testsOrTags.empty()) { + parser.parse("~[.]"); // All not hidden tests + } + else { + m_hasTestFilters = true; + for( auto const& testOrTags : data.testsOrTags ) + parser.parse( testOrTags ); + } + m_testSpec = parser.testSpec(); + } + + std::string const& Config::getFilename() const { + return m_data.outputFilename ; + } + + bool Config::listTests() const { return m_data.listTests; } + bool Config::listTestNamesOnly() const { return m_data.listTestNamesOnly; } + bool Config::listTags() const { return m_data.listTags; } + bool Config::listReporters() const { return m_data.listReporters; } + + std::string Config::getProcessName() const { return m_data.processName; } + std::string const& Config::getReporterName() const { return m_data.reporterName; } + + std::vector const& Config::getTestsOrTags() const { return m_data.testsOrTags; } + std::vector const& Config::getSectionsToRun() const { return m_data.sectionsToRun; } + + TestSpec const& Config::testSpec() const { return m_testSpec; } + bool Config::hasTestFilters() const { return m_hasTestFilters; } + + bool Config::showHelp() const { return m_data.showHelp; } + + // IConfig interface + bool Config::allowThrows() const { return !m_data.noThrow; } + std::ostream& Config::stream() const { return m_stream->stream(); } + std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } + bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; } + bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); } + bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); } + ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; } + RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } + unsigned int Config::rngSeed() const { return m_data.rngSeed; } + int Config::benchmarkResolutionMultiple() const { return m_data.benchmarkResolutionMultiple; } + UseColour::YesOrNo Config::useColour() const { return m_data.useColour; } + bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; } + int Config::abortAfter() const { return m_data.abortAfter; } + bool Config::showInvisibles() const { return m_data.showInvisibles; } + Verbosity Config::verbosity() const { return m_data.verbosity; } + + IStream const* Config::openStream() { + return Catch::makeStream(m_data.outputFilename); + } + +} // end namespace Catch +// end catch_config.cpp +// start catch_console_colour.cpp + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wexit-time-destructors" +#endif + +// start catch_errno_guard.h + +namespace Catch { + + class ErrnoGuard { + public: + ErrnoGuard(); + ~ErrnoGuard(); + private: + int m_oldErrno; + }; + +} + +// end catch_errno_guard.h +#include + +namespace Catch { + namespace { + + struct IColourImpl { + virtual ~IColourImpl() = default; + virtual void use( Colour::Code _colourCode ) = 0; + }; + + struct NoColourImpl : IColourImpl { + void use( Colour::Code ) {} + + static IColourImpl* instance() { + static NoColourImpl s_instance; + return &s_instance; + } + }; + + } // anon namespace +} // namespace Catch + +#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) +# ifdef CATCH_PLATFORM_WINDOWS +# define CATCH_CONFIG_COLOUR_WINDOWS +# else +# define CATCH_CONFIG_COLOUR_ANSI +# endif +#endif + +#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// + +namespace Catch { +namespace { + + class Win32ColourImpl : public IColourImpl { + public: + Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) + { + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); + originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); + originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); + } + + virtual void use( Colour::Code _colourCode ) override { + switch( _colourCode ) { + case Colour::None: return setTextAttribute( originalForegroundAttributes ); + case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + case Colour::Red: return setTextAttribute( FOREGROUND_RED ); + case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); + case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); + case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); + case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); + case Colour::Grey: return setTextAttribute( 0 ); + + case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); + case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); + case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); + case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN ); + + case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); + + default: + CATCH_ERROR( "Unknown colour requested" ); + } + } + + private: + void setTextAttribute( WORD _textAttribute ) { + SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); + } + HANDLE stdoutHandle; + WORD originalForegroundAttributes; + WORD originalBackgroundAttributes; + }; + + IColourImpl* platformColourInstance() { + static Win32ColourImpl s_instance; + + IConfigPtr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = UseColour::Yes; + return colourMode == UseColour::Yes + ? &s_instance + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// + +#include + +namespace Catch { +namespace { + + // use POSIX/ ANSI console terminal codes + // Thanks to Adam Strzelecki for original contribution + // (http://github.com/nanoant) + // https://github.com/philsquared/Catch/pull/131 + class PosixColourImpl : public IColourImpl { + public: + virtual void use( Colour::Code _colourCode ) override { + switch( _colourCode ) { + case Colour::None: + case Colour::White: return setColour( "[0m" ); + case Colour::Red: return setColour( "[0;31m" ); + case Colour::Green: return setColour( "[0;32m" ); + case Colour::Blue: return setColour( "[0;34m" ); + case Colour::Cyan: return setColour( "[0;36m" ); + case Colour::Yellow: return setColour( "[0;33m" ); + case Colour::Grey: return setColour( "[1;30m" ); + + case Colour::LightGrey: return setColour( "[0;37m" ); + case Colour::BrightRed: return setColour( "[1;31m" ); + case Colour::BrightGreen: return setColour( "[1;32m" ); + case Colour::BrightWhite: return setColour( "[1;37m" ); + case Colour::BrightYellow: return setColour( "[1;33m" ); + + case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); + default: CATCH_INTERNAL_ERROR( "Unknown colour requested" ); + } + } + static IColourImpl* instance() { + static PosixColourImpl s_instance; + return &s_instance; + } + + private: + void setColour( const char* _escapeCode ) { + Catch::cout() << '\033' << _escapeCode; + } + }; + + bool useColourOnPlatform() { + return +#ifdef CATCH_PLATFORM_MAC + !isDebuggerActive() && +#endif +#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__)) + isatty(STDOUT_FILENO) +#else + false +#endif + ; + } + IColourImpl* platformColourInstance() { + ErrnoGuard guard; + IConfigPtr config = getCurrentContext().getConfig(); + UseColour::YesOrNo colourMode = config + ? config->useColour() + : UseColour::Auto; + if( colourMode == UseColour::Auto ) + colourMode = useColourOnPlatform() + ? UseColour::Yes + : UseColour::No; + return colourMode == UseColour::Yes + ? PosixColourImpl::instance() + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#else // not Windows or ANSI /////////////////////////////////////////////// + +namespace Catch { + + static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } + +} // end namespace Catch + +#endif // Windows/ ANSI/ None + +namespace Catch { + + Colour::Colour( Code _colourCode ) { use( _colourCode ); } + Colour::Colour( Colour&& rhs ) noexcept { + m_moved = rhs.m_moved; + rhs.m_moved = true; + } + Colour& Colour::operator=( Colour&& rhs ) noexcept { + m_moved = rhs.m_moved; + rhs.m_moved = true; + return *this; + } + + Colour::~Colour(){ if( !m_moved ) use( None ); } + + void Colour::use( Code _colourCode ) { + static IColourImpl* impl = platformColourInstance(); + impl->use( _colourCode ); + } + + std::ostream& operator << ( std::ostream& os, Colour const& ) { + return os; + } + +} // end namespace Catch + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif + +// end catch_console_colour.cpp +// start catch_context.cpp + +namespace Catch { + + class Context : public IMutableContext, NonCopyable { + + public: // IContext + virtual IResultCapture* getResultCapture() override { + return m_resultCapture; + } + virtual IRunner* getRunner() override { + return m_runner; + } + + virtual IConfigPtr const& getConfig() const override { + return m_config; + } + + virtual ~Context() override; + + public: // IMutableContext + virtual void setResultCapture( IResultCapture* resultCapture ) override { + m_resultCapture = resultCapture; + } + virtual void setRunner( IRunner* runner ) override { + m_runner = runner; + } + virtual void setConfig( IConfigPtr const& config ) override { + m_config = config; + } + + friend IMutableContext& getCurrentMutableContext(); + + private: + IConfigPtr m_config; + IRunner* m_runner = nullptr; + IResultCapture* m_resultCapture = nullptr; + }; + + IMutableContext *IMutableContext::currentContext = nullptr; + + void IMutableContext::createContext() + { + currentContext = new Context(); + } + + void cleanUpContext() { + delete IMutableContext::currentContext; + IMutableContext::currentContext = nullptr; + } + IContext::~IContext() = default; + IMutableContext::~IMutableContext() = default; + Context::~Context() = default; +} +// end catch_context.cpp +// start catch_debug_console.cpp + +// start catch_debug_console.h + +#include + +namespace Catch { + void writeToDebugConsole( std::string const& text ); +} + +// end catch_debug_console.h +#ifdef CATCH_PLATFORM_WINDOWS + + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + ::OutputDebugStringA( text.c_str() ); + } + } + +#else + + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + // !TBD: Need a version for Mac/ XCode and other IDEs + Catch::cout() << text; + } + } + +#endif // Platform +// end catch_debug_console.cpp +// start catch_debugger.cpp + +#ifdef CATCH_PLATFORM_MAC + +# include +# include +# include +# include +# include +# include +# include + +namespace Catch { + + // The following function is taken directly from the following technical note: + // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html + + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). + bool isDebuggerActive(){ + + int mib[4]; + struct kinfo_proc info; + std::size_t size; + + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + + info.kp_proc.p_flag = 0; + + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + // Call sysctl. + + size = sizeof(info); + if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) { + Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; + return false; + } + + // We're being debugged if the P_TRACED flag is set. + + return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); + } + } // namespace Catch + +#elif defined(CATCH_PLATFORM_LINUX) + #include + #include + + namespace Catch{ + // The standard POSIX way of detecting a debugger is to attempt to + // ptrace() the process, but this needs to be done from a child and not + // this process itself to still allow attaching to this process later + // if wanted, so is rather heavy. Under Linux we have the PID of the + // "debugger" (which doesn't need to be gdb, of course, it could also + // be strace, for example) in /proc/$PID/status, so just get it from + // there instead. + bool isDebuggerActive(){ + // Libstdc++ has a bug, where std::ifstream sets errno to 0 + // This way our users can properly assert over errno values + ErrnoGuard guard; + std::ifstream in("/proc/self/status"); + for( std::string line; std::getline(in, line); ) { + static const int PREFIX_LEN = 11; + if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) { + // We're traced if the PID is not 0 and no other PID starts + // with 0 digit, so it's enough to check for just a single + // character. + return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; + } + } + + return false; + } + } // namespace Catch +#elif defined(_MSC_VER) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#else + namespace Catch { + bool isDebuggerActive() { return false; } + } +#endif // Platform +// end catch_debugger.cpp +// start catch_decomposer.cpp + +namespace Catch { + + ITransientExpression::~ITransientExpression() = default; + + void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) { + if( lhs.size() + rhs.size() < 40 && + lhs.find('\n') == std::string::npos && + rhs.find('\n') == std::string::npos ) + os << lhs << " " << op << " " << rhs; + else + os << lhs << "\n" << op << "\n" << rhs; + } +} +// end catch_decomposer.cpp +// start catch_errno_guard.cpp + +#include + +namespace Catch { + ErrnoGuard::ErrnoGuard():m_oldErrno(errno){} + ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; } +} +// end catch_errno_guard.cpp +// start catch_exception_translator_registry.cpp + +// start catch_exception_translator_registry.h + +#include +#include +#include + +namespace Catch { + + class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { + public: + ~ExceptionTranslatorRegistry(); + virtual void registerTranslator( const IExceptionTranslator* translator ); + virtual std::string translateActiveException() const override; + std::string tryTranslators() const; + + private: + std::vector> m_translators; + }; +} + +// end catch_exception_translator_registry.h +#ifdef __OBJC__ +#import "Foundation/Foundation.h" +#endif + +namespace Catch { + + ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() { + } + + void ExceptionTranslatorRegistry::registerTranslator( const IExceptionTranslator* translator ) { + m_translators.push_back( std::unique_ptr( translator ) ); + } + + std::string ExceptionTranslatorRegistry::translateActiveException() const { + try { +#ifdef __OBJC__ + // In Objective-C try objective-c exceptions first + @try { + return tryTranslators(); + } + @catch (NSException *exception) { + return Catch::Detail::stringify( [exception description] ); + } +#else + // Compiling a mixed mode project with MSVC means that CLR + // exceptions will be caught in (...) as well. However, these + // do not fill-in std::current_exception and thus lead to crash + // when attempting rethrow. + // /EHa switch also causes structured exceptions to be caught + // here, but they fill-in current_exception properly, so + // at worst the output should be a little weird, instead of + // causing a crash. + if (std::current_exception() == nullptr) { + return "Non C++ exception. Possibly a CLR exception."; + } + return tryTranslators(); +#endif + } + catch( TestFailureException& ) { + std::rethrow_exception(std::current_exception()); + } + catch( std::exception& ex ) { + return ex.what(); + } + catch( std::string& msg ) { + return msg; + } + catch( const char* msg ) { + return msg; + } + catch(...) { + return "Unknown exception"; + } + } + + std::string ExceptionTranslatorRegistry::tryTranslators() const { + if( m_translators.empty() ) + std::rethrow_exception(std::current_exception()); + else + return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); + } +} +// end catch_exception_translator_registry.cpp +// start catch_fatal_condition.cpp + +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif + +#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS ) + +namespace { + // Report the error condition + void reportFatal( char const * const message ) { + Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message ); + } +} + +#endif // signals/SEH handling + +#if defined( CATCH_CONFIG_WINDOWS_SEH ) + +namespace Catch { + struct SignalDefs { DWORD id; const char* name; }; + + // There is no 1-1 mapping between signals and windows exceptions. + // Windows can easily distinguish between SO and SigSegV, + // but SigInt, SigTerm, etc are handled differently. + static SignalDefs signalDefs[] = { + { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" }, + { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" }, + { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" }, + { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" }, + }; + + LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { + for (auto const& def : signalDefs) { + if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { + reportFatal(def.name); + } + } + // If its not an exception we care about, pass it along. + // This stops us from eating debugger breaks etc. + return EXCEPTION_CONTINUE_SEARCH; + } + + FatalConditionHandler::FatalConditionHandler() { + isSet = true; + // 32k seems enough for Catch to handle stack overflow, + // but the value was found experimentally, so there is no strong guarantee + guaranteeSize = 32 * 1024; + exceptionHandlerHandle = nullptr; + // Register as first handler in current chain + exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); + // Pass in guarantee size to be filled + SetThreadStackGuarantee(&guaranteeSize); + } + + void FatalConditionHandler::reset() { + if (isSet) { + RemoveVectoredExceptionHandler(exceptionHandlerHandle); + SetThreadStackGuarantee(&guaranteeSize); + exceptionHandlerHandle = nullptr; + isSet = false; + } + } + + FatalConditionHandler::~FatalConditionHandler() { + reset(); + } + +bool FatalConditionHandler::isSet = false; +ULONG FatalConditionHandler::guaranteeSize = 0; +PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr; + +} // namespace Catch + +#elif defined( CATCH_CONFIG_POSIX_SIGNALS ) + +namespace Catch { + + struct SignalDefs { + int id; + const char* name; + }; + + // 32kb for the alternate stack seems to be sufficient. However, this value + // is experimentally determined, so that's not guaranteed. + constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ; + + static SignalDefs signalDefs[] = { + { SIGINT, "SIGINT - Terminal interrupt signal" }, + { SIGILL, "SIGILL - Illegal instruction signal" }, + { SIGFPE, "SIGFPE - Floating point error signal" }, + { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, + { SIGTERM, "SIGTERM - Termination request signal" }, + { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } + }; + + void FatalConditionHandler::handleSignal( int sig ) { + char const * name = ""; + for (auto const& def : signalDefs) { + if (sig == def.id) { + name = def.name; + break; + } + } + reset(); + reportFatal(name); + raise( sig ); + } + + FatalConditionHandler::FatalConditionHandler() { + isSet = true; + stack_t sigStack; + sigStack.ss_sp = altStackMem; + sigStack.ss_size = sigStackSize; + sigStack.ss_flags = 0; + sigaltstack(&sigStack, &oldSigStack); + struct sigaction sa = { }; + + sa.sa_handler = handleSignal; + sa.sa_flags = SA_ONSTACK; + for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { + sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); + } + } + + FatalConditionHandler::~FatalConditionHandler() { + reset(); + } + + void FatalConditionHandler::reset() { + if( isSet ) { + // Set signals back to previous values -- hopefully nobody overwrote them in the meantime + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { + sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); + } + // Return the old stack + sigaltstack(&oldSigStack, nullptr); + isSet = false; + } + } + + bool FatalConditionHandler::isSet = false; + struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; + stack_t FatalConditionHandler::oldSigStack = {}; + char FatalConditionHandler::altStackMem[sigStackSize] = {}; + +} // namespace Catch + +#else + +namespace Catch { + void FatalConditionHandler::reset() {} +} + +#endif // signals/SEH handling + +#if defined(__GNUC__) +# pragma GCC diagnostic pop +#endif +// end catch_fatal_condition.cpp +// start catch_interfaces_capture.cpp + +namespace Catch { + IResultCapture::~IResultCapture() = default; +} +// end catch_interfaces_capture.cpp +// start catch_interfaces_config.cpp + +namespace Catch { + IConfig::~IConfig() = default; +} +// end catch_interfaces_config.cpp +// start catch_interfaces_exception.cpp + +namespace Catch { + IExceptionTranslator::~IExceptionTranslator() = default; + IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default; +} +// end catch_interfaces_exception.cpp +// start catch_interfaces_registry_hub.cpp + +namespace Catch { + IRegistryHub::~IRegistryHub() = default; + IMutableRegistryHub::~IMutableRegistryHub() = default; +} +// end catch_interfaces_registry_hub.cpp +// start catch_interfaces_reporter.cpp + +// start catch_reporter_listening.h + +namespace Catch { + + class ListeningReporter : public IStreamingReporter { + using Reporters = std::vector; + Reporters m_listeners; + IStreamingReporterPtr m_reporter = nullptr; + + public: + void addListener( IStreamingReporterPtr&& listener ); + void addReporter( IStreamingReporterPtr&& reporter ); + + public: // IStreamingReporter + + ReporterPreferences getPreferences() const override; + + void noMatchingTestCases( std::string const& spec ) override; + + static std::set getSupportedVerbosities(); + + void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override; + void benchmarkEnded( BenchmarkStats const& benchmarkStats ) override; + + void testRunStarting( TestRunInfo const& testRunInfo ) override; + void testGroupStarting( GroupInfo const& groupInfo ) override; + void testCaseStarting( TestCaseInfo const& testInfo ) override; + void sectionStarting( SectionInfo const& sectionInfo ) override; + void assertionStarting( AssertionInfo const& assertionInfo ) override; + + // The return value indicates if the messages buffer should be cleared: + bool assertionEnded( AssertionStats const& assertionStats ) override; + void sectionEnded( SectionStats const& sectionStats ) override; + void testCaseEnded( TestCaseStats const& testCaseStats ) override; + void testGroupEnded( TestGroupStats const& testGroupStats ) override; + void testRunEnded( TestRunStats const& testRunStats ) override; + + void skipTest( TestCaseInfo const& testInfo ) override; + bool isMulti() const override; + + }; + +} // end namespace Catch + +// end catch_reporter_listening.h +namespace Catch { + + ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig ) + : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} + + ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ) + : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} + + std::ostream& ReporterConfig::stream() const { return *m_stream; } + IConfigPtr ReporterConfig::fullConfig() const { return m_fullConfig; } + + TestRunInfo::TestRunInfo( std::string const& _name ) : name( _name ) {} + + GroupInfo::GroupInfo( std::string const& _name, + std::size_t _groupIndex, + std::size_t _groupsCount ) + : name( _name ), + groupIndex( _groupIndex ), + groupsCounts( _groupsCount ) + {} + + AssertionStats::AssertionStats( AssertionResult const& _assertionResult, + std::vector const& _infoMessages, + Totals const& _totals ) + : assertionResult( _assertionResult ), + infoMessages( _infoMessages ), + totals( _totals ) + { + assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression; + + if( assertionResult.hasMessage() ) { + // Copy message into messages list. + // !TBD This should have been done earlier, somewhere + MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); + builder << assertionResult.getMessage(); + builder.m_info.message = builder.m_stream.str(); + + infoMessages.push_back( builder.m_info ); + } + } + + AssertionStats::~AssertionStats() = default; + + SectionStats::SectionStats( SectionInfo const& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ) + : sectionInfo( _sectionInfo ), + assertions( _assertions ), + durationInSeconds( _durationInSeconds ), + missingAssertions( _missingAssertions ) + {} + + SectionStats::~SectionStats() = default; + + TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string const& _stdOut, + std::string const& _stdErr, + bool _aborting ) + : testInfo( _testInfo ), + totals( _totals ), + stdOut( _stdOut ), + stdErr( _stdErr ), + aborting( _aborting ) + {} + + TestCaseStats::~TestCaseStats() = default; + + TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo, + Totals const& _totals, + bool _aborting ) + : groupInfo( _groupInfo ), + totals( _totals ), + aborting( _aborting ) + {} + + TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo ) + : groupInfo( _groupInfo ), + aborting( false ) + {} + + TestGroupStats::~TestGroupStats() = default; + + TestRunStats::TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ) + : runInfo( _runInfo ), + totals( _totals ), + aborting( _aborting ) + {} + + TestRunStats::~TestRunStats() = default; + + void IStreamingReporter::fatalErrorEncountered( StringRef ) {} + bool IStreamingReporter::isMulti() const { return false; } + + IReporterFactory::~IReporterFactory() = default; + IReporterRegistry::~IReporterRegistry() = default; + +} // end namespace Catch +// end catch_interfaces_reporter.cpp +// start catch_interfaces_runner.cpp + +namespace Catch { + IRunner::~IRunner() = default; +} +// end catch_interfaces_runner.cpp +// start catch_interfaces_testcase.cpp + +namespace Catch { + ITestInvoker::~ITestInvoker() = default; + ITestCaseRegistry::~ITestCaseRegistry() = default; +} +// end catch_interfaces_testcase.cpp +// start catch_leak_detector.cpp + +#ifdef CATCH_CONFIG_WINDOWS_CRTDBG +#include + +namespace Catch { + + LeakDetector::LeakDetector() { + int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + flag |= _CRTDBG_LEAK_CHECK_DF; + flag |= _CRTDBG_ALLOC_MEM_DF; + _CrtSetDbgFlag(flag); + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); + // Change this to leaking allocation's number to break there + _CrtSetBreakAlloc(-1); + } +} + +#else + + Catch::LeakDetector::LeakDetector() {} + +#endif +// end catch_leak_detector.cpp +// start catch_list.cpp + +// start catch_list.h + +#include + +namespace Catch { + + std::size_t listTests( Config const& config ); + + std::size_t listTestsNamesOnly( Config const& config ); + + struct TagInfo { + void add( std::string const& spelling ); + std::string all() const; + + std::set spellings; + std::size_t count = 0; + }; + + std::size_t listTags( Config const& config ); + + std::size_t listReporters( Config const& /*config*/ ); + + Option list( Config const& config ); + +} // end namespace Catch + +// end catch_list.h +// start catch_text.h + +namespace Catch { + using namespace clara::TextFlow; +} + +// end catch_text.h +#include +#include +#include + +namespace Catch { + + std::size_t listTests( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( config.hasTestFilters() ) + Catch::cout() << "Matching test cases:\n"; + else { + Catch::cout() << "All available test cases:\n"; + } + + auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( auto const& testCaseInfo : matchedTestCases ) { + Colour::Code colour = testCaseInfo.isHidden() + ? Colour::SecondaryText + : Colour::None; + Colour colourGuard( colour ); + + Catch::cout() << Column( testCaseInfo.name ).initialIndent( 2 ).indent( 4 ) << "\n"; + if( config.verbosity() >= Verbosity::High ) { + Catch::cout() << Column( Catch::Detail::stringify( testCaseInfo.lineInfo ) ).indent(4) << std::endl; + std::string description = testCaseInfo.description; + if( description.empty() ) + description = "(NO DESCRIPTION)"; + Catch::cout() << Column( description ).indent(4) << std::endl; + } + if( !testCaseInfo.tags.empty() ) + Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n"; + } + + if( !config.hasTestFilters() ) + Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl; + else + Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl; + return matchedTestCases.size(); + } + + std::size_t listTestsNamesOnly( Config const& config ) { + TestSpec testSpec = config.testSpec(); + std::size_t matchedTests = 0; + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( auto const& testCaseInfo : matchedTestCases ) { + matchedTests++; + if( startsWith( testCaseInfo.name, '#' ) ) + Catch::cout() << '"' << testCaseInfo.name << '"'; + else + Catch::cout() << testCaseInfo.name; + if ( config.verbosity() >= Verbosity::High ) + Catch::cout() << "\t@" << testCaseInfo.lineInfo; + Catch::cout() << std::endl; + } + return matchedTests; + } + + void TagInfo::add( std::string const& spelling ) { + ++count; + spellings.insert( spelling ); + } + + std::string TagInfo::all() const { + std::string out; + for( auto const& spelling : spellings ) + out += "[" + spelling + "]"; + return out; + } + + std::size_t listTags( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( config.hasTestFilters() ) + Catch::cout() << "Tags for matching test cases:\n"; + else { + Catch::cout() << "All available tags:\n"; + } + + std::map tagCounts; + + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); + for( auto const& testCase : matchedTestCases ) { + for( auto const& tagName : testCase.getTestCaseInfo().tags ) { + std::string lcaseTagName = toLower( tagName ); + auto countIt = tagCounts.find( lcaseTagName ); + if( countIt == tagCounts.end() ) + countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; + countIt->second.add( tagName ); + } + } + + for( auto const& tagCount : tagCounts ) { + ReusableStringStream rss; + rss << " " << std::setw(2) << tagCount.second.count << " "; + auto str = rss.str(); + auto wrapper = Column( tagCount.second.all() ) + .initialIndent( 0 ) + .indent( str.size() ) + .width( CATCH_CONFIG_CONSOLE_WIDTH-10 ); + Catch::cout() << str << wrapper << '\n'; + } + Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; + return tagCounts.size(); + } + + std::size_t listReporters( Config const& /*config*/ ) { + Catch::cout() << "Available reporters:\n"; + IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + std::size_t maxNameLen = 0; + for( auto const& factoryKvp : factories ) + maxNameLen = (std::max)( maxNameLen, factoryKvp.first.size() ); + + for( auto const& factoryKvp : factories ) { + Catch::cout() + << Column( factoryKvp.first + ":" ) + .indent(2) + .width( 5+maxNameLen ) + + Column( factoryKvp.second->getDescription() ) + .initialIndent(0) + .indent(2) + .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) + << "\n"; + } + Catch::cout() << std::endl; + return factories.size(); + } + + Option list( Config const& config ) { + Option listedCount; + if( config.listTests() ) + listedCount = listedCount.valueOr(0) + listTests( config ); + if( config.listTestNamesOnly() ) + listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); + if( config.listTags() ) + listedCount = listedCount.valueOr(0) + listTags( config ); + if( config.listReporters() ) + listedCount = listedCount.valueOr(0) + listReporters( config ); + return listedCount; + } + +} // end namespace Catch +// end catch_list.cpp +// start catch_matchers.cpp + +namespace Catch { +namespace Matchers { + namespace Impl { + + std::string MatcherUntypedBase::toString() const { + if( m_cachedToString.empty() ) + m_cachedToString = describe(); + return m_cachedToString; + } + + MatcherUntypedBase::~MatcherUntypedBase() = default; + + } // namespace Impl +} // namespace Matchers + +using namespace Matchers; +using Matchers::Impl::MatcherBase; + +} // namespace Catch +// end catch_matchers.cpp +// start catch_matchers_floating.cpp + +// start catch_to_string.hpp + +#include + +namespace Catch { + template + std::string to_string(T const& t) { +#if defined(CATCH_CONFIG_CPP11_TO_STRING) + return std::to_string(t); +#else + ReusableStringStream rss; + rss << t; + return rss.str(); +#endif + } +} // end namespace Catch + +// end catch_to_string.hpp +#include +#include +#include +#include + +namespace Catch { +namespace Matchers { +namespace Floating { +enum class FloatingPointKind : uint8_t { + Float, + Double +}; +} +} +} + +namespace { + +template +struct Converter; + +template <> +struct Converter { + static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated"); + Converter(float f) { + std::memcpy(&i, &f, sizeof(f)); + } + int32_t i; +}; + +template <> +struct Converter { + static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated"); + Converter(double d) { + std::memcpy(&i, &d, sizeof(d)); + } + int64_t i; +}; + +template +auto convert(T t) -> Converter { + return Converter(t); +} + +template +bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) { + // Comparison with NaN should always be false. + // This way we can rule it out before getting into the ugly details + if (std::isnan(lhs) || std::isnan(rhs)) { + return false; + } + + auto lc = convert(lhs); + auto rc = convert(rhs); + + if ((lc.i < 0) != (rc.i < 0)) { + // Potentially we can have +0 and -0 + return lhs == rhs; + } + + auto ulpDiff = std::abs(lc.i - rc.i); + return ulpDiff <= maxUlpDiff; +} + +} + +namespace Catch { +namespace Matchers { +namespace Floating { + WithinAbsMatcher::WithinAbsMatcher(double target, double margin) + :m_target{ target }, m_margin{ margin } { + if (m_margin < 0) { + throw std::domain_error("Allowed margin difference has to be >= 0"); + } + } + + // Performs equivalent check of std::fabs(lhs - rhs) <= margin + // But without the subtraction to allow for INFINITY in comparison + bool WithinAbsMatcher::match(double const& matchee) const { + return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee); + } + + std::string WithinAbsMatcher::describe() const { + return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target); + } + + WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType) + :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } { + if (m_ulps < 0) { + throw std::domain_error("Allowed ulp difference has to be >= 0"); + } + } + + bool WithinUlpsMatcher::match(double const& matchee) const { + switch (m_type) { + case FloatingPointKind::Float: + return almostEqualUlps(static_cast(matchee), static_cast(m_target), m_ulps); + case FloatingPointKind::Double: + return almostEqualUlps(matchee, m_target, m_ulps); + default: + throw std::domain_error("Unknown FloatingPointKind value"); + } + } + + std::string WithinUlpsMatcher::describe() const { + return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : ""); + } + +}// namespace Floating + +Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff) { + return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double); +} + +Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff) { + return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float); +} + +Floating::WithinAbsMatcher WithinAbs(double target, double margin) { + return Floating::WithinAbsMatcher(target, margin); +} + +} // namespace Matchers +} // namespace Catch + +// end catch_matchers_floating.cpp +// start catch_matchers_generic.cpp + +std::string Catch::Matchers::Generic::Detail::finalizeDescription(const std::string& desc) { + if (desc.empty()) { + return "matches undescribed predicate"; + } else { + return "matches predicate: \"" + desc + '"'; + } +} +// end catch_matchers_generic.cpp +// start catch_matchers_string.cpp + +#include + +namespace Catch { +namespace Matchers { + + namespace StdString { + + CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_str( adjustString( str ) ) + {} + std::string CasedString::adjustString( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No + ? toLower( str ) + : str; + } + std::string CasedString::caseSensitivitySuffix() const { + return m_caseSensitivity == CaseSensitive::No + ? " (case insensitive)" + : std::string(); + } + + StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator ) + : m_comparator( comparator ), + m_operation( operation ) { + } + + std::string StringMatcherBase::describe() const { + std::string description; + description.reserve(5 + m_operation.size() + m_comparator.m_str.size() + + m_comparator.caseSensitivitySuffix().size()); + description += m_operation; + description += ": \""; + description += m_comparator.m_str; + description += "\""; + description += m_comparator.caseSensitivitySuffix(); + return description; + } + + EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {} + + bool EqualsMatcher::match( std::string const& source ) const { + return m_comparator.adjustString( source ) == m_comparator.m_str; + } + + ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {} + + bool ContainsMatcher::match( std::string const& source ) const { + return contains( m_comparator.adjustString( source ), m_comparator.m_str ); + } + + StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {} + + bool StartsWithMatcher::match( std::string const& source ) const { + return startsWith( m_comparator.adjustString( source ), m_comparator.m_str ); + } + + EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {} + + bool EndsWithMatcher::match( std::string const& source ) const { + return endsWith( m_comparator.adjustString( source ), m_comparator.m_str ); + } + + RegexMatcher::RegexMatcher(std::string regex, CaseSensitive::Choice caseSensitivity): m_regex(std::move(regex)), m_caseSensitivity(caseSensitivity) {} + + bool RegexMatcher::match(std::string const& matchee) const { + auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway + if (m_caseSensitivity == CaseSensitive::Choice::No) { + flags |= std::regex::icase; + } + auto reg = std::regex(m_regex, flags); + return std::regex_match(matchee, reg); + } + + std::string RegexMatcher::describe() const { + return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Choice::Yes)? " case sensitively" : " case insensitively"); + } + + } // namespace StdString + + StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) { + return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) ); + } + StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) { + return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) ); + } + StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { + return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) ); + } + StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { + return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) ); + } + + StdString::RegexMatcher Matches(std::string const& regex, CaseSensitive::Choice caseSensitivity) { + return StdString::RegexMatcher(regex, caseSensitivity); + } + +} // namespace Matchers +} // namespace Catch +// end catch_matchers_string.cpp +// start catch_message.cpp + +// start catch_uncaught_exceptions.h + +namespace Catch { + bool uncaught_exceptions(); +} // end namespace Catch + +// end catch_uncaught_exceptions.h +namespace Catch { + + MessageInfo::MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + type( _type ), + sequence( ++globalCount ) + {} + + bool MessageInfo::operator==( MessageInfo const& other ) const { + return sequence == other.sequence; + } + + bool MessageInfo::operator<( MessageInfo const& other ) const { + return sequence < other.sequence; + } + + // This may need protecting if threading support is added + unsigned int MessageInfo::globalCount = 0; + + //////////////////////////////////////////////////////////////////////////// + + Catch::MessageBuilder::MessageBuilder( std::string const& macroName, + SourceLineInfo const& lineInfo, + ResultWas::OfType type ) + :m_info(macroName, lineInfo, type) {} + + //////////////////////////////////////////////////////////////////////////// + + ScopedMessage::ScopedMessage( MessageBuilder const& builder ) + : m_info( builder.m_info ) + { + m_info.message = builder.m_stream.str(); + getResultCapture().pushScopedMessage( m_info ); + } + + ScopedMessage::~ScopedMessage() { + if ( !uncaught_exceptions() ){ + getResultCapture().popScopedMessage(m_info); + } + } +} // end namespace Catch +// end catch_message.cpp +// start catch_output_redirect.cpp + +// start catch_output_redirect.h +#ifndef TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H +#define TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H + +#include +#include +#include + +namespace Catch { + + class RedirectedStream { + std::ostream& m_originalStream; + std::ostream& m_redirectionStream; + std::streambuf* m_prevBuf; + + public: + RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ); + ~RedirectedStream(); + }; + + class RedirectedStdOut { + ReusableStringStream m_rss; + RedirectedStream m_cout; + public: + RedirectedStdOut(); + auto str() const -> std::string; + }; + + // StdErr has two constituent streams in C++, std::cerr and std::clog + // This means that we need to redirect 2 streams into 1 to keep proper + // order of writes + class RedirectedStdErr { + ReusableStringStream m_rss; + RedirectedStream m_cerr; + RedirectedStream m_clog; + public: + RedirectedStdErr(); + auto str() const -> std::string; + }; + + // Windows's implementation of std::tmpfile is terrible (it tries + // to create a file inside system folder, thus requiring elevated + // privileges for the binary), so we have to use tmpnam(_s) and + // create the file ourselves there. + class TempFile { + public: + TempFile(TempFile const&) = delete; + TempFile& operator=(TempFile const&) = delete; + TempFile(TempFile&&) = delete; + TempFile& operator=(TempFile&&) = delete; + + TempFile(); + ~TempFile(); + + std::FILE* getFile(); + std::string getContents(); + + private: + std::FILE* m_file = nullptr; + #if defined(_MSC_VER) + char m_buffer[L_tmpnam] = { 0 }; + #endif + }; + + class OutputRedirect { + public: + OutputRedirect(OutputRedirect const&) = delete; + OutputRedirect& operator=(OutputRedirect const&) = delete; + OutputRedirect(OutputRedirect&&) = delete; + OutputRedirect& operator=(OutputRedirect&&) = delete; + + OutputRedirect(std::string& stdout_dest, std::string& stderr_dest); + ~OutputRedirect(); + + private: + int m_originalStdout = -1; + int m_originalStderr = -1; + TempFile m_stdoutFile; + TempFile m_stderrFile; + std::string& m_stdoutDest; + std::string& m_stderrDest; + }; + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H +// end catch_output_redirect.h +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) +#include //_dup and _dup2 +#define dup _dup +#define dup2 _dup2 +#define fileno _fileno +#else +#include // dup and dup2 +#endif + +namespace Catch { + + RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ) + : m_originalStream( originalStream ), + m_redirectionStream( redirectionStream ), + m_prevBuf( m_originalStream.rdbuf() ) + { + m_originalStream.rdbuf( m_redirectionStream.rdbuf() ); + } + + RedirectedStream::~RedirectedStream() { + m_originalStream.rdbuf( m_prevBuf ); + } + + RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {} + auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); } + + RedirectedStdErr::RedirectedStdErr() + : m_cerr( Catch::cerr(), m_rss.get() ), + m_clog( Catch::clog(), m_rss.get() ) + {} + auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); } + +#if defined(_MSC_VER) + TempFile::TempFile() { + if (tmpnam_s(m_buffer)) { + throw std::runtime_error("Could not get a temp filename"); + } + if (fopen_s(&m_file, m_buffer, "w")) { + char buffer[100]; + if (strerror_s(buffer, errno)) { + throw std::runtime_error("Could not translate errno to string"); + } + throw std::runtime_error("Could not open the temp file: " + std::string(m_buffer) + buffer); + } + } +#else + TempFile::TempFile() { + m_file = std::tmpfile(); + if (!m_file) { + throw std::runtime_error("Could not create a temp file."); + } + } + +#endif + + TempFile::~TempFile() { + // TBD: What to do about errors here? + std::fclose(m_file); + // We manually create the file on Windows only, on Linux + // it will be autodeleted +#if defined(_MSC_VER) + std::remove(m_buffer); +#endif + } + + FILE* TempFile::getFile() { + return m_file; + } + + std::string TempFile::getContents() { + std::stringstream sstr; + char buffer[100] = {}; + std::rewind(m_file); + while (std::fgets(buffer, sizeof(buffer), m_file)) { + sstr << buffer; + } + return sstr.str(); + } + + OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) : + m_originalStdout(dup(1)), + m_originalStderr(dup(2)), + m_stdoutDest(stdout_dest), + m_stderrDest(stderr_dest) { + dup2(fileno(m_stdoutFile.getFile()), 1); + dup2(fileno(m_stderrFile.getFile()), 2); + } + + OutputRedirect::~OutputRedirect() { + Catch::cout() << std::flush; + fflush(stdout); + // Since we support overriding these streams, we flush cerr + // even though std::cerr is unbuffered + Catch::cerr() << std::flush; + Catch::clog() << std::flush; + fflush(stderr); + + dup2(m_originalStdout, 1); + dup2(m_originalStderr, 2); + + m_stdoutDest += m_stdoutFile.getContents(); + m_stderrDest += m_stderrFile.getContents(); + } + +} // namespace Catch + +#if defined(_MSC_VER) +#undef dup +#undef dup2 +#undef fileno +#endif +// end catch_output_redirect.cpp +// start catch_random_number_generator.cpp + +// start catch_random_number_generator.h + +#include + +namespace Catch { + + struct IConfig; + + void seedRng( IConfig const& config ); + + unsigned int rngSeed(); + + struct RandomNumberGenerator { + using result_type = unsigned int; + + static constexpr result_type (min)() { return 0; } + static constexpr result_type (max)() { return 1000000; } + + result_type operator()( result_type n ) const; + result_type operator()() const; + + template + static void shuffle( V& vector ) { + RandomNumberGenerator rng; + std::shuffle( vector.begin(), vector.end(), rng ); + } + }; + +} + +// end catch_random_number_generator.h +#include + +namespace Catch { + + void seedRng( IConfig const& config ) { + if( config.rngSeed() != 0 ) + std::srand( config.rngSeed() ); + } + unsigned int rngSeed() { + return getCurrentContext().getConfig()->rngSeed(); + } + + RandomNumberGenerator::result_type RandomNumberGenerator::operator()( result_type n ) const { + return std::rand() % n; + } + RandomNumberGenerator::result_type RandomNumberGenerator::operator()() const { + return std::rand() % (max)(); + } + +} +// end catch_random_number_generator.cpp +// start catch_registry_hub.cpp + +// start catch_test_case_registry_impl.h + +#include +#include +#include +#include + +namespace Catch { + + class TestCase; + struct IConfig; + + std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ); + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + + void enforceNoDuplicateTestCases( std::vector const& functions ); + + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + + class TestRegistry : public ITestCaseRegistry { + public: + virtual ~TestRegistry() = default; + + virtual void registerTest( TestCase const& testCase ); + + std::vector const& getAllTests() const override; + std::vector const& getAllTestsSorted( IConfig const& config ) const override; + + private: + std::vector m_functions; + mutable RunTests::InWhatOrder m_currentSortOrder = RunTests::InDeclarationOrder; + mutable std::vector m_sortedFunctions; + std::size_t m_unnamedCount = 0; + std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised + }; + + /////////////////////////////////////////////////////////////////////////// + + class TestInvokerAsFunction : public ITestInvoker { + void(*m_testAsFunction)(); + public: + TestInvokerAsFunction( void(*testAsFunction)() ) noexcept; + + void invoke() const override; + }; + + std::string extractClassName( StringRef const& classOrQualifiedMethodName ); + + /////////////////////////////////////////////////////////////////////////// + +} // end namespace Catch + +// end catch_test_case_registry_impl.h +// start catch_reporter_registry.h + +#include + +namespace Catch { + + class ReporterRegistry : public IReporterRegistry { + + public: + + ~ReporterRegistry() override; + + IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const override; + + void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ); + void registerListener( IReporterFactoryPtr const& factory ); + + FactoryMap const& getFactories() const override; + Listeners const& getListeners() const override; + + private: + FactoryMap m_factories; + Listeners m_listeners; + }; +} + +// end catch_reporter_registry.h +// start catch_tag_alias_registry.h + +// start catch_tag_alias.h + +#include + +namespace Catch { + + struct TagAlias { + TagAlias(std::string const& _tag, SourceLineInfo _lineInfo); + + std::string tag; + SourceLineInfo lineInfo; + }; + +} // end namespace Catch + +// end catch_tag_alias.h +#include + +namespace Catch { + + class TagAliasRegistry : public ITagAliasRegistry { + public: + ~TagAliasRegistry() override; + TagAlias const* find( std::string const& alias ) const override; + std::string expandAliases( std::string const& unexpandedTestSpec ) const override; + void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ); + + private: + std::map m_registry; + }; + +} // end namespace Catch + +// end catch_tag_alias_registry.h +// start catch_startup_exception_registry.h + +#include +#include + +namespace Catch { + + class StartupExceptionRegistry { + public: + void add(std::exception_ptr const& exception) noexcept; + std::vector const& getExceptions() const noexcept; + private: + std::vector m_exceptions; + }; + +} // end namespace Catch + +// end catch_startup_exception_registry.h +namespace Catch { + + namespace { + + class RegistryHub : public IRegistryHub, public IMutableRegistryHub, + private NonCopyable { + + public: // IRegistryHub + RegistryHub() = default; + IReporterRegistry const& getReporterRegistry() const override { + return m_reporterRegistry; + } + ITestCaseRegistry const& getTestCaseRegistry() const override { + return m_testCaseRegistry; + } + IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() override { + return m_exceptionTranslatorRegistry; + } + ITagAliasRegistry const& getTagAliasRegistry() const override { + return m_tagAliasRegistry; + } + StartupExceptionRegistry const& getStartupExceptionRegistry() const override { + return m_exceptionRegistry; + } + + public: // IMutableRegistryHub + void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) override { + m_reporterRegistry.registerReporter( name, factory ); + } + void registerListener( IReporterFactoryPtr const& factory ) override { + m_reporterRegistry.registerListener( factory ); + } + void registerTest( TestCase const& testInfo ) override { + m_testCaseRegistry.registerTest( testInfo ); + } + void registerTranslator( const IExceptionTranslator* translator ) override { + m_exceptionTranslatorRegistry.registerTranslator( translator ); + } + void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override { + m_tagAliasRegistry.add( alias, tag, lineInfo ); + } + void registerStartupException() noexcept override { + m_exceptionRegistry.add(std::current_exception()); + } + + private: + TestRegistry m_testCaseRegistry; + ReporterRegistry m_reporterRegistry; + ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; + TagAliasRegistry m_tagAliasRegistry; + StartupExceptionRegistry m_exceptionRegistry; + }; + + // Single, global, instance + RegistryHub*& getTheRegistryHub() { + static RegistryHub* theRegistryHub = nullptr; + if( !theRegistryHub ) + theRegistryHub = new RegistryHub(); + return theRegistryHub; + } + } + + IRegistryHub& getRegistryHub() { + return *getTheRegistryHub(); + } + IMutableRegistryHub& getMutableRegistryHub() { + return *getTheRegistryHub(); + } + void cleanUp() { + delete getTheRegistryHub(); + getTheRegistryHub() = nullptr; + cleanUpContext(); + ReusableStringStream::cleanup(); + } + std::string translateActiveException() { + return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); + } + +} // end namespace Catch +// end catch_registry_hub.cpp +// start catch_reporter_registry.cpp + +namespace Catch { + + ReporterRegistry::~ReporterRegistry() = default; + + IStreamingReporterPtr ReporterRegistry::create( std::string const& name, IConfigPtr const& config ) const { + auto it = m_factories.find( name ); + if( it == m_factories.end() ) + return nullptr; + return it->second->create( ReporterConfig( config ) ); + } + + void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) { + m_factories.emplace(name, factory); + } + void ReporterRegistry::registerListener( IReporterFactoryPtr const& factory ) { + m_listeners.push_back( factory ); + } + + IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const { + return m_factories; + } + IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const { + return m_listeners; + } + +} +// end catch_reporter_registry.cpp +// start catch_result_type.cpp + +namespace Catch { + + bool isOk( ResultWas::OfType resultType ) { + return ( resultType & ResultWas::FailureBit ) == 0; + } + bool isJustInfo( int flags ) { + return flags == ResultWas::Info; + } + + ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { + return static_cast( static_cast( lhs ) | static_cast( rhs ) ); + } + + bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } + bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } + +} // end namespace Catch +// end catch_result_type.cpp +// start catch_run_context.cpp + +#include +#include +#include + +namespace Catch { + + RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter) + : m_runInfo(_config->name()), + m_context(getCurrentMutableContext()), + m_config(_config), + m_reporter(std::move(reporter)), + m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal }, + m_includeSuccessfulResults( m_config->includeSuccessfulResults() ) + { + m_context.setRunner(this); + m_context.setConfig(m_config); + m_context.setResultCapture(this); + m_reporter->testRunStarting(m_runInfo); + } + + RunContext::~RunContext() { + m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting())); + } + + void RunContext::testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount) { + m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount)); + } + + void RunContext::testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount) { + m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting())); + } + + Totals RunContext::runTest(TestCase const& testCase) { + Totals prevTotals = m_totals; + + std::string redirectedCout; + std::string redirectedCerr; + + auto const& testInfo = testCase.getTestCaseInfo(); + + m_reporter->testCaseStarting(testInfo); + + m_activeTestCase = &testCase; + + ITracker& rootTracker = m_trackerContext.startRun(); + assert(rootTracker.isSectionTracker()); + static_cast(rootTracker).addInitialFilters(m_config->getSectionsToRun()); + do { + m_trackerContext.startCycle(); + m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo)); + runCurrentTest(redirectedCout, redirectedCerr); + } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting()); + + Totals deltaTotals = m_totals.delta(prevTotals); + if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) { + deltaTotals.assertions.failed++; + deltaTotals.testCases.passed--; + deltaTotals.testCases.failed++; + } + m_totals.testCases += deltaTotals.testCases; + m_reporter->testCaseEnded(TestCaseStats(testInfo, + deltaTotals, + redirectedCout, + redirectedCerr, + aborting())); + + m_activeTestCase = nullptr; + m_testCaseTracker = nullptr; + + return deltaTotals; + } + + IConfigPtr RunContext::config() const { + return m_config; + } + + IStreamingReporter& RunContext::reporter() const { + return *m_reporter; + } + + void RunContext::assertionEnded(AssertionResult const & result) { + if (result.getResultType() == ResultWas::Ok) { + m_totals.assertions.passed++; + m_lastAssertionPassed = true; + } else if (!result.isOk()) { + m_lastAssertionPassed = false; + if( m_activeTestCase->getTestCaseInfo().okToFail() ) + m_totals.assertions.failedButOk++; + else + m_totals.assertions.failed++; + } + else { + m_lastAssertionPassed = true; + } + + // We have no use for the return value (whether messages should be cleared), because messages were made scoped + // and should be let to clear themselves out. + static_cast(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); + + // Reset working state + resetAssertionInfo(); + m_lastResult = result; + } + void RunContext::resetAssertionInfo() { + m_lastAssertionInfo.macroName = StringRef(); + m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr; + } + + bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) { + ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo)); + if (!sectionTracker.isOpen()) + return false; + m_activeSections.push_back(§ionTracker); + + m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; + + m_reporter->sectionStarting(sectionInfo); + + assertions = m_totals.assertions; + + return true; + } + + bool RunContext::testForMissingAssertions(Counts& assertions) { + if (assertions.total() != 0) + return false; + if (!m_config->warnAboutMissingAssertions()) + return false; + if (m_trackerContext.currentTracker().hasChildren()) + return false; + m_totals.assertions.failed++; + assertions.failed++; + return true; + } + + void RunContext::sectionEnded(SectionEndInfo const & endInfo) { + Counts assertions = m_totals.assertions - endInfo.prevAssertions; + bool missingAssertions = testForMissingAssertions(assertions); + + if (!m_activeSections.empty()) { + m_activeSections.back()->close(); + m_activeSections.pop_back(); + } + + m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions)); + m_messages.clear(); + } + + void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) { + if (m_unfinishedSections.empty()) + m_activeSections.back()->fail(); + else + m_activeSections.back()->close(); + m_activeSections.pop_back(); + + m_unfinishedSections.push_back(endInfo); + } + void RunContext::benchmarkStarting( BenchmarkInfo const& info ) { + m_reporter->benchmarkStarting( info ); + } + void RunContext::benchmarkEnded( BenchmarkStats const& stats ) { + m_reporter->benchmarkEnded( stats ); + } + + void RunContext::pushScopedMessage(MessageInfo const & message) { + m_messages.push_back(message); + } + + void RunContext::popScopedMessage(MessageInfo const & message) { + m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end()); + } + + std::string RunContext::getCurrentTestName() const { + return m_activeTestCase + ? m_activeTestCase->getTestCaseInfo().name + : std::string(); + } + + const AssertionResult * RunContext::getLastResult() const { + return &(*m_lastResult); + } + + void RunContext::exceptionEarlyReported() { + m_shouldReportUnexpected = false; + } + + void RunContext::handleFatalErrorCondition( StringRef message ) { + // First notify reporter that bad things happened + m_reporter->fatalErrorEncountered(message); + + // Don't rebuild the result -- the stringification itself can cause more fatal errors + // Instead, fake a result data. + AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } ); + tempResult.message = message; + AssertionResult result(m_lastAssertionInfo, tempResult); + + assertionEnded(result); + + handleUnfinishedSections(); + + // Recreate section for test case (as we will lose the one that was in scope) + auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description); + + Counts assertions; + assertions.failed = 1; + SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false); + m_reporter->sectionEnded(testCaseSectionStats); + + auto const& testInfo = m_activeTestCase->getTestCaseInfo(); + + Totals deltaTotals; + deltaTotals.testCases.failed = 1; + deltaTotals.assertions.failed = 1; + m_reporter->testCaseEnded(TestCaseStats(testInfo, + deltaTotals, + std::string(), + std::string(), + false)); + m_totals.testCases.failed++; + testGroupEnded(std::string(), m_totals, 1, 1); + m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false)); + } + + bool RunContext::lastAssertionPassed() { + return m_lastAssertionPassed; + } + + void RunContext::assertionPassed() { + m_lastAssertionPassed = true; + ++m_totals.assertions.passed; + resetAssertionInfo(); + } + + bool RunContext::aborting() const { + return m_totals.assertions.failed == static_cast(m_config->abortAfter()); + } + + void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) { + auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description); + m_reporter->sectionStarting(testCaseSection); + Counts prevAssertions = m_totals.assertions; + double duration = 0; + m_shouldReportUnexpected = true; + m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal }; + + seedRng(*m_config); + + Timer timer; + try { + if (m_reporter->getPreferences().shouldRedirectStdOut) { +#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) + RedirectedStdOut redirectedStdOut; + RedirectedStdErr redirectedStdErr; + + timer.start(); + invokeActiveTestCase(); + redirectedCout += redirectedStdOut.str(); + redirectedCerr += redirectedStdErr.str(); +#else + OutputRedirect r(redirectedCout, redirectedCerr); + timer.start(); + invokeActiveTestCase(); +#endif + } else { + timer.start(); + invokeActiveTestCase(); + } + duration = timer.getElapsedSeconds(); + } catch (TestFailureException&) { + // This just means the test was aborted due to failure + } catch (...) { + // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions + // are reported without translation at the point of origin. + if( m_shouldReportUnexpected ) { + AssertionReaction dummyReaction; + handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction ); + } + } + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions(assertions); + + m_testCaseTracker->close(); + handleUnfinishedSections(); + m_messages.clear(); + + SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); + m_reporter->sectionEnded(testCaseSectionStats); + } + + void RunContext::invokeActiveTestCase() { + FatalConditionHandler fatalConditionHandler; // Handle signals + m_activeTestCase->invoke(); + fatalConditionHandler.reset(); + } + + void RunContext::handleUnfinishedSections() { + // If sections ended prematurely due to an exception we stored their + // infos here so we can tear them down outside the unwind process. + for (auto it = m_unfinishedSections.rbegin(), + itEnd = m_unfinishedSections.rend(); + it != itEnd; + ++it) + sectionEnded(*it); + m_unfinishedSections.clear(); + } + + void RunContext::handleExpr( + AssertionInfo const& info, + ITransientExpression const& expr, + AssertionReaction& reaction + ) { + m_reporter->assertionStarting( info ); + + bool negated = isFalseTest( info.resultDisposition ); + bool result = expr.getResult() != negated; + + if( result ) { + if (!m_includeSuccessfulResults) { + assertionPassed(); + } + else { + reportExpr(info, ResultWas::Ok, &expr, negated); + } + } + else { + reportExpr(info, ResultWas::ExpressionFailed, &expr, negated ); + populateReaction( reaction ); + } + } + void RunContext::reportExpr( + AssertionInfo const &info, + ResultWas::OfType resultType, + ITransientExpression const *expr, + bool negated ) { + + m_lastAssertionInfo = info; + AssertionResultData data( resultType, LazyExpression( negated ) ); + + AssertionResult assertionResult{ info, data }; + assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; + + assertionEnded( assertionResult ); + } + + void RunContext::handleMessage( + AssertionInfo const& info, + ResultWas::OfType resultType, + StringRef const& message, + AssertionReaction& reaction + ) { + m_reporter->assertionStarting( info ); + + m_lastAssertionInfo = info; + + AssertionResultData data( resultType, LazyExpression( false ) ); + data.message = message; + AssertionResult assertionResult{ m_lastAssertionInfo, data }; + assertionEnded( assertionResult ); + if( !assertionResult.isOk() ) + populateReaction( reaction ); + } + void RunContext::handleUnexpectedExceptionNotThrown( + AssertionInfo const& info, + AssertionReaction& reaction + ) { + handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction); + } + + void RunContext::handleUnexpectedInflightException( + AssertionInfo const& info, + std::string const& message, + AssertionReaction& reaction + ) { + m_lastAssertionInfo = info; + + AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); + data.message = message; + AssertionResult assertionResult{ info, data }; + assertionEnded( assertionResult ); + populateReaction( reaction ); + } + + void RunContext::populateReaction( AssertionReaction& reaction ) { + reaction.shouldDebugBreak = m_config->shouldDebugBreak(); + reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal); + } + + void RunContext::handleIncomplete( + AssertionInfo const& info + ) { + m_lastAssertionInfo = info; + + AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); + data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; + AssertionResult assertionResult{ info, data }; + assertionEnded( assertionResult ); + } + void RunContext::handleNonExpr( + AssertionInfo const &info, + ResultWas::OfType resultType, + AssertionReaction &reaction + ) { + m_lastAssertionInfo = info; + + AssertionResultData data( resultType, LazyExpression( false ) ); + AssertionResult assertionResult{ info, data }; + assertionEnded( assertionResult ); + + if( !assertionResult.isOk() ) + populateReaction( reaction ); + } + + IResultCapture& getResultCapture() { + if (auto* capture = getCurrentContext().getResultCapture()) + return *capture; + else + CATCH_INTERNAL_ERROR("No result capture instance"); + } +} +// end catch_run_context.cpp +// start catch_section.cpp + +namespace Catch { + + Section::Section( SectionInfo const& info ) + : m_info( info ), + m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) + { + m_timer.start(); + } + + Section::~Section() { + if( m_sectionIncluded ) { + SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); + if( uncaught_exceptions() ) + getResultCapture().sectionEndedEarly( endInfo ); + else + getResultCapture().sectionEnded( endInfo ); + } + } + + // This indicates whether the section should be executed or not + Section::operator bool() const { + return m_sectionIncluded; + } + +} // end namespace Catch +// end catch_section.cpp +// start catch_section_info.cpp + +namespace Catch { + + SectionInfo::SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description ) + : name( _name ), + description( _description ), + lineInfo( _lineInfo ) + {} + + SectionEndInfo::SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) + : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) + {} + +} // end namespace Catch +// end catch_section_info.cpp +// start catch_session.cpp + +// start catch_session.h + +#include + +namespace Catch { + + class Session : NonCopyable { + public: + + Session(); + ~Session() override; + + void showHelp() const; + void libIdentify(); + + int applyCommandLine( int argc, char const * const * argv ); + + void useConfigData( ConfigData const& configData ); + + int run( int argc, char* argv[] ); + #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) + int run( int argc, wchar_t* const argv[] ); + #endif + int run(); + + clara::Parser const& cli() const; + void cli( clara::Parser const& newParser ); + ConfigData& configData(); + Config& config(); + private: + int runInternal(); + + clara::Parser m_cli; + ConfigData m_configData; + std::shared_ptr m_config; + bool m_startupExceptions = false; + }; + +} // end namespace Catch + +// end catch_session.h +// start catch_version.h + +#include + +namespace Catch { + + // Versioning information + struct Version { + Version( Version const& ) = delete; + Version& operator=( Version const& ) = delete; + Version( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + char const * const _branchName, + unsigned int _buildNumber ); + + unsigned int const majorVersion; + unsigned int const minorVersion; + unsigned int const patchNumber; + + // buildNumber is only used if branchName is not null + char const * const branchName; + unsigned int const buildNumber; + + friend std::ostream& operator << ( std::ostream& os, Version const& version ); + }; + + Version const& libraryVersion(); +} + +// end catch_version.h +#include +#include + +namespace Catch { + + namespace { + const int MaxExitCode = 255; + + IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) { + auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config); + CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'"); + + return reporter; + } + + IStreamingReporterPtr makeReporter(std::shared_ptr const& config) { + if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) { + return createReporter(config->getReporterName(), config); + } + + auto multi = std::unique_ptr(new ListeningReporter); + + auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners(); + for (auto const& listener : listeners) { + multi->addListener(listener->create(Catch::ReporterConfig(config))); + } + multi->addReporter(createReporter(config->getReporterName(), config)); + return std::move(multi); + } + + Catch::Totals runTests(std::shared_ptr const& config) { + // FixMe: Add listeners in order first, then add reporters. + + auto reporter = makeReporter(config); + + RunContext context(config, std::move(reporter)); + + Totals totals; + + context.testGroupStarting(config->name(), 1, 1); + + TestSpec testSpec = config->testSpec(); + + auto const& allTestCases = getAllTestCasesSorted(*config); + for (auto const& testCase : allTestCases) { + if (!context.aborting() && matchTest(testCase, testSpec, *config)) + totals += context.runTest(testCase); + else + context.reporter().skipTest(testCase); + } + + if (config->warnAboutNoTests() && totals.testCases.total() == 0) { + ReusableStringStream testConfig; + + bool first = true; + for (const auto& input : config->getTestsOrTags()) { + if (!first) { testConfig << ' '; } + first = false; + testConfig << input; + } + + context.reporter().noMatchingTestCases(testConfig.str()); + totals.error = -1; + } + + context.testGroupEnded(config->name(), totals, 1, 1); + return totals; + } + + void applyFilenamesAsTags(Catch::IConfig const& config) { + auto& tests = const_cast&>(getAllTestCasesSorted(config)); + for (auto& testCase : tests) { + auto tags = testCase.tags; + + std::string filename = testCase.lineInfo.file; + auto lastSlash = filename.find_last_of("\\/"); + if (lastSlash != std::string::npos) { + filename.erase(0, lastSlash); + filename[0] = '#'; + } + + auto lastDot = filename.find_last_of('.'); + if (lastDot != std::string::npos) { + filename.erase(lastDot); + } + + tags.push_back(std::move(filename)); + setTags(testCase, tags); + } + } + + } // anon namespace + + Session::Session() { + static bool alreadyInstantiated = false; + if( alreadyInstantiated ) { + try { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); } + catch(...) { getMutableRegistryHub().registerStartupException(); } + } + + const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions(); + if ( !exceptions.empty() ) { + m_startupExceptions = true; + Colour colourGuard( Colour::Red ); + Catch::cerr() << "Errors occurred during startup!" << '\n'; + // iterate over all exceptions and notify user + for ( const auto& ex_ptr : exceptions ) { + try { + std::rethrow_exception(ex_ptr); + } catch ( std::exception const& ex ) { + Catch::cerr() << Column( ex.what() ).indent(2) << '\n'; + } + } + } + + alreadyInstantiated = true; + m_cli = makeCommandLineParser( m_configData ); + } + Session::~Session() { + Catch::cleanUp(); + } + + void Session::showHelp() const { + Catch::cout() + << "\nCatch v" << libraryVersion() << "\n" + << m_cli << std::endl + << "For more detailed usage please see the project docs\n" << std::endl; + } + void Session::libIdentify() { + Catch::cout() + << std::left << std::setw(16) << "description: " << "A Catch test executable\n" + << std::left << std::setw(16) << "category: " << "testframework\n" + << std::left << std::setw(16) << "framework: " << "Catch Test\n" + << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl; + } + + int Session::applyCommandLine( int argc, char const * const * argv ) { + if( m_startupExceptions ) + return 1; + + auto result = m_cli.parse( clara::Args( argc, argv ) ); + if( !result ) { + Catch::cerr() + << Colour( Colour::Red ) + << "\nError(s) in input:\n" + << Column( result.errorMessage() ).indent( 2 ) + << "\n\n"; + Catch::cerr() << "Run with -? for usage\n" << std::endl; + return MaxExitCode; + } + + if( m_configData.showHelp ) + showHelp(); + if( m_configData.libIdentify ) + libIdentify(); + m_config.reset(); + return 0; + } + + void Session::useConfigData( ConfigData const& configData ) { + m_configData = configData; + m_config.reset(); + } + + int Session::run( int argc, char* argv[] ) { + if( m_startupExceptions ) + return 1; + int returnCode = applyCommandLine( argc, argv ); + if( returnCode == 0 ) + returnCode = run(); + return returnCode; + } + +#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) + int Session::run( int argc, wchar_t* const argv[] ) { + + char **utf8Argv = new char *[ argc ]; + + for ( int i = 0; i < argc; ++i ) { + int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL ); + + utf8Argv[ i ] = new char[ bufSize ]; + + WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL ); + } + + int returnCode = run( argc, utf8Argv ); + + for ( int i = 0; i < argc; ++i ) + delete [] utf8Argv[ i ]; + + delete [] utf8Argv; + + return returnCode; + } +#endif + int Session::run() { + if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) { + Catch::cout() << "...waiting for enter/ return before starting" << std::endl; + static_cast(std::getchar()); + } + int exitCode = runInternal(); + if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) { + Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl; + static_cast(std::getchar()); + } + return exitCode; + } + + clara::Parser const& Session::cli() const { + return m_cli; + } + void Session::cli( clara::Parser const& newParser ) { + m_cli = newParser; + } + ConfigData& Session::configData() { + return m_configData; + } + Config& Session::config() { + if( !m_config ) + m_config = std::make_shared( m_configData ); + return *m_config; + } + + int Session::runInternal() { + if( m_startupExceptions ) + return 1; + + if( m_configData.showHelp || m_configData.libIdentify ) + return 0; + + try + { + config(); // Force config to be constructed + + seedRng( *m_config ); + + if( m_configData.filenamesAsTags ) + applyFilenamesAsTags( *m_config ); + + // Handle list request + if( Option listed = list( config() ) ) + return static_cast( *listed ); + + auto totals = runTests( m_config ); + // Note that on unices only the lower 8 bits are usually used, clamping + // the return value to 255 prevents false negative when some multiple + // of 256 tests has failed + return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast(totals.assertions.failed))); + } + catch( std::exception& ex ) { + Catch::cerr() << ex.what() << std::endl; + return MaxExitCode; + } + } + +} // end namespace Catch +// end catch_session.cpp +// start catch_startup_exception_registry.cpp + +namespace Catch { + void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { + try { + m_exceptions.push_back(exception); + } + catch(...) { + // If we run out of memory during start-up there's really not a lot more we can do about it + std::terminate(); + } + } + + std::vector const& StartupExceptionRegistry::getExceptions() const noexcept { + return m_exceptions; + } + +} // end namespace Catch +// end catch_startup_exception_registry.cpp +// start catch_stream.cpp + +#include +#include +#include +#include +#include +#include + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wexit-time-destructors" +#endif + +namespace Catch { + + Catch::IStream::~IStream() = default; + + namespace detail { namespace { + template + class StreamBufImpl : public std::streambuf { + char data[bufferSize]; + WriterF m_writer; + + public: + StreamBufImpl() { + setp( data, data + sizeof(data) ); + } + + ~StreamBufImpl() noexcept { + StreamBufImpl::sync(); + } + + private: + int overflow( int c ) override { + sync(); + + if( c != EOF ) { + if( pbase() == epptr() ) + m_writer( std::string( 1, static_cast( c ) ) ); + else + sputc( static_cast( c ) ); + } + return 0; + } + + int sync() override { + if( pbase() != pptr() ) { + m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); + setp( pbase(), epptr() ); + } + return 0; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + struct OutputDebugWriter { + + void operator()( std::string const&str ) { + writeToDebugConsole( str ); + } + }; + + /////////////////////////////////////////////////////////////////////////// + + class FileStream : public IStream { + mutable std::ofstream m_ofs; + public: + FileStream( StringRef filename ) { + m_ofs.open( filename.c_str() ); + CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << "'" ); + } + ~FileStream() override = default; + public: // IStream + std::ostream& stream() const override { + return m_ofs; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + class CoutStream : public IStream { + mutable std::ostream m_os; + public: + // Store the streambuf from cout up-front because + // cout may get redirected when running tests + CoutStream() : m_os( Catch::cout().rdbuf() ) {} + ~CoutStream() override = default; + + public: // IStream + std::ostream& stream() const override { return m_os; } + }; + + /////////////////////////////////////////////////////////////////////////// + + class DebugOutStream : public IStream { + std::unique_ptr> m_streamBuf; + mutable std::ostream m_os; + public: + DebugOutStream() + : m_streamBuf( new StreamBufImpl() ), + m_os( m_streamBuf.get() ) + {} + + ~DebugOutStream() override = default; + + public: // IStream + std::ostream& stream() const override { return m_os; } + }; + + }} // namespace anon::detail + + /////////////////////////////////////////////////////////////////////////// + + auto makeStream( StringRef const &filename ) -> IStream const* { + if( filename.empty() ) + return new detail::CoutStream(); + else if( filename[0] == '%' ) { + if( filename == "%debug" ) + return new detail::DebugOutStream(); + else + CATCH_ERROR( "Unrecognised stream: '" << filename << "'" ); + } + else + return new detail::FileStream( filename ); + } + + // This class encapsulates the idea of a pool of ostringstreams that can be reused. + struct StringStreams { + std::vector> m_streams; + std::vector m_unused; + std::ostringstream m_referenceStream; // Used for copy state/ flags from + static StringStreams* s_instance; + + auto add() -> std::size_t { + if( m_unused.empty() ) { + m_streams.push_back( std::unique_ptr( new std::ostringstream ) ); + return m_streams.size()-1; + } + else { + auto index = m_unused.back(); + m_unused.pop_back(); + return index; + } + } + + void release( std::size_t index ) { + m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state + m_unused.push_back(index); + } + + // !TBD: put in TLS + static auto instance() -> StringStreams& { + if( !s_instance ) + s_instance = new StringStreams(); + return *s_instance; + } + static void cleanup() { + delete s_instance; + s_instance = nullptr; + } + }; + + StringStreams* StringStreams::s_instance = nullptr; + + void ReusableStringStream::cleanup() { + StringStreams::cleanup(); + } + + ReusableStringStream::ReusableStringStream() + : m_index( StringStreams::instance().add() ), + m_oss( StringStreams::instance().m_streams[m_index].get() ) + {} + + ReusableStringStream::~ReusableStringStream() { + static_cast( m_oss )->str(""); + m_oss->clear(); + StringStreams::instance().release( m_index ); + } + + auto ReusableStringStream::str() const -> std::string { + return static_cast( m_oss )->str(); + } + + /////////////////////////////////////////////////////////////////////////// + +#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions + std::ostream& cout() { return std::cout; } + std::ostream& cerr() { return std::cerr; } + std::ostream& clog() { return std::clog; } +#endif +} + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif +// end catch_stream.cpp +// start catch_string_manip.cpp + +#include +#include +#include +#include + +namespace Catch { + + bool startsWith( std::string const& s, std::string const& prefix ) { + return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); + } + bool startsWith( std::string const& s, char prefix ) { + return !s.empty() && s[0] == prefix; + } + bool endsWith( std::string const& s, std::string const& suffix ) { + return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); + } + bool endsWith( std::string const& s, char suffix ) { + return !s.empty() && s[s.size()-1] == suffix; + } + bool contains( std::string const& s, std::string const& infix ) { + return s.find( infix ) != std::string::npos; + } + char toLowerCh(char c) { + return static_cast( std::tolower( c ) ); + } + void toLowerInPlace( std::string& s ) { + std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); + } + std::string toLower( std::string const& s ) { + std::string lc = s; + toLowerInPlace( lc ); + return lc; + } + std::string trim( std::string const& str ) { + static char const* whitespaceChars = "\n\r\t "; + std::string::size_type start = str.find_first_not_of( whitespaceChars ); + std::string::size_type end = str.find_last_not_of( whitespaceChars ); + + return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); + } + + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { + bool replaced = false; + std::size_t i = str.find( replaceThis ); + while( i != std::string::npos ) { + replaced = true; + str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); + if( i < str.size()-withThis.size() ) + i = str.find( replaceThis, i+withThis.size() ); + else + i = std::string::npos; + } + return replaced; + } + + pluralise::pluralise( std::size_t count, std::string const& label ) + : m_count( count ), + m_label( label ) + {} + + std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { + os << pluraliser.m_count << ' ' << pluraliser.m_label; + if( pluraliser.m_count != 1 ) + os << 's'; + return os; + } + +} +// end catch_string_manip.cpp +// start catch_stringref.cpp + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wexit-time-destructors" +#endif + +#include +#include +#include + +namespace { + const uint32_t byte_2_lead = 0xC0; + const uint32_t byte_3_lead = 0xE0; + const uint32_t byte_4_lead = 0xF0; +} + +namespace Catch { + StringRef::StringRef( char const* rawChars ) noexcept + : StringRef( rawChars, static_cast(std::strlen(rawChars) ) ) + {} + + StringRef::operator std::string() const { + return std::string( m_start, m_size ); + } + + void StringRef::swap( StringRef& other ) noexcept { + std::swap( m_start, other.m_start ); + std::swap( m_size, other.m_size ); + std::swap( m_data, other.m_data ); + } + + auto StringRef::c_str() const -> char const* { + if( isSubstring() ) + const_cast( this )->takeOwnership(); + return m_start; + } + auto StringRef::currentData() const noexcept -> char const* { + return m_start; + } + + auto StringRef::isOwned() const noexcept -> bool { + return m_data != nullptr; + } + auto StringRef::isSubstring() const noexcept -> bool { + return m_start[m_size] != '\0'; + } + + void StringRef::takeOwnership() { + if( !isOwned() ) { + m_data = new char[m_size+1]; + memcpy( m_data, m_start, m_size ); + m_data[m_size] = '\0'; + m_start = m_data; + } + } + auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef { + if( start < m_size ) + return StringRef( m_start+start, size ); + else + return StringRef(); + } + auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool { + return + size() == other.size() && + (std::strncmp( m_start, other.m_start, size() ) == 0); + } + auto StringRef::operator != ( StringRef const& other ) const noexcept -> bool { + return !operator==( other ); + } + + auto StringRef::operator[](size_type index) const noexcept -> char { + return m_start[index]; + } + + auto StringRef::numberOfCharacters() const noexcept -> size_type { + size_type noChars = m_size; + // Make adjustments for uft encodings + for( size_type i=0; i < m_size; ++i ) { + char c = m_start[i]; + if( ( c & byte_2_lead ) == byte_2_lead ) { + noChars--; + if (( c & byte_3_lead ) == byte_3_lead ) + noChars--; + if( ( c & byte_4_lead ) == byte_4_lead ) + noChars--; + } + } + return noChars; + } + + auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string { + std::string str; + str.reserve( lhs.size() + rhs.size() ); + str += lhs; + str += rhs; + return str; + } + auto operator + ( StringRef const& lhs, const char* rhs ) -> std::string { + return std::string( lhs ) + std::string( rhs ); + } + auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string { + return std::string( lhs ) + std::string( rhs ); + } + + auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& { + return os.write(str.currentData(), str.size()); + } + + auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& { + lhs.append(rhs.currentData(), rhs.size()); + return lhs; + } + +} // namespace Catch + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif +// end catch_stringref.cpp +// start catch_tag_alias.cpp + +namespace Catch { + TagAlias::TagAlias(std::string const & _tag, SourceLineInfo _lineInfo): tag(_tag), lineInfo(_lineInfo) {} +} +// end catch_tag_alias.cpp +// start catch_tag_alias_autoregistrar.cpp + +namespace Catch { + + RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) { + try { + getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo); + } catch (...) { + // Do not throw when constructing global objects, instead register the exception to be processed later + getMutableRegistryHub().registerStartupException(); + } + } + +} +// end catch_tag_alias_autoregistrar.cpp +// start catch_tag_alias_registry.cpp + +#include + +namespace Catch { + + TagAliasRegistry::~TagAliasRegistry() {} + + TagAlias const* TagAliasRegistry::find( std::string const& alias ) const { + auto it = m_registry.find( alias ); + if( it != m_registry.end() ) + return &(it->second); + else + return nullptr; + } + + std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { + std::string expandedTestSpec = unexpandedTestSpec; + for( auto const& registryKvp : m_registry ) { + std::size_t pos = expandedTestSpec.find( registryKvp.first ); + if( pos != std::string::npos ) { + expandedTestSpec = expandedTestSpec.substr( 0, pos ) + + registryKvp.second.tag + + expandedTestSpec.substr( pos + registryKvp.first.size() ); + } + } + return expandedTestSpec; + } + + void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) { + CATCH_ENFORCE( startsWith(alias, "[@") && endsWith(alias, ']'), + "error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo ); + + CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second, + "error: tag alias, '" << alias << "' already registered.\n" + << "\tFirst seen at: " << find(alias)->lineInfo << "\n" + << "\tRedefined at: " << lineInfo ); + } + + ITagAliasRegistry::~ITagAliasRegistry() {} + + ITagAliasRegistry const& ITagAliasRegistry::get() { + return getRegistryHub().getTagAliasRegistry(); + } + +} // end namespace Catch +// end catch_tag_alias_registry.cpp +// start catch_test_case_info.cpp + +#include +#include +#include +#include + +namespace Catch { + + TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { + if( startsWith( tag, '.' ) || + tag == "!hide" ) + return TestCaseInfo::IsHidden; + else if( tag == "!throws" ) + return TestCaseInfo::Throws; + else if( tag == "!shouldfail" ) + return TestCaseInfo::ShouldFail; + else if( tag == "!mayfail" ) + return TestCaseInfo::MayFail; + else if( tag == "!nonportable" ) + return TestCaseInfo::NonPortable; + else if( tag == "!benchmark" ) + return static_cast( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden ); + else + return TestCaseInfo::None; + } + bool isReservedTag( std::string const& tag ) { + return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( static_cast(tag[0]) ); + } + void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { + CATCH_ENFORCE( !isReservedTag(tag), + "Tag name: [" << tag << "] is not allowed.\n" + << "Tag names starting with non alpha-numeric characters are reserved\n" + << _lineInfo ); + } + + TestCase makeTestCase( ITestInvoker* _testCase, + std::string const& _className, + NameAndTags const& nameAndTags, + SourceLineInfo const& _lineInfo ) + { + bool isHidden = false; + + // Parse out tags + std::vector tags; + std::string desc, tag; + bool inTag = false; + std::string _descOrTags = nameAndTags.tags; + for (char c : _descOrTags) { + if( !inTag ) { + if( c == '[' ) + inTag = true; + else + desc += c; + } + else { + if( c == ']' ) { + TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); + if( ( prop & TestCaseInfo::IsHidden ) != 0 ) + isHidden = true; + else if( prop == TestCaseInfo::None ) + enforceNotReservedTag( tag, _lineInfo ); + + tags.push_back( tag ); + tag.clear(); + inTag = false; + } + else + tag += c; + } + } + if( isHidden ) { + tags.push_back( "." ); + } + + TestCaseInfo info( nameAndTags.name, _className, desc, tags, _lineInfo ); + return TestCase( _testCase, std::move(info) ); + } + + void setTags( TestCaseInfo& testCaseInfo, std::vector tags ) { + std::sort(begin(tags), end(tags)); + tags.erase(std::unique(begin(tags), end(tags)), end(tags)); + testCaseInfo.lcaseTags.clear(); + + for( auto const& tag : tags ) { + std::string lcaseTag = toLower( tag ); + testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); + testCaseInfo.lcaseTags.push_back( lcaseTag ); + } + testCaseInfo.tags = std::move(tags); + } + + TestCaseInfo::TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::vector const& _tags, + SourceLineInfo const& _lineInfo ) + : name( _name ), + className( _className ), + description( _description ), + lineInfo( _lineInfo ), + properties( None ) + { + setTags( *this, _tags ); + } + + bool TestCaseInfo::isHidden() const { + return ( properties & IsHidden ) != 0; + } + bool TestCaseInfo::throws() const { + return ( properties & Throws ) != 0; + } + bool TestCaseInfo::okToFail() const { + return ( properties & (ShouldFail | MayFail ) ) != 0; + } + bool TestCaseInfo::expectedToFail() const { + return ( properties & (ShouldFail ) ) != 0; + } + + std::string TestCaseInfo::tagsAsString() const { + std::string ret; + // '[' and ']' per tag + std::size_t full_size = 2 * tags.size(); + for (const auto& tag : tags) { + full_size += tag.size(); + } + ret.reserve(full_size); + for (const auto& tag : tags) { + ret.push_back('['); + ret.append(tag); + ret.push_back(']'); + } + + return ret; + } + + TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo&& info ) : TestCaseInfo( std::move(info) ), test( testCase ) {} + + TestCase TestCase::withName( std::string const& _newName ) const { + TestCase other( *this ); + other.name = _newName; + return other; + } + + void TestCase::invoke() const { + test->invoke(); + } + + bool TestCase::operator == ( TestCase const& other ) const { + return test.get() == other.test.get() && + name == other.name && + className == other.className; + } + + bool TestCase::operator < ( TestCase const& other ) const { + return name < other.name; + } + + TestCaseInfo const& TestCase::getTestCaseInfo() const + { + return *this; + } + +} // end namespace Catch +// end catch_test_case_info.cpp +// start catch_test_case_registry_impl.cpp + +#include + +namespace Catch { + + std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { + + std::vector sorted = unsortedTestCases; + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( sorted.begin(), sorted.end() ); + break; + case RunTests::InRandomOrder: + seedRng( config ); + RandomNumberGenerator::shuffle( sorted ); + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + return sorted; + } + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { + return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); + } + + void enforceNoDuplicateTestCases( std::vector const& functions ) { + std::set seenFunctions; + for( auto const& function : functions ) { + auto prev = seenFunctions.insert( function ); + CATCH_ENFORCE( prev.second, + "error: TEST_CASE( \"" << function.name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << function.getTestCaseInfo().lineInfo ); + } + } + + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { + std::vector filtered; + filtered.reserve( testCases.size() ); + for( auto const& testCase : testCases ) + if( matchTest( testCase, testSpec, config ) ) + filtered.push_back( testCase ); + return filtered; + } + std::vector const& getAllTestCasesSorted( IConfig const& config ) { + return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); + } + + void TestRegistry::registerTest( TestCase const& testCase ) { + std::string name = testCase.getTestCaseInfo().name; + if( name.empty() ) { + ReusableStringStream rss; + rss << "Anonymous test case " << ++m_unnamedCount; + return registerTest( testCase.withName( rss.str() ) ); + } + m_functions.push_back( testCase ); + } + + std::vector const& TestRegistry::getAllTests() const { + return m_functions; + } + std::vector const& TestRegistry::getAllTestsSorted( IConfig const& config ) const { + if( m_sortedFunctions.empty() ) + enforceNoDuplicateTestCases( m_functions ); + + if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { + m_sortedFunctions = sortTests( config, m_functions ); + m_currentSortOrder = config.runOrder(); + } + return m_sortedFunctions; + } + + /////////////////////////////////////////////////////////////////////////// + TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {} + + void TestInvokerAsFunction::invoke() const { + m_testAsFunction(); + } + + std::string extractClassName( StringRef const& classOrQualifiedMethodName ) { + std::string className = classOrQualifiedMethodName; + if( startsWith( className, '&' ) ) + { + std::size_t lastColons = className.rfind( "::" ); + std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); + if( penultimateColons == std::string::npos ) + penultimateColons = 1; + className = className.substr( penultimateColons, lastColons-penultimateColons ); + } + return className; + } + +} // end namespace Catch +// end catch_test_case_registry_impl.cpp +// start catch_test_case_tracker.cpp + +#include +#include +#include +#include +#include + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wexit-time-destructors" +#endif + +namespace Catch { +namespace TestCaseTracking { + + NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) + : name( _name ), + location( _location ) + {} + + ITracker::~ITracker() = default; + + TrackerContext& TrackerContext::instance() { + static TrackerContext s_instance; + return s_instance; + } + + ITracker& TrackerContext::startRun() { + m_rootTracker = std::make_shared( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, nullptr ); + m_currentTracker = nullptr; + m_runState = Executing; + return *m_rootTracker; + } + + void TrackerContext::endRun() { + m_rootTracker.reset(); + m_currentTracker = nullptr; + m_runState = NotStarted; + } + + void TrackerContext::startCycle() { + m_currentTracker = m_rootTracker.get(); + m_runState = Executing; + } + void TrackerContext::completeCycle() { + m_runState = CompletedCycle; + } + + bool TrackerContext::completedCycle() const { + return m_runState == CompletedCycle; + } + ITracker& TrackerContext::currentTracker() { + return *m_currentTracker; + } + void TrackerContext::setCurrentTracker( ITracker* tracker ) { + m_currentTracker = tracker; + } + + TrackerBase::TrackerHasName::TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {} + bool TrackerBase::TrackerHasName::operator ()( ITrackerPtr const& tracker ) const { + return + tracker->nameAndLocation().name == m_nameAndLocation.name && + tracker->nameAndLocation().location == m_nameAndLocation.location; + } + + TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) + : m_nameAndLocation( nameAndLocation ), + m_ctx( ctx ), + m_parent( parent ) + {} + + NameAndLocation const& TrackerBase::nameAndLocation() const { + return m_nameAndLocation; + } + bool TrackerBase::isComplete() const { + return m_runState == CompletedSuccessfully || m_runState == Failed; + } + bool TrackerBase::isSuccessfullyCompleted() const { + return m_runState == CompletedSuccessfully; + } + bool TrackerBase::isOpen() const { + return m_runState != NotStarted && !isComplete(); + } + bool TrackerBase::hasChildren() const { + return !m_children.empty(); + } + + void TrackerBase::addChild( ITrackerPtr const& child ) { + m_children.push_back( child ); + } + + ITrackerPtr TrackerBase::findChild( NameAndLocation const& nameAndLocation ) { + auto it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) ); + return( it != m_children.end() ) + ? *it + : nullptr; + } + ITracker& TrackerBase::parent() { + assert( m_parent ); // Should always be non-null except for root + return *m_parent; + } + + void TrackerBase::openChild() { + if( m_runState != ExecutingChildren ) { + m_runState = ExecutingChildren; + if( m_parent ) + m_parent->openChild(); + } + } + + bool TrackerBase::isSectionTracker() const { return false; } + bool TrackerBase::isIndexTracker() const { return false; } + + void TrackerBase::open() { + m_runState = Executing; + moveToThis(); + if( m_parent ) + m_parent->openChild(); + } + + void TrackerBase::close() { + + // Close any still open children (e.g. generators) + while( &m_ctx.currentTracker() != this ) + m_ctx.currentTracker().close(); + + switch( m_runState ) { + case NeedsAnotherRun: + break; + + case Executing: + m_runState = CompletedSuccessfully; + break; + case ExecutingChildren: + if( m_children.empty() || m_children.back()->isComplete() ) + m_runState = CompletedSuccessfully; + break; + + case NotStarted: + case CompletedSuccessfully: + case Failed: + CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState ); + + default: + CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState ); + } + moveToParent(); + m_ctx.completeCycle(); + } + void TrackerBase::fail() { + m_runState = Failed; + if( m_parent ) + m_parent->markAsNeedingAnotherRun(); + moveToParent(); + m_ctx.completeCycle(); + } + void TrackerBase::markAsNeedingAnotherRun() { + m_runState = NeedsAnotherRun; + } + + void TrackerBase::moveToParent() { + assert( m_parent ); + m_ctx.setCurrentTracker( m_parent ); + } + void TrackerBase::moveToThis() { + m_ctx.setCurrentTracker( this ); + } + + SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) + : TrackerBase( nameAndLocation, ctx, parent ) + { + if( parent ) { + while( !parent->isSectionTracker() ) + parent = &parent->parent(); + + SectionTracker& parentSection = static_cast( *parent ); + addNextFilters( parentSection.m_filters ); + } + } + + bool SectionTracker::isSectionTracker() const { return true; } + + SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { + std::shared_ptr section; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { + assert( childTracker ); + assert( childTracker->isSectionTracker() ); + section = std::static_pointer_cast( childTracker ); + } + else { + section = std::make_shared( nameAndLocation, ctx, ¤tTracker ); + currentTracker.addChild( section ); + } + if( !ctx.completedCycle() ) + section->tryOpen(); + return *section; + } + + void SectionTracker::tryOpen() { + if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) ) + open(); + } + + void SectionTracker::addInitialFilters( std::vector const& filters ) { + if( !filters.empty() ) { + m_filters.push_back(""); // Root - should never be consulted + m_filters.push_back(""); // Test Case - not a section filter + m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); + } + } + void SectionTracker::addNextFilters( std::vector const& filters ) { + if( filters.size() > 1 ) + m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() ); + } + + IndexTracker::IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ) + : TrackerBase( nameAndLocation, ctx, parent ), + m_size( size ) + {} + + bool IndexTracker::isIndexTracker() const { return true; } + + IndexTracker& IndexTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) { + std::shared_ptr tracker; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { + assert( childTracker ); + assert( childTracker->isIndexTracker() ); + tracker = std::static_pointer_cast( childTracker ); + } + else { + tracker = std::make_shared( nameAndLocation, ctx, ¤tTracker, size ); + currentTracker.addChild( tracker ); + } + + if( !ctx.completedCycle() && !tracker->isComplete() ) { + if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) + tracker->moveNext(); + tracker->open(); + } + + return *tracker; + } + + int IndexTracker::index() const { return m_index; } + + void IndexTracker::moveNext() { + m_index++; + m_children.clear(); + } + + void IndexTracker::close() { + TrackerBase::close(); + if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) + m_runState = Executing; + } + +} // namespace TestCaseTracking + +using TestCaseTracking::ITracker; +using TestCaseTracking::TrackerContext; +using TestCaseTracking::SectionTracker; +using TestCaseTracking::IndexTracker; + +} // namespace Catch + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif +// end catch_test_case_tracker.cpp +// start catch_test_registry.cpp + +namespace Catch { + + auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker* { + return new(std::nothrow) TestInvokerAsFunction( testAsFunction ); + } + + NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {} + + AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept { + try { + getMutableRegistryHub() + .registerTest( + makeTestCase( + invoker, + extractClassName( classOrMethod ), + nameAndTags, + lineInfo)); + } catch (...) { + // Do not throw when constructing global objects, instead register the exception to be processed later + getMutableRegistryHub().registerStartupException(); + } + } + + AutoReg::~AutoReg() = default; +} +// end catch_test_registry.cpp +// start catch_test_spec.cpp + +#include +#include +#include +#include + +namespace Catch { + + TestSpec::Pattern::~Pattern() = default; + TestSpec::NamePattern::~NamePattern() = default; + TestSpec::TagPattern::~TagPattern() = default; + TestSpec::ExcludedPattern::~ExcludedPattern() = default; + + TestSpec::NamePattern::NamePattern( std::string const& name ) + : m_wildcardPattern( toLower( name ), CaseSensitive::No ) + {} + bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const { + return m_wildcardPattern.matches( toLower( testCase.name ) ); + } + + TestSpec::TagPattern::TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} + bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const { + return std::find(begin(testCase.lcaseTags), + end(testCase.lcaseTags), + m_tag) != end(testCase.lcaseTags); + } + + TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} + bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } + + bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const { + // All patterns in a filter must match for the filter to be a match + for( auto const& pattern : m_patterns ) { + if( !pattern->matches( testCase ) ) + return false; + } + return true; + } + + bool TestSpec::hasFilters() const { + return !m_filters.empty(); + } + bool TestSpec::matches( TestCaseInfo const& testCase ) const { + // A TestSpec matches if any filter matches + for( auto const& filter : m_filters ) + if( filter.matches( testCase ) ) + return true; + return false; + } +} +// end catch_test_spec.cpp +// start catch_test_spec_parser.cpp + +namespace Catch { + + TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} + + TestSpecParser& TestSpecParser::parse( std::string const& arg ) { + m_mode = None; + m_exclusion = false; + m_start = std::string::npos; + m_arg = m_tagAliases->expandAliases( arg ); + m_escapeChars.clear(); + for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) + visitChar( m_arg[m_pos] ); + if( m_mode == Name ) + addPattern(); + return *this; + } + TestSpec TestSpecParser::testSpec() { + addFilter(); + return m_testSpec; + } + + void TestSpecParser::visitChar( char c ) { + if( m_mode == None ) { + switch( c ) { + case ' ': return; + case '~': m_exclusion = true; return; + case '[': return startNewMode( Tag, ++m_pos ); + case '"': return startNewMode( QuotedName, ++m_pos ); + case '\\': return escape(); + default: startNewMode( Name, m_pos ); break; + } + } + if( m_mode == Name ) { + if( c == ',' ) { + addPattern(); + addFilter(); + } + else if( c == '[' ) { + if( subString() == "exclude:" ) + m_exclusion = true; + else + addPattern(); + startNewMode( Tag, ++m_pos ); + } + else if( c == '\\' ) + escape(); + } + else if( m_mode == EscapedName ) + m_mode = Name; + else if( m_mode == QuotedName && c == '"' ) + addPattern(); + else if( m_mode == Tag && c == ']' ) + addPattern(); + } + void TestSpecParser::startNewMode( Mode mode, std::size_t start ) { + m_mode = mode; + m_start = start; + } + void TestSpecParser::escape() { + if( m_mode == None ) + m_start = m_pos; + m_mode = EscapedName; + m_escapeChars.push_back( m_pos ); + } + std::string TestSpecParser::subString() const { return m_arg.substr( m_start, m_pos - m_start ); } + + void TestSpecParser::addFilter() { + if( !m_currentFilter.m_patterns.empty() ) { + m_testSpec.m_filters.push_back( m_currentFilter ); + m_currentFilter = TestSpec::Filter(); + } + } + + TestSpec parseTestSpec( std::string const& arg ) { + return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); + } + +} // namespace Catch +// end catch_test_spec_parser.cpp +// start catch_timer.cpp + +#include + +static const uint64_t nanosecondsInSecond = 1000000000; + +namespace Catch { + + auto getCurrentNanosecondsSinceEpoch() -> uint64_t { + return std::chrono::duration_cast( std::chrono::high_resolution_clock::now().time_since_epoch() ).count(); + } + + auto estimateClockResolution() -> uint64_t { + uint64_t sum = 0; + static const uint64_t iterations = 1000000; + + auto startTime = getCurrentNanosecondsSinceEpoch(); + + for( std::size_t i = 0; i < iterations; ++i ) { + + uint64_t ticks; + uint64_t baseTicks = getCurrentNanosecondsSinceEpoch(); + do { + ticks = getCurrentNanosecondsSinceEpoch(); + } while( ticks == baseTicks ); + + auto delta = ticks - baseTicks; + sum += delta; + + // If we have been calibrating for over 3 seconds -- the clock + // is terrible and we should move on. + // TBD: How to signal that the measured resolution is probably wrong? + if (ticks > startTime + 3 * nanosecondsInSecond) { + return sum / i; + } + } + + // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers + // - and potentially do more iterations if there's a high variance. + return sum/iterations; + } + auto getEstimatedClockResolution() -> uint64_t { + static auto s_resolution = estimateClockResolution(); + return s_resolution; + } + + void Timer::start() { + m_nanoseconds = getCurrentNanosecondsSinceEpoch(); + } + auto Timer::getElapsedNanoseconds() const -> uint64_t { + return getCurrentNanosecondsSinceEpoch() - m_nanoseconds; + } + auto Timer::getElapsedMicroseconds() const -> uint64_t { + return getElapsedNanoseconds()/1000; + } + auto Timer::getElapsedMilliseconds() const -> unsigned int { + return static_cast(getElapsedMicroseconds()/1000); + } + auto Timer::getElapsedSeconds() const -> double { + return getElapsedMicroseconds()/1000000.0; + } + +} // namespace Catch +// end catch_timer.cpp +// start catch_tostring.cpp + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wexit-time-destructors" +# pragma clang diagnostic ignored "-Wglobal-constructors" +#endif + +// Enable specific decls locally +#if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +#define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +#endif + +#include +#include + +namespace Catch { + +namespace Detail { + + const std::string unprintableString = "{?}"; + + namespace { + const int hexThreshold = 255; + + struct Endianness { + enum Arch { Big, Little }; + + static Arch which() { + union _{ + int asInt; + char asChar[sizeof (int)]; + } u; + + u.asInt = 1; + return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; + } + }; + } + + std::string rawMemoryToString( const void *object, std::size_t size ) { + // Reverse order for little endian architectures + int i = 0, end = static_cast( size ), inc = 1; + if( Endianness::which() == Endianness::Little ) { + i = end-1; + end = inc = -1; + } + + unsigned char const *bytes = static_cast(object); + ReusableStringStream rss; + rss << "0x" << std::setfill('0') << std::hex; + for( ; i != end; i += inc ) + rss << std::setw(2) << static_cast(bytes[i]); + return rss.str(); + } +} + +template +std::string fpToString( T value, int precision ) { + if (std::isnan(value)) { + return "nan"; + } + + ReusableStringStream rss; + rss << std::setprecision( precision ) + << std::fixed + << value; + std::string d = rss.str(); + std::size_t i = d.find_last_not_of( '0' ); + if( i != std::string::npos && i != d.size()-1 ) { + if( d[i] == '.' ) + i++; + d = d.substr( 0, i+1 ); + } + return d; +} + +//// ======================================================= //// +// +// Out-of-line defs for full specialization of StringMaker +// +//// ======================================================= //// + +std::string StringMaker::convert(const std::string& str) { + if (!getCurrentContext().getConfig()->showInvisibles()) { + return '"' + str + '"'; + } + + std::string s("\""); + for (char c : str) { + switch (c) { + case '\n': + s.append("\\n"); + break; + case '\t': + s.append("\\t"); + break; + default: + s.push_back(c); + break; + } + } + s.append("\""); + return s; +} + +#ifdef CATCH_CONFIG_WCHAR +std::string StringMaker::convert(const std::wstring& wstr) { + std::string s; + s.reserve(wstr.size()); + for (auto c : wstr) { + s += (c <= 0xff) ? static_cast(c) : '?'; + } + return ::Catch::Detail::stringify(s); +} +#endif + +std::string StringMaker::convert(char const* str) { + if (str) { + return ::Catch::Detail::stringify(std::string{ str }); + } else { + return{ "{null string}" }; + } +} +std::string StringMaker::convert(char* str) { + if (str) { + return ::Catch::Detail::stringify(std::string{ str }); + } else { + return{ "{null string}" }; + } +} +#ifdef CATCH_CONFIG_WCHAR +std::string StringMaker::convert(wchar_t const * str) { + if (str) { + return ::Catch::Detail::stringify(std::wstring{ str }); + } else { + return{ "{null string}" }; + } +} +std::string StringMaker::convert(wchar_t * str) { + if (str) { + return ::Catch::Detail::stringify(std::wstring{ str }); + } else { + return{ "{null string}" }; + } +} +#endif + +std::string StringMaker::convert(int value) { + return ::Catch::Detail::stringify(static_cast(value)); +} +std::string StringMaker::convert(long value) { + return ::Catch::Detail::stringify(static_cast(value)); +} +std::string StringMaker::convert(long long value) { + ReusableStringStream rss; + rss << value; + if (value > Detail::hexThreshold) { + rss << " (0x" << std::hex << value << ')'; + } + return rss.str(); +} + +std::string StringMaker::convert(unsigned int value) { + return ::Catch::Detail::stringify(static_cast(value)); +} +std::string StringMaker::convert(unsigned long value) { + return ::Catch::Detail::stringify(static_cast(value)); +} +std::string StringMaker::convert(unsigned long long value) { + ReusableStringStream rss; + rss << value; + if (value > Detail::hexThreshold) { + rss << " (0x" << std::hex << value << ')'; + } + return rss.str(); +} + +std::string StringMaker::convert(bool b) { + return b ? "true" : "false"; +} + +std::string StringMaker::convert(char value) { + if (value == '\r') { + return "'\\r'"; + } else if (value == '\f') { + return "'\\f'"; + } else if (value == '\n') { + return "'\\n'"; + } else if (value == '\t') { + return "'\\t'"; + } else if ('\0' <= value && value < ' ') { + return ::Catch::Detail::stringify(static_cast(value)); + } else { + char chstr[] = "' '"; + chstr[1] = value; + return chstr; + } +} +std::string StringMaker::convert(signed char c) { + return ::Catch::Detail::stringify(static_cast(c)); +} +std::string StringMaker::convert(unsigned char c) { + return ::Catch::Detail::stringify(static_cast(c)); +} + +std::string StringMaker::convert(std::nullptr_t) { + return "nullptr"; +} + +std::string StringMaker::convert(float value) { + return fpToString(value, 5) + 'f'; +} +std::string StringMaker::convert(double value) { + return fpToString(value, 10); +} + +std::string ratio_string::symbol() { return "a"; } +std::string ratio_string::symbol() { return "f"; } +std::string ratio_string::symbol() { return "p"; } +std::string ratio_string::symbol() { return "n"; } +std::string ratio_string::symbol() { return "u"; } +std::string ratio_string::symbol() { return "m"; } + +} // end namespace Catch + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif + +// end catch_tostring.cpp +// start catch_totals.cpp + +namespace Catch { + + Counts Counts::operator - ( Counts const& other ) const { + Counts diff; + diff.passed = passed - other.passed; + diff.failed = failed - other.failed; + diff.failedButOk = failedButOk - other.failedButOk; + return diff; + } + + Counts& Counts::operator += ( Counts const& other ) { + passed += other.passed; + failed += other.failed; + failedButOk += other.failedButOk; + return *this; + } + + std::size_t Counts::total() const { + return passed + failed + failedButOk; + } + bool Counts::allPassed() const { + return failed == 0 && failedButOk == 0; + } + bool Counts::allOk() const { + return failed == 0; + } + + Totals Totals::operator - ( Totals const& other ) const { + Totals diff; + diff.assertions = assertions - other.assertions; + diff.testCases = testCases - other.testCases; + return diff; + } + + Totals& Totals::operator += ( Totals const& other ) { + assertions += other.assertions; + testCases += other.testCases; + return *this; + } + + Totals Totals::delta( Totals const& prevTotals ) const { + Totals diff = *this - prevTotals; + if( diff.assertions.failed > 0 ) + ++diff.testCases.failed; + else if( diff.assertions.failedButOk > 0 ) + ++diff.testCases.failedButOk; + else + ++diff.testCases.passed; + return diff; + } + +} +// end catch_totals.cpp +// start catch_uncaught_exceptions.cpp + +#include + +namespace Catch { + bool uncaught_exceptions() { +#if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) + return std::uncaught_exceptions() > 0; +#else + return std::uncaught_exception(); +#endif + } +} // end namespace Catch +// end catch_uncaught_exceptions.cpp +// start catch_version.cpp + +#include + +namespace Catch { + + Version::Version + ( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + char const * const _branchName, + unsigned int _buildNumber ) + : majorVersion( _majorVersion ), + minorVersion( _minorVersion ), + patchNumber( _patchNumber ), + branchName( _branchName ), + buildNumber( _buildNumber ) + {} + + std::ostream& operator << ( std::ostream& os, Version const& version ) { + os << version.majorVersion << '.' + << version.minorVersion << '.' + << version.patchNumber; + // branchName is never null -> 0th char is \0 if it is empty + if (version.branchName[0]) { + os << '-' << version.branchName + << '.' << version.buildNumber; + } + return os; + } + + Version const& libraryVersion() { + static Version version( 2, 2, 3, "", 0 ); + return version; + } + +} +// end catch_version.cpp +// start catch_wildcard_pattern.cpp + +#include + +namespace Catch { + + WildcardPattern::WildcardPattern( std::string const& pattern, + CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_pattern( adjustCase( pattern ) ) + { + if( startsWith( m_pattern, '*' ) ) { + m_pattern = m_pattern.substr( 1 ); + m_wildcard = WildcardAtStart; + } + if( endsWith( m_pattern, '*' ) ) { + m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); + m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); + } + } + + bool WildcardPattern::matches( std::string const& str ) const { + switch( m_wildcard ) { + case NoWildcard: + return m_pattern == adjustCase( str ); + case WildcardAtStart: + return endsWith( adjustCase( str ), m_pattern ); + case WildcardAtEnd: + return startsWith( adjustCase( str ), m_pattern ); + case WildcardAtBothEnds: + return contains( adjustCase( str ), m_pattern ); + default: + CATCH_INTERNAL_ERROR( "Unknown enum" ); + } + } + + std::string WildcardPattern::adjustCase( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; + } +} +// end catch_wildcard_pattern.cpp +// start catch_xmlwriter.cpp + +#include + +using uchar = unsigned char; + +namespace Catch { + +namespace { + + size_t trailingBytes(unsigned char c) { + if ((c & 0xE0) == 0xC0) { + return 2; + } + if ((c & 0xF0) == 0xE0) { + return 3; + } + if ((c & 0xF8) == 0xF0) { + return 4; + } + CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); + } + + uint32_t headerValue(unsigned char c) { + if ((c & 0xE0) == 0xC0) { + return c & 0x1F; + } + if ((c & 0xF0) == 0xE0) { + return c & 0x0F; + } + if ((c & 0xF8) == 0xF0) { + return c & 0x07; + } + CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); + } + + void hexEscapeChar(std::ostream& os, unsigned char c) { + os << "\\x" + << std::uppercase << std::hex << std::setfill('0') << std::setw(2) + << static_cast(c); + } + +} // anonymous namespace + + XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat ) + : m_str( str ), + m_forWhat( forWhat ) + {} + + void XmlEncode::encodeTo( std::ostream& os ) const { + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: http://www.w3.org/TR/xml/#syntax) + + for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { + uchar c = m_str[idx]; + switch (c) { + case '<': os << "<"; break; + case '&': os << "&"; break; + + case '>': + // See: http://www.w3.org/TR/xml/#syntax + if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']') + os << ">"; + else + os << c; + break; + + case '\"': + if (m_forWhat == ForAttributes) + os << """; + else + os << c; + break; + + default: + // Check for control characters and invalid utf-8 + + // Escape control characters in standard ascii + // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 + if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) { + hexEscapeChar(os, c); + break; + } + + // Plain ASCII: Write it to stream + if (c < 0x7F) { + os << c; + break; + } + + // UTF-8 territory + // Check if the encoding is valid and if it is not, hex escape bytes. + // Important: We do not check the exact decoded values for validity, only the encoding format + // First check that this bytes is a valid lead byte: + // This means that it is not encoded as 1111 1XXX + // Or as 10XX XXXX + if (c < 0xC0 || + c >= 0xF8) { + hexEscapeChar(os, c); + break; + } + + auto encBytes = trailingBytes(c); + // Are there enough bytes left to avoid accessing out-of-bounds memory? + if (idx + encBytes - 1 >= m_str.size()) { + hexEscapeChar(os, c); + break; + } + // The header is valid, check data + // The next encBytes bytes must together be a valid utf-8 + // This means: bitpattern 10XX XXXX and the extracted value is sane (ish) + bool valid = true; + uint32_t value = headerValue(c); + for (std::size_t n = 1; n < encBytes; ++n) { + uchar nc = m_str[idx + n]; + valid &= ((nc & 0xC0) == 0x80); + value = (value << 6) | (nc & 0x3F); + } + + if ( + // Wrong bit pattern of following bytes + (!valid) || + // Overlong encodings + (value < 0x80) || + (0x80 <= value && value < 0x800 && encBytes > 2) || + (0x800 < value && value < 0x10000 && encBytes > 3) || + // Encoded value out of range + (value >= 0x110000) + ) { + hexEscapeChar(os, c); + break; + } + + // If we got here, this is in fact a valid(ish) utf-8 sequence + for (std::size_t n = 0; n < encBytes; ++n) { + os << m_str[idx + n]; + } + idx += encBytes - 1; + break; + } + } + } + + std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { + xmlEncode.encodeTo( os ); + return os; + } + + XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer ) + : m_writer( writer ) + {} + + XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept + : m_writer( other.m_writer ){ + other.m_writer = nullptr; + } + XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept { + if ( m_writer ) { + m_writer->endElement(); + } + m_writer = other.m_writer; + other.m_writer = nullptr; + return *this; + } + + XmlWriter::ScopedElement::~ScopedElement() { + if( m_writer ) + m_writer->endElement(); + } + + XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) { + m_writer->writeText( text, indent ); + return *this; + } + + XmlWriter::XmlWriter( std::ostream& os ) : m_os( os ) + { + writeDeclaration(); + } + + XmlWriter::~XmlWriter() { + while( !m_tags.empty() ) + endElement(); + } + + XmlWriter& XmlWriter::startElement( std::string const& name ) { + ensureTagClosed(); + newlineIfNecessary(); + m_os << m_indent << '<' << name; + m_tags.push_back( name ); + m_indent += " "; + m_tagIsOpen = true; + return *this; + } + + XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) { + ScopedElement scoped( this ); + startElement( name ); + return scoped; + } + + XmlWriter& XmlWriter::endElement() { + newlineIfNecessary(); + m_indent = m_indent.substr( 0, m_indent.size()-2 ); + if( m_tagIsOpen ) { + m_os << "/>"; + m_tagIsOpen = false; + } + else { + m_os << m_indent << ""; + } + m_os << std::endl; + m_tags.pop_back(); + return *this; + } + + XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) { + if( !name.empty() && !attribute.empty() ) + m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; + return *this; + } + + XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) { + m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; + return *this; + } + + XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) { + if( !text.empty() ){ + bool tagWasOpen = m_tagIsOpen; + ensureTagClosed(); + if( tagWasOpen && indent ) + m_os << m_indent; + m_os << XmlEncode( text ); + m_needsNewline = true; + } + return *this; + } + + XmlWriter& XmlWriter::writeComment( std::string const& text ) { + ensureTagClosed(); + m_os << m_indent << ""; + m_needsNewline = true; + return *this; + } + + void XmlWriter::writeStylesheetRef( std::string const& url ) { + m_os << "\n"; + } + + XmlWriter& XmlWriter::writeBlankLine() { + ensureTagClosed(); + m_os << '\n'; + return *this; + } + + void XmlWriter::ensureTagClosed() { + if( m_tagIsOpen ) { + m_os << ">" << std::endl; + m_tagIsOpen = false; + } + } + + void XmlWriter::writeDeclaration() { + m_os << "\n"; + } + + void XmlWriter::newlineIfNecessary() { + if( m_needsNewline ) { + m_os << std::endl; + m_needsNewline = false; + } + } +} +// end catch_xmlwriter.cpp +// start catch_reporter_bases.cpp + +#include +#include +#include +#include +#include + +namespace Catch { + void prepareExpandedExpression(AssertionResult& result) { + result.getExpandedExpression(); + } + + // Because formatting using c++ streams is stateful, drop down to C is required + // Alternatively we could use stringstream, but its performance is... not good. + std::string getFormattedDuration( double duration ) { + // Max exponent + 1 is required to represent the whole part + // + 1 for decimal point + // + 3 for the 3 decimal places + // + 1 for null terminator + const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1; + char buffer[maxDoubleSize]; + + // Save previous errno, to prevent sprintf from overwriting it + ErrnoGuard guard; +#ifdef _MSC_VER + sprintf_s(buffer, "%.3f", duration); +#else + sprintf(buffer, "%.3f", duration); +#endif + return std::string(buffer); + } + + TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config) + :StreamingReporterBase(_config) {} + + void TestEventListenerBase::assertionStarting(AssertionInfo const &) {} + + bool TestEventListenerBase::assertionEnded(AssertionStats const &) { + return false; + } + +} // end namespace Catch +// end catch_reporter_bases.cpp +// start catch_reporter_compact.cpp + +namespace { + +#ifdef CATCH_PLATFORM_MAC + const char* failedString() { return "FAILED"; } + const char* passedString() { return "PASSED"; } +#else + const char* failedString() { return "failed"; } + const char* passedString() { return "passed"; } +#endif + + // Colour::LightGrey + Catch::Colour::Code dimColour() { return Catch::Colour::FileName; } + + std::string bothOrAll( std::size_t count ) { + return count == 1 ? std::string() : + count == 2 ? "both " : "all " ; + } + +} // anon namespace + +namespace Catch { +namespace { +// Colour, message variants: +// - white: No tests ran. +// - red: Failed [both/all] N test cases, failed [both/all] M assertions. +// - white: Passed [both/all] N test cases (no assertions). +// - red: Failed N tests cases, failed M assertions. +// - green: Passed [both/all] N tests cases with M assertions. +void printTotals(std::ostream& out, const Totals& totals) { + if (totals.testCases.total() == 0) { + out << "No tests ran."; + } else if (totals.testCases.failed == totals.testCases.total()) { + Colour colour(Colour::ResultError); + const std::string qualify_assertions_failed = + totals.assertions.failed == totals.assertions.total() ? + bothOrAll(totals.assertions.failed) : std::string(); + out << + "Failed " << bothOrAll(totals.testCases.failed) + << pluralise(totals.testCases.failed, "test case") << ", " + "failed " << qualify_assertions_failed << + pluralise(totals.assertions.failed, "assertion") << '.'; + } else if (totals.assertions.total() == 0) { + out << + "Passed " << bothOrAll(totals.testCases.total()) + << pluralise(totals.testCases.total(), "test case") + << " (no assertions)."; + } else if (totals.assertions.failed) { + Colour colour(Colour::ResultError); + out << + "Failed " << pluralise(totals.testCases.failed, "test case") << ", " + "failed " << pluralise(totals.assertions.failed, "assertion") << '.'; + } else { + Colour colour(Colour::ResultSuccess); + out << + "Passed " << bothOrAll(totals.testCases.passed) + << pluralise(totals.testCases.passed, "test case") << + " with " << pluralise(totals.assertions.passed, "assertion") << '.'; + } +} + +// Implementation of CompactReporter formatting +class AssertionPrinter { +public: + AssertionPrinter& operator= (AssertionPrinter const&) = delete; + AssertionPrinter(AssertionPrinter const&) = delete; + AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) + : stream(_stream) + , result(_stats.assertionResult) + , messages(_stats.infoMessages) + , itMessage(_stats.infoMessages.begin()) + , printInfoMessages(_printInfoMessages) {} + + void print() { + printSourceInfo(); + + itMessage = messages.begin(); + + switch (result.getResultType()) { + case ResultWas::Ok: + printResultType(Colour::ResultSuccess, passedString()); + printOriginalExpression(); + printReconstructedExpression(); + if (!result.hasExpression()) + printRemainingMessages(Colour::None); + else + printRemainingMessages(); + break; + case ResultWas::ExpressionFailed: + if (result.isOk()) + printResultType(Colour::ResultSuccess, failedString() + std::string(" - but was ok")); + else + printResultType(Colour::Error, failedString()); + printOriginalExpression(); + printReconstructedExpression(); + printRemainingMessages(); + break; + case ResultWas::ThrewException: + printResultType(Colour::Error, failedString()); + printIssue("unexpected exception with message:"); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::FatalErrorCondition: + printResultType(Colour::Error, failedString()); + printIssue("fatal error condition with message:"); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::DidntThrowException: + printResultType(Colour::Error, failedString()); + printIssue("expected exception, got none"); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::Info: + printResultType(Colour::None, "info"); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::Warning: + printResultType(Colour::None, "warning"); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::ExplicitFailure: + printResultType(Colour::Error, failedString()); + printIssue("explicitly"); + printRemainingMessages(Colour::None); + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + printResultType(Colour::Error, "** internal error **"); + break; + } + } + +private: + void printSourceInfo() const { + Colour colourGuard(Colour::FileName); + stream << result.getSourceInfo() << ':'; + } + + void printResultType(Colour::Code colour, std::string const& passOrFail) const { + if (!passOrFail.empty()) { + { + Colour colourGuard(colour); + stream << ' ' << passOrFail; + } + stream << ':'; + } + } + + void printIssue(std::string const& issue) const { + stream << ' ' << issue; + } + + void printExpressionWas() { + if (result.hasExpression()) { + stream << ';'; + { + Colour colour(dimColour()); + stream << " expression was:"; + } + printOriginalExpression(); + } + } + + void printOriginalExpression() const { + if (result.hasExpression()) { + stream << ' ' << result.getExpression(); + } + } + + void printReconstructedExpression() const { + if (result.hasExpandedExpression()) { + { + Colour colour(dimColour()); + stream << " for: "; + } + stream << result.getExpandedExpression(); + } + } + + void printMessage() { + if (itMessage != messages.end()) { + stream << " '" << itMessage->message << '\''; + ++itMessage; + } + } + + void printRemainingMessages(Colour::Code colour = dimColour()) { + if (itMessage == messages.end()) + return; + + // using messages.end() directly yields (or auto) compilation error: + std::vector::const_iterator itEnd = messages.end(); + const std::size_t N = static_cast(std::distance(itMessage, itEnd)); + + { + Colour colourGuard(colour); + stream << " with " << pluralise(N, "message") << ':'; + } + + for (; itMessage != itEnd; ) { + // If this assertion is a warning ignore any INFO messages + if (printInfoMessages || itMessage->type != ResultWas::Info) { + stream << " '" << itMessage->message << '\''; + if (++itMessage != itEnd) { + Colour colourGuard(dimColour()); + stream << " and"; + } + } + } + } + +private: + std::ostream& stream; + AssertionResult const& result; + std::vector messages; + std::vector::const_iterator itMessage; + bool printInfoMessages; +}; + +} // anon namespace + + std::string CompactReporter::getDescription() { + return "Reports test results on a single line, suitable for IDEs"; + } + + ReporterPreferences CompactReporter::getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = false; + return prefs; + } + + void CompactReporter::noMatchingTestCases( std::string const& spec ) { + stream << "No test cases matched '" << spec << '\'' << std::endl; + } + + void CompactReporter::assertionStarting( AssertionInfo const& ) {} + + bool CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + + stream << std::endl; + return true; + } + + void CompactReporter::sectionEnded(SectionStats const& _sectionStats) { + if (m_config->showDurations() == ShowDurations::Always) { + stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; + } + } + + void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) { + printTotals( stream, _testRunStats.totals ); + stream << '\n' << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + CompactReporter::~CompactReporter() {} + + CATCH_REGISTER_REPORTER( "compact", CompactReporter ) + +} // end namespace Catch +// end catch_reporter_compact.cpp +// start catch_reporter_console.cpp + +#include +#include + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch + // Note that 4062 (not all labels are handled + // and default is missing) is enabled +#endif + +namespace Catch { + +namespace { + +// Formatter impl for ConsoleReporter +class ConsoleAssertionPrinter { +public: + ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter const&) = delete; + ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete; + ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) + : stream(_stream), + stats(_stats), + result(_stats.assertionResult), + colour(Colour::None), + message(result.getMessage()), + messages(_stats.infoMessages), + printInfoMessages(_printInfoMessages) { + switch (result.getResultType()) { + case ResultWas::Ok: + colour = Colour::Success; + passOrFail = "PASSED"; + //if( result.hasMessage() ) + if (_stats.infoMessages.size() == 1) + messageLabel = "with message"; + if (_stats.infoMessages.size() > 1) + messageLabel = "with messages"; + break; + case ResultWas::ExpressionFailed: + if (result.isOk()) { + colour = Colour::Success; + passOrFail = "FAILED - but was ok"; + } else { + colour = Colour::Error; + passOrFail = "FAILED"; + } + if (_stats.infoMessages.size() == 1) + messageLabel = "with message"; + if (_stats.infoMessages.size() > 1) + messageLabel = "with messages"; + break; + case ResultWas::ThrewException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to unexpected exception with "; + if (_stats.infoMessages.size() == 1) + messageLabel += "message"; + if (_stats.infoMessages.size() > 1) + messageLabel += "messages"; + break; + case ResultWas::FatalErrorCondition: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to a fatal error condition"; + break; + case ResultWas::DidntThrowException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "because no exception was thrown where one was expected"; + break; + case ResultWas::Info: + messageLabel = "info"; + break; + case ResultWas::Warning: + messageLabel = "warning"; + break; + case ResultWas::ExplicitFailure: + passOrFail = "FAILED"; + colour = Colour::Error; + if (_stats.infoMessages.size() == 1) + messageLabel = "explicitly with message"; + if (_stats.infoMessages.size() > 1) + messageLabel = "explicitly with messages"; + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + passOrFail = "** internal error **"; + colour = Colour::Error; + break; + } + } + + void print() const { + printSourceInfo(); + if (stats.totals.assertions.total() > 0) { + if (result.isOk()) + stream << '\n'; + printResultType(); + printOriginalExpression(); + printReconstructedExpression(); + } else { + stream << '\n'; + } + printMessage(); + } + +private: + void printResultType() const { + if (!passOrFail.empty()) { + Colour colourGuard(colour); + stream << passOrFail << ":\n"; + } + } + void printOriginalExpression() const { + if (result.hasExpression()) { + Colour colourGuard(Colour::OriginalExpression); + stream << " "; + stream << result.getExpressionInMacro(); + stream << '\n'; + } + } + void printReconstructedExpression() const { + if (result.hasExpandedExpression()) { + stream << "with expansion:\n"; + Colour colourGuard(Colour::ReconstructedExpression); + stream << Column(result.getExpandedExpression()).indent(2) << '\n'; + } + } + void printMessage() const { + if (!messageLabel.empty()) + stream << messageLabel << ':' << '\n'; + for (auto const& msg : messages) { + // If this assertion is a warning ignore any INFO messages + if (printInfoMessages || msg.type != ResultWas::Info) + stream << Column(msg.message).indent(2) << '\n'; + } + } + void printSourceInfo() const { + Colour colourGuard(Colour::FileName); + stream << result.getSourceInfo() << ": "; + } + + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + Colour::Code colour; + std::string passOrFail; + std::string messageLabel; + std::string message; + std::vector messages; + bool printInfoMessages; +}; + +std::size_t makeRatio(std::size_t number, std::size_t total) { + std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0; + return (ratio == 0 && number > 0) ? 1 : ratio; +} + +std::size_t& findMax(std::size_t& i, std::size_t& j, std::size_t& k) { + if (i > j && i > k) + return i; + else if (j > k) + return j; + else + return k; +} + +struct ColumnInfo { + enum Justification { Left, Right }; + std::string name; + int width; + Justification justification; +}; +struct ColumnBreak {}; +struct RowBreak {}; + +class Duration { + enum class Unit { + Auto, + Nanoseconds, + Microseconds, + Milliseconds, + Seconds, + Minutes + }; + static const uint64_t s_nanosecondsInAMicrosecond = 1000; + static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond; + static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond; + static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond; + + uint64_t m_inNanoseconds; + Unit m_units; + +public: + explicit Duration(uint64_t inNanoseconds, Unit units = Unit::Auto) + : m_inNanoseconds(inNanoseconds), + m_units(units) { + if (m_units == Unit::Auto) { + if (m_inNanoseconds < s_nanosecondsInAMicrosecond) + m_units = Unit::Nanoseconds; + else if (m_inNanoseconds < s_nanosecondsInAMillisecond) + m_units = Unit::Microseconds; + else if (m_inNanoseconds < s_nanosecondsInASecond) + m_units = Unit::Milliseconds; + else if (m_inNanoseconds < s_nanosecondsInAMinute) + m_units = Unit::Seconds; + else + m_units = Unit::Minutes; + } + + } + + auto value() const -> double { + switch (m_units) { + case Unit::Microseconds: + return m_inNanoseconds / static_cast(s_nanosecondsInAMicrosecond); + case Unit::Milliseconds: + return m_inNanoseconds / static_cast(s_nanosecondsInAMillisecond); + case Unit::Seconds: + return m_inNanoseconds / static_cast(s_nanosecondsInASecond); + case Unit::Minutes: + return m_inNanoseconds / static_cast(s_nanosecondsInAMinute); + default: + return static_cast(m_inNanoseconds); + } + } + auto unitsAsString() const -> std::string { + switch (m_units) { + case Unit::Nanoseconds: + return "ns"; + case Unit::Microseconds: + return "µs"; + case Unit::Milliseconds: + return "ms"; + case Unit::Seconds: + return "s"; + case Unit::Minutes: + return "m"; + default: + return "** internal error **"; + } + + } + friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& { + return os << duration.value() << " " << duration.unitsAsString(); + } +}; +} // end anon namespace + +class TablePrinter { + std::ostream& m_os; + std::vector m_columnInfos; + std::ostringstream m_oss; + int m_currentColumn = -1; + bool m_isOpen = false; + +public: + TablePrinter( std::ostream& os, std::vector columnInfos ) + : m_os( os ), + m_columnInfos( std::move( columnInfos ) ) {} + + auto columnInfos() const -> std::vector const& { + return m_columnInfos; + } + + void open() { + if (!m_isOpen) { + m_isOpen = true; + *this << RowBreak(); + for (auto const& info : m_columnInfos) + *this << info.name << ColumnBreak(); + *this << RowBreak(); + m_os << Catch::getLineOfChars<'-'>() << "\n"; + } + } + void close() { + if (m_isOpen) { + *this << RowBreak(); + m_os << std::endl; + m_isOpen = false; + } + } + + template + friend TablePrinter& operator << (TablePrinter& tp, T const& value) { + tp.m_oss << value; + return tp; + } + + friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) { + auto colStr = tp.m_oss.str(); + // This takes account of utf8 encodings + auto strSize = Catch::StringRef(colStr).numberOfCharacters(); + tp.m_oss.str(""); + tp.open(); + if (tp.m_currentColumn == static_cast(tp.m_columnInfos.size() - 1)) { + tp.m_currentColumn = -1; + tp.m_os << "\n"; + } + tp.m_currentColumn++; + + auto colInfo = tp.m_columnInfos[tp.m_currentColumn]; + auto padding = (strSize + 2 < static_cast(colInfo.width)) + ? std::string(colInfo.width - (strSize + 2), ' ') + : std::string(); + if (colInfo.justification == ColumnInfo::Left) + tp.m_os << colStr << padding << " "; + else + tp.m_os << padding << colStr << " "; + return tp; + } + + friend TablePrinter& operator << (TablePrinter& tp, RowBreak) { + if (tp.m_currentColumn > 0) { + tp.m_os << "\n"; + tp.m_currentColumn = -1; + } + return tp; + } +}; + +ConsoleReporter::ConsoleReporter(ReporterConfig const& config) + : StreamingReporterBase(config), + m_tablePrinter(new TablePrinter(config.stream(), + { + { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left }, + { "iters", 8, ColumnInfo::Right }, + { "elapsed ns", 14, ColumnInfo::Right }, + { "average", 14, ColumnInfo::Right } + })) {} +ConsoleReporter::~ConsoleReporter() = default; + +std::string ConsoleReporter::getDescription() { + return "Reports test results as plain lines of text"; +} + +void ConsoleReporter::noMatchingTestCases(std::string const& spec) { + stream << "No test cases matched '" << spec << '\'' << std::endl; +} + +void ConsoleReporter::assertionStarting(AssertionInfo const&) {} + +bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) { + AssertionResult const& result = _assertionStats.assertionResult; + + bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); + + // Drop out if result was successful but we're not printing them. + if (!includeResults && result.getResultType() != ResultWas::Warning) + return false; + + lazyPrint(); + + ConsoleAssertionPrinter printer(stream, _assertionStats, includeResults); + printer.print(); + stream << std::endl; + return true; +} + +void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) { + m_headerPrinted = false; + StreamingReporterBase::sectionStarting(_sectionInfo); +} +void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) { + m_tablePrinter->close(); + if (_sectionStats.missingAssertions) { + lazyPrint(); + Colour colour(Colour::ResultError); + if (m_sectionStack.size() > 1) + stream << "\nNo assertions in section"; + else + stream << "\nNo assertions in test case"; + stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; + } + if (m_config->showDurations() == ShowDurations::Always) { + stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; + } + if (m_headerPrinted) { + m_headerPrinted = false; + } + StreamingReporterBase::sectionEnded(_sectionStats); +} + +void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) { + lazyPrintWithoutClosingBenchmarkTable(); + + auto nameCol = Column( info.name ).width( static_cast( m_tablePrinter->columnInfos()[0].width - 2 ) ); + + bool firstLine = true; + for (auto line : nameCol) { + if (!firstLine) + (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak(); + else + firstLine = false; + + (*m_tablePrinter) << line << ColumnBreak(); + } +} +void ConsoleReporter::benchmarkEnded(BenchmarkStats const& stats) { + Duration average(stats.elapsedTimeInNanoseconds / stats.iterations); + (*m_tablePrinter) + << stats.iterations << ColumnBreak() + << stats.elapsedTimeInNanoseconds << ColumnBreak() + << average << ColumnBreak(); +} + +void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) { + m_tablePrinter->close(); + StreamingReporterBase::testCaseEnded(_testCaseStats); + m_headerPrinted = false; +} +void ConsoleReporter::testGroupEnded(TestGroupStats const& _testGroupStats) { + if (currentGroupInfo.used) { + printSummaryDivider(); + stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; + printTotals(_testGroupStats.totals); + stream << '\n' << std::endl; + } + StreamingReporterBase::testGroupEnded(_testGroupStats); +} +void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) { + printTotalsDivider(_testRunStats.totals); + printTotals(_testRunStats.totals); + stream << std::endl; + StreamingReporterBase::testRunEnded(_testRunStats); +} + +void ConsoleReporter::lazyPrint() { + + m_tablePrinter->close(); + lazyPrintWithoutClosingBenchmarkTable(); +} + +void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() { + + if (!currentTestRunInfo.used) + lazyPrintRunInfo(); + if (!currentGroupInfo.used) + lazyPrintGroupInfo(); + + if (!m_headerPrinted) { + printTestCaseAndSectionHeader(); + m_headerPrinted = true; + } +} +void ConsoleReporter::lazyPrintRunInfo() { + stream << '\n' << getLineOfChars<'~'>() << '\n'; + Colour colour(Colour::SecondaryText); + stream << currentTestRunInfo->name + << " is a Catch v" << libraryVersion() << " host application.\n" + << "Run with -? for options\n\n"; + + if (m_config->rngSeed() != 0) + stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; + + currentTestRunInfo.used = true; +} +void ConsoleReporter::lazyPrintGroupInfo() { + if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1) { + printClosedHeader("Group: " + currentGroupInfo->name); + currentGroupInfo.used = true; + } +} +void ConsoleReporter::printTestCaseAndSectionHeader() { + assert(!m_sectionStack.empty()); + printOpenHeader(currentTestCaseInfo->name); + + if (m_sectionStack.size() > 1) { + Colour colourGuard(Colour::Headers); + + auto + it = m_sectionStack.begin() + 1, // Skip first section (test case) + itEnd = m_sectionStack.end(); + for (; it != itEnd; ++it) + printHeaderString(it->name, 2); + } + + SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; + + if (!lineInfo.empty()) { + stream << getLineOfChars<'-'>() << '\n'; + Colour colourGuard(Colour::FileName); + stream << lineInfo << '\n'; + } + stream << getLineOfChars<'.'>() << '\n' << std::endl; +} + +void ConsoleReporter::printClosedHeader(std::string const& _name) { + printOpenHeader(_name); + stream << getLineOfChars<'.'>() << '\n'; +} +void ConsoleReporter::printOpenHeader(std::string const& _name) { + stream << getLineOfChars<'-'>() << '\n'; + { + Colour colourGuard(Colour::Headers); + printHeaderString(_name); + } +} + +// if string has a : in first line will set indent to follow it on +// subsequent lines +void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t indent) { + std::size_t i = _string.find(": "); + if (i != std::string::npos) + i += 2; + else + i = 0; + stream << Column(_string).indent(indent + i).initialIndent(indent) << '\n'; +} + +struct SummaryColumn { + + SummaryColumn( std::string _label, Colour::Code _colour ) + : label( std::move( _label ) ), + colour( _colour ) {} + SummaryColumn addRow( std::size_t count ) { + ReusableStringStream rss; + rss << count; + std::string row = rss.str(); + for (auto& oldRow : rows) { + while (oldRow.size() < row.size()) + oldRow = ' ' + oldRow; + while (oldRow.size() > row.size()) + row = ' ' + row; + } + rows.push_back(row); + return *this; + } + + std::string label; + Colour::Code colour; + std::vector rows; + +}; + +void ConsoleReporter::printTotals( Totals const& totals ) { + if (totals.testCases.total() == 0) { + stream << Colour(Colour::Warning) << "No tests ran\n"; + } else if (totals.assertions.total() > 0 && totals.testCases.allPassed()) { + stream << Colour(Colour::ResultSuccess) << "All tests passed"; + stream << " (" + << pluralise(totals.assertions.passed, "assertion") << " in " + << pluralise(totals.testCases.passed, "test case") << ')' + << '\n'; + } else { + + std::vector columns; + columns.push_back(SummaryColumn("", Colour::None) + .addRow(totals.testCases.total()) + .addRow(totals.assertions.total())); + columns.push_back(SummaryColumn("passed", Colour::Success) + .addRow(totals.testCases.passed) + .addRow(totals.assertions.passed)); + columns.push_back(SummaryColumn("failed", Colour::ResultError) + .addRow(totals.testCases.failed) + .addRow(totals.assertions.failed)); + columns.push_back(SummaryColumn("failed as expected", Colour::ResultExpectedFailure) + .addRow(totals.testCases.failedButOk) + .addRow(totals.assertions.failedButOk)); + + printSummaryRow("test cases", columns, 0); + printSummaryRow("assertions", columns, 1); + } +} +void ConsoleReporter::printSummaryRow(std::string const& label, std::vector const& cols, std::size_t row) { + for (auto col : cols) { + std::string value = col.rows[row]; + if (col.label.empty()) { + stream << label << ": "; + if (value != "0") + stream << value; + else + stream << Colour(Colour::Warning) << "- none -"; + } else if (value != "0") { + stream << Colour(Colour::LightGrey) << " | "; + stream << Colour(col.colour) + << value << ' ' << col.label; + } + } + stream << '\n'; +} + +void ConsoleReporter::printTotalsDivider(Totals const& totals) { + if (totals.testCases.total() > 0) { + std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total()); + std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total()); + std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total()); + while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1) + findMax(failedRatio, failedButOkRatio, passedRatio)++; + while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1) + findMax(failedRatio, failedButOkRatio, passedRatio)--; + + stream << Colour(Colour::Error) << std::string(failedRatio, '='); + stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '='); + if (totals.testCases.allPassed()) + stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '='); + else + stream << Colour(Colour::Success) << std::string(passedRatio, '='); + } else { + stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '='); + } + stream << '\n'; +} +void ConsoleReporter::printSummaryDivider() { + stream << getLineOfChars<'-'>() << '\n'; +} + +CATCH_REGISTER_REPORTER("console", ConsoleReporter) + +} // end namespace Catch + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif +// end catch_reporter_console.cpp +// start catch_reporter_junit.cpp + +#include +#include +#include +#include + +namespace Catch { + + namespace { + std::string getCurrentTimestamp() { + // Beware, this is not reentrant because of backward compatibility issues + // Also, UTC only, again because of backward compatibility (%z is C++11) + time_t rawtime; + std::time(&rawtime); + auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); + +#ifdef _MSC_VER + std::tm timeInfo = {}; + gmtime_s(&timeInfo, &rawtime); +#else + std::tm* timeInfo; + timeInfo = std::gmtime(&rawtime); +#endif + + char timeStamp[timeStampSize]; + const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; + +#ifdef _MSC_VER + std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); +#else + std::strftime(timeStamp, timeStampSize, fmt, timeInfo); +#endif + return std::string(timeStamp); + } + + std::string fileNameTag(const std::vector &tags) { + auto it = std::find_if(begin(tags), + end(tags), + [] (std::string const& tag) {return tag.front() == '#'; }); + if (it != tags.end()) + return it->substr(1); + return std::string(); + } + } // anonymous namespace + + JunitReporter::JunitReporter( ReporterConfig const& _config ) + : CumulativeReporterBase( _config ), + xml( _config.stream() ) + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + + JunitReporter::~JunitReporter() {} + + std::string JunitReporter::getDescription() { + return "Reports test results in an XML format that looks like Ant's junitreport target"; + } + + void JunitReporter::noMatchingTestCases( std::string const& /*spec*/ ) {} + + void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) { + CumulativeReporterBase::testRunStarting( runInfo ); + xml.startElement( "testsuites" ); + } + + void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) { + suiteTimer.start(); + stdOutForSuite.clear(); + stdErrForSuite.clear(); + unexpectedExceptions = 0; + CumulativeReporterBase::testGroupStarting( groupInfo ); + } + + void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) { + m_okToFail = testCaseInfo.okToFail(); + } + + bool JunitReporter::assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) + unexpectedExceptions++; + return CumulativeReporterBase::assertionEnded( assertionStats ); + } + + void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { + stdOutForSuite += testCaseStats.stdOut; + stdErrForSuite += testCaseStats.stdErr; + CumulativeReporterBase::testCaseEnded( testCaseStats ); + } + + void JunitReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { + double suiteTime = suiteTimer.getElapsedSeconds(); + CumulativeReporterBase::testGroupEnded( testGroupStats ); + writeGroup( *m_testGroups.back(), suiteTime ); + } + + void JunitReporter::testRunEndedCumulative() { + xml.endElement(); + } + + void JunitReporter::writeGroup( TestGroupNode const& groupNode, double suiteTime ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); + TestGroupStats const& stats = groupNode.value; + xml.writeAttribute( "name", stats.groupInfo.name ); + xml.writeAttribute( "errors", unexpectedExceptions ); + xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); + xml.writeAttribute( "tests", stats.totals.assertions.total() ); + xml.writeAttribute( "hostname", "tbd" ); // !TBD + if( m_config->showDurations() == ShowDurations::Never ) + xml.writeAttribute( "time", "" ); + else + xml.writeAttribute( "time", suiteTime ); + xml.writeAttribute( "timestamp", getCurrentTimestamp() ); + + // Write test cases + for( auto const& child : groupNode.children ) + writeTestCase( *child ); + + xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), false ); + xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), false ); + } + + void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) { + TestCaseStats const& stats = testCaseNode.value; + + // All test cases have exactly one section - which represents the + // test case itself. That section may have 0-n nested sections + assert( testCaseNode.children.size() == 1 ); + SectionNode const& rootSection = *testCaseNode.children.front(); + + std::string className = stats.testInfo.className; + + if( className.empty() ) { + className = fileNameTag(stats.testInfo.tags); + if ( className.empty() ) + className = "global"; + } + + if ( !m_config->name().empty() ) + className = m_config->name() + "." + className; + + writeSection( className, "", rootSection ); + } + + void JunitReporter::writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode ) { + std::string name = trim( sectionNode.stats.sectionInfo.name ); + if( !rootName.empty() ) + name = rootName + '/' + name; + + if( !sectionNode.assertions.empty() || + !sectionNode.stdOut.empty() || + !sectionNode.stdErr.empty() ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); + if( className.empty() ) { + xml.writeAttribute( "classname", name ); + xml.writeAttribute( "name", "root" ); + } + else { + xml.writeAttribute( "classname", className ); + xml.writeAttribute( "name", name ); + } + xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) ); + + writeAssertions( sectionNode ); + + if( !sectionNode.stdOut.empty() ) + xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); + if( !sectionNode.stdErr.empty() ) + xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); + } + for( auto const& childNode : sectionNode.childSections ) + if( className.empty() ) + writeSection( name, "", *childNode ); + else + writeSection( className, name, *childNode ); + } + + void JunitReporter::writeAssertions( SectionNode const& sectionNode ) { + for( auto const& assertion : sectionNode.assertions ) + writeAssertion( assertion ); + } + + void JunitReporter::writeAssertion( AssertionStats const& stats ) { + AssertionResult const& result = stats.assertionResult; + if( !result.isOk() ) { + std::string elementName; + switch( result.getResultType() ) { + case ResultWas::ThrewException: + case ResultWas::FatalErrorCondition: + elementName = "error"; + break; + case ResultWas::ExplicitFailure: + elementName = "failure"; + break; + case ResultWas::ExpressionFailed: + elementName = "failure"; + break; + case ResultWas::DidntThrowException: + elementName = "failure"; + break; + + // We should never see these here: + case ResultWas::Info: + case ResultWas::Warning: + case ResultWas::Ok: + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + elementName = "internalError"; + break; + } + + XmlWriter::ScopedElement e = xml.scopedElement( elementName ); + + xml.writeAttribute( "message", result.getExpandedExpression() ); + xml.writeAttribute( "type", result.getTestMacroName() ); + + ReusableStringStream rss; + if( !result.getMessage().empty() ) + rss << result.getMessage() << '\n'; + for( auto const& msg : stats.infoMessages ) + if( msg.type == ResultWas::Info ) + rss << msg.message << '\n'; + + rss << "at " << result.getSourceInfo(); + xml.writeText( rss.str(), false ); + } + } + + CATCH_REGISTER_REPORTER( "junit", JunitReporter ) + +} // end namespace Catch +// end catch_reporter_junit.cpp +// start catch_reporter_listening.cpp + +#include + +namespace Catch { + + void ListeningReporter::addListener( IStreamingReporterPtr&& listener ) { + m_listeners.push_back( std::move( listener ) ); + } + + void ListeningReporter::addReporter(IStreamingReporterPtr&& reporter) { + assert(!m_reporter && "Listening reporter can wrap only 1 real reporter"); + m_reporter = std::move( reporter ); + } + + ReporterPreferences ListeningReporter::getPreferences() const { + return m_reporter->getPreferences(); + } + + std::set ListeningReporter::getSupportedVerbosities() { + return std::set{ }; + } + + void ListeningReporter::noMatchingTestCases( std::string const& spec ) { + for ( auto const& listener : m_listeners ) { + listener->noMatchingTestCases( spec ); + } + m_reporter->noMatchingTestCases( spec ); + } + + void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) { + for ( auto const& listener : m_listeners ) { + listener->benchmarkStarting( benchmarkInfo ); + } + m_reporter->benchmarkStarting( benchmarkInfo ); + } + void ListeningReporter::benchmarkEnded( BenchmarkStats const& benchmarkStats ) { + for ( auto const& listener : m_listeners ) { + listener->benchmarkEnded( benchmarkStats ); + } + m_reporter->benchmarkEnded( benchmarkStats ); + } + + void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) { + for ( auto const& listener : m_listeners ) { + listener->testRunStarting( testRunInfo ); + } + m_reporter->testRunStarting( testRunInfo ); + } + + void ListeningReporter::testGroupStarting( GroupInfo const& groupInfo ) { + for ( auto const& listener : m_listeners ) { + listener->testGroupStarting( groupInfo ); + } + m_reporter->testGroupStarting( groupInfo ); + } + + void ListeningReporter::testCaseStarting( TestCaseInfo const& testInfo ) { + for ( auto const& listener : m_listeners ) { + listener->testCaseStarting( testInfo ); + } + m_reporter->testCaseStarting( testInfo ); + } + + void ListeningReporter::sectionStarting( SectionInfo const& sectionInfo ) { + for ( auto const& listener : m_listeners ) { + listener->sectionStarting( sectionInfo ); + } + m_reporter->sectionStarting( sectionInfo ); + } + + void ListeningReporter::assertionStarting( AssertionInfo const& assertionInfo ) { + for ( auto const& listener : m_listeners ) { + listener->assertionStarting( assertionInfo ); + } + m_reporter->assertionStarting( assertionInfo ); + } + + // The return value indicates if the messages buffer should be cleared: + bool ListeningReporter::assertionEnded( AssertionStats const& assertionStats ) { + for( auto const& listener : m_listeners ) { + static_cast( listener->assertionEnded( assertionStats ) ); + } + return m_reporter->assertionEnded( assertionStats ); + } + + void ListeningReporter::sectionEnded( SectionStats const& sectionStats ) { + for ( auto const& listener : m_listeners ) { + listener->sectionEnded( sectionStats ); + } + m_reporter->sectionEnded( sectionStats ); + } + + void ListeningReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { + for ( auto const& listener : m_listeners ) { + listener->testCaseEnded( testCaseStats ); + } + m_reporter->testCaseEnded( testCaseStats ); + } + + void ListeningReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { + for ( auto const& listener : m_listeners ) { + listener->testGroupEnded( testGroupStats ); + } + m_reporter->testGroupEnded( testGroupStats ); + } + + void ListeningReporter::testRunEnded( TestRunStats const& testRunStats ) { + for ( auto const& listener : m_listeners ) { + listener->testRunEnded( testRunStats ); + } + m_reporter->testRunEnded( testRunStats ); + } + + void ListeningReporter::skipTest( TestCaseInfo const& testInfo ) { + for ( auto const& listener : m_listeners ) { + listener->skipTest( testInfo ); + } + m_reporter->skipTest( testInfo ); + } + + bool ListeningReporter::isMulti() const { + return true; + } + +} // end namespace Catch +// end catch_reporter_listening.cpp +// start catch_reporter_xml.cpp + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch + // Note that 4062 (not all labels are handled + // and default is missing) is enabled +#endif + +namespace Catch { + XmlReporter::XmlReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_xml(_config.stream()) + { + m_reporterPrefs.shouldRedirectStdOut = true; + } + + XmlReporter::~XmlReporter() = default; + + std::string XmlReporter::getDescription() { + return "Reports test results as an XML document"; + } + + std::string XmlReporter::getStylesheetRef() const { + return std::string(); + } + + void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) { + m_xml + .writeAttribute( "filename", sourceInfo.file ) + .writeAttribute( "line", sourceInfo.line ); + } + + void XmlReporter::noMatchingTestCases( std::string const& s ) { + StreamingReporterBase::noMatchingTestCases( s ); + } + + void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) { + StreamingReporterBase::testRunStarting( testInfo ); + std::string stylesheetRef = getStylesheetRef(); + if( !stylesheetRef.empty() ) + m_xml.writeStylesheetRef( stylesheetRef ); + m_xml.startElement( "Catch" ); + if( !m_config->name().empty() ) + m_xml.writeAttribute( "name", m_config->name() ); + } + + void XmlReporter::testGroupStarting( GroupInfo const& groupInfo ) { + StreamingReporterBase::testGroupStarting( groupInfo ); + m_xml.startElement( "Group" ) + .writeAttribute( "name", groupInfo.name ); + } + + void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) { + StreamingReporterBase::testCaseStarting(testInfo); + m_xml.startElement( "TestCase" ) + .writeAttribute( "name", trim( testInfo.name ) ) + .writeAttribute( "description", testInfo.description ) + .writeAttribute( "tags", testInfo.tagsAsString() ); + + writeSourceInfo( testInfo.lineInfo ); + + if ( m_config->showDurations() == ShowDurations::Always ) + m_testCaseTimer.start(); + m_xml.ensureTagClosed(); + } + + void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) { + StreamingReporterBase::sectionStarting( sectionInfo ); + if( m_sectionDepth++ > 0 ) { + m_xml.startElement( "Section" ) + .writeAttribute( "name", trim( sectionInfo.name ) ) + .writeAttribute( "description", sectionInfo.description ); + writeSourceInfo( sectionInfo.lineInfo ); + m_xml.ensureTagClosed(); + } + } + + void XmlReporter::assertionStarting( AssertionInfo const& ) { } + + bool XmlReporter::assertionEnded( AssertionStats const& assertionStats ) { + + AssertionResult const& result = assertionStats.assertionResult; + + bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); + + if( includeResults || result.getResultType() == ResultWas::Warning ) { + // Print any info messages in tags. + for( auto const& msg : assertionStats.infoMessages ) { + if( msg.type == ResultWas::Info && includeResults ) { + m_xml.scopedElement( "Info" ) + .writeText( msg.message ); + } else if ( msg.type == ResultWas::Warning ) { + m_xml.scopedElement( "Warning" ) + .writeText( msg.message ); + } + } + } + + // Drop out if result was successful but we're not printing them. + if( !includeResults && result.getResultType() != ResultWas::Warning ) + return true; + + // Print the expression if there is one. + if( result.hasExpression() ) { + m_xml.startElement( "Expression" ) + .writeAttribute( "success", result.succeeded() ) + .writeAttribute( "type", result.getTestMacroName() ); + + writeSourceInfo( result.getSourceInfo() ); + + m_xml.scopedElement( "Original" ) + .writeText( result.getExpression() ); + m_xml.scopedElement( "Expanded" ) + .writeText( result.getExpandedExpression() ); + } + + // And... Print a result applicable to each result type. + switch( result.getResultType() ) { + case ResultWas::ThrewException: + m_xml.startElement( "Exception" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); + m_xml.endElement(); + break; + case ResultWas::FatalErrorCondition: + m_xml.startElement( "FatalErrorCondition" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); + m_xml.endElement(); + break; + case ResultWas::Info: + m_xml.scopedElement( "Info" ) + .writeText( result.getMessage() ); + break; + case ResultWas::Warning: + // Warning will already have been written + break; + case ResultWas::ExplicitFailure: + m_xml.startElement( "Failure" ); + writeSourceInfo( result.getSourceInfo() ); + m_xml.writeText( result.getMessage() ); + m_xml.endElement(); + break; + default: + break; + } + + if( result.hasExpression() ) + m_xml.endElement(); + + return true; + } + + void XmlReporter::sectionEnded( SectionStats const& sectionStats ) { + StreamingReporterBase::sectionEnded( sectionStats ); + if( --m_sectionDepth > 0 ) { + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); + e.writeAttribute( "successes", sectionStats.assertions.passed ); + e.writeAttribute( "failures", sectionStats.assertions.failed ); + e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); + + m_xml.endElement(); + } + } + + void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { + StreamingReporterBase::testCaseEnded( testCaseStats ); + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); + e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); + + if( !testCaseStats.stdOut.empty() ) + m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false ); + if( !testCaseStats.stdErr.empty() ) + m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false ); + + m_xml.endElement(); + } + + void XmlReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { + StreamingReporterBase::testGroupEnded( testGroupStats ); + // TODO: Check testGroupStats.aborting and act accordingly. + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) + .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) { + StreamingReporterBase::testRunEnded( testRunStats ); + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testRunStats.totals.assertions.passed ) + .writeAttribute( "failures", testRunStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + CATCH_REGISTER_REPORTER( "xml", XmlReporter ) + +} // end namespace Catch + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif +// end catch_reporter_xml.cpp + +namespace Catch { + LeakDetector leakDetector; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// end catch_impl.hpp +#endif + +#ifdef CATCH_CONFIG_MAIN +// start catch_default_main.hpp + +#ifndef __OBJC__ + +#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) +// Standard C/C++ Win32 Unicode wmain entry point +extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) { +#else +// Standard C/C++ main entry point +int main (int argc, char * argv[]) { +#endif + + return Catch::Session().run( argc, argv ); +} + +#else // __OBJC__ + +// Objective-C entry point +int main (int argc, char * const argv[]) { +#if !CATCH_ARC_ENABLED + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; +#endif + + Catch::registerTestMethods(); + int result = Catch::Session().run( argc, (char**)argv ); + +#if !CATCH_ARC_ENABLED + [pool drain]; +#endif + + return result; +} + +#endif // __OBJC__ + +// end catch_default_main.hpp +#endif + +#if !defined(CATCH_CONFIG_IMPL_ONLY) + +#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED +# undef CLARA_CONFIG_MAIN +#endif + +#if !defined(CATCH_CONFIG_DISABLE) +////// +// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ +#ifdef CATCH_CONFIG_PREFIX_ALL + +#define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) +#define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) + +#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", __VA_ARGS__ ) +#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) +#endif// CATCH_CONFIG_DISABLE_MATCHERS +#define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) + +#define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) +#define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) + +#define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", __VA_ARGS__ ) +#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) + +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) + +#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) +#endif // CATCH_CONFIG_DISABLE_MATCHERS + +#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) +#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) +#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) ) + +#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) +#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) +#define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) +#define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) +#define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) +#define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) + +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() + +// "BDD-style" convenience wrappers +#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc ) +#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc ) +#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc ) +#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc ) +#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc ) + +// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required +#else + +#define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) +#define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) + +#define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ ) +#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) +#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) + +#define CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) +#define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) + +#define CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) +#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) + +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) + +#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) +#endif // CATCH_CONFIG_DISABLE_MATCHERS + +#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) +#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) +#define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) ) + +#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) +#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) +#define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) +#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) +#define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) +#define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() + +#endif + +#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) + +// "BDD-style" convenience wrappers +#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) + +#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc ) +#define WHEN( desc ) SECTION( std::string(" When: ") + desc ) +#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc ) +#define THEN( desc ) SECTION( std::string(" Then: ") + desc ) +#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc ) + +using Catch::Detail::Approx; + +#else +////// +// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ +#ifdef CATCH_CONFIG_PREFIX_ALL + +#define CATCH_REQUIRE( ... ) (void)(0) +#define CATCH_REQUIRE_FALSE( ... ) (void)(0) + +#define CATCH_REQUIRE_THROWS( ... ) (void)(0) +#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) +#endif// CATCH_CONFIG_DISABLE_MATCHERS +#define CATCH_REQUIRE_NOTHROW( ... ) (void)(0) + +#define CATCH_CHECK( ... ) (void)(0) +#define CATCH_CHECK_FALSE( ... ) (void)(0) +#define CATCH_CHECKED_IF( ... ) if (__VA_ARGS__) +#define CATCH_CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) +#define CATCH_CHECK_NOFAIL( ... ) (void)(0) + +#define CATCH_CHECK_THROWS( ... ) (void)(0) +#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) (void)(0) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define CATCH_CHECK_NOTHROW( ... ) (void)(0) + +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CATCH_CHECK_THAT( arg, matcher ) (void)(0) + +#define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0) +#endif // CATCH_CONFIG_DISABLE_MATCHERS + +#define CATCH_INFO( msg ) (void)(0) +#define CATCH_WARN( msg ) (void)(0) +#define CATCH_CAPTURE( msg ) (void)(0) + +#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define CATCH_METHOD_AS_TEST_CASE( method, ... ) +#define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0) +#define CATCH_SECTION( ... ) +#define CATCH_FAIL( ... ) (void)(0) +#define CATCH_FAIL_CHECK( ... ) (void)(0) +#define CATCH_SUCCEED( ... ) (void)(0) + +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) + +// "BDD-style" convenience wrappers +#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) +#define CATCH_GIVEN( desc ) +#define CATCH_WHEN( desc ) +#define CATCH_AND_WHEN( desc ) +#define CATCH_THEN( desc ) +#define CATCH_AND_THEN( desc ) + +// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required +#else + +#define REQUIRE( ... ) (void)(0) +#define REQUIRE_FALSE( ... ) (void)(0) + +#define REQUIRE_THROWS( ... ) (void)(0) +#define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) +#define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define REQUIRE_NOTHROW( ... ) (void)(0) + +#define CHECK( ... ) (void)(0) +#define CHECK_FALSE( ... ) (void)(0) +#define CHECKED_IF( ... ) if (__VA_ARGS__) +#define CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) +#define CHECK_NOFAIL( ... ) (void)(0) + +#define CHECK_THROWS( ... ) (void)(0) +#define CHECK_THROWS_AS( expr, exceptionType ) (void)(0) +#define CHECK_THROWS_WITH( expr, matcher ) (void)(0) +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) +#endif // CATCH_CONFIG_DISABLE_MATCHERS +#define CHECK_NOTHROW( ... ) (void)(0) + +#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) +#define CHECK_THAT( arg, matcher ) (void)(0) + +#define REQUIRE_THAT( arg, matcher ) (void)(0) +#endif // CATCH_CONFIG_DISABLE_MATCHERS + +#define INFO( msg ) (void)(0) +#define WARN( msg ) (void)(0) +#define CAPTURE( msg ) (void)(0) + +#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define METHOD_AS_TEST_CASE( method, ... ) +#define REGISTER_TEST_CASE( Function, ... ) (void)(0) +#define SECTION( ... ) +#define FAIL( ... ) (void)(0) +#define FAIL_CHECK( ... ) (void)(0) +#define SUCCEED( ... ) (void)(0) +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) + +#endif + +#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) + +// "BDD-style" convenience wrappers +#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) + +#define GIVEN( desc ) +#define WHEN( desc ) +#define AND_WHEN( desc ) +#define THEN( desc ) +#define AND_THEN( desc ) + +using Catch::Detail::Approx; + +#endif + +#endif // ! CATCH_CONFIG_IMPL_ONLY + +// start catch_reenable_warnings.h + + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(pop) +# else +# pragma clang diagnostic pop +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic pop +#endif + +// end catch_reenable_warnings.h +// end catch.hpp +#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED diff --git a/bls/contrib/relic/include/low/relic_bn_low.h b/bls/contrib/relic/include/low/relic_bn_low.h new file mode 100644 index 00000000..9f224ffb --- /dev/null +++ b/bls/contrib/relic/include/low/relic_bn_low.h @@ -0,0 +1,306 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @file + * + * Interface of the low-level multiple precision integer arithmetic module. + * + * All functions assume that the destination has enough capacity to store + * the result of the computation. + * + * @ingroup bn + */ + +#ifndef RLC_BN_LOW_H +#define RLC_BN_LOW_H + +/*============================================================================*/ +/* Constant definitions */ +/*============================================================================*/ + +#ifdef ASM + +#include "relic_conf.h" + +#if (BN_PRECI % WSIZE) > 0 +#define RLC_BN_DIGS (BN_PRECI/WSIZE + 1) +#else +#define RLC_BN_DIGS (BN_PRECI/WSIZE) +#endif + +#if BN_MAGNI == DOUBLE +#define RLC_BN_SIZE (2 * RLC_BN_DIGS + 2) +#elif BN_MAGNI == CARRY +#define RLC_BN_SIZE ((RLC_BN_DIGS + 1) +#elif BN_MAGNI == SINGLE +#define RLC_BN_SIZE (RLC_BN_DIGS) +#endif + +#else + +#include "relic_types.h" + +/*============================================================================*/ +/* Function prototypes */ +/*============================================================================*/ + +/** + * Adds a digit to a digit vector. Computes c = a + digit. + * + * @param[out] c - the result. + * @param[in] a - the first digit vector to add. + * @param[in] digit - the digit to add. + * @param[in] size - the number of digits in the first operand. + * @return the carry of the last digit addition. + */ +dig_t bn_add1_low(dig_t *c, const dig_t *a, const dig_t digit, const int size); + +/** + * Adds two digit vectors of the same size. Computes c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the first digit vector to add. + * @param[in] b - the second digit vector to add. + * @param[in] size - the number of digits to add. + * @return the carry of the last digit addition. + */ +dig_t bn_addn_low(dig_t *c, const dig_t *a, const dig_t *b, int size); + +/** + * Subtracts a digit from a digit vector. Computes c = a - digit. + * + * @param[out] c - the result. + * @param[in] a - the digit vector. + * @param[in] digit - the digit to subtract. + * @param[in] size - the number of digits in a. + * @return the carry of the last digit subtraction. + */ +dig_t bn_sub1_low(dig_t *c, const dig_t *a, dig_t digit, int size); + +/** + * Subtracts a digit vector from another digit vector. Computes c = a - b. + * + * @param[out] c - the result. + * @param[in] a - the digit vector. + * @param[in] b - the digit vector to subtract. + * @param[in] size - the number of digits to subtract. + * @return the carry of the last digit subtraction. + */ +dig_t bn_subn_low(dig_t *c, const dig_t *a, const dig_t *b, int size); + +/** + * Compares two digits. + * + * @param[in] a - the first digit to compare. + * @param[in] b - the second digit to compare. + * @return BN_LT if a < b, BN_EQ if a == b and BN_GT if a > b. + */ +int bn_cmp1_low(dig_t a, dig_t b); + +/** + * Compares two digit vectors of the same size. + * + * @param[in] a - the first digit vector to compare. + * @param[in] b - the second digit vector to compare. + * @param[in] size - the number of digits to compare. + * @return BN_LT if a < b, BN_EQ if a == b and BN_GT if a > b. + */ +int bn_cmpn_low(const dig_t *a, const dig_t *b, int size); + +/** + * Shifts a digit vector to the left by 1 bit. Computes c = a << 1. + * + * @param[out] c - the result + * @param[in] a - the digit vector to shift. + * @param[in] size - the number of digits to shift. + * @return the carry of the last digit shift. + */ +dig_t bn_lsh1_low(dig_t *c, const dig_t *a, int size); + +/** + * Shifts a digit vector to the left by an amount smaller than a digit. Computes + * c = a << bits. + * + * @param[out] c - the result + * @param[in] a - the digit vector to shift. + * @param[in] size - the number of digits to shift. + * @param[in] bits - the shift amount. + * @return the carry of the last digit shift. + */ +dig_t bn_lshb_low(dig_t *c, const dig_t *a, int size, int bits); + +/** + * Shifts a digit vector to the left by some digits. + * Computes c = a << (digits * RLC_DIG). + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer to shift. + * @param[in] size - the number of digits to shift. + * @param[in] digits - the shift amount. + */ +void bn_lshd_low(dig_t *c, const dig_t *a, int size, int digits); + +/** + * Shifts a digit vector to the right by 1 bit. Computes c = a >> 1. + * + * @param[out] c - the result + * @param[in] a - the digit vector to shift. + * @param[in] size - the number of digits to shift. + * @return the carry of the last digit shift. + */ +dig_t bn_rsh1_low(dig_t *c, const dig_t *a, int size); + +/** + * Shifts a digit vector to the right by an amount smaller than a digit. + * Computes c = a >> bits. + * + * @param[out] c - the result + * @param[in] a - the digit vector to shift. + * @param[in] size - the number of digits to shift. + * @param[in] bits - the shift amount. + * @return the carry of the last digit shift. + */ +dig_t bn_rshb_low(dig_t *c, const dig_t *a, int size, int bits); + +/** + * Shifts a digit vector to the right by some digits. + * Computes c = a >> (digits * RLC_DIG). + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer to shift. + * @param[in] size - the number of digits to shift. + * @param[in] digits - the shift amount. + */ +void bn_rshd_low(dig_t *c, const dig_t *a, int size, int digits); + +/** + * Multiplies a digit vector by a digit and adds this result to another digit + * vector. Computes c = c + a * digit. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to multiply. + * @param[in] digit - the digit to multiply. + * @param[in] size - the number of digits to multiply. + * @return the carry of the addition. + */ +dig_t bn_mula_low(dig_t *c, const dig_t *a, dig_t digit, int size); + +/** + * Multiplies a digit vector by a digit and stores this result in another digit + * vector. Computes c = a * digit. + * + * @param[out] c - the result. + * @param[in] a - the first digit vector to multiply. + * @param[in] digit - the digit to multiply. + * @param[in] size - the number of digits to multiply. + * @return the most significant digit. + */ +dig_t bn_mul1_low(dig_t *c, const dig_t *a, dig_t digit, int size); + +/** + * Multiplies two digit vectors of the same size. Computes c = a * b. + * + * @param[out] c - the result. + * @param[in] a - the first digit vector to multiply. + * @param[in] b - the second digit vector to multiply. + * @param[in] size - the number of digits to multiply. + */ +void bn_muln_low(dig_t *c, const dig_t *a, const dig_t *b, int size); + +/** + * Multiplies two digit vectors of different sizes, with sa > sb. Computes + * c = a * b. This function outputs as result only the digits between low and + * high, inclusive, with high > sa and low < sb. + * + * @param[out] c - the result. + * @param[in] a - the first digit vector to multiply. + * @param[in] b - the second digit vector to multiply. + * @param[in] sa - the number of digits in the first operand. + * @param[in] sb - the number of digits in the second operand. + * @param[in] low - the first digit to compute. + * @param[in] high - the last digit to compute. + */ +void bn_muld_low(dig_t *c, const dig_t *a, int sa, const dig_t *b, int sb, + int low, int high); + +/** + * Squares a digit vector and adds this result to another digit vector. + * Computes c = c + a * a. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to square. + * @param[in] size - the number of digitss to square. + */ +void bn_sqra_low(dig_t *c, const dig_t *a, int size); + +/** + * Squares a digit vector. Computes c = a * a. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to square. + * @param[in] size - the number of digits to square. + */ +void bn_sqrn_low(dig_t *c, const dig_t *a, int size); + +/** + * Divides a digit vector by another digit vector. Computes c = floor(a / b) and + * d = a mod b. The dividend and divisor may be destroyed inside the function. + * + * @param[out] c - the quotient. + * @param[out] d - the remainder. + * @param[in,out] a - the dividend. + * @param[in] sa - the size of the dividend. + * @param[in,out] b - the divisor. + * @param[in] sb - the size of the divisor. + */ +void bn_divn_low(dig_t *c, dig_t *d, dig_t *a, int sa, dig_t *b, int sb); + +/** + * Divides a digit vector by a digit. Computes c = floor(a / digit) and + * d = a mod digit. + * + * @param[out] c - the quotient. + * @param[out] d - the remainder. + * @param[in] a - the dividend. + * @param[in] size - the size of the dividend. + * @param[in] digit - the divisor. + */ +void bn_div1_low(dig_t *c, dig_t *d, const dig_t *a, int size, dig_t digit); + +/** + * Reduces a digit vector modulo m by Montgomery's algorithm. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to reduce. + * @param[in] sa - the number of digits to reduce + * @param[in] m - the modulus. + * @param[in] sm - the size of the modulus. + * @param[in] u - the reciprocal of the modulus. + */ +void bn_modn_low(dig_t *c, const dig_t *a, int sa, const dig_t *m, int sm, + dig_t u); + +#endif /* !ASM */ + +#endif /* !RLC_BN_LOW_H */ diff --git a/bls/contrib/relic/include/low/relic_dv_low.h b/bls/contrib/relic/include/low/relic_dv_low.h new file mode 100644 index 00000000..4f25d5e7 --- /dev/null +++ b/bls/contrib/relic/include/low/relic_dv_low.h @@ -0,0 +1,82 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @file + * + * Interface of the low-level digit vector module. + * + * @ingroup dv + */ + +#ifndef RELIC_DV_LOW_H +#define RELIC_DV_LOW_H + +#include "relic_bn_low.h" +#include "relic_fb_low.h" +#include "relic_fp_low.h" + +/*============================================================================*/ +/* Constant definitions */ +/*============================================================================*/ + +#ifdef ASM + +/** + * Size in digits of a squaring result in a prime field. + */ +#ifdef WITH_FP +#define DV_FP (2 * FP_DIGS + 1) +#else +#define DV_FP (0) +#endif + +/** + * Size in digits of a squaring result in a binary field. + */ +#ifdef WITH_FB +#define DV_FB (2 * FB_DIGS) +#else +#define DV_FB (0) +#endif + +/** + * Size in digits of a temporary vector. + * + * A temporary vector has enough size to store a multiplication/squaring/cubing + * result in any finite field. + */ +#if DV_FB > DV_FP +#define RLC_DV_DIGS DV_FB +#else +#define RLC_DV_DIGS DV_FP +#endif + +#if RLC_BN_SIZE > DV_DIGS +#undef RLC_DV_DIGS +#define RLC_DV_DIGS RLC_BN_SIZE +#endif + +#endif /* ASM */ + +#endif /* !RELIC_DV_LOW_H */ diff --git a/bls/contrib/relic/include/low/relic_fb_low.h b/bls/contrib/relic/include/low/relic_fb_low.h new file mode 100644 index 00000000..9b7cb9d7 --- /dev/null +++ b/bls/contrib/relic/include/low/relic_fb_low.h @@ -0,0 +1,290 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @file + * + * Interface of the low-level binary field arithmetic module. + * + * All functions assume a configured polynomial basis f(z) and that the + * destination has enough capacity to store the result of the computation. + * + * @ingroup fb + */ + +#ifndef RLC_FB_LOW_H +#define RLC_FB_LOW_H + +/*============================================================================*/ +/* Constant definitions */ +/*============================================================================*/ + +#ifdef ASM + +#include "relic_conf.h" + +#undef RLC_FB_DIGS +#if (FB_POLYN % WSIZE) > 0 +#define RLC_FB_DIGS (FB_POLYN/WSIZE + 1) +#else +#define RLC_FB_DIGS (FB_POLYN/WSIZE) +#endif + +#else + +#include "relic_types.h" + +/*============================================================================*/ +/* Function prototypes */ +/*============================================================================*/ + +/** + * Adds a digit vector and a digit. Computes c = a + digit. + * + * @param[out] c - the result. + * @param[in] a - the first digit vector to add. + * @param[in] digit - the digit to add. + */ +void fb_add1_low(dig_t *c, const dig_t *a, dig_t digit); + +/** + * Adds two digit vectors of the same size. Computes c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the first digit vector to add. + * @param[in] b - the second digit vector to add. + */ +void fb_addn_low(dig_t *c, const dig_t *a, const dig_t *b); + +/** + * Adds two digit vectors of the same size, with this size different than the + * standard precision and specified in the last parameter. Computes c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the first digit vector to add. + * @param[in] b - the second digit vector to add. + * @param[in] size - the number of digits to add. + */ +void fb_addd_low(dig_t *c, const dig_t *a, const dig_t *b, int size); + +/** + * Shifts a digit vector to the left by 1 bit. Computes c = a * z. + * + * @param[out] c - the result + * @param[in] a - the digit vector to shift. + * @return the carry of the last digit shift. + */ +dig_t fb_lsh1_low(dig_t *c, const dig_t *a); + +/** + * Shifts a digit vector to the left by an amount smaller than a digit. + * The shift amount must be bigger than 0 and smaller than RLC_DIG. Computes + * c = a * z^bits. + * + * @param[out] c - the result + * @param[in] a - the digit vector to shift. + * @param[in] bits - the shift ammount. + * @return the carry of the last digit shift. + */ +dig_t fb_lshb_low(dig_t *c, const dig_t *a, int bits); + +/** + * Shifts a digit vector to the left by some digits. + * Computes c = a * z^(digits * RLC_DIG). + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer to shift. + * @param[in] digits - the shift amount. + */ +void fb_lshd_low(dig_t *c, const dig_t *a, int digits); + +/** + * Shifts a digit vector to the right by 1 bit. Computes c = a / z. + * + * @param[out] c - the result + * @param[in] a - the digit vector to shift. + * @return the carry of the last digit shift. + */ +dig_t fb_rsh1_low(dig_t *c, const dig_t *a); + +/** + * Shifts a digit vector to the right by an amount smaller than a digit. + * The shift amount must be bigger than 0 and smaller than RLC_DIG. + * Computes c = a / (z^bits). + * + * @param[out] c - the result + * @param[in] a - the digit vector to shift. + * @param[in] bits - the shift amount. + * @return the carry of the last digit shift. + */ +dig_t fb_rshb_low(dig_t *c, const dig_t *a, int bits); + +/** + * Shifts a digit vector to the right by some digits. + * Computes c = a / z^(digits * RLC_DIG). + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer to shift. + * @param[in] digits - the shift amount. + */ +void fb_rshd_low(dig_t *c, const dig_t *a, int digits); + +/** + * Adds a left-shifted digit vector to another digit vector. + * The shift amount must be shorter than the digit size. + * Computes c = c + (a * z^bits). + * + * @param[out] c - the result. + * @param[in] a - the digit vector to shift and add. + * @param[in] size - the number of digits to add. + * @param[in] bits - the shift amount. + * @return the carry of the last shift. + */ +dig_t fb_lsha_low(dig_t *c, const dig_t *a, int bits, int size); + +/** + * Multiplies a digit vector by a digit. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to multiply. + * @param[in] digit - the digit to multiply. + */ +void fb_mul1_low(dig_t *c, const dig_t *a, dig_t digit); + +/** + * Multiplies two digit vectors of the same size. + * + * @param[out] c - the result. + * @param[in] a - the first digit vector to multiply. + * @param[in] b - the second digit vector to multiply. + */ +void fb_muln_low(dig_t *c, const dig_t *a, const dig_t *b); + +/** + * Multiplies two digit vectors of the same size but smaller than the standard + * precision. + * + * @param[out] c - the result. + * @param[in] a - the first digit vector to multiply. + * @param[in] b - the second digit vector to multiply. + * @param[in] size - the size of the digit vectors. + */ +void fb_muld_low(dig_t *c, const dig_t *a, const dig_t *b, int size); + +/** + * Multiplies two digit vectors of the same size with embedded modular + * reduction. + * + * @param[out] c - the result. + * @param[in] a - the first digit vector to multiply. + * @param[in] b - the second digit vector to multiply. + */ +void fb_mulm_low(dig_t *c, const dig_t *a, const dig_t *b); + +/** + * Squares a digit vector using bit manipulation. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to square. + */ +void fb_sqrn_low(dig_t *c, const dig_t *a); + +/** + * Squares a digit vector using a lookup table. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to square. + */ +void fb_sqrl_low(dig_t *c, const dig_t *a); + +/** + * Squares a digit vector with embedded modular reduction. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to square. + */ +void fb_sqrm_low(dig_t *c, const dig_t *a); + +/** + * Exponentiates consecutively a digit vector to a fixed power 2^k/2^-k given a + * precomputed table. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to square. + * @param[in] t - the + */ +void fb_itrn_low(dig_t *c, const dig_t *a, dig_t *t); + +/** + * Extracts the square root of a digit vector. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to extract the square root. + */ +void fb_srtn_low(dig_t *c, const dig_t *a); + +/** + * Solves a quadratic equation for c^2 + c = a. + * + * @param[out] c - the result. + * @param[in] a - the digit vector. + */ +void fb_slvn_low(dig_t *c, const dig_t *a); + +/** + * Computes the trace of a digit vector. + * + * @param[in] a - the digit vector. + * @return the trace of the argument. + */ +dig_t fb_trcn_low(const dig_t *a); + +/** + * Reduces a digit vector modulo the configured irreducible polynomial. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to reduce. + */ +void fb_rdcn_low(dig_t *c, dig_t *a); + +/** + * Reduces the most significant bits of a digit vector modulo the configured + * irreducible polynomial. The maximum number of bits to be reduced is equal + * to the size of the digit. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to reduce. + */ +void fb_rdc1_low(dig_t *c, dig_t *a); + +/** + * Inverts a digit vector modulo the configured irreducible polynomial. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to invert. + */ +void fb_invn_low(dig_t *c, const dig_t *a); + +#endif /* !ASM */ + +#endif /* !RLC_FB_LOW_H */ diff --git a/bls/contrib/relic/include/low/relic_fp_low.h b/bls/contrib/relic/include/low/relic_fp_low.h new file mode 100644 index 00000000..0b12cd06 --- /dev/null +++ b/bls/contrib/relic/include/low/relic_fp_low.h @@ -0,0 +1,346 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @file + * + * Interface of the low-level prime field arithmetic module. + * + * @ingroup fp + */ + +#ifndef RLC_FP_LOW_H +#define RLC_FP_LOW_H + +/*============================================================================*/ +/* Constant definitions */ +/*============================================================================*/ + +#ifdef ASM + +#include "relic_conf.h" +#include "relic_label.h" + +#if (FP_PRIME % WSIZE) > 0 +#define RLC_FP_DIGS (FP_PRIME/WSIZE + 1) +#else +#define RLC_FP_DIGS (FP_PRIME/WSIZE) +#endif +#else + +/*============================================================================*/ +/* Function prototypes */ +/*============================================================================*/ + +/** + * Adds a digit vector and a digit. Computes c = a + digit. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to add. + * @param[in] digit - the digit to add. + * @return the carry of the last digit addition. + */ +dig_t fp_add1_low(dig_t *c, const dig_t *a, dig_t digit); + +/** + * Adds two digit vectors of the same size. Computes c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the first digit vector to add. + * @param[in] b - the second digit vector to add. + * @return the carry of the last digit addition. + */ +dig_t fp_addn_low(dig_t *c, const dig_t *a, const dig_t *b); + +/** + * Adds two digit vectors of the same size with integrated modular reduction. + * Computes c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the first digit vector to add. + * @param[in] b - the second digit vector to add. + */ +void fp_addm_low(dig_t *c, const dig_t *a, const dig_t *b); + +/** + * Adds two double-length digit vectors. Computes c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the first digit vector to add. + * @param[in] b - the second digit vector to add. + * @return the carry of the last digit addition. + */ +dig_t fp_addd_low(dig_t *c, const dig_t *a, const dig_t *b); + +/** + * Adds two double-length digit vectors and reduces modulo p * R. Computes + * c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the first digit vector to add. + * @param[in] b - the second digit vector to add. + */ +void fp_addc_low(dig_t *c, const dig_t *a, const dig_t *b); + +/** + * Subtracts a digit from a digit vector. Computes c = a - digit. + * + * @param[out] c - the result. + * @param[in] a - the digit vector. + * @param[in] digit - the digit to subtract. + * @return the carry of the last digit subtraction. + */ +dig_t fp_sub1_low(dig_t *c, const dig_t *a, dig_t digit); + +/** + * Subtracts a digit vector from another digit vector. Computes c = a - b. + * + * @param[out] c - the result. + * @param[in] a - the digit vector. + * @param[in] b - the digit vector to subtract. + * @return the carry of the last digit subtraction. + */ +dig_t fp_subn_low(dig_t *c, const dig_t *a, const dig_t *b); + +/** + * Subtracts two digit vectors of the same size with integrated modular + * reduction. + * Computes c = a - b. + * + * @param[out] c - the result. + * @param[in] a - the first digit vector to add. + * @param[in] b - the second digit vector to add. + */ +void fp_subm_low(dig_t *c, const dig_t *a, const dig_t *b); + +/** + * Subtracts a double-length digit vector from another digit vector. + * Computes c = a - b. + * + * @param[out] c - the result. + * @param[in] a - the first digit vector to add. + * @param[in] b - the second digit vector to add. + * @return the carry of the last digit subtraction. + */ +dig_t fp_subd_low(dig_t *c, const dig_t *a, const dig_t *b); + +/** + * Subtracts a double-length digit vector from another digit vector. + * Computes c = a - b. This version of the function should handle possible + * carries by adding p * R. + * + * @param[out] c - the result. + * @param[in] a - the first digit vector to add. + * @param[in] b - the second digit vector to add. + */ +void fp_subc_low(dig_t *c, const dig_t *a, const dig_t *b); + +/** + * Negates a digit vector. Computes c = -a. + * + * @param[out] c - the result. + * @param[out] a - the prime field element to negate. + */ +void fp_negm_low(dig_t *c, const dig_t *a); + +/** + * Doubles a digit vector. Computes c = a + a. + * + * @param[out] c - the result. + * @param[in] a - the digit vector. + * @return the carry of the last digit doubling. + */ +dig_t fp_dbln_low(dig_t *c, const dig_t *a); + +/** + * Doubles a digit vector with integrated modular reduction. + * Computes c = a + a. + * + * @param[out] c - the result. + * @param[in] a - the first digit vector to add. + */ +void fp_dblm_low(dig_t *c, const dig_t *a); + +/** + * Halves a digit vector with integrated modular reduction. + * Computes c = a/2. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to halve. + */ +void fp_hlvm_low(dig_t *c, const dig_t *a); + +/** + * Halves a double-precision digit vector. Computes c = a/2. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to halve. + */ +void fp_hlvd_low(dig_t *c, const dig_t *a); + +/** + * Shifts a digit vector to the left by 1 bits. Computes c = a << 1. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to shift. + * @return the carry of the last digit shift. + */ +dig_t fp_lsh1_low(dig_t *c, const dig_t *a); + +/** + * Shifts a digit vector to the left by an amount smaller than a digit. Computes + * c = a << bits. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to shift. + * @param[in] bits - the shift amount. + * @return the carry of the last digit shift. + */ +dig_t fp_lshb_low(dig_t *c, const dig_t *a, int bits); + +/** + * Shifts a digit vector to the left by some digits. + * Computes c = a << (digits * RLC_DIG). + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer to shift. + * @param[in] digits - the shift ammount. + */ +void fp_lshd_low(dig_t *c, const dig_t *a, int digits); + +/** + * Shifts a digit vector to the right by 1 bit. Computes c = a >> 1. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to shift. + * @return the carry of the last digit shift. + */ +dig_t fp_rsh1_low(dig_t *c, const dig_t *a); + +/** + * Shifts a digit vector to the right by an amount smaller than a digit. + * Computes c = a >> bits. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to shift. + * @param[in] bits - the shift amount. + * @return the carry of the last digit shift. + */ +dig_t fp_rshb_low(dig_t *c, const dig_t *a, int bits); + +/** + * Shifts a digit vector to the right by some digits. + * Computes c = a >> (digits * RLC_DIG). + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer to shift. + * @param[in] digits - the shift amount. + */ +void fp_rshd_low(dig_t *c, const dig_t *a, int digits); + +/** + * Multiplies a digit vector by a digit and adds this result to another digit + * vector. Computes c = c + a * digit. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to multiply. + * @param[in] digit - the digit to multiply. + * @return the carry of the addition. + */ +dig_t fp_mula_low(dig_t *c, const dig_t *a, dig_t digit); + +/** + * Multiplies a digit vector by a digit and stores this result in another digit + * vector. Computes c = a * digit. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to multiply. + * @param[in] digit - the digit to multiply. + * @return the most significant digit. + */ +dig_t fp_mul1_low(dig_t *c, const dig_t *a, dig_t digit); + +/** + * Multiplies two digit vectors of the same size. Computes c = a * b. + * + * @param[out] c - the result. + * @param[in] a - the first digit vector to multiply. + * @param[in] b - the second digit vector to multiply. + */ +void fp_muln_low(dig_t *c, const dig_t *a, const dig_t *b); + +/** + * Multiplies two digit vectors of the same size with embedded modular + * reduction. Computes c = (a * b) mod p. + * + * @param[out] c - the result. + * @param[in] a - the first digit vector to multiply. + * @param[in] b - the second digit vector to multiply. + */ +void fp_mulm_low(dig_t *c, const dig_t *a, const dig_t *b); + +/** + * Squares a digit vector. Computes c = a * a. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to square. + */ +void fp_sqrn_low(dig_t *c, const dig_t *a); + +/** + * Squares a digit vector with embedded modular reduction. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to square. + */ +void fp_sqrm_low(dig_t *c, const dig_t *a); + +/** + * Reduces a digit vector modulo m represented in special form. + * Computes c = a mod m. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to reduce. + * @param[in] m - the modulus. + */ +void fp_rdcs_low(dig_t *c, const dig_t *a, const dig_t *m); + +/** + * Reduces a digit vector modulo the configured prime p. Computes c = a mod p. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to reduce. + */ +void fp_rdcn_low(dig_t *c, dig_t *a); + +/** + * Inverts a digit vector modulo the configured prime. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to invert. + */ +void fp_invm_low(dig_t *c, const dig_t *a); + +#endif /* ASM */ + +#endif /* !RLC_FP_LOW_H */ diff --git a/bls/contrib/relic/include/low/relic_fpx_low.h b/bls/contrib/relic/include/low/relic_fpx_low.h new file mode 100644 index 00000000..981818e1 --- /dev/null +++ b/bls/contrib/relic/include/low/relic_fpx_low.h @@ -0,0 +1,390 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @file + * + * Interface of the low-level prime extension field arithmetic module. + * + * @ingroup fpx + */ + +#ifndef RLC_FPX_LOW_H +#define RLC_FPX_LOW_H + +#include "relic_fpx.h" + +/*============================================================================*/ +/* Function prototypes */ +/*============================================================================*/ + +/** + * Adds two quadratic extension field elements of the same size. + * Computes c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the first field element to add. + * @param[in] b - the second field element to add. + */ +void fp2_addn_low(fp2_t c, fp2_t a, fp2_t b); + +/** + * Adds two quadratic extension field elements of the same size with integrated + * modular reduction. Computes c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the first field element to add. + * @param[in] b - the second field element to add. + */ +void fp2_addm_low(fp2_t c, fp2_t a, fp2_t b); + +/** + * Adds two double-precision quadratic extension field elements of the same + * size. Computes c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the first field element to add. + * @param[in] b - the second field element to add. + */ +void fp2_addd_low(dv2_t c, dv2_t a, dv2_t b); + +/** + * Adds two double-precision quadratic extension field elements of the same size + * and corrects the result by conditionally adding 2^(RLC_FP_DIGS * WSIZE) * p. + * Computes c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the first field element to add. + * @param[in] b - the second field element to add. + */ +void fp2_addc_low(dv2_t c, dv2_t a, dv2_t b); + +/** + * Subtracts a quadratic extension field element from another of the same size. + * Computes c = a - b. + * + * @param[out] c - the result. + * @param[in] a - the first field element. + * @param[in] b - the field element to subtract. + */ +void fp2_subn_low(fp2_t c, fp2_t a, fp2_t b); + +/** + * Subtracts a quadratic extension field element from another of the same size + * with integrated modular reduction. Computes c = a - b. + * + * @param[out] c - the result. + * @param[in] a - the first field element. + * @param[in] b - the field element to subtract. + */ +void fp2_subm_low(fp2_t c, fp2_t a, fp2_t b); + +/** + * Subtracts a double-precision quadratic extension field element from another + * of the same size. Computes c = a - b. + * + * @param[out] c - the result. + * @param[in] a - the first field element to add. + * @param[in] b - the second field element to add. + */ +void fp2_subd_low(dv2_t c, dv2_t a, dv2_t b); + +/** + * Subtracts a double-precision quadratic extension field element from another + * of the same size and corrects the result by conditionally adding + * 2^(RLC_FP_DIGS * WSIZE) * p. Computes c = a - b. + * + * @param[out] c - the result. + * @param[in] a - the first field element to add. + * @param[in] b - the second field element to add. + */ +void fp2_subc_low(dv2_t c, dv2_t a, dv2_t b); + +/** + * Doubles a quadratic extension field element. Computes c = a + a. + * + * @param[out] c - the result. + * @param[in] a - the first field element to multiply. + */ +void fp2_dbln_low(fp2_t c, fp2_t a); + +/** + * Doubles a quadratic extension field element with integrated modular + * reduction. Computes c = a + a. + * + * @param[out] c - the result. + * @param[in] a - the field element to double. + */ +void fp2_dblm_low(fp2_t c, fp2_t a); + +/** + * Multiplies a quadratic extension field element by the quadratic + * non-residue. Computes c = a * E. + * + * @param[out] c - the result. + * @param[in] a - the field element to multiply. + */ +void fp2_norm_low(fp2_t c, fp2_t a); + +/** + * Multiplies a double-precision quadratic extension field element by the + * quadratic non-residue, reducing only half of the result. Computes + * c = a * E. + * + * @param[out] c - the result. + * @param[in] a - the field element to multiply. + */ +void fp2_norh_low(dv2_t c, dv2_t a); + +/** + * Multiplies a double-precision quadratic extension field element by the + * quadratic non-residue. Computes c = a * E. + * + * @param[out] c - the result. + * @param[in] a - the field element to multiply. + */ +void fp2_nord_low(dv2_t c, dv2_t a); + +/** + * Multiplies two quadratic extension field elements of the same size. + * Computes c = a * b. + * + * @param[out] c - the result. + * @param[in] a - the first field element to multiply. + * @param[in] b - the second field element to multiply. + */ +void fp2_muln_low(dv2_t c, fp2_t a, fp2_t b); + +/** + * Multiplies two quadratic extension elements of the same size and corrects + * the result by adding (2^(RLC_FP_DIGS * WSIZE) * p)/4. This function should + * be used when the RLC_FP_ROOM optimization is detected. Computes c = a * b. + * + * @param[out] c - the result. + * @param[in] a - the first field element to multiply. + * @param[in] b - the second field element to multiply. + */ +void fp2_mulc_low(dv2_t c, fp2_t a, fp2_t b); + +/** + * Multiplies two quadratic extension field elements of the same size with + * embedded modular reduction. Computes c = (a * b) mod p. + * + * @param[out] c - the result. + * @param[in] a - the first field element to multiply. + * @param[in] b - the second field element to multiply. + */ +void fp2_mulm_low(fp2_t c, fp2_t a, fp2_t b); + +/** + * Squares a quadratic extension element. Computes c = a * a. + * + * @param[out] c - the result. + * @param[in] a - the field element to square. + */ +void fp2_sqrn_low(dv2_t c, fp2_t a); + +/** + * Squares a quadratic extension field element with integrated modular + * reduction. Computes c = (a * a) mod p. + * + * @param[out] c - the result. + * @param[in] a - the field element to square. + */ +void fp2_sqrm_low(fp2_t c, fp2_t a); + +/** + * Reduces a quadratic extension element modulo the configured prime p. + * Computes c = a mod p. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to reduce. + */ +void fp2_rdcn_low(fp2_t c, dv2_t a); + +/** + * Adds two cubic extension field elements of the same size. + * Computes c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the first field element to add. + * @param[in] b - the second field element to add. + */ +void fp3_addn_low(fp3_t c, fp3_t a, fp3_t b); + +/** + * Adds two cubic extension field elements of the same size with integrated + * modular reduction. Computes c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the first field element to add. + * @param[in] b - the second field element to add. + */ +void fp3_addm_low(fp3_t c, fp3_t a, fp3_t b); + +/** + * Adds two double-precision cubic extension field elements of the same + * size. Computes c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the first field element to add. + * @param[in] b - the second field element to add. + */ +void fp3_addd_low(dv3_t c, dv3_t a, dv3_t b); + +/** + * Adds two double-precision cubic extension field elements of the same size + * and corrects the result by conditionally adding 3^(RLC_FP_DIGS * WSIZE) * p. + * Computes c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the first field element to add. + * @param[in] b - the second field element to add. + */ +void fp3_addc_low(dv3_t c, dv3_t a, dv3_t b); + +/** + * Subtracts a cubic extension field element from another of the same size. + * Computes c = a - b. + * + * @param[out] c - the result. + * @param[in] a - the first field element. + * @param[in] b - the field element to subtract. + */ +void fp3_subn_low(fp3_t c, fp3_t a, fp3_t b); + +/** + * Subtracts a cubic extension field element from another of the same size + * with integrated modular reduction. Computes c = a - b. + * + * @param[out] c - the result. + * @param[in] a - the first field element. + * @param[in] b - the field element to subtract. + */ +void fp3_subm_low(fp3_t c, fp3_t a, fp3_t b); + +/** + * Subtracts a double-precision cubic extension field element from another + * of the same size. Computes c = a - b. + * + * @param[out] c - the result. + * @param[in] a - the first field element to add. + * @param[in] b - the second field element to add. + */ +void fp3_subd_low(dv3_t c, dv3_t a, dv3_t b); + +/** + * Subtracts a double-precision cubic extension field element from another + * of the same size and corrects the result by conditionally adding + * 3^(RLC_FP_DIGS * WSIZE) * p. Computes c = a - b. + * + * @param[out] c - the result. + * @param[in] a - the first field element to add. + * @param[in] b - the second field element to add. + */ +void fp3_subc_low(dv3_t c, dv3_t a, dv3_t b); + +/** + * Doubles a cubic extension field element. Computes c = a + a. + * + * @param[out] c - the result. + * @param[in] a - the first field element to multiply. + */ +void fp3_dbln_low(fp3_t c, fp3_t a); + +/** + * Doubles a cubic extension field element with integrated modular + * reduction. Computes c = a + a. + * + * @param[out] c - the result. + * @param[in] a - the field element to double. + */ +void fp3_dblm_low(fp3_t c, fp3_t a); + +/** + * Multiplies a double-precision cubic extension field element by the + * cubic non-residue. Computes c = a * E. + * + * @param[out] c - the result. + * @param[in] a - the field element to multiply. + */ +void fp3_nord_low(dv3_t c, dv3_t a); + +/** + * Multiplies two cubic extension field elements of the same size. + * Computes c = a * b. + * + * @param[out] c - the result. + * @param[in] a - the first field element to multiply. + * @param[in] b - the second field element to multiply. + */ +void fp3_muln_low(dv3_t c, fp3_t a, fp3_t b); + +/** + * Multiplies two cubic extension elements of the same size and corrects + * the result by adding (2^(RLC_FP_DIGS * WSIZE) * p)/4. This function should + * be used when the RLC_FP_ROOM optimization is detected. Computes c = a * b. + * + * @param[out] c - the result. + * @param[in] a - the first field element to multiply. + * @param[in] b - the second field element to multiply. + */ +void fp3_mulc_low(dv3_t c, fp3_t a, fp3_t b); + +/** + * Multiplies two cubic extension field elements of the same size with + * embedded modular reduction. Computes c = (a * b) mod p. + * + * @param[out] c - the result. + * @param[in] a - the first field element to multiply. + * @param[in] b - the second field element to multiply. + */ +void fp3_mulm_low(fp3_t c, fp3_t a, fp3_t b); + +/** + * Squares a cubic extension element. Computes c = a * a. + * + * @param[out] c - the result. + * @param[in] a - the field element to square. + */ +void fp3_sqrn_low(dv2_t c, fp3_t a); + +/** + * Squares a cubic extension field element with integrated modular + * reduction. Computes c = (a * a) mod p. + * + * @param[out] c - the result. + * @param[in] a - the field element to square. + */ +void fp3_sqrm_low(fp3_t c, fp3_t a); + +/** + * Reduces a cubic extension element modulo the configured prime p. + * Computes c = a mod p. + * + * @param[out] c - the result. + * @param[in] a - the digit vector to reduce. + */ +void fp3_rdcn_low(fp3_t c, dv3_t a); + +#endif /* !RLC_FPX_LOW_H */ diff --git a/bls/contrib/relic/include/relic.h b/bls/contrib/relic/include/relic.h new file mode 100644 index 00000000..ca362962 --- /dev/null +++ b/bls/contrib/relic/include/relic.h @@ -0,0 +1,112 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @mainpage + * + * RELIC is a modern cryptographic meta-toolkit with emphasis on efficiency and + * flexibility. RELIC can be used to build efficient and usable cryptographic + * toolkits tailored for specific security levels and algorithmic choices. + * + * @section goals_sec Goals + * + * RELIC is an ongoing project and features will be added on demand. + * The focus is to provide: + * + *
    + *
  • Ease of portability and inclusion of architecture-dependent code + *
  • Simple experimentation with alternative implementations + *
  • Tests and benchmarks for every implemented function + *
  • Flexible configuration + *
  • Maximum efficiency + *
+ * + * @section algo_sec Algorithms + * + * RELIC implements to date: + * + *
    + *
  • Multiple-precision integer arithmetic + *
  • Prime and Binary field arithmetic + *
  • Elliptic curves over prime and binary fields (NIST curves and + * pairing-friendly curves) + *
  • Bilinear maps and related extension fields + *
  • Cryptographic protocols + *
+ * + * @section lic_sec Licensing + * + * RELIC is dual-licensed under Apache 2.0 and LGPL 2.1-or-above to encourage + * collaboration with other research groups and contributions from the industry. + * You can choose between one of them. + * + * @section disc_sec Disclaimer + * + * RELIC is at most alpha-quality software. Implementations may not be correct + * or secure and may include patented algorithms. There are many configuration + * options which make the library horribly insecure. Backward API compatibility + * with early versions may not necessarily be maintained. Use at your own risk. + */ + +/** + * @file + * + * Library interface. + * + */ + +#ifndef RLC_H +#define RLC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "relic_arch.h" +#include "relic_conf.h" +#include "relic_core.h" +#include "relic_types.h" +#include "relic_bn.h" +#include "relic_dv.h" +#include "relic_fp.h" +#include "relic_fpx.h" +#include "relic_fb.h" +#include "relic_fbx.h" +#include "relic_ep.h" +#include "relic_eb.h" +#include "relic_ed.h" +#include "relic_ec.h" +#include "relic_pp.h" +#include "relic_pc.h" +#include "relic_cp.h" +#include "relic_bc.h" +#include "relic_md.h" +#include "relic_err.h" +#include "relic_rand.h" +#include "relic_util.h" + +#ifdef __cplusplus +} +#endif + +#endif /* !RLC_H */ diff --git a/bls/contrib/relic/include/relic_alloc.h b/bls/contrib/relic/include/relic_alloc.h new file mode 100644 index 00000000..caebe38d --- /dev/null +++ b/bls/contrib/relic/include/relic_alloc.h @@ -0,0 +1,87 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @file + * + * Implementation of the auxiliary memory allocation functions. + * + * @ingroup utils + */ + +#include "relic_conf.h" + +#ifdef _MSC_VER + +#include + +/* + * Dynamiclly allocates an array of "Type" with the specified size on the stack. + * This memory will be automaticlly deallocated from the stack when the function + * frame is returned from. + * Note: This is the Windows specific implementation. + * + * @param[in] T - the type of each object. + * @param[in] S - the number of obecs to allocate. + */ +#if ALLOC == DYNAMIC +#define RLC_ALLOCA(T, S) (T*) calloc((S), sizeof(T)) +#else +#define RLC_ALLOCA(T, S) (T*) _alloca((S) * sizeof(T)) +#endif + +#else /* _MSC_VER */ + +#include + +/* + * Dynamiclly allocates an array of "Type" with the specified size on the stack. + * This memory will be automaticlly deallocated from the stack when the function + * frame is returned from. + * Note: This is the POSIX specific implementation. + * + * @param[in] T - the type of each object. + * @param[in] S - the number of obecs to allocate. + */ +#if ALLOC == DYNAMIC +#define RLC_ALLOCA(T, S) (T*) malloc((S) * sizeof(T)) +#else +#define RLC_ALLOCA(T, S) (T*) alloca((S) * sizeof(T)) +#endif + +#endif + +/* + * Free memory allocated with RLC_ALLOCA. + * + * @param[in] A - the variable to free. + */ +#if ALLOC == DYNAMIC +#define RLC_FREE(A) \ + if (A != NULL) { \ + free(A); \ + A = NULL; \ + } +#else +#define RLC_FREE(A) (void)A; +#endif diff --git a/bls/contrib/relic/include/relic_arch.h b/bls/contrib/relic/include/relic_arch.h new file mode 100644 index 00000000..9990a693 --- /dev/null +++ b/bls/contrib/relic/include/relic_arch.h @@ -0,0 +1,106 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @defgroup arch Architecture-dependent utilities + */ + +/** + * @file + * + * Interface of architecture-dependent functions. + * + * @ingroup arch + */ + +#ifndef RLC_ARCH_H +#define RLC_ARCH_H + +#include "relic_types.h" +#include "relic_label.h" + +#if ARCH == AVR +#include +#endif + +/*============================================================================*/ +/* Macro definitions */ +/*============================================================================*/ + +/** + * Chooses a proper way to store a string in the target architecture. + * + * @param[in] S - the string to store. + */ +#if ARCH == AVR +#define RLC_STR(S) PSTR(S) +#else +#define RLC_STR(S) S +#endif + +/** + * Fetches a constant string to be used by the library. + * + * @param[out] S - the resulting prepared parameter. + * @param[in] ID - the parameter represented as a string. + * @param[in] L - the length of the string. + */ +#if ARCH == AVR +#define RLC_GET(S, ID, L) arch_copy_rom(S, RLC_STR(ID), L); +#else +#define RLC_GET(S, ID, L) memcpy(S, ID, L); +#endif + +/*============================================================================*/ +/* Function prototypes */ +/*============================================================================*/ + +/** + * Performs architecture-dependent initialization. + */ +void arch_init(void); + +/** + * Performs architecture-dependent finalization. + */ +void arch_clean(void); + +/** + * Return the number of elapsed cycles. + */ +ull_t arch_cycles(void); + +#if ARCH == AVR + +/** + * Copies a string from the text section to the destination vector. + * + * @param[out] dest - the destination vector. + * @param[in] src - the pointer to the string stored on the text section. + * @param[in] len - the length of the string. + */ +void arch_copy_rom(char *dest, const char *src, int len); + +#endif + +#endif /* !RLC_ARCH_H */ diff --git a/bls/contrib/relic/include/relic_bc.h b/bls/contrib/relic/include/relic_bc.h new file mode 100644 index 00000000..46457de3 --- /dev/null +++ b/bls/contrib/relic/include/relic_bc.h @@ -0,0 +1,84 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @defgroup bc Block ciphers + */ + +/** + * @file + * + * Interface of the module for encrypting with block ciphers. + * + * @ingroup bc + */ + +#ifndef RLC_BC_H +#define RLC_BC_H + +#include "relic_conf.h" +#include "relic_types.h" +#include "relic_label.h" + +/*============================================================================*/ +/* Constant definitions */ +/*============================================================================*/ + +/** + * Length in bytes of the default block cipher length. + */ +#define RLC_BC_LEN 16 + +/*============================================================================*/ +/* Function prototypes */ +/*============================================================================*/ + +/** + * Encrypts with AES in CBC mode. + * + * @param[out] out - the resulting ciphertext. + * @param[in,out] out_len - the buffer capacity and number of bytes written. + * @param[in] in - the bytes to be encrypted. + * @param[in] in_len - the number of bytes to encrypt. + * @param[in] key - the key. + * @param[in] key_len - the key size in bytes. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int bc_aes_cbc_enc(uint8_t *out, int *out_len, uint8_t *in, + int in_len, uint8_t *key, int key_len, uint8_t *iv); + +/** + * Decrypts with AES in CBC mode. + * + * @param[out] out - the resulting plaintext. + * @param[in,out] out_len - the buffer capacity and number of bytes written. + * @param[in] in - the bytes to be decrypted. + * @param[in] in_len - the number of bytes to decrypt. + * @param[in] key - the key. + * @param[in] key_len - the key size in bytes. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int bc_aes_cbc_dec(uint8_t *out, int *out_len, uint8_t *in, + int in_len, uint8_t *key, int key_len, uint8_t *iv); + +#endif /* !RLC_BC_H */ diff --git a/bls/contrib/relic/include/relic_bench.h b/bls/contrib/relic/include/relic_bench.h new file mode 100644 index 00000000..2ccdd09e --- /dev/null +++ b/bls/contrib/relic/include/relic_bench.h @@ -0,0 +1,202 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @defgroup bench Automated benchmarks + */ + +/** + * @file + * + * Interface of useful routines for benchmarking. + * + * @ingroup bench + */ + +#ifndef RLC_BENCH_H +#define RLC_BENCH_H + +#include "relic_conf.h" +#include "relic_label.h" +#include "relic_util.h" + +/*============================================================================*/ +/* Macro definitions */ +/*============================================================================*/ + +/** + * Runs a new benchmark once. + * + * @param[in] LABEL - the label for this benchmark. + * @param[in] FUNCTION - the function to benchmark. + */ +#define BENCH_ONCE(LABEL, FUNCTION) \ + bench_reset(); \ + util_print("BENCH: " LABEL "%*c = ", (int)(32 - strlen(LABEL)), ' '); \ + bench_before(); \ + FUNCTION; \ + bench_after(); \ + bench_compute(1); \ + bench_print(); \ + +/** + * Runs a new benchmark a small number of times. + * + * @param[in] LABEL - the label for this benchmark. + * @param[in] FUNCTION - the function to benchmark. + */ +#define BENCH_SMALL(LABEL, FUNCTION) \ + bench_reset(); \ + util_print("BENCH: " LABEL "%*c = ", (int)(32 - strlen(LABEL)), ' '); \ + bench_before(); \ + for (int i = 0; i < BENCH; i++) { \ + FUNCTION; \ + } \ + bench_after(); \ + bench_compute(BENCH); \ + bench_print(); \ + +/** + * Runs a new benchmark. + * + * @param[in] LABEL - the label for this benchmark. + */ +#define BENCH_BEGIN(LABEL) \ + bench_reset(); \ + util_print("BENCH: " LABEL "%*c = ", (int)(32 - strlen(LABEL)), ' '); \ + for (int _b = 0; _b < BENCH; _b++) { \ + +/** + * Prints the average timing of each execution in the chosen metric. + */ +#define BENCH_END \ + } \ + bench_compute(BENCH * BENCH); \ + bench_print() \ + +/** + * Prints the average timing of each execution amortized by N. + * + * @param N - the amortization factor. + */ +#define BENCH_DIV(N) \ + } \ + bench_compute(BENCH * BENCH * N); \ + bench_print() \ + +/** + * Measures the time of one execution and adds it to the benchmark total. + * + * @param[in] FUNCTION - the function executed. + */ +#define BENCH_ADD(FUNCTION) \ + FUNCTION; \ + bench_before(); \ + for (int _b = 0; _b < BENCH; _b++) { \ + FUNCTION; \ + } \ + bench_after(); \ + +/*============================================================================*/ +/* Type definitions */ +/*============================================================================*/ + +/** + * Timer type. + */ +#if OPSYS == DUINO && TIMER == HREAL + +typedef uint32_t bench_t; + +#elif TIMER == HREAL || TIMER == HPROC || TIMER == HTHRD + +#include +#include +typedef struct timespec bench_t; + +#elif TIMER == ANSI + +#include +typedef clock_t bench_t; + +#elif TIMER == POSIX + +#include +typedef struct timeval bench_t; + +#elif TIMER == CYCLE + +typedef unsigned long long bench_t; + +#else + +typedef unsigned long long bench_t; + +#endif + +/*============================================================================*/ +/* Function prototypes */ +/*============================================================================*/ + +/** + * Measures and prints benchmarking overhead. + */ +void bench_overhead(void); + +/** + * Resets the benchmark data. + * + * @param[in] label - the benchmark label. + */ +void bench_reset(void); + +/** + * Measures the time before a benchmark is executed. + */ +void bench_before(void); + +/** + * Measures the time after a benchmark was started and adds it to the total. + */ +void bench_after(void); + +/** + * Computes the mean elapsed time between the start and the end of a benchmark. + * + * @param benches - the number of executed benchmarks. + */ +void bench_compute(int benches); + +/** + * Prints the last benchmark. + */ +void bench_print(void); + +/** + * Returns the result of the last benchmark. + * + * @return the last benchmark. + */ +ull_t bench_total(void); + +#endif /* !RLC_BENCH_H */ diff --git a/bls/contrib/relic/include/relic_bn.h b/bls/contrib/relic/include/relic_bn.h new file mode 100644 index 00000000..adbdac72 --- /dev/null +++ b/bls/contrib/relic/include/relic_bn.h @@ -0,0 +1,1377 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @defgroup bn Multiple precision integer arithmetic + */ + +/** + * @file + * + * Interface of the module for multiple precision integer arithmetic. + * + * @ingroup bn + */ + +#ifndef RLC_BN_H +#define RLC_BN_H + +#include "relic_conf.h" +#include "relic_util.h" +#include "relic_types.h" +#include "relic_label.h" + +/*============================================================================*/ +/* Constant definitions */ +/*============================================================================*/ + +/** + * Precision in bits of a multiple precision integer. + * + * If the library is built with support for dynamic allocation, this constant + * represents the size in bits of the memory block allocated each time a + * multiple precision integer must grow. Otherwise, it represents the fixed + * fixed precision. + */ +#define RLC_BN_BITS ((int)BN_PRECI) + +/** + * Size in digits of a block sufficient to store the required precision. + */ +#define RLC_BN_DIGS ((int)RLC_CEIL(BN_PRECI, RLC_DIG)) + +/** + * Size in digits of a block sufficient to store a multiple precision integer. + */ +#if BN_MAGNI == DOUBLE +#define RLC_BN_SIZE ((int)(2 * RLC_BN_DIGS + 2)) +#elif BN_MAGNI == CARRY +#define RLC_BN_SIZE ((int)(RLC_BN_DIGS + 1)) +#elif BN_MAGNI == SINGLE +#define RLC_BN_SIZE ((int)RLC_BN_DIGS) +#endif + +/** + * Positive sign of a multiple precision integer. + */ +#define RLC_POS 0 + +/** + * Negative sign of a multiple precision integer. + */ +#define RLC_NEG 1 + +/*============================================================================*/ +/* Type definitions */ +/*============================================================================*/ + +/** + * Represents a multiple precision integer. + * + * The field dp points to a vector of digits. These digits are organized + * in little-endian format, that is, the least significant digits are + * stored in the first positions of the vector. + */ +typedef struct { + /** The number of digits allocated to this multiple precision integer. */ + int alloc; + /** The number of digits actually used. */ + int used; + /** The sign of this multiple precision integer. */ + int sign; +#if ALLOC == DYNAMIC + /** The sequence of contiguous digits that forms this integer. */ + dig_t *dp; +#elif ALLOC == STACK || ALLOC == AUTO + /** The sequence of contiguous digits that forms this integer. */ + rlc_align dig_t dp[RLC_BN_SIZE]; +#endif +} bn_st; + +/** + * Pointer to a multiple precision integer structure. + */ +#if ALLOC == AUTO +typedef bn_st bn_t[1]; +#else +typedef bn_st *bn_t; +#endif + +/*============================================================================*/ +/* Macro definitions */ +/*============================================================================*/ + +/** + * Initializes a multiple precision integer with a null value. + * + * @param[out] A - the multiple precision integer to initialize. + */ +#if ALLOC == AUTO +#define bn_null(A) /* empty */ +#else +#define bn_null(A) A = NULL; +#endif + +/** + * Calls a function to allocate and initialize a multiple precision integer. + * + * @param[in,out] A - the multiple precision integer to initialize. + * @throw ERR_NO_MEMORY - if there is no available memory. + */ +#if ALLOC == DYNAMIC +#define bn_new(A) \ + A = (bn_t)calloc(1, sizeof(bn_st)); \ + if ((A) == NULL) { \ + THROW(ERR_NO_MEMORY); \ + } \ + bn_init(A, RLC_BN_SIZE); \ + +#elif ALLOC == AUTO +#define bn_new(A) \ + bn_init(A, RLC_BN_SIZE); \ + +#elif ALLOC == STACK +#define bn_new(A) \ + A = (bn_t)alloca(sizeof(bn_st)); \ + bn_init(A, RLC_BN_SIZE); \ + +#endif + +/** + * Calls a function to allocate and initialize a multiple precision integer + * with the required precision in digits. + * + * @param[in,out] A - the multiple precision integer to initialize. + * @param[in] D - the precision in digits. + * @throw ERR_NO_MEMORY - if there is no available memory. + * @throw ERR_PRECISION - if the required precision cannot be represented + * by the library. + */ +#if ALLOC == DYNAMIC +#define bn_new_size(A, D) \ + A = (bn_t)calloc(1, sizeof(bn_st)); \ + if (A == NULL) { \ + THROW(ERR_NO_MEMORY); \ + } \ + bn_init(A, D); \ + +#elif ALLOC == AUTO +#define bn_new_size(A, D) \ + bn_init(A, D); \ + +#elif ALLOC == STACK +#define bn_new_size(A, D) \ + A = (bn_t)alloca(sizeof(bn_st)); \ + bn_init(A, D); \ + +#endif + +/** + * Calls a function to clean and free a multiple precision integer. + * + * @param[in,out] A - the multiple precision integer to free. + */ +#if ALLOC == DYNAMIC +#define bn_free(A) \ + if (A != NULL) { \ + bn_clean(A); \ + free(A); \ + A = NULL; \ + } + +#elif ALLOC == AUTO +#define bn_free(A) /* empty */ \ + +#elif ALLOC == STACK +#define bn_free(A) \ + A = NULL; \ + +#endif + +/** + * Multiples two multiple precision integers. Computes c = a * b. + * + * @param[out] C - the result. + * @param[in] A - the first multiple precision integer to multiply. + * @param[in] B - the second multiple precision integer to multiply. + */ +#if BN_KARAT > 0 +#define bn_mul(C, A, B) bn_mul_karat(C, A, B) +#elif BN_MUL == BASIC +#define bn_mul(C, A, B) bn_mul_basic(C, A, B) +#elif BN_MUL == COMBA +#define bn_mul(C, A, B) bn_mul_comba(C, A, B) +#endif + +/** + * Computes the square of a multiple precision integer. Computes c = a * a. + * + * @param[out] C - the result. + * @param[in] A - the multiple precision integer to square. + */ +#if BN_KARAT > 0 +#define bn_sqr(C, A) bn_sqr_karat(C, A) +#elif BN_SQR == BASIC +#define bn_sqr(C, A) bn_sqr_basic(C, A) +#elif BN_SQR == COMBA +#define bn_sqr(C, A) bn_sqr_comba(C, A) +#elif BN_SQR == MULTP +#define bn_sqr(C, A) bn_mul(C, A, A) +#endif + +/** + * Computes the auxiliar value derived from the modulus to be used during + * modular reduction. + * + * @param[out] U - the result. + * @param[in] M - the modulus. + */ +#if BN_MOD == BASIC +#define bn_mod_pre(U, M) (void)(U), (void)(M) +#elif BN_MOD == BARRT +#define bn_mod_pre(U, M) bn_mod_pre_barrt(U, M) +#elif BN_MOD == MONTY +#define bn_mod_pre(U, M) bn_mod_pre_monty(U, M) +#elif BN_MOD == PMERS +#define bn_mod_pre(U, M) bn_mod_pre_pmers(U, M) +#endif + +/** + * Reduces a multiple precision integer modulo another integer. If the number + * of arguments is 3, then simple division is used. If the number of arguments + * is 4, then a modular reduction algorithm is used and the fourth argument + * is an auxiliary value derived from the modulus. The variant with 4 arguments + * should be used when several modular reductions are computed with the same + * modulus. Computes c = a mod m. + * + * @param[out] C - the result. + * @param[in] A - the multiple precision integer to reduce. + * @param[in] ... - the modulus and an optional argument. + */ +#define bn_mod(C, A, ...) RLC_CAT(bn_mod, RLC_OPT(__VA_ARGS__))(C, A, __VA_ARGS__) + +/** + * Reduces a multiple precision integer modulo another integer. This macro + * should not be called directly. Use bn_mod with 4 arguments instead. + * + * @param[out] C - the result. + * @param[in] A - the the multiple precision integer to reduce. + * @param[in] M - the modulus. + * @param[in] U - the auxiliar value derived from the modulus. + */ +#if BN_MOD == BASIC +#define bn_mod_imp(C, A, M, U) bn_mod_basic(C, A, M) +#elif BN_MOD == BARRT +#define bn_mod_imp(C, A, M, U) bn_mod_barrt(C, A, M, U) +#elif BN_MOD == MONTY +#define bn_mod_imp(C, A, M, U) bn_mod_monty(C, A, M, U) +#elif BN_MOD == PMERS +#define bn_mod_imp(C, A, M, U) bn_mod_pmers(C, A, M, U) +#endif + +/** + * Reduces a multiple precision integer modulo a positive integer using + * Montgomery reduction. Computes c = a * u^(-1) (mod m). + * + * @param[out] C - the result. + * @param[in] A - the multiple precision integer to reduce. + * @param[in] M - the modulus. + * @param[in] U - the reciprocal of the modulus. + */ +#if BN_MUL == BASIC +#define bn_mod_monty(C, A, M, U) bn_mod_monty_basic(C, A, M, U) +#elif BN_MUL == COMBA +#define bn_mod_monty(C, A, M, U) bn_mod_monty_comba(C, A, M, U) +#endif + +/** + * Exponentiates a multiple precision integer modulo another multiple precision + * integer. Computes c = a^b mod m. If Montgomery reduction is used, the basis + * must not be in Montgomery form. + * + * @param[out] C - the result. + * @param[in] A - the basis. + * @param[in] B - the exponent. + * @param[in] M - the modulus. + */ +#if BN_MXP == BASIC +#define bn_mxp(C, A, B, M) bn_mxp_basic(C, A, B, M) +#elif BN_MXP == SLIDE +#define bn_mxp(C, A, B, M) bn_mxp_slide(C, A, B, M) +#elif BN_MXP == MONTY +#define bn_mxp(C, A, B, M) bn_mxp_monty(C, A, B, M) +#endif + +/** + * Computes the greatest common divisor of two multiple precision integers. + * Computes c = gcd(a, b). + * + * @param[out] C - the result; + * @param[in] A - the first multiple precision integer. + * @param[in] B - the second multiple precision integer. + */ +#if BN_GCD == BASIC +#define bn_gcd(C, A, B) bn_gcd_basic(C, A, B) +#elif BN_GCD == LEHME +#define bn_gcd(C, A, B) bn_gcd_lehme(C, A, B) +#elif BN_GCD == STEIN +#define bn_gcd(C, A, B) bn_gcd_stein(C, A, B) +#endif + +/** + * Computes the extended greatest common divisor of two multiple precision + * integers. This function can be used to compute multiplicative inverses. + * Computes c = gcd(a, b) and c = a * d + b * e. + * + * @param[out] C - the result; + * @param[out] D - the cofactor of the first operand, cannot be NULL. + * @param[out] E - the cofactor of the second operand, can be NULL. + * @param[in] A - the first multiple precision integer. + * @param[in] B - the second multiple precision integer. + */ +#if BN_GCD == BASIC +#define bn_gcd_ext(C, D, E, A, B) bn_gcd_ext_basic(C, D, E, A, B) +#elif BN_GCD == LEHME +#define bn_gcd_ext(C, D, E, A, B) bn_gcd_ext_lehme(C, D, E, A, B) +#elif BN_GCD == STEIN +#define bn_gcd_ext(C, D, E, A, B) bn_gcd_ext_stein(C, D, E, A, B) +#endif + +/** + * Generates a probable prime number. + * + * @param[out] A - the result. + * @param[in] B - the length of the number in bits. + */ +#if BN_GEN == BASIC +#define bn_gen_prime(A, B) bn_gen_prime_basic(A, B) +#elif BN_GEN == SAFEP +#define bn_gen_prime(A, B) bn_gen_prime_safep(A, B) +#elif BN_GEN == STRON +#define bn_gen_prime(A, B) bn_gen_prime_stron(A, B) +#endif + +/*============================================================================*/ +/* Function prototypes */ +/*============================================================================*/ + +/** + * Initializes a previously allocated multiple precision integer. + * + * @param[out] a - the multiple precision integer to initialize. + * @param[in] digits - the required precision in digits. + * @throw ERR_NO_MEMORY - if there is no available memory. + * @throw ERR_PRECISION - if the required precision cannot be represented + * by the library. + */ +void bn_init(bn_t a, int digits); + +/** + * Cleans a multiple precision integer. + * + * @param[out] a - the multiple precision integer to free. + */ +void bn_clean(bn_t a); + +/** + * Checks the current precision of a multiple precision integer and optionally + * expands its precision to a given size in digits. + * + * @param[out] a - the multiple precision integer to expand. + * @param[in] digits - the number of digits to expand. + * @throw ERR_NO_MEMORY - if there is no available memory. + * @throw ERR_PRECISION - if the required precision cannot be represented + * by the library. + */ +void bn_grow(bn_t a, int digits); + +/** + * Adjust the number of valid digits of a multiple precision integer. + * + * @param[out] a - the multiple precision integer to adjust. + */ +void bn_trim(bn_t a); + +/** + * Copies the second argument to the first argument. + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer to copy. + */ +void bn_copy(bn_t c, const bn_t a); + +/** + * Returns the absolute value of a multiple precision integer. + * + * @param[out] c - the result. + * @param[in] a - the argument of the absolute function. + */ +void bn_abs(bn_t c, const bn_t a); + +/** + * Inverts the sign of a multiple precision integer. + * + * @param[out] c - the result. + * @param[out] a - the multiple precision integer to negate. + */ +void bn_neg(bn_t c, const bn_t a); + +/** + * Returns the sign of a multiple precision integer. + * + * @param[in] a - the multiple precision integer. + * @return RLC_POS if the argument is positive and RLC_NEG otherwise. + */ +int bn_sign(const bn_t a); + +/** + * Assigns zero to a multiple precision integer. + * + * @param[out] a - the multiple precision integer to assign. + */ +void bn_zero(bn_t a); + +/** + * Tests if a multiple precision integer is zero or not. + * + * @param[in] a - the multiple precision integer to test. + * @return 1 if the argument is zero, 0 otherwise. + */ +int bn_is_zero(const bn_t a); + +/** + * Tests if a multiple precision integer is even or odd. + * + * @param[in] a - the multiple precision integer to test. + * @return 1 if the argument is even, 0 otherwise. + */ +int bn_is_even(const bn_t a); + +/** + * Returns the number of bits of a multiple precision integer. + * + * @param[in] a - the multiple precision integer. + * @return number of bits. + */ +int bn_bits(const bn_t a); + +/** + * Returns the bit stored in the given position on a multiple precision integer. + * + * @param[in] a - the multiple precision integer. + * @param[in] bit - the bit position to read. + * @return the bit value. + */ +int bn_get_bit(const bn_t a, int bit); + +/** + * Stores a bit in a given position on a multiple precision integer. + * + * @param[out] a - the multiple precision integer. + * @param[in] bit - the bit position to store. + * @param[in] value - the bit value. + */ +void bn_set_bit(bn_t a, int bit, int value); + +/** + * Returns the Hamming weight of a multiple precision integer. + * + * @param[in] a - the multiple precision integer. + * @return the number of non-zero bits. + */ +int bn_ham(const bn_t a); + +/** + * Reads the first digit in a multiple precision integer. + * + * @param[out] digit - the result. + * @param[in] a - the multiple precision integer. + */ +void bn_get_dig(dig_t *digit, const bn_t a); + +/** + * Assigns a small positive constant to a multiple precision integer. + * + * The constant must fit on a multiple precision digit, or dig_t type using + * only the number of bits specified on RLC_DIG. + * + * @param[out] a - the result. + * @param[in] digit - the constant to assign. + */ +void bn_set_dig(bn_t a, dig_t digit); + +/** + * Assigns a multiple precision integer to 2^b. + * + * @param[out] a - the result. + * @param[in] b - the power of 2 to assign. + */ +void bn_set_2b(bn_t a, int b); + +/** + * Assigns a random value to a multiple precision integer. + * + * @param[out] a - the multiple precision integer to assign. + * @param[in] sign - the sign to be assigned (RLC_NEG or RLC_POS). + * @param[in] bits - the number of bits. + */ +void bn_rand(bn_t a, int sign, int bits); + +/** + * Assigns a non-zero random value to a multiple precision integer with absolute + * value smaller than a given modulus. + * + * @param[out] a - the multiple precision integer to assign. + * @param[in] b - the modulus. + */ +void bn_rand_mod(bn_t a, bn_t b); + +/** + * Prints a multiple precision integer to standard output. + * + * @param[in] a - the multiple precision integer to print. + */ +void bn_print(const bn_t a); + +/** + * Returns the number of digits in radix necessary to store a multiple precision + * integer. The radix must be included in the interval [2, 64]. + * + * @param[in] a - the multiple precision integer. + * @param[in] radix - the radix. + * @throw ERR_NO_VALID - if the radix is invalid. + * @return the number of digits in the given radix. + */ +int bn_size_str(const bn_t a, int radix); + +/** + * Reads a multiple precision integer from a string in a given radix. The radix + * must be included in the interval [2, 64]. + * + * @param[out] a - the result. + * @param[in] str - the string. + * @param[in] len - the size of the string. + * @param[in] radix - the radix. + * @throw ERR_NO_VALID - if the radix is invalid. + */ +void bn_read_str(bn_t a, const char *str, int len, int radix); + +/** + * Writes a multiple precision integer to a string in a given radix. The radix + * must be included in the interval [2, 64]. + * + * @param[out] str - the string. + * @param[in] len - the buffer capacity. + * @param[in] a - the multiple integer to write. + * @param[in] radix - the radix. + * @throw ERR_NO_BUFFER - if the buffer capacity is insufficient. + * @throw ERR_NO_VALID - if the radix is invalid. + */ +void bn_write_str(char *str, int len, const bn_t a, int radix); + +/** + * Returns the number of bytes necessary to store a multiple precision integer. + * + * @param[in] a - the multiple precision integer. + * @return the number of bytes. + */ +int bn_size_bin(const bn_t a); + +/** + * Reads a positive multiple precision integer from a byte vector in big-endian + * format. + * + * @param[out] a - the result. + * @param[in] bin - the byte vector. + * @param[in] len - the buffer capacity. + */ +void bn_read_bin(bn_t a, const uint8_t *bin, int len); + +/** + * Writes a positive multiple precision integer to a byte vector in big-endian + * format. + * + * @param[out] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @param[in] a - the multiple integer to write. + * @throw ERR_NO_BUFFER - if the buffer capacity is insufficient. + */ +void bn_write_bin(uint8_t *bin, int len, const bn_t a); + +/** + * Returns the number of digits necessary to store a multiple precision integer. + * + * @param[in] a - the multiple precision integer. + * @return the number of digits. + */ +int bn_size_raw(const bn_t a); + +/** + * Reads a positive multiple precision integer from a digit vector. + * + * @param[out] a - the result. + * @param[in] raw - the digit vector. + * @param[in] len - the size of the string. + */ +void bn_read_raw(bn_t a, const dig_t *raw, int len); + +/** + * Writes a positive multiple precision integer to a byte vector. + * + * @param[out] raw - the digit vector. + * @param[in] len - the buffer capacity. + * @param[in] a - the multiple integer to write. + * @throw ERR_NO_BUFFER - if the buffer capacity is insufficient. + */ +void bn_write_raw(dig_t *raw, int len, const bn_t a); + +/** + * Returns the result of an unsigned comparison between two multiple precision + * integers. + * + * @param[in] a - the first multiple precision integer. + * @param[in] b - the second multiple precision integer. + * @return RLC_LT if a < b, RLC_EQ if a == b and RLC_GT if a > b. + */ +int bn_cmp_abs(const bn_t a, const bn_t b); + +/** + * Returns the result of a signed comparison between a multiple precision + * integer and a digit. + * + * @param[in] a - the multiple precision integer. + * @param[in] b - the digit. + * @return RLC_LT if a < b, RLC_EQ if a == b and RLC_GT if a > b. + */ +int bn_cmp_dig(const bn_t a, dig_t b); + +/** + * Returns the result of a signed comparison between two multiple precision + * integers. + * + * @param[in] a - the first multiple precision integer. + * @param[in] b - the second multiple precision integer. + * @return RLC_LT if a < b, RLC_EQ if a == b and RLC_GT if a > b. + */ +int bn_cmp(const bn_t a, const bn_t b); + +/** + * Adds two multiple precision integers. Computes c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the first multiple precision integer to add. + * @param[in] b - the second multiple precision integer to add. + */ +void bn_add(bn_t c, const bn_t a, const bn_t b); + +/** + * Adds a multiple precision integers and a digit. Computes c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer to add. + * @param[in] b - the digit to add. + */ +void bn_add_dig(bn_t c, const bn_t a, dig_t b); + +/** + * Subtracts a multiple precision integer from another, that is, computes + * c = a - b. + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer. + * @param[in] b - the multiple precision integer to subtract. + */ +void bn_sub(bn_t c, const bn_t a, const bn_t b); + +/** + * Subtracts a digit from a multiple precision integer. Computes c = a - b. + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer. + * @param[in] b - the digit to subtract. + */ +void bn_sub_dig(bn_t c, const bn_t a, const dig_t b); + +/** + * Multiplies a multiple precision integer by a digit. Computes c = a * b. + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer to multiply. + * @param[in] b - the digit to multiply. + */ +void bn_mul_dig(bn_t c, const bn_t a, dig_t b); + +/** + * Multiplies two multiple precision integers using Schoolbook multiplication. + * + * @param[out] c - the result. + * @param[in] a - the first multiple precision integer to multiply. + * @param[in] b - the second multiple precision integer to multiply. + */ +void bn_mul_basic(bn_t c, const bn_t a, const bn_t b); + +/** + * Multiplies two multiple precision integers using Comba multiplication. + * + * @param[out] c - the result. + * @param[in] a - the first multiple precision integer to multiply. + * @param[in] b - the second multiple precision integer to multiply. + */ +void bn_mul_comba(bn_t c, const bn_t a, const bn_t b); + +/** + * Multiplies two multiple precision integers using Karatsuba multiplication. + * + * @param[out] c - the result. + * @param[in] a - the first multiple precision integer to multiply. + * @param[in] b - the second multiple precision integer to multiply. + */ +void bn_mul_karat(bn_t c, const bn_t a, const bn_t b); + +/** + * Computes the square of a multiple precision integer using Schoolbook + * squaring. + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer to square. + */ +void bn_sqr_basic(bn_t c, const bn_t a); + +/** + * Computes the square of a multiple precision integer using Comba squaring. + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer to square. + */ +void bn_sqr_comba(bn_t c, const bn_t a); + +/** + * Computes the square of a multiple precision integer using Karatsuba squaring. + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer to square. + */ +void bn_sqr_karat(bn_t c, const bn_t a); + +/** + * Doubles a multiple precision. Computes c = a + a. + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer to double. + */ +void bn_dbl(bn_t c, const bn_t a); + +/** + * Halves a multiple precision. Computes c = floor(a / 2) + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer to halve. + */ +void bn_hlv(bn_t c, const bn_t a); + +/** + * Shifts a multiple precision number to the left. Computes c = a * 2^bits. + * c = a * 2^bits. + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer to shift. + * @param[in] bits - the number of bits to shift. + */ +void bn_lsh(bn_t c, const bn_t a, int bits); + +/** + * Shifts a multiple precision number to the right. Computes + * c = floor(a / 2^bits). + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer to shift. + * @param[in] bits - the number of bits to shift. + */ +void bn_rsh(bn_t c, const bn_t a, int bits); + +/** + * Divides a multiple precision integer by another multiple precision integer + * without producing the positive remainder. Computes c = floor(a / b). + * + * @param[out] c - the resulting quotient. + * @param[in] a - the dividend. + * @param[in] b - the divisor. + * @throw ERR_NO_VALID - if the divisor is zero. + */ +void bn_div(bn_t c, const bn_t a, const bn_t b); + +/** + * Divides a multiple precision integer by another multiple precision integer + * and produces a positive remainder. Computes c = floor(a / b) and d = a mod b. + * + * @param[out] c - the resulting quotient. + * @param[out] d - the positive remainder. + * @param[in] a - the dividend. + * @param[in] b - the divisor. + * @throw ERR_NO_VALID - if the divisor is zero. + */ +void bn_div_rem(bn_t c, bn_t d, const bn_t a, const bn_t b); + +/** + * Divides a multiple precision integers by a digit without computing the + * remainder. Computes c = floor(a / b). + * + * @param[out] c - the resulting quotient. + * @param[out] d - the remainder. + * @param[in] a - the dividend. + * @param[in] b - the divisor. + * @throw ERR_NO_VALID - if the divisor is zero. + */ +void bn_div_dig(bn_t c, const bn_t a, dig_t b); + +/** + * Divides a multiple precision integers by a digit. Computes c = floor(a / b) + * and d = a mod b. + * + * @param[out] c - the resulting quotient. + * @param[out] d - the remainder. + * @param[in] a - the dividend. + * @param[in] b - the divisor. + * @throw ERR_NO_VALID - if the divisor is zero. + */ +void bn_div_rem_dig(bn_t c, dig_t *d, const bn_t a, const dig_t b); + +/** + * Reduces a multiple precision integer modulo a power of 2. Computes + * c = a mod 2^b. + * + * @param[out] c - the result. + * @param[in] a - the dividend. + * @param[in] b - the exponent of the divisor. + */ +void bn_mod_2b(bn_t c, const bn_t a, int b); + +/** + * Reduces a multiple precision integer modulo a digit. Computes c = a mod b. + * + * @param[out] c - the result. + * @param[in] a - the dividend. + * @param[in] b - the divisor. + */ +void bn_mod_dig(dig_t *c, const bn_t a, dig_t b); + +/** + * Reduces a multiple precision integer modulo an integer using straightforward + * division. + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer to reduce. + * @param[in] m - the modulus. + */ +void bn_mod_basic(bn_t c, const bn_t a, const bn_t m); + +/** + * Computes the reciprocal of the modulus to be used in the Barrett modular + * reduction algorithm. + * + * @param[out] u - the result. + * @param[in] m - the modulus. + */ +void bn_mod_pre_barrt(bn_t u, const bn_t m); + +/** + * Reduces a multiple precision integer modulo a positive integer using Barrett + * reduction. + * + * @param[out] c - the result. + * @param[in] a - the the multiple precision integer to reduce. + * @param[in] m - the modulus. + * @param[in] u - the reciprocal of the modulus. + */ +void bn_mod_barrt(bn_t c, const bn_t a, const bn_t m, const bn_t u); + +/** + * Computes the reciprocal of the modulus to be used in the Montgomery reduction + * algorithm. + * + * @param[out] u - the result. + * @param[in] m - the modulus. + * @throw ERR_NO_VALID - if the modulus is even. + */ +void bn_mod_pre_monty(bn_t u, const bn_t m); + +/** + * Converts a multiple precision integer to Montgomery form. + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer to convert. + * @param[in] m - the modulus. + */ +void bn_mod_monty_conv(bn_t c, const bn_t a, const bn_t m); + +/** + * Converts a multiple precision integer from Montgomery form. + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer to convert. + * @param[in] m - the modulus. + */ +void bn_mod_monty_back(bn_t c, const bn_t a, const bn_t m); + +/** + * Reduces a multiple precision integer modulo a positive integer using + * Montgomery reduction with Schoolbook multiplication. + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer to reduce. + * @param[in] m - the modulus. + * @param[in] u - the reciprocal of the modulus. + */ +void bn_mod_monty_basic(bn_t c, const bn_t a, const bn_t m, const bn_t u); + +/** + * Reduces a multiple precision integer modulo a positive integer using + * Montgomery reduction with Comba multiplication. + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer to reduce. + * @param[in] m - the modulus. + * @param[in] u - the reciprocal of the modulus. + */ +void bn_mod_monty_comba(bn_t c, const bn_t a, const bn_t m, const bn_t u); + +/** + * Computes u if the modulus has the form 2^b - u. + * + * @param[out] u - the result. + * @param[in] m - the modulus. + */ +void bn_mod_pre_pmers(bn_t u, const bn_t m); + +/** + * Reduces a multiple precision integer modulo a positive integer using + * pseudo-Mersenne modular reduction. + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer to reduce. + * @param[in] m - the modulus. + * @param[in] u - the auxiliar value derived from the modulus. + */ +void bn_mod_pmers(bn_t c, const bn_t a, const bn_t m, const bn_t u); + +/** + * Exponentiates a multiple precision integer modulo a positive integer using + * the binary method. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent. + * @param[in] m - the modulus. + */ +void bn_mxp_basic(bn_t c, const bn_t a, const bn_t b, const bn_t m); + +/** + * Exponentiates a multiple precision integer modulo a positive integer using + * the sliding window method. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent. + * @param[in] m - the modulus. + */ +void bn_mxp_slide(bn_t c, const bn_t a, const bn_t b, const bn_t m); + +/** + * Exponentiates a multiple precision integer modulo a positive integer using + * the constant-time Montgomery powering ladder method. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent. + * @param[in] m - the modulus. + */ +void bn_mxp_monty(bn_t c, const bn_t a, const bn_t b, const bn_t m); + +/** + * Exponentiates a multiple precision integer by a small power modulo a positive + * integer using the binary method. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent. + * @param[in] m - the modulus. + */ +void bn_mxp_dig(bn_t c, const bn_t a, dig_t b, const bn_t m); + +/** + * Extracts an approximate integer square-root of a multiple precision integer. + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer to extract. + * + * @throw ERR_NO_VALID - if the argument is negative. + */ +void bn_srt(bn_t c, bn_t a); + +/** + * Computes the greatest common divisor of two multiple precision integers + * using the standard Euclidean algorithm. + * + * @param[out] c - the result; + * @param[in] a - the first multiple precision integer. + * @param[in] b - the second multiple precision integer. + */ +void bn_gcd_basic(bn_t c, const bn_t a, const bn_t b); + +/** + * Computes the greatest common divisor of two multiple precision integers + * using Lehmer's GCD algorithm. + * + * @param[out] c - the result; + * @param[in] a - the first multiple precision integer. + * @param[in] b - the second multiple precision integer. + */ +void bn_gcd_lehme(bn_t c, const bn_t a, const bn_t b); + +/** + * Computes the greatest common divisor of two multiple precision integers + * using Stein's binary GCD algorithm. + * + * @param[out] c - the result; + * @param[in] a - the first multiple precision integer. + * @param[in] b - the second multiple precision integer. + */ +void bn_gcd_stein(bn_t c, const bn_t a, const bn_t b); + +/** + * Computes the greatest common divisor of a multiple precision integer and a + * digit. + * + * @param[out] c - the result; + * @param[in] a - the multiple precision integer. + * @param[in] b - the digit. + */ +void bn_gcd_dig(bn_t c, const bn_t a, dig_t b); + +/** + * Computes the extended greatest common divisor of two multiple precision + * integer using the Euclidean algorithm. + * + * @param[out] c - the result. + * @param[out] d - the cofactor of the first operand, can be NULL. + * @param[out] e - the cofactor of the second operand, can be NULL. + * @param[in] a - the first multiple precision integer. + * @param[in] b - the second multiple precision integer. + */ +void bn_gcd_ext_basic(bn_t c, bn_t d, bn_t e, const bn_t a, const bn_t b); + +/** + * Computes the greatest common divisor of two multiple precision integers + * using Lehmer's algorithm. + * + * @param[out] c - the result; + * @param[out] d - the cofactor of the first operand, can be NULL. + * @param[out] e - the cofactor of the second operand, can be NULL. + * @param[in] a - the first multiple precision integer. + * @param[in] b - the second multiple precision integer. + */ +void bn_gcd_ext_lehme(bn_t c, bn_t d, bn_t e, const bn_t a, const bn_t b); + +/** + * Computes the greatest common divisor of two multiple precision integers + * using Stein's binary algorithm. + * + * @param[out] c - the result; + * @param[out] d - the cofactor of the first operand, can be NULL. + * @param[out] e - the cofactor of the second operand, can be NULL. + * @param[in] a - the first multiple precision integer. + * @param[in] b - the second multiple precision integer. + */ +void bn_gcd_ext_stein(bn_t c, bn_t d, bn_t e, const bn_t a, const bn_t b); + +/** + * Computes the extended greatest common divisor of two multiple precision + * integers halfway through the algorithm. Returns also two short vectors + * v1 = (c, d), v2 = (-e, f) useful to decompose an integer k into k0, k1 such + * that k = k_0 + k_1 * a (mod b). + * + * @param[out] c - the first component of the first vector. + * @param[out] d - the second component of the first vector. + * @param[out] e - the first component of the second vector. + * @param[out] f - the second component of the second vector. + * @param[in] a - the first multiple precision integer. + * @param[in] b - the second multiple precision integer. + */ +void bn_gcd_ext_mid(bn_t c, bn_t d, bn_t e, bn_t f, const bn_t a, const bn_t b); + +/** + * Computes the extended greatest common divisor of a multiple precision integer + * and a digit. + * + * @param[out] c - the result. + * @param[out] d - the cofactor of the first operand, can be NULL. + * @param[out] e - the cofactor of the second operand, can be NULL. + * @param[in] a - the multiple precision integer. + * @param[in] b - the digit. + */ +void bn_gcd_ext_dig(bn_t c, bn_t d, bn_t e, const bn_t a, dig_t b); + +/** + * Computes the last common multiple of two multiple precision integers. + * Computes c = lcm(a, b). + * + * @param[out] c - the result. + * @param[in] a - the first integer. + * @param[in] b - the second integer. + */ +void bn_lcm(bn_t c, const bn_t a, const bn_t b); + +/** + * Computes the Legendre symbol c = (a|b), b prime. + * + * @param[out] c - the result. + * @param[in] a - the first parameter. + * @param[in] b - the second parameter. + */ +void bn_smb_leg(bn_t c, const bn_t a, const bn_t b); + +/** + * Computes the Jacobi symbol c = (a|b). + * + * @param[out] c - the result. + * @param[in] a - the first parameter. + * @param[in] b - the second parameter. + */ +void bn_smb_jac(bn_t c, const bn_t a, const bn_t b); + +/** + * Returns a small precomputed prime from a given position in the list of prime + * numbers. + * + * @param[in] pos - the position in the prime sequence. + * @return a prime if the position is lower than 512, 0 otherwise. + */ +dig_t bn_get_prime(int pos); + +/** + * Tests if a number is a probable prime. + * + * @param[in] a - the multiple precision integer to test. + * @return 1 if a is prime, 0 otherwise. + */ +int bn_is_prime(const bn_t a); + +/** + * Tests if a number is prime using a series of trial divisions. + * + * @param[in] a - the number to test. + * @return 1 if a is a probable prime, 0 otherwise. + */ +int bn_is_prime_basic(const bn_t a); + +/** + * Tests if a number a > 2 is prime using the Miller-Rabin test with probability + * 2^(-80) of error. + * + * @param[in] a - the number to test. + * @return 1 if a is a probable prime, 0 otherwise. + */ +int bn_is_prime_rabin(const bn_t a); + +/** + * Tests if a number a > 2 is prime using the Solovay-Strassen test with + * probability 2^(-80) of error. + * + * @param[in] a - the number to test. + * @return 1 if a is a probable prime, 0 otherwise. + */ +int bn_is_prime_solov(const bn_t a); + +/** + * Generates a probable prime number. + * + * @param[out] a - the result. + * @param[in] bits - the length of the number in bits. + */ +void bn_gen_prime_basic(bn_t a, int bits); + +/** + * Generates a probable prime number a with (a - 1)/2 also prime. + * + * @param[out] a - the result. + * @param[in] bits - the length of the number in bits. + */ +void bn_gen_prime_safep(bn_t a, int bits); + +/** + * Generates a probable prime number with (a - 1)/2, (a + 1)/2 and + * ((a - 1)/2 - 1)/2 also prime. + * + * @param[out] a - the result. + * @param[in] bits - the length of the number in bits. + */ +void bn_gen_prime_stron(bn_t a, int bits); + +/** + * Tries to factorize an integer using Pollard (p - 1) factoring algorithm. + * The maximum length of the returned factor is 16 bits. + * + * @param[out] c - the resulting factor. + * @param[in] a - the integer to fatorize. + * @return 1 if a factor is found and stored into c; 0 otherwise. + */ +int bn_factor(bn_t c, const bn_t a); + +/** + * Tests if an integer divides other integer. + * + * @param[in] c - the factor. + * @param[in] a - the integer. + * @return 1 if the first integer is a factor; 0 otherwise. + */ +int bn_is_factor(bn_t c, const bn_t a); + +/** + * Recodes a positive integer in window form. If a negative integer is given + * instead, its absolute value is taken. + * + * @param[out] win - the recoded integer. + * @param[out] len - the number of bytes written. + * @param[in] k - the integer to recode. + * @param[in] w - the window size in bits. + * @throw ERR_NO_BUFFER - if the buffer capacity is insufficient. + */ +void bn_rec_win(uint8_t *win, int *len, const bn_t k, int w); + +/** + * Recodes a positive integer in sliding window form. If a negative integer is + * given instead, its absolute value is taken. + * + * @param[out] win - the recoded integer. + * @param[out] len - the number of bytes written. + * @param[in] k - the integer to recode. + * @param[in] w - the window size in bits. + * @throw ERR_NO_BUFFER - if the buffer capacity is insufficient. + */ +void bn_rec_slw(uint8_t *win, int *len, const bn_t k, int w); + +/** + * Recodes a positive integer in width-w Non-Adjacent Form. If a negative + * integer is given instead, its absolute value is taken. + * + * @param[out] naf - the recoded integer. + * @param[out] len - the number of bytes written. + * @param[in] k - the integer to recode. + * @param[in] w - the window size in bits. + * @throw ERR_NO_BUFFER - if the buffer capacity is insufficient. + */ +void bn_rec_naf(int8_t *naf, int *len, const bn_t k, int w); + +/** + * Recodes a positive integer in width-w \tau-NAF. If a negative integer is + * given instead, its absolute value is taken. + * + * @param[out] tnaf - the recoded integer. + * @param[out] len - the number of bytes written. + * @param[in] k - the integer to recode. + * @param[in] u - the u curve parameter. + * @param[in] m - the extension degree of the binary field. + * @param[in] w - the window size in bits. + * @throw ERR_NO_BUFFER - if the buffer capacity is insufficient. + */ +void bn_rec_tnaf(int8_t *tnaf, int *len, const bn_t k, int8_t u, int m, int w); + +/** + * Recodes a positive integer in regular fixed-length width-w \tau-NAF. + * If a negative integer is given instead, its absolute value is taken. + * + * @param[out] tnaf - the recoded integer. + * @param[out] len - the number of bytes written. + * @param[in] k - the integer to recode. + * @param[in] u - the u curve parameter. + * @param[in] m - the extension degree of the binary field. + * @param[in] w - the window size in bits. + * @throw ERR_NO_BUFFER - if the buffer capacity is insufficient. + */ +void bn_rec_rtnaf(int8_t *tnaf, int *len, const bn_t k, int8_t u, int m, int w); + +/** + * Write the constants needed for \tau-NAF recoding as a set of \alpha_u = + * \beta_u + \gamma_u * \tau elements. + * + * @param[out] t - the integer corresponding to \tau. + * @param[out] beta - the first coefficients of the constants. + * @param[out] gama - the second coefficients of the constants. + * @param[in] u - the u curve parameter. + * @param[in] w - the window size in bits. + */ +void bn_rec_tnaf_get(uint8_t *t, int8_t *beta, int8_t *gama, int8_t u, int w); + +/** + * Computes the partial reduction k partmod d = r0 + r1 * t, where + * d = (t^m - 1)/(t - 1). + * + * @param[out] r0 - the first half of the result. + * @param[out] r1 - the second half of the result. + * @param[in] k - the number to reduce. + * @param[in] u - the u curve parameter. + * @param[in] m - the extension degree of the binary field. + */ +void bn_rec_tnaf_mod(bn_t r0, bn_t r1, const bn_t k, int u, int m); + +/** + * Recodes a positive integer in regular fixed-length width-w NAF. If a negative + * integer is given instead, its absolute value is taken. + * + * @param[out] naf - the recoded integer. + * @param[out] len - the number of bytes written. + * @param[in] k - the integer to recode. + * @param[in] n - the length of the recoding. + * @param[in] w - the window size in bits. + * @throw ERR_NO_BUFFER - if the buffer capacity is insufficient. + */ +void bn_rec_reg(int8_t *naf, int *len, const bn_t k, int n, int w); + +/** + * Recodes of a pair of positive integers in Joint Sparse Form. If negative + * integers are given instead, takes their absolute value. + * + * @param[out] jsf - the recoded pair of integers. + * @param[out] len - the number of bytes written. + * @param[in] k - the first integer to recode. + * @param[in] l - the second integer to recode. + * @throw ERR_NO_BUFFER - if the buffer capacity is insufficient. + */ +void bn_rec_jsf(int8_t *jsf, int *len, const bn_t k, const bn_t l); + +/** + * Recodes a positive integer into two parts k0,k1 such that k = k0 + phi(k1), + * where phi is an efficient curve endomorphism. If a negative integer is + * given instead, its absolute value is taken. + * + * @param[out] k0 - the first part of the result. + * @param[out] k1 - the second part of the result. + * @param[in] k - the integer to recode. + * @param[in] n - the group order. + * @param[in] v1 - the set of parameters v1 for the GLV method. + * @param[in] v2 - the set of parameters v2 for the GLV method. + */ +void bn_rec_glv(bn_t k0, bn_t k1, const bn_t k, const bn_t n, const bn_t v1[], + const bn_t v2[]); + +#endif /* !RLC_BN_H */ diff --git a/bls/contrib/relic/include/relic_conf.h.in b/bls/contrib/relic/include/relic_conf.h.in new file mode 100644 index 00000000..b9ef38d8 --- /dev/null +++ b/bls/contrib/relic/include/relic_conf.h.in @@ -0,0 +1,722 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @file + * + * Project configuration. + * + * @version $Id: relic_conf.h.in 45 2009-07-04 23:45:48Z dfaranha $ + * @ingroup relic + */ + +#ifndef RLC_CONF_H +#define RLC_CONF_H + +/** Project version. */ +#define RLC_VERSION "@VERSION@" + +/** Debugging support. */ +#cmakedefine DEBUG +/** Profiling support. */ +#cmakedefine PROFL +/** Error handling support. */ +#cmakedefine CHECK +/** Verbose error messages. */ +#cmakedefine VERBS +/** Build with overhead estimation. */ +#cmakedefine OVERH +/** Build documentation. */ +#cmakedefine DOCUM +/** Build only the selected algorithms. */ +#cmakedefine STRIP +/** Build with printing disabled. */ +#cmakedefine QUIET +/** Build with colored output. */ +#cmakedefine COLOR +/** Build with big-endian support. */ +#cmakedefine BIGED +/** Build shared library. */ +#cmakedefine SHLIB +/** Build static library. */ +#cmakedefine STLIB + +/** Number of times each test is ran. */ +#define TESTS @TESTS@ +/** Number of times each benchmark is ran. */ +#define BENCH @BENCH@ + +/** Number of available cores. */ +#define CORES @CORES@ + +/** Atmel AVR ATMega128 8-bit architecture. */ +#define AVR 1 +/** MSP430 16-bit architecture. */ +#define MSP 2 +/** ARM 32-bit architecture. */ +#define ARM 3 +/** Intel x86-compatible 32-bit architecture. */ +#define X86 4 +/** AMD64-compatible 64-bit architecture. */ +#define X64 5 +/** Architecture. */ +#cmakedefine ARCH @ARCH@ + +/** Size of word in this architecture. */ +#define WSIZE @WSIZE@ + +/** Byte boundary to align digit vectors. */ +#define ALIGN @ALIGN@ + +/** Build multiple precision integer module. */ +#cmakedefine WITH_BN +/** Build prime field module. */ +#cmakedefine WITH_FP +/** Build prime field extension module. */ +#cmakedefine WITH_FPX +/** Build binary field module. */ +#cmakedefine WITH_FB +/** Build prime elliptic curve module. */ +#cmakedefine WITH_EP +/** Build prime field extension elliptic curve module. */ +#cmakedefine WITH_EPX +/** Build binary elliptic curve module. */ +#cmakedefine WITH_EB +/** Build elliptic Edwards curve module. */ +#cmakedefine WITH_ED +/** Build elliptic curve cryptography module. */ +#cmakedefine WITH_EC +/** Build pairings over prime curves module. */ +#cmakedefine WITH_PP +/** Build pairing-based cryptography module. */ +#cmakedefine WITH_PC +/** Build block ciphers. */ +#cmakedefine WITH_BC +/** Build hash functions. */ +#cmakedefine WITH_MD +/** Build cryptographic protocols. */ +#cmakedefine WITH_CP + +/** Easy C-only backend. */ +#define EASY 1 +/** GMP backend. */ +#define GMP 2 +/** Arithmetic backend. */ +#define ARITH @ARITH@ + +/** Required precision in bits. */ +#define BN_PRECI @BN_PRECI@ +/** A multiple precision integer can store w words. */ +#define SINGLE 0 +/** A multiple precision integer can store the result of an addition. */ +#define CARRY 1 +/** A multiple precision integer can store the result of a multiplication. */ +#define DOUBLE 2 +/** Effective size of a multiple precision integer. */ +#define BN_MAGNI @BN_MAGNI@ +/** Number of Karatsuba steps. */ +#define BN_KARAT @BN_KARAT@ + +/** Schoolbook multiplication. */ +#define BASIC 1 +/** Comba multiplication. */ +#define COMBA 2 +/** Chosen multiple precision multiplication method. */ +#define BN_MUL @BN_MUL@ + +/** Schoolbook squaring. */ +#define BASIC 1 +/** Comba squaring. */ +#define COMBA 2 +/** Reuse multiplication for squaring. */ +#define MULTP 4 +/** Chosen multiple precision multiplication method. */ +#define BN_SQR @BN_SQR@ + +/** Division modular reduction. */ +#define BASIC 1 +/** Barrett modular reduction. */ +#define BARRT 2 +/** Montgomery modular reduction. */ +#define MONTY 3 +/** Pseudo-Mersenne modular reduction. */ +#define PMERS 4 +/** Chosen multiple precision modular reduction method. */ +#define BN_MOD @BN_MOD@ + +/** Binary modular exponentiation. */ +#define BASIC 1 +/** Sliding window modular exponentiation. */ +#define SLIDE 2 +/** Montgomery powering ladder. */ +#define MONTY 3 +/** Chosen multiple precision modular exponentiation method. */ +#define BN_MXP @BN_MXP@ + +/** Basic Euclidean GCD Algorithm. */ +#define BASIC 1 +/** Lehmer's fast GCD Algorithm. */ +#define LEHME 2 +/** Stein's binary GCD Algorithm. */ +#define STEIN 3 +/** Chosen multiple precision greatest common divisor method. */ +#define BN_GCD @BN_GCD@ + +/** Basic prime generation. */ +#define BASIC 1 +/** Safe prime generation. */ +#define SAFEP 2 +/** Strong prime generation. */ +#define STRON 3 +/** Chosen prime generation algorithm. */ +#define BN_GEN @BN_GEN@ + +/** Multiple precision arithmetic method */ +#define BN_METHD "@BN_METHD@" + +/** Prime field size in bits. */ +#define FP_PRIME @FP_PRIME@ +/** Number of Karatsuba steps. */ +#define FP_KARAT @FP_KARAT@ +/** Prefer Pseudo-Mersenne primes over random primes. */ +#cmakedefine FP_PMERS +/** Use -1 as quadratic non-residue. */ +#cmakedefine FP_QNRES +/** Width of window processing for exponentiation methods. */ +#define FP_WIDTH @FP_WIDTH@ + +/** Schoolbook addition. */ +#define BASIC 1 +/** Integrated modular addtion. */ +#define INTEG 3 +/** Chosen prime field multiplication method. */ +#define FP_ADD @FP_ADD@ + +/** Schoolbook multiplication. */ +#define BASIC 1 +/** Comba multiplication. */ +#define COMBA 2 +/** Integrated modular multiplication. */ +#define INTEG 3 +/** Chosen prime field multiplication method. */ +#define FP_MUL @FP_MUL@ + +/** Schoolbook squaring. */ +#define BASIC 1 +/** Comba squaring. */ +#define COMBA 2 +/** Integrated modular squaring. */ +#define INTEG 3 +/** Reuse multiplication for squaring. */ +#define MULTP 4 +/** Chosen prime field multiplication method. */ +#define FP_SQR @FP_SQR@ + +/** Division-based reduction. */ +#define BASIC 1 +/** Fast reduction modulo special form prime. */ +#define QUICK 2 +/** Montgomery modular reduction. */ +#define MONTY 3 +/** Chosen prime field reduction method. */ +#define FP_RDC @FP_RDC@ + +/** Inversion by Fermat's Little Theorem. */ +#define BASIC 1 +/** Binary inversion. */ +#define BINAR 2 +/** Integrated modular multiplication. */ +#define MONTY 3 +/** Extended Euclidean algorithm. */ +#define EXGCD 4 +/** Constant-time inversion by Bernstein-Yang division steps. */ +#define DIVST 5 +/** Use implementation provided by the lower layer. */ +#define LOWER 8 +/** Chosen prime field inversion method. */ +#define FP_INV @FP_INV@ + +/** Binary modular exponentiation. */ +#define BASIC 1 +/** Sliding window modular exponentiation. */ +#define SLIDE 2 +/** Constant-time Montgomery powering ladder. */ +#define MONTY 3 +/** Chosen multiple precision modular exponentiation method. */ +#define FP_EXP @FP_EXP@ + +/** Prime field arithmetic method */ +#define FP_METHD "@FP_METHD@" + +/** Basic quadratic extension field arithmetic. */ +#define BASIC 1 +/** Integrated extension field arithmetic. */ +#define INTEG 3 +/* Chosen extension field arithmetic method. */ +#define FPX_QDR @FPX_QDR@ + +/** Basic cubic extension field arithmetic. */ +#define BASIC 1 +/** Integrated extension field arithmetic. */ +#define INTEG 3 +/* Chosen extension field arithmetic method. */ +#define FPX_CBC @FPX_CBC@ + +/** Basic quadratic extension field arithmetic. */ +#define BASIC 1 +/** Lazy-reduced extension field arithmetic. */ +#define LAZYR 2 +/* Chosen extension field arithmetic method. */ +#define FPX_RDC @FPX_RDC@ + +/** Prime extension field arithmetic method */ +#define FPX_METHD "@FPX_METHD@" + +/** Irreducible polynomial size in bits. */ +#define FB_POLYN @FB_POLYN@ +/** Number of Karatsuba steps. */ +#define FB_KARAT @FB_KARAT@ +/** Prefer trinomials over pentanomials. */ +#cmakedefine FB_TRINO +/** Prefer square-root friendly polynomials. */ +#cmakedefine FB_SQRTF +/** Precompute multiplication table for sqrt(z). */ +#cmakedefine FB_PRECO +/** Width of window processing for exponentiation methods. */ +#define FB_WIDTH @FB_WIDTH@ + +/** Shift-and-add multiplication. */ +#define BASIC 1 +/** Lopez-Dahab multiplication. */ +#define LODAH 2 +/** Integrated modular multiplication. */ +#define INTEG 3 +/** Chosen binary field multiplication method. */ +#define FB_MUL @FB_MUL@ + +/** Basic squaring. */ +#define BASIC 1 +/** Table-based squaring. */ +#define QUICK 2 +/** Integrated modular squaring. */ +#define INTEG 3 +/** Chosen binary field squaring method. */ +#define FB_SQR @FB_SQR@ + +/** Shift-and-add modular reduction. */ +#define BASIC 1 +/** Fast reduction modulo a trinomial or pentanomial. */ +#define QUICK 2 +/** Chosen binary field modular reduction method. */ +#define FB_RDC @FB_RDC@ + +/** Square root by repeated squaring. */ +#define BASIC 1 +/** Fast square root extraction. */ +#define QUICK 2 +/** Chosen binary field modular reduction method. */ +#define FB_SRT @FB_SRT@ + +/** Trace by repeated squaring. */ +#define BASIC 1 +/** Fast trace computation. */ +#define QUICK 2 +/** Chosen trace computation method. */ +#define FB_TRC @FB_TRC@ + +/** Solve by half-trace computation. */ +#define BASIC 1 +/** Solve with precomputed half-traces. */ +#define QUICK 2 +/** Chosen method to solve a quadratic equation. */ +#define FB_SLV @FB_SLV@ + +/** Inversion by Fermat's Little Theorem. */ +#define BASIC 1 +/** Binary inversion. */ +#define BINAR 2 +/** Almost inverse algorithm. */ +#define ALMOS 3 +/** Extended Euclidean algorithm. */ +#define EXGCD 4 +/** Itoh-Tsuji inversion. */ +#define ITOHT 5 +/** Hardware-friendly inversion by Brunner-Curiger-Hofstetter.*/ +#define BRUCH 6 +/** Constant-time version of almost inverse. */ +#define CTAIA 7 +/** Use implementation provided by the lower layer. */ +#define LOWER 8 +/** Chosen binary field inversion method. */ +#define FB_INV @FB_INV@ + +/** Binary modular exponentiation. */ +#define BASIC 1 +/** Sliding window modular exponentiation. */ +#define SLIDE 2 +/** Constant-time Montgomery powering ladder. */ +#define MONTY 3 +/** Chosen multiple precision modular exponentiation method. */ +#define FB_EXP @FB_EXP@ + +/** Iterated squaring/square-root by consecutive squaring/square-root. */ +#define BASIC 1 +/** Iterated squaring/square-root by table-based method. */ +#define QUICK 2 +/** Chosen method to solve a quadratic equation. */ +#define FB_ITR @FB_ITR@ + +/** Binary field arithmetic method */ +#define FB_METHD "@FB_METHD@" + +/** Support for ordinary curves. */ +#cmakedefine EP_PLAIN +/** Support for supersingular curves. */ +#cmakedefine EP_SUPER +/** Support for prime curves with efficient endormorphisms. */ +#cmakedefine EP_ENDOM +/** Use mixed coordinates. */ +#cmakedefine EP_MIXED +/** Build precomputation table for generator. */ +#cmakedefine EP_PRECO +/** Enable isogeny map for SSWU map-to-curve. */ +#cmakedefine EP_CTMAP +/** Width of precomputation table for fixed point methods. */ +#define EP_DEPTH @EP_DEPTH@ +/** Width of window processing for unknown point methods. */ +#define EP_WIDTH @EP_WIDTH@ + +/** Affine coordinates. */ +#define BASIC 1 +/** Projective coordinates. */ +#define PROJC 2 +/** Chosen prime elliptic curve coordinate method. */ +#define EP_ADD @EP_ADD@ + +/** Binary point multiplication. */ +#define BASIC 1 +/** Sliding window. */ +#define SLIDE 2 +/** Montgomery powering ladder. */ +#define MONTY 3 +/** Left-to-right Width-w NAF. */ +#define LWNAF 4 +/** Left-to-right Width-w NAF. */ +#define LWREG 5 +/** Chosen prime elliptic curve point multiplication method. */ +#define EP_MUL @EP_MUL@ + +/** Binary point multiplication. */ +#define BASIC 1 +/** Single-table comb method. */ +#define COMBS 2 +/** Double-table comb method. */ +#define COMBD 3 +/** Left-to-right Width-w NAF. */ +#define LWNAF 4 +/** Chosen prime elliptic curve point multiplication method. */ +#define EP_FIX @EP_FIX@ + +/** Basic simultaneouns point multiplication. */ +#define BASIC 1 +/** Shamir's trick. */ +#define TRICK 2 +/** Interleaving of w-(T)NAFs. */ +#define INTER 3 +/** Joint sparse form. */ +#define JOINT 4 +/** Chosen prime elliptic curve simulteanous point multiplication method. */ +#define EP_SIM @EP_SIM@ + +/** Prime elliptic curve arithmetic method. */ +#define EP_METHD "@EP_METHD@" + +/** Support for ordinary curves without endormorphisms. */ +#cmakedefine EB_PLAIN +/** Support for Koblitz anomalous binary curves. */ +#cmakedefine EB_KBLTZ +/** Use mixed coordinates. */ +#cmakedefine EB_MIXED +/** Build precomputation table for generator. */ +#cmakedefine EB_PRECO +/** Width of precomputation table for fixed point methods. */ +#define EB_DEPTH @EB_DEPTH@ +/** Width of window processing for unknown point methods. */ +#define EB_WIDTH @EB_WIDTH@ + +/** Binary elliptic curve arithmetic method. */ +#define EB_METHD "@EB_METHD@" + +/** Affine coordinates. */ +#define BASIC 1 +/** López-Dahab Projective coordinates. */ +#define PROJC 2 +/** Chosen binary elliptic curve coordinate method. */ +#define EB_ADD @EB_ADD@ + +/** Binary point multiplication. */ +#define BASIC 1 +/** López-Dahab point multiplication. */ +#define LODAH 2 +/** Halving. */ +#define HALVE 3 +/** Left-to-right width-w (T)NAF. */ +#define LWNAF 4 +/** Right-to-left width-w (T)NAF. */ +#define RWNAF 5 +/** Chosen binary elliptic curve point multiplication method. */ +#define EB_MUL @EB_MUL@ + +/** Binary point multiplication. */ +#define BASIC 1 +/** Single-table comb method. */ +#define COMBS 2 +/** Double-table comb method. */ +#define COMBD 3 +/** Left-to-right Width-w NAF. */ +#define LWNAF 4 +/** Chosen binary elliptic curve point multiplication method. */ +#define EB_FIX @EB_FIX@ + +/** Basic simultaneouns point multiplication. */ +#define BASIC 1 +/** Shamir's trick. */ +#define TRICK 2 +/** Interleaving of w-(T)NAFs. */ +#define INTER 3 +/** Joint sparse form. */ +#define JOINT 4 +/** Chosen binary elliptic curve simulteanous point multiplication method. */ +#define EB_SIM @EB_SIM@ + +/** Build precomputation table for generator. */ +#cmakedefine ED_PRECO +/** Width of precomputation table for fixed point methods. */ +#define ED_DEPTH @ED_DEPTH@ +/** Width of window processing for unknown point methods. */ +#define ED_WIDTH @ED_WIDTH@ + +/** Edwards elliptic curve arithmetic method. */ +#define ED_METHD "@ED_METHD@" + +/** Affine coordinates. */ +#define BASIC 1 +/** Simple projective twisted Edwards coordinates */ +#define PROJC 2 +/** Extended projective twisted Edwards coordinates */ +#define EXTND 3 +/** Chosen binary elliptic curve coordinate method. */ +#define ED_ADD @ED_ADD@ + +/** Binary point multiplication. */ +#define BASIC 1 +/** Sliding window. */ +#define SLIDE 2 +/** Montgomery powering ladder. */ +#define MONTY 3 +/** Left-to-right Width-w NAF. */ +#define LWNAF 4 +/** Left-to-right Width-w NAF. */ +#define LWREG 5 +/** Chosen prime elliptic twisted Edwards curve point multiplication method. */ +#define ED_MUL @ED_MUL@ + +/** Binary point multiplication. */ +#define BASIC 1 +/** Single-table comb method. */ +#define COMBS 2 +/** Double-table comb method. */ +#define COMBD 3 +/** Left-to-right Width-w NAF. */ +#define LWNAF 4 +/** Chosen prime elliptic twisted Edwards curve point multiplication method. */ +#define ED_FIX @ED_FIX@ + +/** Basic simultaneouns point multiplication. */ +#define BASIC 1 +/** Shamir's trick. */ +#define TRICK 2 +/** Interleaving of w-(T)NAFs. */ +#define INTER 3 +/** Joint sparse form. */ +#define JOINT 4 +/** Chosen prime elliptic curve simulteanous point multiplication method. */ +#define ED_SIM @ED_SIM@ + +/** Prime curves. */ +#define PRIME 1 +/** Binary curves. */ +#define CHAR2 2 +/** Edwards curves */ +#define EDDIE 3 +/** Chosen elliptic curve type. */ +#define EC_CUR @EC_CUR@ + +/** Chosen elliptic curve cryptography method. */ +#define EC_METHD "@EC_METHD@" +/** Prefer curves with efficient endomorphisms. */ +#cmakedefine EC_ENDOM + +/** Basic quadratic extension field arithmetic. */ +#define BASIC 1 +/** Lazy-reduced extension field arithmetic. */ +#define LAZYR 2 +/* Chosen extension field arithmetic method. */ +#define PP_EXT @PP_EXT@ + +/** Bilinear pairing method. */ +#define PP_METHD "@PP_METHD@" + +/** Tate pairing. */ +#define TATEP 1 +/** Weil pairing. */ +#define WEILP 2 +/** Optimal ate pairing. */ +#define OATEP 3 +/** Chosen pairing method over prime elliptic curves. */ +#define PP_MAP @PP_MAP@ + +/** SHA-224 hash function. */ +#define SH224 2 +/** SHA-256 hash function. */ +#define SH256 3 +/** SHA-384 hash function. */ +#define SH384 4 +/** SHA-512 hash function. */ +#define SH512 5 +/** BLAKE2s-160 hash function. */ +#define B2S160 6 +/** BLAKE2s-256 hash function. */ +#define B2S256 7 +/** Chosen hash function. */ +#define MD_MAP @MD_MAP@ + +/** Choice of hash function. */ +#define MD_METHD "@MD_METHD@" + +/** RSA without padding. */ +#define BASIC 1 +/** RSA PKCS#1 v1.5 padding. */ +#define PKCS1 2 +/** RSA PKCS#1 v2.1 padding. */ +#define PKCS2 3 +/** Chosen RSA padding method. */ +#define CP_RSAPD @CP_RSAPD@ + +/** Slow RSA decryption/signature. */ +#define BASIC 1 +/** Fast RSA decryption/signature with CRT. */ +#define QUICK 2 +/** Chosen RSA method. */ +#define CP_RSA @CP_RSA@ + +/** Standard ECDSA. */ +#define BASIC 1 +/** ECDSA with fast verification. */ +#define QUICK 2 +/** Chosen ECDSA method. */ +#define CP_ECDSA @CP_ECDSA@ + +/** Automatic memory allocation. */ +#define AUTO 1 +/** Dynamic memory allocation. */ +#define DYNAMIC 2 +/** Stack memory allocation. */ +#define STACK 3 +/** Chosen memory allocation policy. */ +#define ALLOC @ALLOC@ + +/** NIST HASH-DRBG generator. */ +#define HASHD 1 +/** Intel RdRand instruction. */ +#define RDRND 2 +/** Operating system underlying generator. */ +#define UDEV 3 +/** Override library generator with the callback. */ +#define CALL 4 +/** Chosen random generator. */ +#define RAND @RAND@ + +/** Standard C library generator. */ +#define LIBC 1 +/** Intel RdRand instruction. */ +#define RDRND 2 +/** Device node generator. */ +#define UDEV 3 +/** Use Windows' CryptGenRandom. */ +#define WCGR 4 +/** Chosen random generator seeder. */ +#cmakedefine SEED @SEED@ + +/** GNU/Linux operating system. */ +#define LINUX 1 +/** FreeBSD operating system. */ +#define FREEBSD 2 +/** Windows operating system. */ +#define MACOSX 3 +/** Windows operating system. */ +#define WINDOWS 4 +/** Android operating system. */ +#define DROID 5 +/* Arduino platform. */ +#define DUINO 6 +/** Detected operation system. */ +#cmakedefine OPSYS @OPSYS@ + +/** OpenMP multithreading support. */ +#define OPENMP 1 +/** POSIX multithreading support. */ +#define PTHREAD 2 +/** Chosen multithreading API. */ +#cmakedefine MULTI @MULTI@ + +/** Per-process high-resolution timer. */ +#define HREAL 1 +/** Per-process high-resolution timer. */ +#define HPROC 2 +/** Per-thread high-resolution timer. */ +#define HTHRD 3 +/** POSIX-compatible timer. */ +#define POSIX 4 +/** ANSI-compatible timer. */ +#define ANSI 5 +/** Cycle-counting timer. */ +#define CYCLE 6 +/** Chosen timer. */ +#cmakedefine TIMER @TIMER@ + +/** Prefix to identity this build of the library. */ +#cmakedefine LABEL @LABEL@ + +#ifndef ASM + +#include "relic_label.h" + +/** + * Prints the project options selected at build time. + */ +void conf_print(void); + +#endif /* ASM */ + +#endif /* !RLC_CONF_H */ diff --git a/bls/contrib/relic/include/relic_core.h b/bls/contrib/relic/include/relic_core.h new file mode 100644 index 00000000..4a0fa488 --- /dev/null +++ b/bls/contrib/relic/include/relic_core.h @@ -0,0 +1,464 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @defgroup relic Core functions + */ + +/** + * @file + * + * Interface of the library core functions. + * + * @ingroup relic + */ + +#ifndef RLC_CORE_H +#define RLC_CORE_H + +#include +#include +#include +#include + +#include "relic_err.h" +#include "relic_bn.h" +#include "relic_eb.h" +#include "relic_epx.h" +#include "relic_ed.h" +#include "relic_conf.h" +#include "relic_bench.h" +#include "relic_rand.h" +#include "relic_label.h" +#include "relic_alloc.h" + +#if defined(MULTI) +#include +#if MULTI == OPENMP +#include +#elif MULTI == PTHREAD +#include +#endif /* OPENMP */ +#endif /* MULTI */ + +/*============================================================================*/ +/* Constant definitions */ +/*============================================================================*/ + +/** + * Indicates that the function executed correctly. + */ +#define RLC_OK 0 + +/** + * Indicates that an error occurred during the function execution. + */ +#define RLC_ERR 1 + +/** + * Indicates that a comparison returned that the first argument was lesser than + * the second argument. + */ +#define RLC_LT -1 + +/** + * Indicates that a comparison returned that the first argument was equal to + * the second argument. + */ +#define RLC_EQ 0 + +/** + * Indicates that a comparison returned that the first argument was greater than + * the second argument. + */ +#define RLC_GT 1 + +/** + * Indicates that two incomparable elements are not equal. + */ +#define RLC_NE 2 + +/** + * Optimization identifer for the case where a coefficient is 0. + */ +#define RLC_ZERO 0 + +/** + * Optimization identifer for the case where a coefficient is 1. + */ +#define RLC_ONE 1 + +/** + * Optimization identifer for the case where a coefficient is 2. + */ +#define RLC_TWO 2 + +/** + * Optimization identifier for the case where a coefficient is -3. + */ +#define RLC_MIN3 3 + +/** + * Optimization identifer for the case where a coefficient is small. + */ +#define RLC_TINY 4 + +/** + * Optimization identifier for the case where the coefficient is arbitrary. + */ +#define RLC_HUGE 5 + +/** + * Maximum number of terms to describe a sparse object. + */ +#define RLC_TERMS 16 + +/*============================================================================*/ +/* Type definitions */ +/*============================================================================*/ + +/** + * Library context. + */ +typedef struct _ctx_t { + /** The value returned by the last call, can be RLC_OK or RLC_ERR. */ + int code; + +#ifdef CHECK + /** The state of the last error caught. */ + sts_t *last; + /** Error state to be used outside try-catch blocks. */ + sts_t error; + /** Error number to be used outside try-catch blocks. */ + err_t number; + /** The error message respective to the last error. */ + char *reason[ERR_MAX]; + /** A flag to indicate if the last error was already caught. */ + int caught; +#endif /* CHECK */ + +#ifdef WITH_FB + /** Identifier of the currently configured binary field. */ + int fb_id; + /** Irreducible binary polynomial. */ + fb_st fb_poly; + /** Non-zero coefficients of a trinomial or pentanomial. */ + int fb_pa, fb_pb, fb_pc; + /** Positions of the non-zero coefficients of trinomials or pentanomials. */ + int fb_na, fb_nb, fb_nc; +#if FB_TRC == QUICK || !defined(STRIP) + /** Powers of z with non-zero traces. */ + int fb_ta, fb_tb, fb_tc; +#endif /* FB_TRC == QUICK */ +#if FB_SLV == QUICK || !defined(STRIP) + /** Table of precomputed half-traces. */ + fb_st fb_half[(RLC_DIG / 8 + 1) * RLC_FB_DIGS][16]; +#endif /* FB_SLV == QUICK */ +#if FB_SRT == QUICK || !defined(STRIP) + /** Square root of z. */ + fb_st fb_srz; +#ifdef FB_PRECO + /** Multiplication table for the z^(1/2). */ + fb_st fb_tab_srz[256]; +#endif /* FB_PRECO */ +#endif /* FB_SRT == QUICK */ +#if FB_INV == ITOHT || !defined(STRIP) + /** Stores an addition chain for (RLC_FB_BITS - 1). */ + int chain[RLC_TERMS + 1]; + /** Stores the length of the addition chain. */ + int chain_len; + /** Tables for repeated squarings. */ + fb_st fb_tab_sqr[RLC_TERMS][RLC_FB_TABLE]; + /** Pointers to the elements in the tables of repeated squarings. */ + fb_st *fb_tab_ptr[RLC_TERMS][RLC_FB_TABLE]; +#endif /* FB_INV == ITOHT */ +#endif /* WITH_FB */ + +#ifdef WITH_EB + /** Identifier of the currently configured binary elliptic curve. */ + int eb_id; + /** The 'a' coefficient of the elliptic curve. */ + fb_st eb_a; + /** The 'b' coefficient of the elliptic curve. */ + fb_st eb_b; + /** Optimization identifier for the 'a' coefficient. */ + int eb_opt_a; + /** Optimization identifier for the 'b' coefficient. */ + int eb_opt_b; + /** The generator of the elliptic curve. */ + eb_st eb_g; + /** The order of the group of points in the elliptic curve. */ + bn_st eb_r; + /** The cofactor of the group order in the elliptic curve. */ + bn_st eb_h; + /** Flag that stores if the binary curve has efficient endomorphisms. */ + int eb_is_kbltz; +#ifdef EB_PRECO + /** Precomputation table for generator multiplication. */ + eb_st eb_pre[RLC_EB_TABLE]; + /** Array of pointers to the precomputation table. */ + eb_st *eb_ptr[RLC_EB_TABLE]; +#endif /* EB_PRECO */ +#endif /* WITH_EB */ + +#ifdef WITH_FP + /** Identifier of the currently configured prime field. */ + int fp_id; + /** Prime modulus. */ + bn_st prime; + /** Parameter for generating prime. */ + bn_st par; + /** Parameter in sparse form. */ + int par_sps[RLC_TERMS + 1]; + /** Length of sparse prime representation. */ + int par_len; +#if FP_RDC == MONTY || !defined(STRIP) + /** Value (R^2 mod p) for converting small integers to Montgomery form. */ + bn_st conv; + /** Value of constant one in Montgomery form. */ + bn_st one; +#endif /* FP_RDC == MONTY */ + /** Prime modulus modulo 8. */ + dig_t mod8; + /** Value derived from the prime used for modular reduction. */ + dig_t u; + /** Quadratic non-residue. */ + int qnr; + /** Cubic non-residue. */ + int cnr; + /** 2-adicity. */ + int ad2; +#if FP_RDC == QUICK || !defined(STRIP) + /** Sparse representation of prime modulus. */ + int sps[RLC_TERMS + 1]; + /** Length of sparse prime representation. */ + int sps_len; +#endif /* FP_RDC == QUICK */ +#endif /* WITH_FP */ + +#ifdef WITH_EP + /** Identifier of the currently configured prime elliptic curve. */ + int ep_id; + /** The 'a' coefficient of the elliptic curve. */ + fp_st ep_a; + /** The 'b' coefficient of the elliptic curve. */ + fp_st ep_b; + /** The generator of the elliptic curve. */ + ep_st ep_g; + /** The order of the group of points in the elliptic curve. */ + bn_st ep_r; + /** The cofactor of the group order in the elliptic curve. */ + bn_st ep_h; + /** The distinguished non-square used by the mapping function */ + fp_st ep_map_u; + /** Precomputed constants for hashing. */ + fp_st ep_map_c[4]; +#ifdef EP_ENDOM +#if EP_MUL == LWNAF || EP_FIX == COMBS || EP_FIX == LWNAF || EP_SIM == INTER || !defined(STRIP) + /** Parameters required by the GLV method. @{ */ + fp_st beta; + bn_st ep_v1[3]; + bn_st ep_v2[3]; + /** @} */ +#endif /* EP_MUL */ +#endif /* EP_ENDOM */ + /** Optimization identifier for the a-coefficient. */ + int ep_opt_a; + /** Optimization identifier for the b-coefficient. */ + int ep_opt_b; + /** Flag that stores if the prime curve has efficient endomorphisms. */ + int ep_is_endom; + /** Flag that stores if the prime curve is supersingular. */ + int ep_is_super; + /** Flag that stores if the prime curve is pairing-friendly. */ + int ep_is_pairf; + /** Flag that indicates whether this curve uses an isogeny for the SSWU mapping. */ + int ep_is_ctmap; +#ifdef EP_PRECO + /** Precomputation table for generator multiplication. */ + ep_st ep_pre[RLC_EP_TABLE]; + /** Array of pointers to the precomputation table. */ + ep_st *ep_ptr[RLC_EP_TABLE]; +#endif /* EP_PRECO */ +#ifdef EP_CTMAP + /** The isogeny map coefficients for the SSWU mapping. */ + iso_st ep_iso; +#endif /* EP_CTMAP */ +#endif /* WITH_EP */ + +#ifdef WITH_EPX + /** The generator of the elliptic curve. */ + ep2_t ep2_g; + /** The 'a' coefficient of the curve. */ + fp2_t ep2_a; + /** The 'b' coefficient of the curve. */ + fp2_t ep2_b; + /** The order of the group of points in the elliptic curve. */ + bn_st ep2_r; + /** The cofactor of the group order in the elliptic curve. */ + bn_st ep2_h; + /** sqrt(-3) in the field for this curve */ + bn_st ep2_s3; + /** (sqrt(-3) - 1) / 2 in the field for this curve */ + bn_st ep2_s32; + /** The distinguished non-square used by the mapping function */ + fp2_t ep2_map_u; + /** The constants needed for hashing. */ + fp2_t ep2_map_c[4]; + /** Optimization identifier for the a-coefficient. */ + int ep2_opt_a; + /** Optimization identifier for the b-coefficient. */ + int ep2_opt_b; + /** Flag that stores if the prime curve is a twist. */ + int ep2_is_twist; + /** Flag that indicates whether this curve uses an isogeny for the SSWU mapping. */ + int ep2_is_ctmap; +#ifdef EP_PRECO + /** Precomputation table for generator multiplication.*/ + ep2_st ep2_pre[RLC_EP_TABLE]; + /** Array of pointers to the precomputation table. */ + ep2_st *ep2_ptr[RLC_EP_TABLE]; +#endif /* EP_PRECO */ +#if ALLOC == STACK + /** In case of stack allocation, we need to get global memory for the table. */ + fp2_st _ep2_pre[3 * RLC_EP_TABLE]; + /** In case of stack allocation, storage for the EPX constants. */ + ep2_st _ep2_g; + /* 3 for ep2_g, plus ep2_a, ep2_b, ep2_map_u, and ep2_map_c[4] */ + fp2_st _ep2_storage[10]; +#endif /* ALLOC == STACK */ +#ifdef EP_CTMAP + /** The isogeny map coefficients for the SSWU mapping. */ + iso2_st ep2_iso; +#endif /* EP_CTMAP */ +#endif /* WITH_EPX */ + +#ifdef WITH_ED + /** Identifier of the currently configured Edwards elliptic curve. */ + int ed_id; + /** The 'a' coefficient of the Edwards elliptic curve. */ + fp_st ed_a; + /** The 'd' coefficient of the Edwards elliptic curve. */ + fp_st ed_d; + /** The square root of -1 needed for hashing. */ + fp_st srm1; + /** The generator of the Edwards elliptic curve. */ + ed_st ed_g; + /** The order of the group of points in the Edwards elliptic curve. */ + bn_st ed_r; + /** The cofactor of the Edwards elliptic curve. */ + bn_st ed_h; + +#ifdef ED_PRECO + /** Precomputation table for generator multiplication. */ + ed_st ed_pre[RLC_ED_TABLE]; + /** Array of pointers to the precomputation table. */ + ed_st *ed_ptr[RLC_ED_TABLE]; +#endif /* ED_PRECO */ +#endif + +#if defined(WITH_FPX) || defined(WITH_PP) + /** Integer part of the quadratic non-residue. */ + int qnr2; + /** Constants for computing Frobenius maps in higher extensions. @{ */ + fp2_st fp2_p1[5]; + fp2_st fp2_p2[3]; + /** @} */ + /** Constants for computing Frobenius maps in higher extensions. @{ */ + int frb3[3]; + fp_st fp3_p0[2]; + fp_st fp3_p1[5]; + fp_st fp3_p2[2]; + /** @} */ +#endif /* WITH_PP */ + +#if BENCH > 0 + /** Stores the time measured before the execution of the benchmark. */ + bench_t before; + /** Stores the time measured after the execution of the benchmark. */ + bench_t after; + /** Stores the sum of timings for the current benchmark. */ + long long total; +#ifdef OVERH + /** Benchmarking overhead to be measured and subtracted from benchmarks. */ + long long over; +#endif +#endif + +#if RAND != CALL + /** Internal state of the PRNG. */ + uint8_t rand[RAND_SIZE]; +#else + void (*rand_call)(uint8_t *, int, void *); + void *rand_args; +#endif + /** Flag to indicate if PRNG is seed. */ + int seeded; + /** Counter to keep track of number of calls since last seeding. */ + int counter; +} ctx_t; + +/*============================================================================*/ +/* Function prototypes */ +/*============================================================================*/ + +/** + * Initializes the library. + * + * @return RLC_OK if no error occurs, RLC_ERR otherwise. + */ +int core_init(void); + +/** + * Finalizes the library. + * + * @return RLC_OK if no error occurs, RLC_ERR otherwise. + */ +int core_clean(void); + +/** + * Returns a pointer to the current library context. + * + * @return a pointer to the library context. + */ +ctx_t *core_get(void); + +/** + * Switched the library context to a new context. + * + * @param[in] ctx - the new library context. + */ +void core_set(ctx_t *ctx); + +#if MULTI != RELIC_NONE +/** + * Set an initializer function which is called when the context + * is uninitialized. This function is called for every thread. + * + * @param[in] init function to call when the current context is not initialized + * @param[in] init_ptr a pointer which is passed to the initialized + */ +void core_set_thread_initializer(void(*init)(void *init_ptr), void* init_ptr); +#endif + +#endif /* !RLC_CORE_H */ diff --git a/bls/contrib/relic/include/relic_cp.h b/bls/contrib/relic/include/relic_cp.h new file mode 100644 index 00000000..5cb3aad3 --- /dev/null +++ b/bls/contrib/relic/include/relic_cp.h @@ -0,0 +1,1751 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @defgroup cp Cryptographic protocols + */ + +/** + * @file + * + * Interface of cryptographic protocols. + * + * @ingroup bn + */ + +#ifndef RLC_CP_H +#define RLC_CP_H + +#include "relic_conf.h" +#include "relic_types.h" +#include "relic_bn.h" +#include "relic_ec.h" +#include "relic_pc.h" + +/*============================================================================*/ +/* Type definitions. */ +/*============================================================================*/ + +/** + * Represents an RSA key pair. + */ +typedef struct _rsa_t { + /** The modulus n = pq. */ + bn_t n; + /** The public exponent. */ + bn_t e; + /** The private exponent. */ + bn_t d; + /** The first prime p. */ + bn_t p; + /** The second prime q. */ + bn_t q; + /** The inverse of e modulo (p-1). */ + bn_t dp; + /** The inverse of e modulo (q-1). */ + bn_t dq; + /** The inverse of q modulo p. */ + bn_t qi; +} relic_rsa_st; + +/** + * Pointer to an RSA key pair. + */ +#if ALLOC == AUTO +typedef relic_rsa_st rsa_t[1]; +#else +typedef relic_rsa_st *rsa_t; +#endif + +/** + * Represents a Rabin key pair. + */ +typedef struct _rabin_t { + /** The modulus n = pq. */ + bn_t n; + /** The first prime p. */ + bn_t p; + /** The second prime q. */ + bn_t q; + /** The cofactor of the first prime. */ + bn_t dp; + /** The cofactor of the second prime. */ + bn_t dq; +} rabin_st; + +/** + * Pointer to a Rabin key pair. + */ +#if ALLOC == AUTO +typedef rabin_st rabin_t[1]; +#else +typedef rabin_st *rabin_t; +#endif + +/** + * Represents a Benaloh's Dense Probabilistic Encryption key pair. + */ +typedef struct _bdpe_t { + /** The modulus n = pq. */ + bn_t n; + /** The first prime p. */ + bn_t p; + /** The second prime q. */ + bn_t q; + /** The random element in {0, ..., n - 1}. */ + bn_t y; + /** The divisor of (p-1) such that gcd(t, (p-1)/t) = gcd(t, q-1) = 1. */ + dig_t t; +} bdpe_st; + +/** + * Pointer to a Benaloh's Dense Probabilistic Encryption key pair. + */ +#if ALLOC == AUTO +typedef bdpe_st bdpe_t[1]; +#else +typedef bdpe_st *bdpe_t; +#endif + +/** + * Represents a SOKAKA key pair. + */ +typedef struct _sokaka { + /** The private key in G_1. */ + g1_t s1; + /** The private key in G_2. */ + g2_t s2; +} sokaka_st; + +/** + * Pointer to SOKAKA key pair. + */ +#if ALLOC == AUTO +typedef sokaka_st sokaka_t[1]; +#else +typedef sokaka_st *sokaka_t; +#endif + +/** + * Represents a Boneh-Goh-Nissim cryptosystem key pair. + */ +typedef struct _bgn_t { + /** The first exponent. */ + bn_t x; + /** The second exponent. */ + bn_t y; + /** The third exponent. */ + bn_t z; + /* The first element from the first group. */ + g1_t gx; + /* The second element from the first group. */ + g1_t gy; + /* The thirs element from the first group. */ + g1_t gz; + /* The first element from the second group. */ + g2_t hx; + /* The second element from the second group. */ + g2_t hy; + /* The third element from the second group. */ + g2_t hz; +} bgn_st; + +/** + * Pointer to a a Boneh-Goh-Nissim cryptosystem key pair. + */ +#if ALLOC == AUTO +typedef bgn_st bgn_t[1]; +#else +typedef bgn_st *bgn_t; +#endif + +/*============================================================================*/ +/* Macro definitions */ +/*============================================================================*/ + +/** + * Initializes an RSA key pair with a null value. + * + * @param[out] A - the key pair to initialize. + */ +#if ALLOC == AUTO +#define rsa_null(A) /* empty */ +#else +#define rsa_null(A) A = NULL; +#endif + +/** + * Calls a function to allocate and initialize an RSA key pair. + * + * @param[out] A - the new key pair. + */ +#if ALLOC == DYNAMIC +#define rsa_new(A) \ + A = (rsa_t)calloc(1, sizeof(relic_rsa_st)); \ + if (A == NULL) { \ + THROW(ERR_NO_MEMORY); \ + } \ + bn_null((A)->e); \ + bn_null((A)->n); \ + bn_null((A)->d); \ + bn_null((A)->dp); \ + bn_null((A)->dq); \ + bn_null((A)->p); \ + bn_null((A)->q); \ + bn_null((A)->qi); \ + bn_new((A)->e); \ + bn_new((A)->n); \ + bn_new((A)->d); \ + bn_new((A)->dp); \ + bn_new((A)->dq); \ + bn_new((A)->p); \ + bn_new((A)->q); \ + bn_new((A)->qi); \ + +#elif ALLOC == AUTO +#define rsa_new(A) \ + bn_new((A)->e); \ + bn_new((A)->n); \ + bn_new((A)->d); \ + bn_new((A)->dp); \ + bn_new((A)->dq); \ + bn_new((A)->p); \ + bn_new((A)->q); \ + bn_new((A)->qi); \ + +#elif ALLOC == STACK +#define rsa_new(A) \ + A = (rsa_t)alloca(sizeof(relic_rsa_st)); \ + bn_new((A)->e); \ + bn_new((A)->n); \ + bn_new((A)->d); \ + bn_new((A)->dp); \ + bn_new((A)->dq); \ + bn_new((A)->p); \ + bn_new((A)->q); \ + bn_new((A)->qi); \ + +#endif + +/** + * Calls a function to clean and free an RSA key pair. + * + * @param[out] A - the key pair to clean and free. + */ +#if ALLOC == DYNAMIC +#define rsa_free(A) \ + if (A != NULL) { \ + bn_free((A)->e); \ + bn_free((A)->n); \ + bn_free((A)->d); \ + bn_free((A)->dp); \ + bn_free((A)->dq); \ + bn_free((A)->p); \ + bn_free((A)->q); \ + bn_free((A)->qi); \ + free(A); \ + A = NULL; \ + } + +#elif ALLOC == AUTO +#define rsa_free(A) /* empty */ + +#elif ALLOC == STACK +#define rsa_free(A) \ + bn_free((A)->e); \ + bn_free((A)->n); \ + bn_free((A)->d); \ + bn_free((A)->dp); \ + bn_free((A)->dq); \ + bn_free((A)->p); \ + bn_free((A)->q); \ + bn_free((A)->qi); \ + A = NULL; \ + +#endif + +/** + * Initializes a Rabin key pair with a null value. + * + * @param[out] A - the key pair to initialize. + */ +#if ALLOC == AUTO +#define rabin_null(A) /* empty */ +#else +#define rabin_null(A) A = NULL; +#endif + +/** + * Calls a function to allocate and initialize a Rabin key pair. + * + * @param[out] A - the new key pair. + */ +#if ALLOC == DYNAMIC +#define rabin_new(A) \ + A = (rabin_t)calloc(1, sizeof(rabin_st)); \ + if (A == NULL) { \ + THROW(ERR_NO_MEMORY); \ + } \ + bn_new((A)->n); \ + bn_new((A)->dp); \ + bn_new((A)->dq); \ + bn_new((A)->p); \ + bn_new((A)->q); \ + +#elif ALLOC == AUTO +#define rabin_new(A) \ + bn_new((A)->n); \ + bn_new((A)->dp); \ + bn_new((A)->dq); \ + bn_new((A)->p); \ + bn_new((A)->q); \ + +#elif ALLOC == STACK +#define rabin_new(A) \ + A = (rabin_t)alloca(sizeof(rabin_st)); \ + bn_new((A)->n); \ + bn_new((A)->dp); \ + bn_new((A)->dq); \ + bn_new((A)->p); \ + bn_new((A)->q); \ + +#endif + +/** + * Calls a function to clean and free a Rabin key pair. + * + * @param[out] A - the key pair to clean and free. + */ +#if ALLOC == DYNAMIC +#define rabin_free(A) \ + if (A != NULL) { \ + bn_free((A)->n); \ + bn_free((A)->dp); \ + bn_free((A)->dq); \ + bn_free((A)->p); \ + bn_free((A)->q); \ + free(A); \ + A = NULL; \ + } + +#elif ALLOC == AUTO +#define rabin_free(A) /* empty */ + +#elif ALLOC == STACK +#define rabin_free(A) \ + bn_free((A)->n); \ + bn_free((A)->dp); \ + bn_free((A)->dq); \ + bn_free((A)->p); \ + bn_free((A)->q); \ + A = NULL; \ + +#endif + +/** + * Initializes a Benaloh's key pair with a null value. + * + * @param[out] A - the key pair to initialize. + */ +#if ALLOC == AUTO +#define bdpe_null(A) /* empty */ +#else +#define bdpe_null(A) A = NULL; +#endif + +/** + * Calls a function to allocate and initialize a Benaloh's key pair. + * + * @param[out] A - the new key pair. + */ +#if ALLOC == DYNAMIC +#define bdpe_new(A) \ + A = (bdpe_t)calloc(1, sizeof(bdpe_st)); \ + if (A == NULL) { \ + THROW(ERR_NO_MEMORY); \ + } \ + bn_new((A)->n); \ + bn_new((A)->y); \ + bn_new((A)->p); \ + bn_new((A)->q); \ + (A)->t = 0; \ + +#elif ALLOC == AUTO +#define bdpe_new(A) \ + bn_new((A)->n); \ + bn_new((A)->y); \ + bn_new((A)->p); \ + bn_new((A)->q); \ + (A)->t = 0; \ + +#elif ALLOC == STACK +#define bdpe_new(A) \ + A = (bdpe_t)alloca(sizeof(bdpe_st)); \ + bn_new((A)->n); \ + bn_new((A)->y); \ + bn_new((A)->p); \ + bn_new((A)->q); \ + +#endif + +/** + * Calls a function to clean and free a Benaloh's key pair. + * + * @param[out] A - the key pair to clean and free. + */ +#if ALLOC == DYNAMIC +#define bdpe_free(A) \ + if (A != NULL) { \ + bn_free((A)->n); \ + bn_free((A)->y); \ + bn_free((A)->p); \ + bn_free((A)->q); \ + (A)->t = 0; \ + free(A); \ + A = NULL; \ + } + +#elif ALLOC == AUTO +#define bdpe_free(A) /* empty */ + +#elif ALLOC == STACK +#define bdpe_free(A) \ + bn_free((A)->n); \ + bn_free((A)->y); \ + bn_free((A)->p); \ + bn_free((A)->q); \ + (A)->t = 0; \ + A = NULL; \ + +#endif + +/** + * Initializes a SOKAKA key pair with a null value. + * + * @param[out] A - the key pair to initialize. + */ +#if ALLOC == AUTO +#define sokaka_null(A) /* empty */ +#else +#define sokaka_null(A) A = NULL; +#endif + +/** + * Calls a function to allocate and initialize a SOKAKA key pair. + * + * @param[out] A - the new key pair. + */ +#if ALLOC == DYNAMIC +#define sokaka_new(A) \ + A = (sokaka_t)calloc(1, sizeof(sokaka_st)); \ + if (A == NULL) { \ + THROW(ERR_NO_MEMORY); \ + } \ + g1_new((A)->s1); \ + g2_new((A)->s2); \ + +#elif ALLOC == AUTO +#define sokaka_new(A) /* empty */ + +#elif ALLOC == STACK +#define sokaka_new(A) \ + A = (sokaka_t)alloca(sizeof(sokaka_st)); \ + g1_new((A)->s1); \ + g2_new((A)->s2); \ + +#endif + +/** + * Calls a function to clean and free a SOKAKA key pair. + * + * @param[out] A - the key pair to clean and free. + */ +#if ALLOC == DYNAMIC +#define sokaka_free(A) \ + if (A != NULL) { \ + g1_free((A)->s1); \ + g2_free((A)->s2); \ + free(A); \ + A = NULL; \ + } + +#elif ALLOC == AUTO +#define sokaka_free(A) /* empty */ + +#elif ALLOC == STACK +#define sokaka_free(A) \ + g1_free((A)->s1); \ + g2_free((A)->s2); \ + A = NULL; \ + +#endif + +/** + * Initializes a BGN key pair with a null value. + * + * @param[out] A - the key pair to initialize. + */ +#if ALLOC == AUTO +#define bgn_null(A) /* empty */ +#else +#define bgn_null(A) A = NULL; +#endif + +/** + * Calls a function to allocate and initialize a BGN key pair. + * + * @param[out] A - the new key pair. + */ +#if ALLOC == DYNAMIC +#define bgn_new(A) \ + A = (bgn_t)calloc(1, sizeof(bgn_st)); \ + if (A == NULL) { \ + THROW(ERR_NO_MEMORY); \ + } \ + bn_new((A)->x); \ + bn_new((A)->y); \ + bn_new((A)->z); \ + g1_new((A)->gx); \ + g1_new((A)->gy); \ + g1_new((A)->gz); \ + g2_new((A)->hx); \ + g2_new((A)->hy); \ + g2_new((A)->hz); \ + +#elif ALLOC == AUTO +#define bgn_new(A) /* empty */ + +#elif ALLOC == STACK +#define bgn_new(A) \ + A = (bgn_t)alloca(sizeof(bgn_st)); \ + bn_new((A)->x); \ + bn_new((A)->y); \ + bn_new((A)->z); \ + g1_new((A)->gx); \ + g1_new((A)->gy); \ + g1_new((A)->gz); \ + g2_new((A)->hx); \ + g2_new((A)->hy); \ + g2_new((A)->hz); \ + +#endif + +/** + * Calls a function to clean and free a BGN key pair. + * + * @param[out] A - the key pair to clean and free. + */ +#if ALLOC == DYNAMIC +#define bgn_free(A) \ + if (A != NULL) { \ + bn_free((A)->x); \ + bn_free((A)->y); \ + bn_free((A)->z); \ + g1_free((A)->gx); \ + g1_free((A)->gy); \ + g1_free((A)->gz); \ + g2_free((A)->hx); \ + g2_free((A)->hy); \ + g2_free((A)->hz); \ + free(A); \ + A = NULL; \ + } + +#elif ALLOC == AUTO +#define bgn_free(A) /* empty */ + +#elif ALLOC == STACK +#define bgn_free(A) \ + bn_free((A)->x); \ + bn_free((A)->y); \ + bn_free((A)->z); \ + g1_free((A)->gx); \ + g1_free((A)->gy); \ + g1_free((A)->gz); \ + g2_free((A)->hx); \ + g2_free((A)->hy); \ + g2_free((A)->hz); \ + A = NULL; \ + +#endif + +/** + * Generates a new RSA key pair. + * + * @param[out] PB - the public key. + * @param[out] PV - the private key. + * @param[in] B - the key length in bits. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +#if CP_RSA == BASIC +#define cp_rsa_gen(PB, PV, B) cp_rsa_gen_basic(PB, PV, B) +#elif CP_RSA == QUICK +#define cp_rsa_gen(PB, PV, B) cp_rsa_gen_quick(PB, PV, B) +#endif + +/** + * Decrypts using RSA. + * + * @param[out] O - the output buffer. + * @param[out] OL - the number of bytes written in the output buffer. + * @param[in] I - the input buffer. + * @param[in] IL - the number of bytes to encrypt. + * @param[in] K - the private key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +#if CP_RSA == BASIC +#define cp_rsa_dec(O, OL, I, IL, K) cp_rsa_dec_basic(O, OL, I, IL, K) +#elif CP_RSA == QUICK +#define cp_rsa_dec(O, OL, I, IL, K) cp_rsa_dec_quick(O, OL, I, IL, K) +#endif + +/** + * Signs a message using the RSA cryptosystem. + * + * @param[out] O - the output buffer. + * @param[out] OL - the number of bytes written in the output buffer. + * @param[in] I - the input buffer. + * @param[in] IL - the number of bytes to sign. + * @param[in] H - the flag to indicate the message format. + * @param[in] K - the private key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +#if CP_RSA == BASIC +#define cp_rsa_sig(O, OL, I, IL, H, K) cp_rsa_sig_basic(O, OL, I, IL, H, K) +#elif CP_RSA == QUICK +#define cp_rsa_sig(O, OL, I, IL, H, K) cp_rsa_sig_quick(O, OL, I, IL, H, K) +#endif + +/*============================================================================*/ +/* Function prototypes */ +/*============================================================================*/ + +/** + * Generates a key pair for the basic RSA algorithm. + * + * @param[out] pub - the public key. + * @param[out] prv - the private key. + * @param[in] bits - the key length in bits. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_rsa_gen_basic(rsa_t pub, rsa_t prv, int bits); + +/** + * Generates a key pair for fast RSA operations with the CRT optimization. + * + * @param[out] pub - the public key. + * @param[out] prv - the private key. + * @param[in] bits - the key length in bits. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_rsa_gen_quick(rsa_t pub, rsa_t prv, int bits); + +/** + * Encrypts using the RSA cryptosystem. + * + * @param[out] out - the output buffer. + * @param[in, out] out_len - the buffer capacity and number of bytes written. + * @param[in] in - the input buffer. + * @param[in] in_len - the number of bytes to encrypt. + * @param[in] pub - the public key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_rsa_enc(uint8_t *out, int *out_len, uint8_t *in, int in_len, rsa_t pub); + +/** + * Decrypts using the basic RSA decryption method. + * + * @param[out] out - the output buffer. + * @param[in, out] out_len - the buffer capacity and number of bytes written. + * @param[in] in - the input buffer. + * @param[in] in_len - the number of bytes to decrypt. + * @param[in] prv - the private key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_rsa_dec_basic(uint8_t *out, int *out_len, uint8_t *in, int in_len, + rsa_t prv); + +/** + * Decrypts using the fast RSA decryption with CRT optimization. + * + * @param[out] out - the output buffer. + * @param[in, out] out_len - the buffer capacity and number of bytes written. + * @param[in] in - the input buffer. + * @param[in] in_len - the number of bytes to decrypt. + * @param[in] prv - the private key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_rsa_dec_quick(uint8_t *out, int *out_len, uint8_t *in, int in_len, + rsa_t prv); + +/** + * Signs using the basic RSA signature algorithm. The flag must be non-zero if + * the message being signed is already a hash value. + * + * @param[out] sig - the signature + * @param[out] sig_len - the number of bytes written in the signature. + * @param[in] msg - the message to sign. + * @param[in] msg_len - the number of bytes to sign. + * @param[in] hash - the flag to indicate the message format. + * @param[in] prv - the private key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_rsa_sig_basic(uint8_t *sig, int *sig_len, uint8_t *msg, int msg_len, + int hash, rsa_t prv); + +/** + * Signs using the fast RSA signature algorithm with CRT optimization. The flag + * must be non-zero if the message being signed is already a hash value. + * + * @param[out] sig - the signature + * @param[out] sig_len - the number of bytes written in the signature. + * @param[in] msg - the message to sign. + * @param[in] msg_len - the number of bytes to sign. + * @param[in] hash - the flag to indicate the message format. + * @param[in] prv - the private key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_rsa_sig_quick(uint8_t *sig, int *sig_len, uint8_t *msg, int msg_len, + int hash, rsa_t prv); + +/** + * Verifies an RSA signature. The flag must be non-zero if the message being + * signed is already a hash value. + * + * @param[in] sig - the signature to verify. + * @param[in] sig_len - the signature length in bytes. + * @param[in] msg - the signed message. + * @param[in] msg_len - the message length in bytes. + * @param[in] hash - the flag to indicate the message format. + * @param[in] pub - the public key. + * @return a boolean value indicating if the signature is valid. + */ +int cp_rsa_ver(uint8_t *sig, int sig_len, uint8_t *msg, int msg_len, int hash, + rsa_t pub); + +/** + * Generates a key pair for the Rabin cryptosystem. + * + * @param[out] pub - the public key. + * @param[out] prv - the private key, + * @param[in] bits - the key length in bits. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_rabin_gen(rabin_t pub, rabin_t prv, int bits); + +/** + * Encrypts using the Rabin cryptosystem. + * + * @param[out] out - the output buffer. + * @param[in, out] out_len - the buffer capacity and number of bytes written. + * @param[in] in - the input buffer. + * @param[in] in_len - the number of bytes to encrypt. + * @param[in] pub - the public key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_rabin_enc(uint8_t *out, int *out_len, uint8_t *in, int in_len, + rabin_t pub); + +/** + * Decrypts using the Rabin cryptosystem. + * + * @param[out] out - the output buffer. + * @param[in, out] out_len - the buffer capacity and number of bytes written. + * @param[in] in - the input buffer. + * @param[in] in_len - the number of bytes to decrypt. + * @param[in] prv - the private key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_rabin_dec(uint8_t *out, int *out_len, uint8_t *in, int in_len, + rabin_t prv); + +/** + * Generates a key pair for Benaloh's Dense Probabilistic Encryption. + * + * @param[out] pub - the public key. + * @param[out] prv - the private key. + * @param[in] block - the block size. + * @param[in] bits - the key length in bits. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_bdpe_gen(bdpe_t pub, bdpe_t prv, dig_t block, int bits); + +/** + * Encrypts using Benaloh's cryptosystem. + * + * @param[out] out - the output buffer. + * @param[in, out] out_len - the buffer capacity and number of bytes written. + * @param[in] in - the plaintext as a small integer. + * @param[in] pub - the public key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_bdpe_enc(uint8_t *out, int *out_len, dig_t in, bdpe_t pub); + +/** + * Decrypts using Benaloh's cryptosystem. + * + * @param[out] out - the decrypted small integer. + * @param[in] in - the input buffer. + * @param[in] in_len - the number of bytes to encrypt. + * @param[in] prv - the private key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_bdpe_dec(dig_t *out, uint8_t *in, int in_len, bdpe_t prv); + +/** + * Generates a key pair for Paillier's Homomorphic Probabilistic Encryption. + * + * @param[out] n - the public key. + * @param[out] l - the private key. + * @param[in] bits - the key length in bits. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_phpe_gen(bn_t n, bn_t l, int bits); + +/** + * Encrypts using the Paillier cryptosystem. + * + * @param[out] out - the output buffer. + * @param[in, out] out_len - the buffer capacity and number of bytes written. + * @param[in] in - the input buffer. + * @param[in] in_len - the number of bytes to encrypt. + * @param[in] n - the public key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_phpe_enc(uint8_t *out, int *out_len, uint8_t *in, int in_len, bn_t n); + +/** + * Decrypts using the Paillier cryptosystem. Since this system is homomorphic, + * no padding can be applied and the user is responsible for specifying the + * resulting plaintext size. + * + * @param[out] out - the output buffer. + * @param[out] out_len - the number of bytes to write in the output buffer. + * @param[in] in_len - the number of bytes to decrypt. + * @param[in] n - the public key. + * @param[in] l - the private key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_phpe_dec(uint8_t *out, int out_len, uint8_t *in, int in_len, bn_t n, + bn_t l); + +/** + * Generates an ECDH key pair. + * + * @param[out] d - the private key. + * @param[in] q - the public key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_ecdh_gen(bn_t d, ec_t q); + +/** + * Derives a shared secret using ECDH. + * + * @param[out] key - the shared key. + * @param[int] key_len - the intended shared key length in bytes. + * @param[in] d - the private key. + * @param[in] q - the point received from the other party. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_ecdh_key(uint8_t *key, int key_len, bn_t d, ec_t q); + +/** + * Generate an ECMQV key pair. + * + * Should also be used to generate the ephemeral key pair. + * + * @param[out] d - the private key. + * @param[out] q - the public key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_ecmqv_gen(bn_t d, ec_t q); + +/** + * Derives a shared secret using ECMQV. + * + * @param[out] key - the shared key. + * @param[int] key_len - the intended shared key length in bytes. + * @param[in] d1 - the private key. + * @param[in] d2 - the ephemeral private key. + * @param[in] q2u - the ephemeral public key. + * @param[in] q1v - the point received from the other party. + * @param[in] q2v - the ephemeral point received from the party. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_ecmqv_key(uint8_t *key, int key_len, bn_t d1, bn_t d2, ec_t q2u, + ec_t q1v, ec_t q2v); + +/** + * Generates an ECIES key pair. + * + * @param[out] d - the private key. + * @param[in] q - the public key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_ecies_gen(bn_t d, ec_t q); + +/** + * Encrypts using the ECIES cryptosystem. + * + * @param[out] r - the resulting elliptic curve point. + * @param[out] out - the output buffer. + * @param[in, out] out_len - the buffer capacity and number of bytes written. + * @param[in] in - the input buffer. + * @param[in] in_len - the number of bytes to encrypt. + * @param[in] iv - the block cipher initialization vector. + * @param[in] q - the public key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_ecies_enc(ec_t r, uint8_t *out, int *out_len, uint8_t *in, int in_len, + ec_t q); + +/** + * Decrypts using the ECIES cryptosystem. + * + * @param[out] out - the output buffer. + * @param[in, out] out_len - the buffer capacity and number of bytes written. + * @param[in] in - the input buffer. + * @param[in] in_len - the number of bytes to encrypt. + * @param[in] iv - the block cipher initialization vector. + * @param[in] d - the private key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_ecies_dec(uint8_t *out, int *out_len, ec_t r, uint8_t *in, int in_len, + bn_t d); + +/** + * Generates an ECDSA key pair. + * + * @param[out] d - the private key. + * @param[in] q - the public key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_ecdsa_gen(bn_t d, ec_t q); + +/** + * Signs a message using ECDSA. + * + * @param[out] r - the first component of the signature. + * @param[out] s - the second component of the signature. + * @param[in] msg - the message to sign. + * @param[in] len - the message length in bytes. + * @param[in] hash - the flag to indicate the message format. + * @param[in] d - the private key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_ecdsa_sig(bn_t r, bn_t s, uint8_t *msg, int len, int hash, bn_t d); + +/** + * Verifies a message signed with ECDSA using the basic method. + * + * @param[out] r - the first component of the signature. + * @param[out] s - the second component of the signature. + * @param[in] msg - the message to sign. + * @param[in] len - the message length in bytes. + * @param[in] hash - the flag to indicate the message format. + * @param[in] q - the public key. + * @return a boolean value indicating if the signature is valid. + */ +int cp_ecdsa_ver(bn_t r, bn_t s, uint8_t *msg, int len, int hash, ec_t q); + +/** + * Generates an Elliptic Curve Schnorr Signature key pair. + * + * @param[out] d - the private key. + * @param[in] q - the public key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_ecss_gen(bn_t d, ec_t q); + +/** + * Signs a message using the Elliptic Curve Schnorr Signature. + * + * @param[out] r - the first component of the signature. + * @param[out] s - the second component of the signature. + * @param[in] msg - the message to sign. + * @param[in] len - the message length in bytes. + * @param[in] d - the private key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_ecss_sig(bn_t e, bn_t s, uint8_t *msg, int len, bn_t d); + +/** + * Verifies a message signed with the Elliptic Curve Schnorr Signature using the + * basic method. + * + * @param[out] r - the first component of the signature. + * @param[out] s - the second component of the signature. + * @param[in] msg - the message to sign. + * @param[in] len - the message length in bytes. + * @param[in] q - the public key. + * @return a boolean value indicating if the signature is valid. + */ +int cp_ecss_ver(bn_t e, bn_t s, uint8_t *msg, int len, ec_t q); + +/** + * Generates a master key for the SOKAKA identity-based non-interactive + * authenticated key agreement protocol. + * + * @param[out] master - the master key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_sokaka_gen(bn_t master); + +/** + * Generates a private key for the SOKAKA protocol. + * + * @param[out] k - the private key. + * @param[in] id - the identity. + * @param[in] len - the length of identity in bytes. + * @param[in] master - the master key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_sokaka_gen_prv(sokaka_t k, char *id, int len, bn_t master); + +/** + * Computes a shared key between two entities. + * + * @param[out] key - the shared key. + * @param[int] key_len - the intended shared key length in bytes. + * @param[in] id1 - the first identity. + * @param[in] len1 - the length of the first identity in bytes. + * @param[in] k - the private key of the first identity. + * @param[in] id2 - the second identity. + * @param[in] len2 - the length of the second identity in bytes. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_sokaka_key(uint8_t *key, unsigned int key_len, char *id1, int len1, + sokaka_t k, char *id2, int len2); + +/** + * Generates a key pair for the Boneh-Go-Nissim (BGN) cryptosystem. + * + * @param[out] pub - the public key. + * @param[out] prv - the private key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_bgn_gen(bgn_t pub, bgn_t prv); + +/** + * Encrypts in G_1 using the BGN cryptosystem. + * + * @param[out] out - the ciphertext. + * @param[in] in - the plaintext as a small integer. + * @param[in] pub - the public key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_bgn_enc1(g1_t out[2], dig_t in, bgn_t pub); + +/** + * Decrypts in G_1 using the BGN cryptosystem. + * + * @param[out] out - the decrypted small integer. + * @param[in] in - the ciphertext. + * @param[in] prv - the private key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_bgn_dec1(dig_t *out, g1_t in[2], bgn_t prv); + +/** + * Encrypts in G_2 using the BGN cryptosystem. + * + * @param[out] c - the ciphertext. + * @param[in] m - the plaintext as a small integer. + * @param[in] pub - the public key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_bgn_enc2(g2_t out[2], dig_t in, bgn_t pub); + +/** + * Decrypts in G_2 using the BGN cryptosystem. + * + * @param[out] out - the decrypted small integer. + * @param[in] c - the ciphertext. + * @param[in] prv - the private key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_bgn_dec2(dig_t *out, g2_t in[2], bgn_t prv); + +/** + * Adds homomorphically two BGN ciphertexts in G_T. + * + * @param[out] e - the resulting ciphertext. + * @param[in] c - the first ciphertext to add. + * @param[in] d - the second ciphertext to add. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_bgn_add(gt_t e[4], gt_t c[4], gt_t d[4]); + +/** + * Multiplies homomorphically two BGN ciphertexts in G_T. + * + * @param[out] e - the resulting ciphertext. + * @param[in] c - the first ciphertext to add. + * @param[in] d - the second ciphertext to add. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_bgn_mul(gt_t e[4], g1_t c[2], g2_t d[2]); + +/** + * Decrypts in G_T using the BGN cryptosystem. + * + * @param[out] out - the decrypted small integer. + * @param[in] c - the ciphertext. + * @param[in] prv - the private key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_bgn_dec(dig_t *out, gt_t in[4], bgn_t prv); + +/** + * Generates a master key for a Private Key Generator (PKG) in the + * Boneh-Franklin Identity-Based Encryption (BF-IBE). + * + * @param[out] master - the master key. + * @param[out] pub - the public key of the private key generator. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_ibe_gen(bn_t master, g1_t pub); + +/** + * Generates a private key for a user in the BF-IBE protocol. + * + * @param[out] prv - the private key. + * @param[in] id - the identity. + * @param[in] len - the length of identity in bytes. + * @param[in] s - the master key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_ibe_gen_prv(g2_t prv, char *id, int len, bn_t master); + +/** + * Encrypts a message using the BF-IBE protocol. + * + * @param[out] out - the output buffer. + * @param[in, out] out_len - the buffer capacity and number of bytes written. + * @param[in] in - the input buffer. + * @param[in] in_len - the number of bytes to encrypt. + * @param[in] pub - the public key of the PKG. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_ibe_enc(uint8_t *out, int *out_len, uint8_t *in, int in_len, + char *id, int len, g1_t pub); + +/** + * Decrypts a message using the BF-IBE protocol. + * + * @param[out] out - the output buffer. + * @param[in, out] out_len - the buffer capacity and number of bytes written. + * @param[in] in - the input buffer. + * @param[in] in_len - the number of bytes to decrypt. + * @param[in] pub - the private key of the user. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_ibe_dec(uint8_t *out, int *out_len, uint8_t *in, int in_len, g2_t prv); + +/** + * Generates a key pair for the Boneh-Lynn-Schacham (BLS) signature protocol. + * + * @param[out] d - the private key. + * @param[out] q - the public key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_bls_gen(bn_t d, g2_t q); + +/** + * Signs a message using the BLS protocol. + * + * @param[out] s - the signature. + * @param[in] msg - the message to sign. + * @param[in] len - the message length in bytes. + * @param[in] d - the private key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_bls_sig(g1_t s, uint8_t *msg, int len, bn_t d); + +/** + * Verifies a message signed with BLS protocol. + * + * @param[out] s - the signature. + * @param[in] msg - the message to sign. + * @param[in] len - the message length in bytes. + * @param[in] q - the public key. + * @return a boolean value indicating if the signature is valid. + */ +int cp_bls_ver(g1_t s, uint8_t *msg, int len, g2_t q); + +/** + * Generates a key pair for the Boneh-Boyen (BB) signature protocol. + * + * @param[out] d - the private key. + * @param[out] q - the first component of the public key. + * @param[out] z - the second component of the public key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_bbs_gen(bn_t d, g2_t q, gt_t z); + +/** + * Signs a message using the BB protocol. + * + * @param[out] s - the signature. + * @param[in] msg - the message to sign. + * @param[in] len - the message length in bytes. + * @param[in] hash - the flag to indicate the message format. + * @param[in] d - the private key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_bbs_sig(g1_t s, uint8_t *msg, int len, int hash, bn_t d); + +/** + * Verifies a message signed with the BB protocol. + * + * @param[in] s - the signature. + * @param[in] msg - the message to sign. + * @param[in] len - the message length in bytes. + * @param[in] hash - the flag to indicate the message format. + * @param[out] q - the first component of the public key. + * @param[out] z - the second component of the public key. + * @return a boolean value indicating the verification result. + */ +int cp_bbs_ver(g1_t s, uint8_t *msg, int len, int hash, g2_t q, gt_t z); + +/** + * Generates a key pair for the Camenisch-Lysyanskaya simple signature (CLS) + * protocol. + * + * @param[out] u - the first part of the private key. + * @param[out] v - the second part of the private key. + * @param[out] x - the first part of the public key. + * @param[out] y - the second part of the public key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_cls_gen(bn_t u, bn_t v, g2_t x, g2_t y); + +/** + * Signs a message using the CLS protocol. + * + * @param[out] a - the first part of the signature. + * @param[out] b - the second part of the signature. + * @param[out] c - the third part of the signature. + * @param[in] msg - the message to sign. + * @param[in] len - the message length in bytes. + * @param[in] u - the first part of the private key. + * @param[in] v - the second part of the private key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_cls_sig(g1_t a, g1_t b, g1_t c, uint8_t *msg, int len, bn_t u, bn_t v); + +/** + ** Verifies a signature using the CLS protocol. + * + * @param[in] a - the first part of the signature. + * @param[in] b - the second part of the signature. + * @param[in] c - the third part of the signature. + * @param[in] msg - the message to sign. + * @param[in] len - the message length in bytes. + * @param[in] u - the first part of the public key. + * @param[in] v - the second part of the public key. + * @return a boolean value indicating the verification result. + */ +int cp_cls_ver(g1_t a, g1_t b, g1_t c, uint8_t *msg, int len, g2_t x, g2_t y); + +/** + * Generates a key pair for the Camenisch-Lysyanskaya message-independent (CLI) + * signature protocol. + * + * @param[out] t - the first part of the private key. + * @param[out] u - the second part of the private key. + * @param[out] v - the third part of the private key. + * @param[out] x - the first part of the public key. + * @param[out] y - the second part of the public key. + * @param[out] z - the third part of the public key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_cli_gen(bn_t t, bn_t u, bn_t v, g2_t x, g2_t y, g2_t z); + +/** + * Signs a message using the CLI protocol. + * + * @param[out] a - one of the components of the signature. + * @param[out] A - one of the components of the signature. + * @param[out] b - one of the components of the signature. + * @param[out] B - one of the components of the signature. + * @param[out] c - one of the components of the signature. + * @param[in] msg - the message to sign. + * @param[in] len - the message length in bytes. + * @param[in] r - the per-message randomness. + * @param[in] t - the first part of the private key. + * @param[in] u - the second part of the private key. + * @param[in] v - the third part of the private key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_cli_sig(g1_t a, g1_t A, g1_t b, g1_t B, g1_t c, uint8_t *msg, int len, + bn_t r, bn_t t, bn_t u, bn_t v); + +/** + * Verifies a message signed using the CLI protocol. + * + * @param[in] a - one of the components of the signature. + * @param[in] A - one of the components of the signature. + * @param[in] b - one of the components of the signature. + * @param[in] B - one of the components of the signature. + * @param[in] c - one of the components of the signature. + * @param[in] msg - the message to sign. + * @param[in] len - the message length in bytes. + * @param[in] r - the per-message randomness. + * @param[in] x - the first part of the public key. + * @param[in] y - the second part of the public key. + * @param[in] z - the third part of the public key. + * @return a boolean value indicating the verification result. + */ +int cp_cli_ver(g1_t a, g1_t A, g1_t b, g1_t B, g1_t c, uint8_t *msg, int len, + bn_t r, g2_t x, g2_t y, g2_t z); + +/** + * Generates a key pair for the Camenisch-Lysyanskaya message-block (CLB) + * signature protocol. + * + * @param[out] t - the first part of the private key. + * @param[out] u - the second part of the private key. + * @param[out] v - the remaining (l - 1) parts of the private key. + * @param[out] x - the first part of the public key. + * @param[out] y - the second part of the public key. + * @param[out] z - the remaining (l - 1) parts of the public key. + * @param[in] l - the number of messages to sign. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_clb_gen(bn_t t, bn_t u, bn_t v[], g2_t x, g2_t y, g2_t z[], int l); + +/** + * Signs a block of messages using the CLB protocol. + * + * @param[out] a - the first component of the signature. + * @param[out] A - the (l - 1) next components of the signature. + * @param[out] b - the next component of the signature. + * @param[out] B - the (l - 1) next components of the signature. + * @param[out] c - the last component of the signature. + * @param[in] msgs - the l messages to sign. + * @param[in] lens - the l message lengths in bytes. + * @param[in] t - the first part of the private key. + * @param[in] u - the second part of the private key. + * @param[in] v - the remaining (l - 1) parts of the private key. + * @param[in] l - the number of messages to sign. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_clb_sig(g1_t a, g1_t A[], g1_t b, g1_t B[], g1_t c, uint8_t *msgs[], + int lens[], bn_t t, bn_t u, bn_t v[], int l); + +/** + * Verifies a block of messages signed using the CLB protocol. + * + * @param[out] a - the first component of the signature. + * @param[out] A - the (l - 1) next components of the signature. + * @param[out] b - the next component of the signature. + * @param[out] B - the (l - 1) next components of the signature. + * @param[out] c - the last component of the signature. + * @param[in] msgs - the l messages to sign. + * @param[in] lens - the l message lengths in bytes. + * @param[in] x - the first part of the public key. + * @param[in] y - the second part of the public key. + * @param[in] z - the remaining (l - 1) parts of the public key. + * @param[in] l - the number of messages to sign. + * @return a boolean value indicating the verification result. + */ +int cp_clb_ver(g1_t a, g1_t A[], g1_t b, g1_t B[], g1_t c, uint8_t *msgs[], + int lens[], g2_t x, g2_t y, g2_t z[], int l); + +/** + * Generates a key pair for the Pointcheval-Sanders simple signature (PSS) + * protocol. + * + * @param[out] u - the first part of the private key. + * @param[out] v - the second part of the private key. + * @param[out] g - the first part of the public key. + * @param[out] x - the secpmd part of the public key. + * @param[out] y - the third part of the public key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_pss_gen(bn_t u, bn_t v, g2_t g, g2_t x, g2_t y); + +/** + * Signs a message using the PSS protocol. + * + * @param[out] a - the first part of the signature. + * @param[out] b - the second part of the signature. + * @param[in] msg - the message to sign. + * @param[in] len - the message length in bytes. + * @param[in] u - the first part of the private key. + * @param[in] v - the second part of the private key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_pss_sig(g1_t a, g1_t b, uint8_t *msg, int len, bn_t u, bn_t v); + +/** + ** Verifies a signature using the PSS protocol. + * + * @param[in] a - the first part of the signature. + * @param[in] b - the second part of the signature. + * @param[in] msg - the message to sign. + * @param[in] len - the message length in bytes. + * @param[in] g - the first part of the public key. + * @param[in] u - the second part of the public key. + * @param[in] v - the third part of the public key. + * @return a boolean value indicating the verification result. + */ +int cp_pss_ver(g1_t a, g1_t b, uint8_t *msg, int len, g2_t g, g2_t x, g2_t y); + +/** + * Generates a key pair for the Pointcheval-Sanders block signature (PSB) + * protocol. + * + * @param[out] r - the first part of the private key. + * @param[out] s - the second part of the private key. + * @param[out] g - the first part of the public key. + * @param[out] x - the secpmd part of the public key. + * @param[out] y - the third part of the public key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_psb_gen(bn_t r, bn_t s[], g2_t g, g2_t x, g2_t y[], int l); + +/** + * Signs a block of messages using the PSB protocol. + * + * @param[out] a - the first component of the signature. + * @param[out] b - the second component of the signature. + * @param[in] msgs - the l messages to sign. + * @param[in] lens - the l message lengths in bytes. + * @param[in] r - the first part of the private key. + * @param[in] s - the remaining l part of the private key. + * @param[in] l - the number of messages to sign. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_psb_sig(g1_t a, g1_t b, uint8_t *msgs[], int lens[], bn_t r, bn_t s[], + int l); + +/** + * Verifies a block of messages signed using the PSB protocol. + * + * @param[out] a - the first component of the signature. + * @param[out] b - the seconed component of the signature. + * @param[in] msgs - the l messages to sign. + * @param[in] lens - the l message lengths in bytes. + * @param[in] g - the first part of the public key. + * @param[in] x - the second part of the public key. + * @param[in] y - the remaining l parts of the public key. + * @param[in] l - the number of messages to sign. + * @return a boolean value indicating the verification result. + */ +int cp_psb_ver(g1_t a, g1_t b, uint8_t *msgs[], int lens[], g2_t g, g2_t x, + g2_t y[], int l); + +/** + * Generates a Zhang-Safavi-Naini-Susilo (ZSS) key pair. + * + * @param[out] d - the private key. + * @param[out] q - the first component of the public key. + * @param[out] z - the second component of the public key. + */ +int cp_zss_gen(bn_t d, g1_t q, gt_t z); + +/** + * Signs a message using ZSS scheme. + * + * @param[out] s - the signature. + * @param[in] msg - the message to sign. + * @param[in] len - the message length in bytes. + * @param[in] hash - the flag to indicate the message format. + * @param[in] d - the private key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_zss_sig(g2_t s, uint8_t *msg, int len, int hash, bn_t d); + +/** + * Verifies a message signed with ZSS scheme. + * + * @param[in] s - the signature. + * @param[in] msg - the message to sign. + * @param[in] len - the message length in bytes. + * @param[in] hash - the flag to indicate the message format. + * @param[out] q - the first component of the public key. + * @param[out] z - the second component of the public key. + * @return a boolean value indicating the verification result. + */ +int cp_zss_ver(g2_t s, uint8_t *msg, int len, int hash, g1_t q, gt_t z); + +/** + * Generates a vBNN-IBS key generation center (KGC). + * + * @param[out] msk - the KGC master key. + * @param[out] mpk - the KGC public key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_vbnn_gen(bn_t msk, ec_t mpk); + +/** + * Extract a user key from an identity and a vBNN-IBS key generation center. + * + * @param[out] sk - the extracted vBNN-IBS user private key. + * @param[out] pk - the extracted vBNN-IBS user public key. + * @param[in] msk - the KGC master key. + * @param[in] id - the identity used for extraction. + * @param[in] id_len - the identity length in bytes. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_vbnn_gen_prv(bn_t sk, ec_t pk, bn_t msk, uint8_t *id, int id_len); + +/** + * Signs a message using the vBNN-IBS scheme. + * + * @param[out] r - the R value of the signature. + * @param[out] z - the z value of the signature. + * @param[out] h - the h value of the signature. + * @param[in] id - the identity buffer. + * @param[in] id_len - the size of identity buffer. + * @param[in] msg - the message buffer to sign. + * @param[in] msg_len - the size of message buffer. + * @param[in] sk - the signer private key. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_vbnn_sig(ec_t r, bn_t z, bn_t h, uint8_t *id, int id_len, uint8_t *msg, + int msg_len, bn_t sk, ec_t pk); + +/** + * Verifies a signature and message using the vBNN-IBS scheme. + * + * @param[in] r - the R value of the signature. + * @param[in] z - the z value of the signature. + * @param[in] h - the h value of the signature. + * @param[in] id - the identity buffer. + * @param[in] id_len - the size of identity buffer. + * @param[in] msg - the message buffer to sign. + * @param[in] msg_len - the size of message buffer. + * @param[in] mpk - the master public key of the generation center. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_vbnn_ver(ec_t r, bn_t z, bn_t h, uint8_t *id, int id_len, uint8_t *msg, + int msg_len, ec_t mpk); + +/** + * Initialize the Context-hiding Multi-key Homomorphic Signature scheme (CMLHS). + * The scheme due to Schabhuser et al. signs a vector of messages. + * + * @param[out] h - the random element (message as one component). + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_cmlhs_init(g1_t h); + +/** + * Generates a key pair for the CMLHS scheme using BLS as underlying signature. + * + * @param[out] x - the exponent values, one per label. + * @param[out] hs - the hash values, one per label. + * @param[in] len - the number of possible labels. + * @param[out] prf - the key for the pseudo-random function (PRF). + * @param[out] plen - the PRF key length. + * @param[out] sk - the private key for the BLS signature scheme. + * @param[out] pk - the public key for the BLS signature scheme. + * @param[out] d - the secret exponent. + * @param[out] y - the corresponding public element. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_cmlhs_gen(bn_t x[], gt_t hs[], int len, uint8_t prf[], int plen, + bn_t sk, g2_t pk, bn_t d, g2_t y); + +/** + * Signs a message vector using the CMLHS. + * + * @param[out] sig - the resulting BLS signature. + * @param[out] z - the power of the output of the PRF. + * @param[out] a - the first component of the signature. + * @param[out] c - the second component of the signature. + * @param[out] r - the third component of the signature. + * @param[out] s - the fourth component of the signature. + * @param[in] msg - the message vector to sign (one component). + * @param[in] data - the dataset identifier. + * @param[in] dlen - the length of the dataset identifier. + * @param[in] label - the integer label. + * @param[in] x - the exponent value for the label. + * @param[in] h - the random value (message has one component). + * @param[in] prf - the key for the pseudo-random function (PRF). + * @param[in] plen - the PRF key length. + * @param[in] sk - the private key for the BLS signature scheme. + * @param[out] d - the secret exponent. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_cmlhs_sig(g1_t sig, g2_t z, g1_t a, g1_t c, g1_t r, g2_t s, bn_t msg, + char *data, int dlen, int label, bn_t x, g1_t h, + uint8_t prf[], int plen, bn_t sk, bn_t d); + +/** + * Applies a function over a set of CMLHS signatures from the same user. + * + * @param[out] a - the resulting first component of the signature. + * @param[out] c - the resulting second component of the signature. + * @param[in] as - the vector of first components of the signatures. + * @param[in] cs - the vector of second components of the signatures. + * @param[in] f - the linear coefficients in the function. + * @param[in] len - the number of coefficients. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_cmlhs_fun(g1_t a, g1_t c, g1_t as[], g1_t cs[], dig_t f[], int len); + +/** + * Evaluates a function over a set of CMLHS signatures. + * + * @param[out] r - the resulting third component of the signature. + * @param[out] s - the resulting fourth component of the signature. + * @param[in] rs - the vector of third components of the signatures. + * @param[in] ss - the vector of fourth components of the signatures. + * @param[in] f - the linear coefficients in the function. + * @param[in] len - the number of coefficients. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_cmlhs_evl(g1_t r, g2_t s, g1_t rs[], g2_t ss[], dig_t f[], int len); + +/** + * Verifies a CMLHS signature over a set of messages. + * + * @param[in] r - the first component of the homomorphic signature. + * @param[in] s - the second component of the homomorphic signature. + * @param[in] sig - the BLS signatures. + * @param[in] z - the powers of the outputs of the PRF. + * @param[in] a - the vector of first components of the signatures. + * @param[in] c - the vector of second components of the signatures. + * @param[in] msg - the combined message. + * @param[in] data - the dataset identifier. + * @param[in] dlen - the length of the dataset identifier. + * @param[in] label - the integer labels. + * @param[in] h - the random element (message has one component). + * @param[in] hs - the hash values, one per label. + * @param[in] f - the linear coefficients in the function. + * @param[in] flen - the number of coefficients. + * @param[in] y - the public elements of the users. + * @param[in] pk - the public keys of the users. + * @param[in] slen - the number of signatures. + * @return a boolean value indicating the verification result. + */ +int cp_cmlhs_ver(g1_t r, g2_t s, g1_t sig[], g2_t z[], g1_t a[], g1_t c[], + bn_t m, char *data, int dlen, int label[], g1_t h, + gt_t hs[][RLC_TERMS], dig_t f[][RLC_TERMS], int flen[], g2_t y[], + g2_t pk[], int slen); + +/** + * Generates a key pair for the Multi-Key Homomorphic Signature (MKLHS) scheme. + * + * @param[out] sk - the private key for the signature scheme. + * @param[out] pk - the public key for the signature scheme. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_mklhs_gen(bn_t sk, g2_t pk); + +/** + * Signs a message using the MKLHS. + * + * @param[out] s - the resulting signature. + * @param[in] m - the message to sign. + * @param[in] data - the dataset identifier. + * @param[in] dlen - the length of the dataset identifier. + * @param[in] label - the label. + * @param[in] llen - the length of the label. + * @param[in] sk - the private key for the signature scheme. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_mklhs_sig(g1_t s, bn_t m, char *data, int dlen, char *label, int llen, + bn_t sk); + +/** + * Applies a function over a set of messages from the same user. + * + * @param[out] mu - the combined message. + * @param[in] m - the vector of individual messages. + * @param[in] f - the linear coefficients in the function. + * @param[in] len - the number of coefficients. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_mklhs_fun(bn_t mu, bn_t m[], dig_t f[], int len); + +/** + * Evaluates a function over a set of MKLHS signatures. + * + * @param[out] sig - the resulting signature + * @param[in] s - the set of signatures. + * @param[in] f - the linear coefficients in the function. + * @param[in] len - the number of coefficients. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_mklhs_evl(g1_t sig, g1_t s[], dig_t f[], int len); + +/** + * Verifies a MKLHS signature over a set of messages. + * + * @param[in] sig - the homomorphic signature to verify. + * @param[in] m - the signed message. + * @param[in] mu - the vector of signed messages per user. + * @param[in] data - the dataset identifier. + * @param[in] dlen - the length of the dataset identifier. + * @param[in] label - the vector of labels. + * @param[in] llen - the vector of label lengths. + * @param[in] f - the linear coefficients in the function. + * @param[in] flen - the number of coefficients. + * @param[in] pk - the public keys of the users. + * @param[in] slen - the number of signatures. + * @return a boolean value indicating the verification result. + */ +int cp_mklhs_ver(g1_t sig, bn_t m, bn_t mu[], char *data, int dlen, + char *label[], int llen[], dig_t f[][RLC_TERMS], int flen[], g2_t pk[], + int slen); + +/** + * Computes the offline part of veryfying a MKLHS signature over a set of + * messages. + * + * @param[out] h - the hashes of labels + * @param[out] ft - the precomputed linear coefficients. + * @param[in] label - the vector of labels. + * @param[in] llen - the vector of label lengths. + * @param[in] f - the linear coefficients in the function. + * @param[in] flen - the number of coefficients. + * @param[in] slen - the number of signatures. + * @return RLC_OK if no errors occurred, RLC_ERR otherwise. + */ +int cp_mklhs_off(g1_t h[], dig_t ft[], char *label[], int llen[], + dig_t f[][RLC_TERMS], int flen[], int slen); + +/** + * Computes the online part of veryfying a MKLHS signature over a set of + * messages. + * + * @param[in] sig - the homomorphic signature to verify. + * @param[in] m - the signed message. + * @param[in] mu - the vector of signed messages per user. + * @param[in] data - the dataset identifier. + * @param[in] dlen - the length of the dataset identifier. + * @param[in] d - the hashes of labels. + * @param[in] ft - the precomputed linear coefficients. + * @param[in] pk - the public keys of the users. + * @param[in] slen - the number of signatures. + * @return a boolean value indicating the verification result. + */ +int cp_mklhs_onv(g1_t sig, bn_t m, bn_t mu[], char *data, int dlen, + g1_t h[], dig_t ft[], g2_t pk[], int slen); + +#endif /* !RLC_CP_H */ diff --git a/bls/contrib/relic/include/relic_dv.h b/bls/contrib/relic/include/relic_dv.h new file mode 100644 index 00000000..dc71b463 --- /dev/null +++ b/bls/contrib/relic/include/relic_dv.h @@ -0,0 +1,262 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @defgroup dv Digit vector handling + */ + +/** + * @file + * + * Interface of the module for manipulating temporary double-precision digit + * vectors. + * + * @ingroup dv + */ + +#ifndef RLC_DV_H +#define RLC_DV_H + +#include "relic_bn.h" +#include "relic_conf.h" +#include "relic_types.h" +#include "relic_util.h" +#include "relic_label.h" + +/*============================================================================*/ +/* Constant definitions */ +/*============================================================================*/ + +/** + * Size in bits of the largest field element. + */ +#ifdef WITH_FP + +#ifdef WITH_FB +#define RLC_DV_MAX (RLC_MAX(FP_PRIME, FB_POLYN)) +#else /* !WITH_FB */ +#define RLC_DV_MAX (FP_PRIME) +#endif + +#else /* !WITH_FP */ + +#ifdef WITH_FB +#define RLC_DV_MAX (FB_POLYN) +#else /* !WITH_FB */ +#define RLC_DV_MAX (0) +#endif + +#endif /* WITH_FP */ + +/** + * Size in digits of a temporary vector. + * + * A temporary vector has enough size to store a multiplication/squaring result + * produced by any module. + */ +#define RLC_DV_DIGS (RLC_MAX(RLC_CEIL(RLC_DV_MAX, RLC_DIG), RLC_BN_SIZE)) + +/** + * Size in bytes of a temporary vector. + */ +#define RLC_DV_BYTES (RLC_DV_DIGS * (RLC_DIG / 8)) + +/*============================================================================*/ +/* Macro definitions */ +/*============================================================================*/ + +/** + * Size of padding to be added so that digit vectors are aligned. + */ +#if ALIGN > 1 +#define RLC_PAD(A) ((A) % ALIGN == 0 ? 0 : ALIGN - ((A) % ALIGN)) +#else +#define RLC_PAD(A) (0) +#endif + +/** + * Align digit vector pointer to specified byte-boundary. + * + * @param[in,out] A - the pointer to align. + */ +#if ALIGN > 1 +#if ARCH == AVR || ARCH == MSP || ARCH == X86 || ARCH == ARM +#define ALIGNED(A) ((unsigned int)(A) + RLC_PAD((unsigned int)(A))); + +#elif ARCH == X64 +#define ALIGNED(A) ((unsigned long)(A) + RLC_PAD((unsigned long)(A))); + +#endif +#else +#define ALIGNED(A) (A) +#endif + +/*============================================================================*/ +/* Type definitions */ +/*============================================================================*/ + +/** + * Represents a temporary double-precision digit vector. + */ +#if ALLOC == AUTO +typedef rlc_align dig_t dv_t[RLC_DV_DIGS + RLC_PAD(RLC_DV_BYTES)/(RLC_DIG / 8)]; +#else +typedef dig_t *dv_t; +#endif + +/*============================================================================*/ +/* Macro definitions */ +/*============================================================================*/ + +/** + * Initializes a digit vector with a null value. + * + * @param[out] A - the digit vector to initialize. + */ +#if ALLOC == AUTO +#define dv_null(A) /* empty */ +#else +#define dv_null(A) A = NULL; +#endif + +/** + * Calls a function to allocate a temporary double-precision digit vector. + * + * @param[out] A - the double-precision result. + */ +#if ALLOC == DYNAMIC +#define dv_new(A) dv_new_dynam(&(A), RLC_DV_DIGS) +#elif ALLOC == AUTO +#define dv_new(A) /* empty */ +#elif ALLOC == STACK +#define dv_new(A) \ + A = (dig_t *)alloca(RLC_DV_BYTES + RLC_PAD(RLC_DV_BYTES)); \ + A = (dig_t *)RLC_ALIGN(A); \ + +#endif + +/** + * Calls a function to clean and free a temporary double-precision digit vector. + * + * @param[out] A - the temporary digit vector to clean and free. + */ +#if ALLOC == DYNAMIC +#define dv_free(A) dv_free_dynam(&(A)) +#elif ALLOC == AUTO +#define dv_free(A) (void)A +#elif ALLOC == STACK +#define dv_free(A) (void)A +#endif + +/*============================================================================*/ +/* Function prototypes */ +/*============================================================================*/ + +/** + * Prints a temporary digit vector. + * + * @param[in] a - the temporary digit vector to print. + * @param[in] digits - the number of digits to print. + */ +void dv_print(dig_t *a, int digits); + +/** + * Assigns zero to a temporary double-precision digit vector. + * + * @param[out] a - the temporary digit vector to assign. + * @param[in] digits - the number of words to initialize with zero. + */ +void dv_zero(dig_t *a, int digits); + +/** + * Copies some digits from a digit vector to another digit vector. + * + * @param[out] c - the destination. + * @param[in] a - the source. + * @param[in] digits - the number of digits to copy. + */ +void dv_copy(dig_t *c, const dig_t *a, int digits); + +/** + * Conditionally copies some digits from a digit vector to another digit vector. + * + * @param[out] c - the destination. + * @paraim[in] a - the source. + * @param[in] digits - the number of digits to copy. + * @param[in] cond - the condition to evaluate. + */ +void dv_copy_cond(dig_t *c, const dig_t *a, int digits, dig_t cond); + +/** + * Conditionally swap two digit vectors. + * + * @param[in,out] c - the destination. + * @paraim[in,out] a - the source. + * @param[in] digits - the number of digits to copy. + * @param[in] cond - the condition to evaluate. + */ +void dv_swap_cond(dig_t *c, dig_t *a, int digits, dig_t cond); + +/** + * Returns the result of a comparison between two digit vectors. + * + * @param[in] a - the first digit vector. + * @param[in] b - the second digit vector. + * @param[in] size - the length in digits of the vectors. + * @return RLC_LT if a < b, RLC_EQ if a == b and RLC_GT if a > b. + */ +int dv_cmp(const dig_t *a, const dig_t *b, int size); + +/** + * Compares two digit vectors in constant time. + * + * @param[in] a - the first digit vector. + * @param[in] b - the second digit vector. + * @param[in] size - the length in digits of the vectors. + * @return RLC_EQ if they are equal and RLC_NE otherwise. + */ +int dv_cmp_const(const dig_t *a, const dig_t *b, int size); + +/** + * Allocates and initializes a temporary double-precision digit vector. + * + * @param[out] a - the new temporary digit vector. + * @param[in] digits - the required precision in digits. + * @throw ERR_NO_MEMORY - if there is no available memory. + * @throw ERR_PRECISION - if the required precision cannot be represented + * by the library. + */ +#if ALLOC == DYNAMIC +void dv_new_dynam(dv_t *a, int digits); +#endif + +/** + * Cleans and frees a temporary double-precision digit vector. + * + * @param[out] a - the temporary digit vector to clean and free. + */ +#if ALLOC == DYNAMIC +void dv_free_dynam(dv_t *a); +#endif + +#endif /* !RLC_DV_H */ diff --git a/bls/contrib/relic/include/relic_eb.h b/bls/contrib/relic/include/relic_eb.h new file mode 100644 index 00000000..35000a95 --- /dev/null +++ b/bls/contrib/relic/include/relic_eb.h @@ -0,0 +1,967 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @defgroup eb Elliptic curves over binary fields + */ + +/** + * @file + * + * Interface of the module for arithmetic on binary elliptic curves. + * + * @ingroup eb + */ + +#ifndef RLC_EB_H +#define RLC_EB_H + +#include "relic_fb.h" +#include "relic_bn.h" +#include "relic_conf.h" +#include "relic_types.h" +#include "relic_label.h" + +/*============================================================================*/ +/* Constant definitions */ +/*============================================================================*/ + +/** + * Binary elliptic curve identifiers. + */ +enum { + /** NIST B-163 binary curve. */ + NIST_B163 = 1, + /** NIST K-163 Koblitz curve. */ + NIST_K163, + /** NIST B-133 binary curve. */ + NIST_B233, + /** NIST K-233 Koblitz curve. */ + NIST_K233, + /** Curve over 2^{251} used in eBATs. */ + EBACS_B251, + /** Curve over 2^{257} good for halving. */ + HALVE_B257, + /** SECG K-239 binary curve. */ + SECG_K239, + /** NIST B-283 binary curve. */ + NIST_B283, + /** NIST K-283 Koblitz curve. */ + NIST_K283, + /** NIST B-409 binary curve. */ + NIST_B409, + /** NIST K-409 Koblitz curve. */ + NIST_K409, + /** NIST B-571 binary curve. */ + NIST_B571, + /** NIST K-571 Koblitz curve. */ + NIST_K571, +}; + +/** + * Size of a precomputation table using the binary method. + */ +#define RLC_EB_TABLE_BASIC (RLC_FB_BITS) + +/** + * Size of a precomputation table using the single-table comb method. + */ +#define RLC_EB_TABLE_COMBS (1 << EB_DEPTH) + +/** + * Size of a precomputation table using the double-table comb method. + */ +#define RLC_EB_TABLE_COMBD (1 << (EB_DEPTH + 1)) + +/** + * Size of a precomputation table using the w-(T)NAF method. + */ +#define RLC_EB_TABLE_LWNAF (1 << (EB_DEPTH - 2)) + +/** + * Size of a precomputation table using the chosen algorithm. + */ +#if EB_FIX == BASIC +#define RLC_EB_TABLE RLC_EB_TABLE_BASIC +#elif EB_FIX == COMBS +#define RLC_EB_TABLE RLC_EB_TABLE_COMBS +#elif EB_FIX == COMBD +#define RLC_EB_TABLE RLC_EB_TABLE_COMBD +#elif EB_FIX == LWNAF +#define RLC_EB_TABLE RLC_EB_TABLE_LWNAF +#endif + +/** + * Maximum size of a precomputation table. + */ +#ifdef STRIP +#define RLC_EB_TABLE_MAX RLC_EB_TABLE +#else +#define RLC_EB_TABLE_MAX RLC_MAX(RLC_EB_TABLE_BASIC, RLC_EB_TABLE_COMBD) +#endif + +/*============================================================================*/ +/* Type definitions */ +/*============================================================================*/ + +/** + * Represents an elliptic curve point over a binary field. + */ +typedef struct { + /** The first coordinate. */ + fb_st x; + /** The second coordinate. */ + fb_st y; + /** The third coordinate (projective representation). */ + fb_st z; + /** Flag to indicate that this point is normalized. */ + int norm; +} eb_st; + +/** + * Pointer to an elliptic curve point. + */ +#if ALLOC == AUTO +typedef eb_st eb_t[1]; +#else +typedef eb_st *eb_t; +#endif + +/*============================================================================*/ +/* Macro definitions */ +/*============================================================================*/ + +/** + * Initializes a point on a binary elliptic curve with a null value. + * + * @param[out] A - the point to initialize. + */ +#if ALLOC == AUTO +#define eb_null(A) /* empty */ +#else +#define eb_null(A) A = NULL; +#endif + +/** + * Calls a function to allocate a point on a binary elliptic curve. + * + * @param[out] A - the new point. + * @throw ERR_NO_MEMORY - if there is no available memory. + */ +#if ALLOC == DYNAMIC +#define eb_new(A) \ + A = (eb_t)calloc(1, sizeof(eb_st)); \ + if (A == NULL) { \ + THROW(ERR_NO_MEMORY); \ + } \ + +#elif ALLOC == AUTO +#define eb_new(A) /* empty */ + +#elif ALLOC == STACK +#define eb_new(A) \ + A = (eb_t)alloca(sizeof(eb_st)); \ + +#endif + +/** + * Calls a function to clean and free a point on a binary elliptic curve. + * + * @param[out] A - the point to clean and free. + */ +#if ALLOC == DYNAMIC +#define eb_free(A) \ + if (A != NULL) { \ + free(A); \ + A = NULL; \ + } \ + +#elif ALLOC == AUTO +#define eb_free(A) /* empty */ + +#elif ALLOC == STACK +#define eb_free(A) \ + A = NULL; \ + +#endif + +/** + * Negates a binary elliptic curve point. Computes R = -P. + * + * @param[out] R - the result. + * @param[in] P - the point to negate. + */ +#if EB_ADD == BASIC +#define eb_neg(R, P) eb_neg_basic(R, P) +#elif EB_ADD == PROJC +#define eb_neg(R, P) eb_neg_projc(R, P) +#endif + +/** + * Adds two binary elliptic curve points. Computes R = P + Q. + * + * @param[out] R - the result. + * @param[in] P - the first point to add. + * @param[in] Q - the second point to add. + */ +#if EB_ADD == BASIC +#define eb_add(R, P, Q) eb_add_basic(R, P, Q); +#elif EB_ADD == PROJC +#define eb_add(R, P, Q) eb_add_projc(R, P, Q); +#endif + +/** + * Subtracts a binary elliptic curve point from another. Computes R = P - Q. + * + * @param[out] R - the result. + * @param[in] P - the first point. + * @param[in] Q - the second point. + */ +#if EB_ADD == BASIC +#define eb_sub(R, P, Q) eb_sub_basic(R, P, Q) +#elif EB_ADD == PROJC +#define eb_sub(R, P, Q) eb_sub_projc(R, P, Q) +#endif + +/** + * Doubles a binary elliptic curve point. Computes R = 2P. + * + * @param[out] R - the result. + * @param[in] P - the point to double. + */ +#if EB_ADD == BASIC +#define eb_dbl(R, P) eb_dbl_basic(R, P); +#elif EB_ADD == PROJC +#define eb_dbl(R, P) eb_dbl_projc(R, P); +#endif + +/** + * Computes the Frobenius map of a binary elliptic curve point on a Koblitz + * curve. Computes R = t(P). + * + * @param[out] R - the result. + * @param[in] P - the point. + */ +#if EB_ADD == BASIC +#define eb_frb(R, P) eb_frb_basic(R, P) +#elif EB_ADD == PROJC +#define eb_frb(R, P) eb_frb_projc(R, P) +#endif + +/** + * Multiplies a binary elliptic curve point by an integer. Computes R = kP. + * + * @param[out] R - the result. + * @param[in] P - the point to multiply. + * @param[in] K - the integer. + */ +#if EB_MUL == BASIC +#define eb_mul(R, P, K) eb_mul_basic(R, P, K) +#elif EB_MUL == LODAH +#define eb_mul(R, P, K) eb_mul_lodah(R, P, K) +#elif EB_MUL == HALVE +#define eb_mul(R, P, K) eb_mul_halve(R, P, K) +#elif EB_MUL == LWNAF +#define eb_mul(R, P, K) eb_mul_lwnaf(R, P, K) +#elif EB_MUL == RWNAF +#define eb_mul(R, P, K) eb_mul_rwnaf(R, P, K) +#endif + +/** + * Builds a precomputation table for multiplying a fixed binary elliptic point + * point. + * + * @param[out] T - the precomputation table. + * @param[in] P - the point to multiply. + */ +#if EB_FIX == BASIC +#define eb_mul_pre(T, P) eb_mul_pre_basic(T, P) +#elif EB_FIX == COMBS +#define eb_mul_pre(T, P) eb_mul_pre_combs(T, P) +#elif EB_FIX == COMBD +#define eb_mul_pre(T, P) eb_mul_pre_combd(T, P) +#elif EB_FIX == LWNAF +#define eb_mul_pre(T, P) eb_mul_pre_lwnaf(T, P) +#endif + +/** + * Multiplies a fixed binary elliptic point using a precomputation table. + * Computes R = kP. + * + * @param[out] R - the result. + * @param[in] T - the precomputation table. + * @param[in] K - the integer. + */ +#if EB_FIX == BASIC +#define eb_mul_fix(R, T, K) eb_mul_fix_basic(R, T, K) +#elif EB_FIX == COMBS +#define eb_mul_fix(R, T, K) eb_mul_fix_combs(R, T, K) +#elif EB_FIX == COMBD +#define eb_mul_fix(R, T, K) eb_mul_fix_combd(R, T, K) +#elif EB_FIX == LWNAF +#define eb_mul_fix(R, T, K) eb_mul_fix_lwnaf(R, T, K) +#endif + +/** + * Multiplies and adds two binary elliptic curve points simultaneously. Computes + * R = kP + mQ. + * + * @param[out] R - the result. + * @param[in] P - the first point to multiply. + * @param[in] K - the first integer. + * @param[in] Q - the second point to multiply. + * @param[in] M - the second integer, + */ +#if EB_SIM == BASIC +#define eb_mul_sim(R, P, K, Q, M) eb_mul_sim_basic(R, P, K, Q, M) +#elif EB_SIM == TRICK +#define eb_mul_sim(R, P, K, Q, M) eb_mul_sim_trick(R, P, K, Q, M) +#elif EB_SIM == INTER +#define eb_mul_sim(R, P, K, Q, M) eb_mul_sim_inter(R, P, K, Q, M) +#elif EB_SIM == JOINT +#define eb_mul_sim(R, P, K, Q, M) eb_mul_sim_joint(R, P, K, Q, M) +#endif + +/*============================================================================*/ +/* Function prototypes */ +/*============================================================================*/ + +/** + * Initializes the binary elliptic curve arithmetic module. + */ +void eb_curve_init(void); + +/** + * Finalizes the binary elliptic curve arithmetic module. + */ +void eb_curve_clean(void); + +/** + * Returns the 'a' coefficient of the currently configured binary elliptic + * curve. + * + * @return the 'a' coefficient of the elliptic curve. + */ +dig_t *eb_curve_get_a(void); + +/** + * Returns the 'b' coefficient of the currently configured binary elliptic + * curve. + * + * @return the 'b' coefficient of the elliptic curve. + */ +dig_t *eb_curve_get_b(void); + +/** + * Returns a optimization identifier based on the 'a' coefficient of the curve. + * + * @return the optimization identifier. + */ +int eb_curve_opt_a(void); + +/** + * Returns a optimization identifier based on the 'b' coefficient of the curve. + * + * @return the optimization identifier. + */ +int eb_curve_opt_b(void); + +/** + * Tests if the configured binary elliptic curve is a Koblitz curve. + * + * @return 1 if the binary elliptic curve is a Koblitz curve, 0 otherwise. + */ +int eb_curve_is_kbltz(void); + +/** + * Returns the generator of the group of points in the binary elliptic curve. + * + * @param[out] g - the returned generator. + */ +void eb_curve_get_gen(eb_t g); + +/** + * Returns the precomputation table for the generator. + * + * @return the table. + */ +const eb_t *eb_curve_get_tab(void); + +/** + * Returns the order of the group of points in the binary elliptic curve. + * + * @param[out] n - the returned order. + */ +void eb_curve_get_ord(bn_t n); + +/** + * Returns the cofactor of the binary elliptic curve. + * + * @param[out] n - the returned cofactor. + */ +void eb_curve_get_cof(bn_t h); + +/** + * Configures an ordinary binary elliptic curve by its coefficients and + * generator. + * + * @param[in] a - the 'a' coefficient of the curve. + * @param[in] b - the 'b' coefficient of the curve. + * @param[in] g - the generator. + * @param[in] n - the order of the generator. + * @param[in] h - the cofactor of the group order. + */ +void eb_curve_set(const fb_t a, const fb_t b, const eb_t g, const bn_t n, + const bn_t h); + +/** + * Configures a new binary elliptic curve by its parameter identifier. + * + * @param[in] param - the parameters identifier. + */ +void eb_param_set(int param); + +/** + * Configures some set of curve parameters for the current security level. + */ +int eb_param_set_any(void); + +/** + * Configures a set of curve parameters without endormorphisms for the current + * security level. + * + * @return RLC_OK if there is a curve at this security level, RLC_ERR otherwise. + */ +int eb_param_set_any_plain(void); + +/** + * Configures a set of Koblitz curve parameters for the current security level. + * + * @return RLC_OK if there is a curve at this security level, RLC_ERR otherwise. + */ +int eb_param_set_any_kbltz(void); + +/** + * Returns the parameter identifier of the currently configured binary elliptic + * curve. + * + * @return the parameter identifier. + */ +int eb_param_get(void); + +/** + * Prints the current configured binary elliptic curve. + */ +void eb_param_print(void); + +/** + * Returns the current security level. + */ +int eb_param_level(void); + +/** + * Tests if a point on a binary elliptic curve is at the infinity. + * + * @param[in] p - the point to test. + * @return 1 if the point is at infinity, 0 otherise. + */ +int eb_is_infty(const eb_t p); + +/** + * Assigns a binary elliptic curve point to a point at the infinity. + * + * @param[out] p - the point to assign. + */ +void eb_set_infty(eb_t p); + +/** + * Copies the second argument to the first argument. + * + * @param[out] r - the result. + * @param[in] p - the binary elliptic curve point to copy. + */ +void eb_copy(eb_t r, const eb_t p); + +/** + * Compares two binary elliptic curve points. + * + * @param[in] p - the first binary elliptic curve point. + * @param[in] q - the second binary elliptic curve point. + * @return RLC_EQ if p == q and RLC_NE if p != q. + */ +int eb_cmp(const eb_t p, const eb_t q); + +/** + * Assigns a random value to a binary elliptic curve point. + * + * @param[out] p - the binary elliptic curve point to assign. + */ +void eb_rand(eb_t p); + +/** + * Computes the right-hand side of the elliptic curve equation at a certain + * elliptic curve point. + * + * @param[out] rhs - the result. + * @param[in] p - the point. + */ +void eb_rhs(fb_t rhs, const eb_t p); + +/** Tests if a point is in the curve. + * + * @param[in] p - the point to test. + */ +int eb_is_valid(const eb_t p); + +/** + * Builds a precomputation table for multiplying a random binary elliptic point. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + * @param[in] w - the window width. + */ +void eb_tab(eb_t *t, const eb_t p, int w); + +/** + * Prints a binary elliptic curve point. + * + * @param[in] p - the binary elliptic curve point to print. + */ +void eb_print(const eb_t p); + +/** + * Returns the number of bytes necessary to store a binary elliptic curve point + * with optional point compression. + * + * @param[in] a - the binary field element. + * @param[in] pack - the flag to indicate compression. + * @return the number of bytes. + */ +int eb_size_bin(const eb_t a, int pack); + +/** + * Reads a binary elliptic curve point from a byte vector in big-endian format. + * + * @param[out] a - the result. + * @param[in] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @throw ERR_NO_VALID - if the encoded point is invalid. + * @throw ERR_NO_BUFFER - if the buffer capacity is invalid. + */ +void eb_read_bin(eb_t a, const uint8_t *bin, int len); + +/** + * Writes a binary field element to a byte vector in big-endian format with + * optional point compression. + * + * @param[out] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @param[in] a - the binary elliptic curve point to write. + * @param[in] pack - the flag to indicate point compression. + * @throw ERR_NO_BUFFER - if the buffer capacity is invalid. + */ +void eb_write_bin(uint8_t *bin, int len, const eb_t a, int pack); + +/** + * Negates a binary elliptic curve point represented by affine coordinates. + * + * @param[out] r - the result. + * @param[in] p - the point to negate. + */ +void eb_neg_basic(eb_t r, const eb_t p); + +/** + * Negates a binary elliptic curve point represented by projective coordinates. + * + * @param[out] r - the result. + * @param[in] p - the point to negate. + */ +void eb_neg_projc(eb_t r, const eb_t p); + +/** + * Adds two binary elliptic curve points represented in affine coordinates. + * + * @param[out] r - the result. + * @param[in] p - the first point to add. + * @param[in] q - the second point to add. + */ +void eb_add_basic(eb_t r, const eb_t p, const eb_t q); + +/** + * Adds two binary elliptic curve points represented in projective coordinates. + * Computes R = P + Q. + * + * @param[out] r - the result. + * @param[in] p - the first point to add. + * @param[in] q - the second point to add. + */ +void eb_add_projc(eb_t r, const eb_t p, const eb_t q); + +/** + * Subtracts a binary elliptic curve point from another, both points represented + * by affine coordinates. + * + * @param[out] r - the result. + * @param[in] p - the first point. + * @param[in] q - the second point. + */ +void eb_sub_basic(eb_t r, const eb_t p, const eb_t q); + +/** + * Subtracts a binary elliptic curve point from another, both points represented + * by projective coordinates. + * + * @param[out] r - the result. + * @param[in] p - the first point. + * @param[in] q - the second point. + */ +void eb_sub_projc(eb_t r, const eb_t p, const eb_t q); + +/** + * Doubles a binary elliptic curve point represented in affine coordinates. + * + * @param[out] r - the result. + * @param[in] p - the point to double. + */ +void eb_dbl_basic(eb_t r, const eb_t p); + +/** + * Doubles a binary elliptic curve point represented in projective coordinates. + * + * @param[out] r - the result. + * @param[in] p - the point to double. + */ +void eb_dbl_projc(eb_t r, const eb_t p); + +/** + * Halves a point represented in affine coordinates. + * + * @param[out] r - the result. + * @param[in] p - the point to halve. + */ +void eb_hlv(eb_t r, const eb_t p); + +/** + * Computes the Frobenius map of a binary elliptic curve point represented + * by affine coordinates. + * + * @param[out] r - the result. + * @param[in] p - the point. + */ +void eb_frb_basic(eb_t r, const eb_t p); + +/** + * Computes the Frobenius map of a binary elliptic curve point represented + * by projective coordinates. + * + * @param[out] r - the result. + * @param[in] p - the point. + */ +void eb_frb_projc(eb_t r, const eb_t p); + +/** + * Multiplies a binary elliptic point by an integer using the binary method. + * + * @param[out] r - the result. + * @param[in] p - the point to multiply. + * @param[in] k - the integer. + */ +void eb_mul_basic(eb_t r, const eb_t p, const bn_t k); + +/** + * Multiplies a binary elliptic point by an integer using the constant-time + * López-Dahab point multiplication method. + * + * @param[out] r - the result. + * @param[in] p - the point to multiply. + * @param[in] k - the integer. + */ +void eb_mul_lodah(eb_t r, const eb_t p, const bn_t k); + +/** + * Multiplies a binary elliptic point by an integer using the left-to-right + * w-NAF method. If the binary curve is a Koblitz curve, w-TNAF is used. + * + * @param[out] r - the result. + * @param[in] p - the point to multiply. + * @param[in] k - the integer. + */ +void eb_mul_lwnaf(eb_t r, const eb_t p, const bn_t k); + +/** + * Multiplies a binary elliptic point by an integer using the right-to-left + * w-NAF method. If the binary curve is a Koblitz curve, w-TNAF is used. + * + * @param[out] r - the result. + * @param[in] p - the point to multiply. + * @param[in] k - the integer. + */ +void eb_mul_rwnaf(eb_t r, const eb_t p, const bn_t k); + +/** + * Multiplies a binary elliptic point by an integer using the halving method. + * + * @param[out] r - the result. + * @param[in] p - the point to multiply. + * @param[in] k - the integer. + */ +void eb_mul_halve(eb_t r, const eb_t p, const bn_t k); + +/** + * Multiplies the generator of a binary elliptic curve by an integer. + * + * @param[out] r - the result. + * @param[in] k - the integer. + */ +void eb_mul_gen(eb_t r, const bn_t k); + +/** + * Multiplies a binary elliptic point by a small positive integer. + * + * @param[out] r - the result. + * @param[in] p - the point to multiply. + * @param[in] k - the integer. + */ +void eb_mul_dig(eb_t r, const eb_t p, const dig_t k); + +/** + * Builds a precomputation table for multiplying a fixed binary elliptic point + * using the binary method. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + */ +void eb_mul_pre_basic(eb_t *t, const eb_t p); + +/** + * Builds a precomputation table for multiplying a fixed binary elliptic point + * using Yao's windowing method. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + */ +void eb_mul_pre_yaowi(eb_t *t, const eb_t p); + +/** + * Builds a precomputation table for multiplying a fixed binary elliptic point + * using the NAF windowing method. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + */ +void eb_mul_pre_nafwi(eb_t *t, const eb_t p); + +/** + * Builds a precomputation table for multiplying a fixed binary elliptic point + * using the single-table comb method. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + */ +void eb_mul_pre_combs(eb_t *t, const eb_t p); + +/** + * Builds a precomputation table for multiplying a fixed binary elliptic point + * using the double-table comb method. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + */ +void eb_mul_pre_combd(eb_t *t, const eb_t p); + +/** + * Builds a precomputation table for multiplying a fixed binary elliptic point + * using the w-(T)NAF method. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + */ +void eb_mul_pre_lwnaf(eb_t *t, const eb_t p); + +/** + * Multiplies a fixed binary elliptic point using a precomputation table and + * the binary method. + * + * @param[out] r - the result. + * @param[in] t - the precomputation table. + * @param[in] k - the integer. + */ +void eb_mul_fix_basic(eb_t r, const eb_t *t, const bn_t k); + +/** + * Multiplies a fixed binary elliptic point using a precomputation table and + * Yao's windowing method + * + * @param[out] r - the result. + * @param[in] t - the precomputation table. + * @param[in] k - the integer. + */ +void eb_mul_fix_yaowi(eb_t r, const eb_t *t, const bn_t k); + +/** + * Multiplies a fixed binary elliptic point using a precomputation table and + * the w-(T)NAF method. + * + * @param[out] r - the result. + * @param[in] t - the precomputation table. + * @param[in] k - the integer. + */ +void eb_mul_fix_nafwi(eb_t r, const eb_t *t, const bn_t k); + +/** + * Multiplies a fixed binary elliptic point using a precomputation table and + * the single-table comb method. + * + * @param[out] r - the result. + * @param[in] t - the precomputation table. + * @param[in] k - the integer. + */ +void eb_mul_fix_combs(eb_t r, const eb_t *t, const bn_t k); + +/** + * Multiplies a fixed binary elliptic point using a precomputation table and + * the double-table comb method. + * + * @param[out] r - the result. + * @param[in] t - the precomputation table. + * @param[in] k - the integer. + */ +void eb_mul_fix_combd(eb_t r, const eb_t *t, const bn_t k); + +/** + * Multiplies a fixed binary elliptic point using a precomputation table and + * the w-(T)NAF method. + * + * @param[out] r - the result. + * @param[in] t - the precomputation table. + * @param[in] k - the integer. + */ +void eb_mul_fix_lwnaf(eb_t r, const eb_t *t, const bn_t k); + +/** + * Multiplies and adds two binary elliptic curve points simultaneously using + * scalar multiplication and point addition. + * + * @param[out] r - the result. + * @param[in] p - the first point to multiply. + * @param[in] k - the first integer. + * @param[in] q - the second point to multiply. + * @param[in] m - the second integer, + */ +void eb_mul_sim_basic(eb_t r, const eb_t p, const bn_t k, const eb_t q, + const bn_t m); + +/** + * Multiplies and adds two binary elliptic curve points simultaneously using + * shamir's trick. + * + * @param[out] r - the result. + * @param[in] p - the first point to multiply. + * @param[in] k - the first integer. + * @param[in] q - the second point to multiply. + * @param[in] m - the second integer, + */ +void eb_mul_sim_trick(eb_t r, const eb_t p, const bn_t k, const eb_t q, + const bn_t m); + +/** + * Multiplies and adds two binary elliptic curve points simultaneously using + * interleaving of NAFs. + * + * @param[out] r - the result. + * @param[in] p - the first point to multiply. + * @param[in] k - the first integer. + * @param[in] q - the second point to multiply. + * @param[in] m - the second integer, + */ +void eb_mul_sim_inter(eb_t r, const eb_t p, const bn_t k, const eb_t q, + const bn_t m); + +/** + * Multiplies and adds two binary elliptic curve points simultaneously using + * Solinas' Joint Sparse Form. + * + * @param[out] r - the result. + * @param[in] p - the first point to multiply. + * @param[in] k - the first integer. + * @param[in] q - the second point to multiply. + * @param[in] m - the second integer, + */ +void eb_mul_sim_joint(eb_t r, const eb_t p, const bn_t k, const eb_t q, + const bn_t m); + +/** + * Multiplies and adds the generator and a binary elliptic curve point + * simultaneously. Computes R = kG + mQ. + * + * @param[out] r - the result. + * @param[in] k - the first integer. + * @param[in] q - the second point to multiply. + * @param[in] m - the second integer. + */ +void eb_mul_sim_gen(eb_t r, const bn_t k, const eb_t q, const bn_t m); + +/** + * Converts a point to affine coordinates. + * + * @param[out] r - the result. + * @param[in] p - the point to convert. + */ +void eb_norm(eb_t r, const eb_t p); + +/** + * Converts multiple points to affine coordinates. + * + * @param[out] r - the result. + * @param[in] t - the points to convert. + * @param[in] n - the number of points. + */ +void eb_norm_sim(eb_t *r, const eb_t *t, int n); + +/** + * Maps a byte array to a point in a binary elliptic curve. + * + * @param[out] p - the result. + * @param[in] msg - the byte array to map. + * @param[in] len - the array length in bytes. + */ +void eb_map(eb_t p, const uint8_t *msg, int len); + +/** + * Compresses a point. + * + * @param[out] r - the result. + * @param[in] p - the point to compress. + */ +void eb_pck(eb_t r, const eb_t p); + +/** + * Decompresses a point. + * + * @param[out] r - the result. + * @param[in] p - the point to decompress. + * @return if the decompression was successful + */ +int eb_upk(eb_t r, const eb_t p); + +#endif /* !RLC_EB_H */ diff --git a/bls/contrib/relic/include/relic_ec.h b/bls/contrib/relic/include/relic_ec.h new file mode 100644 index 00000000..7ab33680 --- /dev/null +++ b/bls/contrib/relic/include/relic_ec.h @@ -0,0 +1,455 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @defgroup ec Elliptic curve cryptography + */ + +/** + * @file + * + * Abstractions of elliptic curve arithmetic useful to protocol implementors. + * + * @ingroup ec + */ + +#ifndef RLC_EC_H +#define RLC_EC_H + +#include "relic_ep.h" +#include "relic_eb.h" +#include "relic_ed.h" +#include "relic_bn.h" +#include "relic_util.h" +#include "relic_conf.h" +#include "relic_types.h" + +/*============================================================================*/ +/* Constant definitions */ +/*============================================================================*/ + +/** + * Prefix for mappings of functions. + */ +#if EC_CUR == PRIME +#define EC_LOWER ep_ +#elif EC_CUR == CHAR2 +#define EC_LOWER eb_ +#elif EC_CUR == EDDIE +#define EC_LOWER ed_ +#endif + +/** + * Prefix for mappings of constant definitions. + */ +#if EC_CUR == PRIME +#define EC_UPPER EP_ +#elif EC_CUR == CHAR2 +#define EC_UPPER EB_ +#elif EC_CUR == EDDIE +#define EC_UPPER ED_ +#endif + +/** + * Size of a precomputation table using the chosen algorithm. + */ +#if EC_CUR == PRIME +#define RLC_EC_TABLE RLC_EP_TABLE +#elif EC_CUR == CHAR2 +#define RLC_EC_TABLE RLC_EB_TABLE +#elif EC_CUR == EDDIE +#define RLC_EC_TABLE RLC_ED_TABLE +#endif + +/** + * Size of a field element in words. + */ +#if EC_CUR == PRIME +#define RLC_FC_DIGS RLC_FP_DIGS +#elif EC_CUR == CHAR2 +#define RLC_FC_DIGS RLC_FB_DIGS +#elif EC_CUR == EDDIE +#define RLC_FC_DIGS RLC_FP_DIGS +#endif + +/** + * Size of a field element in bits. + */ +#if EC_CUR == PRIME +#define RLC_FC_BITS RLC_FP_BITS +#elif EC_CUR == CHAR2 +#define RLC_FC_BITS RLC_FB_BITS +#elif EC_CUR == EDDIE +#define RLC_FC_BITS RLC_FP_BITS +#endif + +/** + * Size of a field element in bytes. + */ +#if EC_CUR == PRIME +#define RLC_FC_BYTES RLC_FP_BYTES +#elif EC_CUR == CHAR2 +#define RLC_FC_BYTES RLC_FB_BYTES +#elif EC_CUR == EDDIE +#define RLC_FC_BYTES RLC_FP_BYTES +#endif + +/*============================================================================*/ +/* Type definitions */ +/*============================================================================*/ + +/** + * Represents an elliptic curve point. + */ +typedef RLC_CAT(EC_LOWER, t) ec_t; + +/*============================================================================*/ +/* Macro definitions */ +/*============================================================================*/ + +/** + * Initializes a point on an elliptic curve with a null value. + * + * @param[out] A - the point to initialize. + */ +#define ec_null(A) RLC_CAT(EC_LOWER, null)(A) + +/** + * Calls a function to allocate a point on an elliptic curve. + * + * @param[out] A - the new point. + * @throw ERR_NO_MEMORY - if there is no available memory. + */ +#define ec_new(A) RLC_CAT(EC_LOWER, new)(A) + +/** + * Calls a function to clean and free a point on an elliptic curve. + * + * @param[out] A - the point to clean and free. + */ +#define ec_free(A) RLC_CAT(EC_LOWER, free)(A) + +/** + * Returns the generator of the group of points in the elliptic curve. + * + * @param[out] G - the returned generator. + */ +#define ec_curve_get_gen(G) RLC_CAT(EC_LOWER, curve_get_gen)(G) + +/** + * Returns the precomputation table for the generator. + * + * @return the table. + */ +#define ec_curve_get_tab() RLC_CAT(EC_LOWER, curve_get_tab)() + +/** + * Returns the order of the group of points in the elliptic curve. + * + * @param[out] N - the returned order. + */ +#define ec_curve_get_ord(N) RLC_CAT(EC_LOWER, curve_get_ord)(N) + +/** + * Returns the cofactor of the group of points in the elliptic curve. + * + * @param[out] H - the returned order. + */ +#define ec_curve_get_cof(H) RLC_CAT(EC_LOWER, curve_get_cof)(H) + +/** + * Configures some set of curve parameters for the current security level. + */ +#if EC_CUR == PRIME +#if defined(EC_ENDOM) +#define ec_param_set_any() ep_param_set_any_endom() +#else +#define ec_param_set_any() ep_param_set_any() +#endif +#elif EC_CUR == CHAR2 +#if defined(EC_ENDOM) +#define ec_param_set_any() eb_param_set_any_kbltz() +#else +#define ec_param_set_any() eb_param_set_any() +#endif +#elif EC_CUR == EDDIE +#define ec_param_set_any() ed_param_set_any() +#endif + +/** + * Prints the current configured elliptic curve. + */ +#define ec_param_print() RLC_CAT(EC_LOWER, param_print)() + + /** + * Returns the current configured elliptic curve. + */ +#define ec_param_get() RLC_CAT(EC_LOWER, param_get)() + +/** + * Returns the current security level. + */ +#define ec_param_level() RLC_CAT(EC_LOWER, param_level)() + +/** + * Tests if a point on a elliptic curve is at the infinity. + * + * @param[in] P - the point to test. + * @return 1 if the point is at infinity, 0 otherwise. + */ +#define ec_is_infty(P) RLC_CAT(EC_LOWER, is_infty)(P) + +/** + * Assigns a elliptic curve point to a point at the infinity. + * + * @param[out] P - the point to assign. + */ +#define ec_set_infty(P) RLC_CAT(EC_LOWER, set_infty)(P) + +/** + * Copies the second argument to the first argument. + * + * @param[out] R - the result. + * @param[in] P - the elliptic curve point to copy. + */ +#define ec_copy(R, P) RLC_CAT(EC_LOWER, copy)(R, P) + +/** + * Compares two elliptic curve points. + * + * @param[in] P - the first elliptic curve point. + * @param[in] Q - the second elliptic curve point. + * @return RLC_EQ if P == Q and RLC_NE if P != Q. + */ +#define ec_cmp(P, Q) RLC_CAT(EC_LOWER, cmp)(P, Q) + +/** + * Assigns a random value to a elliptic curve point. + * + * @param[out] P - the elliptic curve point to assign. + */ +#define ec_rand(P) RLC_CAT(EC_LOWER, rand)(P) + +/** Tests if a point is in the curve. + * + * @param[in] P - the point to test. + */ +#define ec_is_valid(P) RLC_CAT(EC_LOWER, is_valid)(P) + +/** + * Returns the number of bytes necessary to store an elliptic curve point with + * optional point compression. + * + * @param[in] A - the elliptic curve point. + * @param[in] P - the flag to indicate compression. + */ +#define ec_size_bin(A, P) RLC_CAT(EC_LOWER, size_bin)(A, P) + +/** + * Reads an elliptic curve point from a byte vector in big-endian format. + * + * @param[out] A - the result. + * @param[in] B - the byte vector. + * @param[in] L - the buffer capacity. + */ +#define ec_read_bin(A, B, L) RLC_CAT(EC_LOWER, read_bin)(A, B, L) + +/** + * Writes an elliptic curve point to a byte vector in big-endian format with + * optional point compression. + * + * @param[out] B - the byte vector. + * @param[in] L - the buffer capacity. + * @param[in] A - the prime elliptic curve point to write. + * @param[in] P - the flag to indicate point compression. + */ +#define ec_write_bin(B, L, A, P) RLC_CAT(EC_LOWER, write_bin)(B, L, A, P) + +/** + * Prints a elliptic curve point. + * + * @param[in] P - the elliptic curve point to print. + */ +#define ec_print(P) RLC_CAT(EC_LOWER, print)(P) + +/** + * Negates an elliptic curve point. Computes R = -P. + * + * @param[out] R - the result. + * @param[in] P - the point to negate. + */ +#define ec_neg(R, P) RLC_CAT(EC_LOWER, neg)(R, P) + +/** + * Adds two elliptic curve points. Computes R = P + Q. + * + * @param[out] R - the result. + * @param[in] P - the first point to add. + * @param[in] Q - the second point to add. + */ +#define ec_add(R, P, Q) RLC_CAT(EC_LOWER, add)(R, P, Q) + +/** + * Subtracts an elliptic curve point from another. Computes R = P - Q. + * + * @param[out] R - the result. + * @param[in] P - the first point. + * @param[in] Q - the second point. + */ +#define ec_sub(R, P, Q) RLC_CAT(EC_LOWER, sub)(R, P, Q) + +/** + * Doubles an elliptic curve point. Computes R = 2P. + * + * @param[out] R - the result. + * @param[in] P - the point to double. + */ +#define ec_dbl(R, P) RLC_CAT(EC_LOWER, dbl)(R, P) + +/** + * Multiplies an elliptic curve point by an integer. Computes R = kP. + * + * @param[out] R - the result. + * @param[in] P - the point to multiply. + * @param[in] K - the integer. + */ +#define ec_mul(R, P, K) RLC_CAT(EC_LOWER, mul)(R, P, K) + +/** + * Multiplies the generator of a prime elliptic curve by an integer. + * + * @param[out] R - the result. + * @param[in] K - the integer. + */ +#define ec_mul_gen(R, K) RLC_CAT(EC_LOWER, mul_gen)(R, K) + +/** + * Multiplies an elliptic curve point by a small integer. Computes R = kP. + * + * @param[out] R - the result. + * @param[in] P - the point to multiply. + * @param[in] K - the integer. + */ +#define ec_mul_dig(R, P, K) RLC_CAT(EC_LOWER, mul_dig)(R, P, K) + +/** + * Builds a precomputation table for multiplying a fixed elliptic curve + * point. + * + * @param[out] T - the precomputation table. + * @param[in] P - the point to multiply. + */ +#define ec_mul_pre(T, P) RLC_CAT(EC_LOWER, mul_pre)(T, P) +/** + * Multiplies a elliptic point using a precomputation table. + * Computes R = kP. + * + * @param[out] R - the result. + * @param[in] T - the precomputation table. + * @param[in] K - the integer. + */ +#define ec_mul_fix(R, T, K) RLC_CAT(EC_LOWER, mul_fix)(R, T, K) + +/** + * Multiplies and adds two elliptic curve points simultaneously. Computes + * R = kP + lQ. + * + * @param[out] R - the result. + * @param[in] P - the first point to multiply. + * @param[in] K - the first integer. + * @param[in] Q - the second point to multiply. + * @param[in] L - the second integer, + */ +#define ec_mul_sim(R, P, K, Q, L) RLC_CAT(EC_LOWER, mul_sim)(R, P, K, Q, L) + +/** + * Multiplies and adds two elliptic curve points simultaneously. Computes + * R = kG + lQ. + * + * @param[out] R - the result. + * @param[in] K - the first integer. + * @param[in] Q - the second point to multiply. + * @param[in] L - the second integer, + */ +#define ec_mul_sim_gen(R, K, Q, L) RLC_CAT(EC_LOWER, mul_sim_gen)(R, K, Q, L) + +/** + * Converts a point to affine coordinates. + * + * @param[out] R - the result. + * @param[in] P - the point to convert. + */ +#define ec_norm(R, P) RLC_CAT(EC_LOWER, norm)(R, P) + +/** + * Maps a byte array to a point in an elliptic curve. + * + * @param[out] P - the result. + * @param[in] M - the byte array to map. + * @param[in] L - the array length in bytes. + */ +#define ec_map(P, M, L) RLC_CAT(EC_LOWER, map)(P, M, L) + +/** + * Compresses a point. + * + * @param[out] R - the result. + * @param[in] P - the point to compress. + */ +#define ec_pck(R, P) RLC_CAT(EC_LOWER, pck)(R, P) + +/** + * Decompresses a point. + * + * @param[out] R - the result. + * @param[in] P - the point to decompress. + */ +#define ec_upk(R, P) RLC_CAT(EC_LOWER, upk)(R, P) + +/** + * Returns the x-coordinate of an elliptic curve point represented as a + * multiple precision integer. + * + * @param[out] X - the x-coordinate. + * @param[in] P - the point to read. + */ +#if EC_CUR == PRIME || EC_CUR == EDDIE +#define ec_get_x(X, P) fp_prime_back(X, P->x) +#else +#define ec_get_x(X, P) bn_read_raw(X, P->x, RLC_FC_DIGS) +#endif + +/** +* Returns the y-coordinate of an elliptic curve point represented as a +* multiple precision integer. +* +* @param[out] Y - the y-coordinate. +* @param[in] P - the point to read. +*/ +#if EC_CUR == PRIME || EC_CUR == EDDIE +#define ec_get_y(Y, P) fp_prime_back(Y, (P)->y) +#else +#define ec_get_y(Y, P) bn_read_raw(Y, (P)->y, RLC_FC_DIGS) +#endif + +#endif /* !RLC_EC_H */ diff --git a/bls/contrib/relic/include/relic_ed.h b/bls/contrib/relic/include/relic_ed.h new file mode 100644 index 00000000..97bf0f36 --- /dev/null +++ b/bls/contrib/relic/include/relic_ed.h @@ -0,0 +1,894 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @defgroup ed Edwards curves over prime fields. + */ + +/** + * @file + * + * Interface of the module for arithmetic on elliptic curves. + * + * @ingroup ed + */ + + #ifndef RLC_ED_H + #define RLC_ED_H + +#include "relic_fp.h" +#include "relic_bn.h" +#include "relic_types.h" +#include "relic_label.h" + +/*============================================================================*/ +/* Constant definitions */ +/*============================================================================*/ + +/** + * Prime elliptic curve identifiers. + */ +enum { + /** ED25519 Edwards curve. */ + CURVE_ED25519 = 1 +}; + +/*============================================================================*/ +/* Precomputaion table */ +/*============================================================================*/ +/** + * Size of a precomputation table using the binary method. + */ +#define RLC_ED_TABLE_BASIC (RLC_FP_BITS + 1) + +/** + * Size of a precomputation table using the single-table comb method. + */ +#define RLC_ED_TABLE_COMBS (1 << ED_DEPTH) + +/** + * Size of a precomputation table using the double-table comb method. + */ +#define RLC_ED_TABLE_COMBD (1 << (ED_DEPTH + 1)) + +/** + * Size of a precomputation table using the w-(T)NAF method. + */ +#define RLC_ED_TABLE_LWNAF (1 << (ED_DEPTH - 2)) + +/** + * Size of a precomputation table using the chosen algorithm. + */ +#if ED_FIX == BASIC +#define RLC_ED__TABLE RLC_ED_TABLE_BASIC +#elif ED_FIX == COMBS +#define RLC_ED_TABLE RLC_ED_TABLE_COMBS +#elif ED_FIX == COMBD +#define RLC_ED_TABLE RLC_ED_TABLE_COMBD +#elif ED_FIX == LWNAF +#define RLC_ED_TABLE RLC_ED_TABLE_LWNAF +#endif + +/** + * Maximum size of a precomputation table. + */ +#ifdef STRIP +#define RLC_ED_TABLE_MAX RLC_ED_TABLE +#else +#define RLC_ED_TABLE_MAX RLC_MAX(RLC_ED_TABLE_BASIC, RLC_ED_TABLE_COMBD) +#endif + +/*============================================================================*/ +/* Type definitions */ +/*============================================================================*/ + +/** + * Represents an elliptic curve point over an Edwards field. + */ +typedef struct { + /** The first coordinate. */ + fp_st x; + /** The second coordinate. */ + fp_st y; + /** The third coordinate (projective representation). */ + fp_st z; +#if ED_ADD == EXTND || !defined(STRIP) + /** The forth coordinate (extended coordinates) */ + fp_st t; +#endif + /** Flag to indicate that this point is normalized. */ + int norm; +} ed_st; + +/** + * Pointer to an elliptic curve point. + */ +#if ALLOC == AUTO +typedef ed_st ed_t[1]; +#else +typedef ed_st *ed_t; +#endif + +/*============================================================================*/ +/* Macro definitions */ +/*============================================================================*/ + +/** + * Initializes a point on an Edwards curve with a null value. + * + * @param[out] A - the point to initialize. + */ +#if ALLOC == AUTO +#define ed_null(A) /* empty */ +#else +#define ed_null(A) A = NULL; +#endif + +/** + * Calls a function to allocate a point on an Edwards curve. + * + * @param[out] A - the new point. + * @throw ERR_NO_MEMORY - if there is no available memory. + */ +#if ALLOC == DYNAMIC +#define ed_new(A) \ + A = (ed_t)calloc(1, sizeof(ed_st)); \ + if (A == NULL) { \ + THROW(ERR_NO_MEMORY); \ + } + +#elif ALLOC == AUTO +#define ed_new(A) /* empty */ + +#elif ALLOC == STACK +#define ed_new(A) \ + A = (ed_t)alloca(sizeof(ed_st)); \ + +#endif + +/** + * Calls a function to clean and free a point on an Edwards curve. + * + * @param[out] A - the point to free. + */ +#if ALLOC == DYNAMIC +#define ed_free(A) \ + if (A != NULL) { \ + free(A); \ + A = NULL; \ + } + +#elif ALLOC == AUTO +#define ed_free(A) /* empty */ + +#elif ALLOC == STACK +#define ed_free(A) \ + A = NULL; \ + +#endif + +/** + * Negates an Edwards elliptic curve point. Computes R = -P. + * + * @param[out] R - the result. + * @param[in] P - the point to negate. + */ +#if ED_ADD == BASIC +#define ed_neg(R, P) ed_neg_basic(R, P) +#elif ED_ADD == PROJC || ED_ADD == EXTND +#define ed_neg(R, P) ed_neg_projc(R, P) +#endif + +/** + * Adds two Edwards elliptic curve points. Computes R = P + Q. + * + * @param[out] R - the result. + * @param[in] P - the first point to add. + * @param[in] Q - the second point to add. + */ +#if ED_ADD == BASIC +#define ed_add(R, P, Q) ed_add_basic(R, P, Q) +#elif ED_ADD == PROJC +#define ed_add(R, P, Q) ed_add_projc(R, P, Q) +#elif ED_ADD == EXTND +#define ed_add(R, P, Q) ed_add_extnd(R, P, Q) +#endif + +/** + * Subtracts an Edwards elliptic curve point from another. Computes R = P - Q. + * + * @param[out] R - the result. + * @param[in] P - the first point. + * @param[in] Q - the second point. + */ +#if ED_ADD == BASIC +#define ed_sub(R, P, Q) ed_sub_basic(R, P, Q) +#elif ED_ADD == PROJC +#define ed_sub(R, P, Q) ed_sub_projc(R, P, Q) +#elif ED_ADD == EXTND +#define ed_sub(R, P, Q) ed_sub_extnd(R, P, Q) +#endif + +/** + * Doubles an Edwards elliptic curve point. Computes R = 2P. + * + * @param[out] R - the result. + * @param[in] P - the point to double. + */ +#if ED_ADD == BASIC +#define ed_dbl(R, P) ed_dbl_basic(R, P) +#elif ED_ADD == PROJC +#define ed_dbl(R, P) ed_dbl_projc(R, P) +#elif ED_ADD == EXTND +#define ed_dbl(R, P) ed_dbl_extnd(R, P) +#endif + + +/** + * Configures an Edwards curve by its parameter identifier. + * + * @param - the parameter identifier. + */ +void ed_param_set(int param); + +/** + * Configures some set of curve parameters for the current security level. + */ +int ed_param_set_any(void); + +/** + * Returns the parameter identifier of the currently configured Edwards elliptic + * curve. + * + * @return the parameter identifier. + */ +int ed_param_get(void); + +/** + * Returns the order of the group of points in the Edwards curve. + * + * @param[out] r - the returned order. + */ +void ed_curve_get_ord(bn_t r); + +/** + * Returns the generator of the group of points in the curve. + * + * @param[out] g - the returned generator. + */ +void ed_curve_get_gen(ed_t g); + +/** + * Returns the precomputation table for the generator. + * + * @return the table. + */ +const ed_t *ed_curve_get_tab(void); + +/** + * Returns the cofactor of the Edwards elliptic curve. + * + * @param[out] n - the returned cofactor. + */ +void ed_curve_get_cof(bn_t h); + +/** + * Prints the current configured Edwards elliptic curve. + */ +void ed_param_print(void); + +/** + * Returns the current security level. + */ +int ed_param_level(void); + +#if ED_ADD == EXTND +/** + * Converts projective point into extended point. + */ +void ed_projc_to_extnd(ed_t r, const fp_t x, const fp_t y, const fp_t z); +#endif + +/** + * Assigns a random value to an Edwards elliptic curve point. + * + * @param[out] p - the Edwards elliptic curve point to assign. + */ +void ed_rand(ed_t p); + +/** + * Computes the right-hand side of the elliptic curve equation at a certain + * Edwards elliptic curve point. + * + * @param[out] rhs - the result. + * @param[in] p - the point. + */ +void ed_rhs(fp_t rhs, const ed_t p); + +/** + * Copies the second argument to the first argument. + * + * @param[out] q - the result. + * @param[in] p - the Edwards elliptic curve point to copy. + */ +void ed_copy(ed_t r, const ed_t p); + +/** + * Compares two Edwards elliptic curve points. + * + * @param[in] p - the first Edwards elliptic curve point. + * @param[in] q - the second Edwards elliptic curve point. + * @return RLC_EQ if p == q and RLC_NE if p != q. + */ +int ed_cmp(const ed_t p, const ed_t q); + +/** + * Assigns an Edwards elliptic curve point to a point at the infinity. + * + * @param[out] p - the point to assign. + */ +void ed_set_infty(ed_t p); + +/** + * Tests if a point on an Edwards elliptic curve is at the infinity. + * + * @param[in] p - the point to test. + * @return 1 if the point is at infinity, 0 otherise. + */ +int ed_is_infty(const ed_t p); + +/** + * Negates an Edwards elliptic curve point represented by affine coordinates. + * + * @param[out] r - the result. + * @param[in] p - the point to negate. + */ +void ed_neg_basic(ed_t r, const ed_t p); + +/** + * Negates an Edwards elliptic curve point represented by projective coordinates. + * + * @param[out] r - the result. + * @param[in] p - the point to negate. + */ +void ed_neg_projc(ed_t r, const ed_t p); + +/** + * Adds two Edwards elliptic curve points represented in affine coordinates. + * + * @param[out] r - the result. + * @param[in] p - the first point to add. + * @param[in] q - the second point to add. + */ +void ed_add_basic(ed_t r, const ed_t p, const ed_t q); + +/** + * Adds two Edwards elliptic curve points represented in projective coordinates. + * + * @param[out] r - the result. + * @param[in] p - the first point to add. + * @param[in] q - the second point to add. + */ +void ed_add_projc(ed_t r, const ed_t p, const ed_t q); + +/** + * Adds two Edwards elliptic curve points represented in exteded coordinates. + * + * @param[out] r - the result. + * @param[in] p - the first point to add. + * @param[in] q - the second point to add. + */ +void ed_add_extnd(ed_t r, const ed_t p, const ed_t q); + +/** + * Subtracts an Edwards elliptic curve point from another, both points represented + * by affine coordinates.. + * + * @param[out] r - the result. + * @param[in] p - the first point. + * @param[in] q - the second point. + */ +void ed_sub_basic(ed_t r, const ed_t p, const ed_t q); + +/** + * Subtracts an Edwards elliptic curve point from another, both represented + * by projective coordinates. + * + * @param[out] r - the result. + * @param[in] p - the first point. + * @param[in] q - the second point. + */ +void ed_sub_projc(ed_t r, const ed_t p, const ed_t q); + +/** + * Subtracts an Edwards elliptic curve point from another, both represented + * by extended coordinates. + * + * @param[out] r - the result. + * @param[in] p - the first point. + * @param[in] q - the second point. + */ +void ed_sub_extnd(ed_t r, const ed_t p, const ed_t q); + +/** + * Doubles an Edwards elliptic curve point represented in affine coordinates. + * + * @param[out] r - the result. + * @param[in] p - the point to double. + */ +void ed_dbl_basic(ed_t r, const ed_t p); + +/** + * Doubles an Edwards elliptic curve point represented in projective coordinates. + * + * @param[out] r - the result. + * @param[in] p - the point to double. + */ +void ed_dbl_projc(ed_t r, const ed_t p); + +/** + * Doubles an Edwards elliptic curve point represented in extended coordinates. + * + * @param[out] r - the result. + * @param[in] p - the point to double. + */ +void ed_dbl_extnd(ed_t r, const ed_t p); + +/** + * Converts a point to affine coordinates. + * + * @param[out] r - the result. + * @param[in] p - the point to convert. + */ +void ed_norm(ed_t r, const ed_t p); + +/** + * Converts multiple points to affine coordinates. + * + * @param[out] r - the result. + * @param[in] t - the points to convert. + * @param[in] n - the number of points. + */ +void ed_norm_sim(ed_t *r, const ed_t *t, int n); + +/** + * Maps a byte array to a point in an Edwards elliptic curve. + * + * @param[out] p - the result. + * @param[in] msg - the byte array to map. + * @param[in] len - the array length in bytes. + */ +void ed_map(ed_t p, const uint8_t *msg, int len); + +/** + * Multiplies an Edwards elliptic curve point by an integer. Computes R = kP. + * + * @param[out] R - the result. + * @param[in] P - the point to multiply. + * @param[in] K - the integer. + */ +#if ED_MUL == BASIC +#define ed_mul(R, P, K) ed_mul_basic(R, P, K) +#elif ED_MUL == SLIDE +#define ed_mul(R, P, K) ed_mul_slide(R, P, K) +#elif ED_MUL == MONTY +#define ed_mul(R, P, K) ed_mul_monty(R, P, K) +#elif ED_MUL == LWNAF +#define ed_mul(R, P, K) ed_mul_lwnaf(R, P, K) +#elif ED_MUL == LWREG +#define ed_mul(R, P, K) ed_mul_lwreg(R, P, K) +#endif + +/** + * Builds a precomputation table for multiplying a fixed Edwards elliptic point. + * + * @param[out] T - the precomputation table. + * @param[in] P - the point to multiply. + */ +#if ED_FIX == BASIC +#define ed_mul_pre(T, P) ed_mul_pre_basic(T, P) +#elif ED_FIX == COMBS +#define ed_mul_pre(T, P) ed_mul_pre_combs(T, P) +#elif ED_FIX == COMBD +#define ed_mul_pre(T, P) ed_mul_pre_combd(T, P) +#elif ED_FIX == LWNAF +#define ed_mul_pre(T, P) ed_mul_pre_lwnaf(T, P) +#endif + +/** + * Multiplies a fixed Edwards elliptic point using a precomputation table. + * Computes R = kP. + * + * @param[out] R - the result. + * @param[in] T - the precomputation table. + * @param[in] K - the integer. + */ +#if ED_FIX == BASIC +#define ed_mul_fix(R, T, K) ed_mul_fix_basic(R, T, K) +#elif ED_FIX == COMBS +#define ed_mul_fix(R, T, K) ed_mul_fix_combs(R, T, K) +#elif ED_FIX == COMBD +#define ed_mul_fix(R, T, K) ed_mul_fix_combd(R, T, K) +#elif ED_FIX == LWNAF +#define ed_mul_fix(R, T, K) ed_mul_fix_lwnaf(R, T, K) +#endif + + /** + * Multiplies and adds two Edwards elliptic curve points simultaneously. Computes + * R = kP + mQ. + * + * @param[out] R - the result. + * @param[in] P - the first point to multiply. + * @param[in] K - the first integer. + * @param[in] Q - the second point to multiply. + * @param[in] M - the second integer, + */ +#if ED_SIM == BASIC +#define ed_mul_sim(R, P, K, Q, M) ed_mul_sim_basic(R, P, K, Q, M) +#elif ED_SIM == TRICK +#define ed_mul_sim(R, P, K, Q, M) ed_mul_sim_trick(R, P, K, Q, M) +#elif ED_SIM == INTER +#define ed_mul_sim(R, P, K, Q, M) ed_mul_sim_inter(R, P, K, Q, M) +#elif ED_SIM == JOINT +#define ed_mul_sim(R, P, K, Q, M) ed_mul_sim_joint(R, P, K, Q, M) +#endif + +/*============================================================================*/ +/* Function prototypes */ +/*============================================================================*/ + +/** + * Initializes the Edwards elliptic curve arithmetic module. + */ +void ed_curve_init(void); + +/** + * Finalizes the Edwards elliptic curve arithmetic module. + */ +void ed_curve_clean(void); + +/** + * Builds a precomputation table for multiplying a fixed Edwards elliptic point + * using the binary method. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + */ +void ed_mul_pre_basic(ed_t *t, const ed_t p); + +/** + * Builds a precomputation table for multiplying a fixed Edwards elliptic point + * using Yao's windowing method. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + */ +void ed_mul_pre_yaowi(ed_t *t, const ed_t p); + +/** + * Builds a precomputation table for multiplying a fixed Edwards elliptic point + * using the NAF windowing method. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + */ +void ed_mul_pre_nafwi(ed_t *t, const ed_t p); + +/** + * Builds a precomputation table for multiplying a fixed Edwards elliptic point + * using the single-table comb method. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + */ +void ed_mul_pre_combs(ed_t *t, const ed_t p); + +/** + * Builds a precomputation table for multiplying a fixed Edwards elliptic point + * using the double-table comb method. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + */ +void ed_mul_pre_combd(ed_t *t, const ed_t p); + +/** + * Builds a precomputation table for multiplying a fixed Edwards elliptic point + * using the w-(T)NAF method. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + */ +void ed_mul_pre_lwnaf(ed_t *t, const ed_t p); + +/** + * Multiplies a fixed Edwards elliptic point using a precomputation table and + * the binary method. + * + * @param[out] r - the result. + * @param[in] t - the precomputation table. + * @param[in] k - the integer. + */ +void ed_mul_fix_basic(ed_t r, const ed_t *t, const bn_t k); + +/** + * Multiplies a fixed Edwards elliptic point using a precomputation table and + * Yao's windowing method + * + * @param[out] r - the result. + * @param[in] t - the precomputation table. + * @param[in] k - the integer. + */ +void ed_mul_fix_yaowi(ed_t r, const ed_t *t, const bn_t k); + +/** + * Multiplies a fixed Edwards elliptic point using a precomputation table and + * the w-(T)NAF method. + * + * @param[out] r - the result. + * @param[in] t - the precomputation table. + * @param[in] k - the integer. + */ +void ed_mul_fix_nafwi(ed_t r, const ed_t *t, const bn_t k); + +/** + * Multiplies a fixed Edwards elliptic point using a precomputation table and + * the single-table comb method. + * + * @param[out] r - the result. + * @param[in] t - the precomputation table. + * @param[in] k - the integer. + */ +void ed_mul_fix_combs(ed_t r, const ed_t *t, const bn_t k); + +/** + * Multiplies a fixed Edwards elliptic point using a precomputation table and + * the double-table comb method. + * + * @param[out] r - the result. + * @param[in] t - the precomputation table. + * @param[in] k - the integer. + */ +void ed_mul_fix_combd(ed_t r, const ed_t *t, const bn_t k); + +/** + * Multiplies a fixed Edwards elliptic point using a precomputation table and + * the w-(T)NAF method. + * + * @param[out] r - the result. + * @param[in] t - the precomputation table. + * @param[in] k - the integer. + */ +void ed_mul_fix_lwnaf(ed_t r, const ed_t *t, const bn_t k); + +/** + * Multiplies a fixed Edwards elliptic point using a precomputation table and + * the w-(T)NAF mixed coordinate method. + * + * @param[out] r - the result. + * @param[in] t - the precomputation table. + * @param[in] k - the integer. + */ +void ed_mul_fix_lwnaf_mixed(ed_t r, const ed_t *t, const bn_t k); + +/** + * Multiplies the generator of an Edwards elliptic curve by an integer. + * + * @param[out] r - the result. + * @param[in] k - the integer. + */ +void ed_mul_gen(ed_t r, const bn_t k); + +/** + * Multiplies an Edwards elliptic curve point by a small positive integer. + * + * @param[out] r - the result. + * @param[in] p - the point to multiply. + * @param[in] k - the integer. + */ +void ed_mul_dig(ed_t r, const ed_t p, dig_t k); + +/** + * Multiplies and adds two Edwards elliptic curve points simultaneously using + * scalar multiplication and point addition. + * + * @param[out] r - the result. + * @param[in] p - the first point to multiply. + * @param[in] k - the first integer. + * @param[in] q - the second point to multiply. + * @param[in] m - the second integer, + */ +void ed_mul_sim_basic(ed_t r, const ed_t p, const bn_t k, const ed_t q, + const bn_t m); + +/** + * Multiplies and adds two Edwards elliptic curve points simultaneously using + * shamir's trick. + * + * @param[out] r - the result. + * @param[in] p - the first point to multiply. + * @param[in] k - the first integer. + * @param[in] q - the second point to multiply. + * @param[in] m - the second integer, + */ +void ed_mul_sim_trick(ed_t r, const ed_t p, const bn_t k, const ed_t q, + const bn_t m); + +/** + * Multiplies and adds two Edwards elliptic curve points simultaneously using + * interleaving of NAFs. + * + * @param[out] r - the result. + * @param[in] p - the first point to multiply. + * @param[in] k - the first integer. + * @param[in] q - the second point to multiply. + * @param[in] m - the second integer, + */ +void ed_mul_sim_inter(ed_t r, const ed_t p, const bn_t k, const ed_t q, + const bn_t m); + +/** + * Multiplies and adds two Edwards elliptic curve points simultaneously using + * Solinas' Joint Sparse Form. + * + * @param[out] r - the result. + * @param[in] p - the first point to multiply. + * @param[in] k - the first integer. + * @param[in] q - the second point to multiply. + * @param[in] m - the second integer, + */ +void ed_mul_sim_joint(ed_t r, const ed_t p, const bn_t k, const ed_t q, + const bn_t m); + +/** + * Multiplies and adds the generator and an Edwards elliptic curve point + * simultaneously. Computes R = kG + mQ. + * + * @param[out] r - the result. + * @param[in] k - the first integer. + * @param[in] q - the second point to multiply. + * @param[in] m - the second integer. + */ +void ed_mul_sim_gen(ed_t r, const bn_t k, const ed_t q, const bn_t m); + +/** + * Builds a precomputation table for multiplying a random Edwards elliptic point. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + * @param[in] w - the window width. + */ +void ed_tab(ed_t *t, const ed_t p, int w); + +/** + * Prints an Edwards elliptic curve point. + * + * @param[in] p - the Edwards elliptic curve point to print. + */ +void ed_print(const ed_t p); + +/** + * Tests if a point is in the curve. + * + * @param[in] p - the point to test. + */ +int ed_is_valid(const ed_t p); + +/** + * Returns the number of bytes necessary to store an Edwards elliptic curve point + * with optional point compression. + * + * @param[in] a - the Edwards field element. + * @param[in] pack - the flag to indicate compression. + * @return the number of bytes. + */ +int ed_size_bin(const ed_t a, int pack); + +/** + * Reads an Edwards elliptic curve point from a byte vector in big-endian format. + * + * @param[out] a - the result. + * @param[in] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @throw ERR_NO_VALID - if the encoded point is invalid. + * @throw ERR_NO_BUFFER - if the buffer capacity is invalid. + */ +void ed_read_bin(ed_t a, const uint8_t *bin, int len); + +/** + * Writes an Edwards elliptic curve point to a byte vector in big-endian format + * with optional point compression. + * + * @param[out] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @param[in] a - the Edwards elliptic curve point to write. + * @param[in] pack - the flag to indicate point compression. + * @throw ERR_NO_BUFFER - if the buffer capacity is invalid. + */ +void ed_write_bin(uint8_t *bin, int len, const ed_t a, int pack); + +/** + * Multiplies an Edwards elliptic point by an integer using the binary method. + * + * @param[out] r - the result. + * @param[in] p - the point to multiply. + * @param[in] k - the integer. + */ +void ed_mul_basic(ed_t r, const ed_t p, const bn_t k); + +/** + * Multiplies an Edwards elliptic point by an integer using the sliding window + * method. + * + * @param[out] r - the result. + * @param[in] p - the point to multiply. + * @param[in] k - the integer. + */ +void ed_mul_slide(ed_t r, const ed_t p, const bn_t k); + +/** + * Multiplies an Edwards elliptic point by an integer using the constant-time + * Montgomery laddering point multiplication method. + * + * @param[out] r - the result. + * @param[in] p - the point to multiply. + * @param[in] k - the integer. + */ +void ed_mul_monty(ed_t r, const ed_t p, const bn_t k); + +/** + * Multiplies an Edwards elliptic point by an integer using the w-NAF method. + * + * @param[out] r - the result. + * @param[in] p - the point to multiply. + * @param[in] k - the integer. + */ +void ed_mul_lwnaf(ed_t r, const ed_t p, const bn_t k); + +/** + * Multiplies an Edwards elliptic point by an integer using a regular method. + * + * @param[out] r - the result. + * @param[in] p - the point to multiply. + * @param[in] k - the integer. + */ +void ed_mul_lwreg(ed_t r, const ed_t p, const bn_t k); + +/** + * Compresses a point. + * + * @param[out] r - the result. + * @param[in] p - the point to compress. + */ +void ed_pck(ed_t r, const ed_t p); + +/** + * Decompresses a point. + * + * @param[out] r - the result. + * @param[in] p - the point to decompress. + * @return if the decompression was successful + */ +int ed_upk(ed_t r, const ed_t p); + +#endif diff --git a/bls/contrib/relic/include/relic_ep.h b/bls/contrib/relic/include/relic_ep.h new file mode 100644 index 00000000..4ff6ad27 --- /dev/null +++ b/bls/contrib/relic/include/relic_ep.h @@ -0,0 +1,1185 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @defgroup ep Elliptic curves over prime fields + */ + +/** + * @file + * + * Interface of the module for arithmetic on prime elliptic curves. + * + * @ingroup ep + */ + +#ifndef RLC_EP_H +#define RLC_EP_H + +#include "relic_fp.h" +#include "relic_bn.h" +#include "relic_types.h" +#include "relic_label.h" + +/*============================================================================*/ +/* Constant definitions */ +/*============================================================================*/ + +/** + * Prime elliptic curve identifiers. + */ +enum { + /** SECG P-160 prime curve. */ + SECG_P160 = 1, + /** SECG K-160 prime curve. */ + SECG_K160, + /** NIST P-192 prime curve. */ + NIST_P192, + /** SECG K-192 prime curve. */ + SECG_K192, + /** Curve22103 prime curve. */ + CURVE_22103, + /** NIST P-224 prime curve. */ + NIST_P224, + /** SECG K-224 prime curve. */ + SECG_K224, + /** Curve4417 prime curve. */ + CURVE_4417, + /** Curve1147 prime curve. */ + CURVE_1174, + /** Curve25519 prime curve. */ + CURVE_25519, + /** NIST P-256 prime curve. */ + NIST_P256, + /** Brainpool P256r1 curve. */ + BSI_P256, + /** SECG K-256 prime curve. */ + SECG_K256, + /** Curve67254 prime curve. */ + CURVE_67254, + /** Curve383187 prime curve. */ + CURVE_383187, + /** NIST P-384 prime curve. */ + NIST_P384, + /** Curve 511187 prime curve. */ + CURVE_511187, + /** NIST P-521 prime curve. */ + NIST_P521, + /** Barreto-Naehrig curve with positive x */ + BN_P158, + /** Barreto-Naehrig curve with negative x (found by Nogami et al.). */ + BN_P254, + /** Barreto-Naehrig curve with negative x. */ + BN_P256, + /** Barreto-Lynn-Scott curve with embedding degree 12 (ZCash curve). */ + B12_P381, + /** Barreto-Naehrig curve with negative x. */ + BN_P382, + /** Barreto-Naehrig curve with embedding degree 12. */ + BN_P446, + /** Barreto-Lynn-Scott curve with embedding degree 12. */ + B12_P446, + /** Barreto-Lynn-Scott curve with embedding degree 12. */ + B12_P455, + /** Barreto-Lynn-Scott curve with embedding degree 24. */ + B24_P477, + /** Kachisa-Schafer-Scott with negative x. */ + KSS_P508, + /** Optimal TNFS-secure curve with embedding degree 8. */ + OT8_P511, + /** Cocks-pinch curve with embedding degree 8. */ + CP8_P544, + /** Kachisa-Scott-Schaefer curve with embedding degree 54. */ + K54_P569, + /** Barreto-Lynn-Scott curve with embedding degree 48. */ + B48_P575, + /** Barreto-Naehrig curve with positive x. */ + BN_P638, + /** Barreto-Lynn-Scott curve with embedding degree 12. */ + B12_P638, + /** 1536-bit supersingular curve. */ + SS_P1536, +}; + +/** + * Pairing-friendly elliptic curve identifiers. + */ +enum { + /** Supersingular curves with embedding degree 2. */ + EP_SS2 = 1, + /** Barreto-Naehrig. */ + EP_BN, + /* Optimal TNFS-secure. */ + EP_OT8, + /* Cocks-Pinch curve. */ + EP_CP8, + /* Barreto-Lynn-Scott with embedding degree 12. */ + EP_B12, + /* Kachisa-Schafer-Scott with embedding degree 16. */ + EP_K16, + /* Barreto-Lynn-Scott with embedding degree 24. */ + EP_B24, + /* Barreto-Lynn-Scott with embedding degree 48. */ + EP_B48, + /** Kachisa-Scott-Schaefer curve with embedding degree 54. */ + EP_K54, +}; + +/*============================================================================*/ +/* Constant definitions */ +/*============================================================================*/ + +/** + * Denotes a divisive twist. + */ +#define EP_DTYPE 1 + +/** + * Denotes a multiplicative twist. + */ +#define EP_MTYPE 2 + +/** + * Size of a precomputation table using the binary method. + */ +#define RLC_EP_TABLE_BASIC (RLC_FP_BITS + 1) + +/** + * Size of a precomputation table using the single-table comb method. + */ +#define RLC_EP_TABLE_COMBS (1 << EP_DEPTH) + +/** + * Size of a precomputation table using the double-table comb method. + */ +#define RLC_EP_TABLE_COMBD (1 << (EP_DEPTH + 1)) + +/** + * Size of a precomputation table using the w-(T)NAF method. + */ +#define RLC_EP_TABLE_LWNAF (1 << (EP_DEPTH - 2)) + +/** + * Size of a precomputation table using the chosen algorithm. + */ +#if EP_FIX == BASIC +#define RLC_EP_TABLE RLC_EP_TABLE_BASIC +#elif EP_FIX == COMBS +#define RLC_EP_TABLE RLC_EP_TABLE_COMBS +#elif EP_FIX == COMBD +#define RLC_EP_TABLE RLC_EP_TABLE_COMBD +#elif EP_FIX == LWNAF +#define RLC_EP_TABLE RLC_EP_TABLE_LWNAF +#endif + +/** + * Maximum size of a precomputation table. + */ +#ifdef STRIP +#define RLC_EP_TABLE_MAX RLC_EP_TABLE +#else +#define RLC_EP_TABLE_MAX RLC_MAX(RLC_EP_TABLE_BASIC, RLC_EP_TABLE_COMBD) +#endif + +/** + * Maximum number of coefficients of an isogeny map polynomial. + * RLC_TERMS of value 16 is sufficient for a degree-11 isogeny polynomial. + */ +#define RLC_EP_CTMAP_MAX 16 + +/*============================================================================*/ +/* Type definitions */ +/*============================================================================*/ + +/** + * Represents an elliptic curve point over a prime field. + */ +typedef struct { + /** The first coordinate. */ + fp_st x; + /** The second coordinate. */ + fp_st y; + /** The third coordinate (projective representation). */ + fp_st z; + /** Flag to indicate that this point is normalized. */ + int norm; +} ep_st; + + +/** + * Pointer to an elliptic curve point. + */ +#if ALLOC == AUTO +typedef ep_st ep_t[1]; +#else +typedef ep_st *ep_t; +#endif + +/** + * Data structure representing an isogeny map. + */ +typedef struct { + /** The a-coefficient of the isogenous curve used for SSWU mapping. */ + fp_st a; + /** The b-coefficient of the isogenous curve used for SSWU mapping. */ + fp_st b; + /** Degree of x numerator */ + int deg_xn; + /** Degree of x denominator */ + int deg_xd; + /** Degree of y numerator */ + int deg_yn; + /** Degree of y denominator */ + int deg_yd; + /** x numerator coefficients */ + fp_st xn[RLC_EP_CTMAP_MAX]; + /** x denominator coefficients */ + fp_st xd[RLC_EP_CTMAP_MAX]; + /** y numerator coefficients */ + fp_st yn[RLC_EP_CTMAP_MAX]; + /** y denominator coefficients */ + fp_st yd[RLC_EP_CTMAP_MAX]; +} iso_st; + +/** + * Pointer to isogeny map coefficients. + */ +typedef iso_st *iso_t; + +/*============================================================================*/ +/* Macro definitions */ +/*============================================================================*/ + +/** + * Initializes a point on a prime elliptic curve with a null value. + * + * @param[out] A - the point to initialize. + */ +#if ALLOC == AUTO +#define ep_null(A) /* empty */ +#else +#define ep_null(A) A = NULL; +#endif + +/** + * Calls a function to allocate a point on a prime elliptic curve. + * + * @param[out] A - the new point. + * @throw ERR_NO_MEMORY - if there is no available memory. + */ +#if ALLOC == DYNAMIC +#define ep_new(A) \ + A = (ep_t)calloc(1, sizeof(ep_st)); \ + if (A == NULL) { \ + THROW(ERR_NO_MEMORY); \ + } \ + +#elif ALLOC == AUTO +#define ep_new(A) /* empty */ + +#elif ALLOC == STACK +#define ep_new(A) \ + A = (ep_t)alloca(sizeof(ep_st)); \ + +#endif + +/** + * Calls a function to clean and free a point on a prime elliptic curve. + * + * @param[out] A - the point to free. + */ +#if ALLOC == DYNAMIC +#define ep_free(A) \ + if (A != NULL) { \ + free(A); \ + A = NULL; \ + } + +#elif ALLOC == AUTO +#define ep_free(A) /* empty */ + +#elif ALLOC == STACK +#define ep_free(A) \ + A = NULL; \ + +#endif + +/** + * Negates a prime elliptic curve point. Computes R = -P. + * + * @param[out] R - the result. + * @param[in] P - the point to negate. + */ +#if EP_ADD == BASIC +#define ep_neg(R, P) ep_neg_basic(R, P) +#elif EP_ADD == PROJC +#define ep_neg(R, P) ep_neg_projc(R, P) +#endif + +/** + * Adds two prime elliptic curve points. Computes R = P + Q. + * + * @param[out] R - the result. + * @param[in] P - the first point to add. + * @param[in] Q - the second point to add. + */ +#if EP_ADD == BASIC +#define ep_add(R, P, Q) ep_add_basic(R, P, Q) +#elif EP_ADD == PROJC +#define ep_add(R, P, Q) ep_add_projc(R, P, Q) +#endif + +/** + * Subtracts a prime elliptic curve point from another. Computes R = P - Q. + * + * @param[out] R - the result. + * @param[in] P - the first point. + * @param[in] Q - the second point. + */ +#if EP_ADD == BASIC +#define ep_sub(R, P, Q) ep_sub_basic(R, P, Q) +#elif EP_ADD == PROJC +#define ep_sub(R, P, Q) ep_sub_projc(R, P, Q) +#endif + +/** + * Doubles a prime elliptic curve point. Computes R = 2P. + * + * @param[out] R - the result. + * @param[in] P - the point to double. + */ +#if EP_ADD == BASIC +#define ep_dbl(R, P) ep_dbl_basic(R, P) +#elif EP_ADD == PROJC +#define ep_dbl(R, P) ep_dbl_projc(R, P) +#endif + +/** + * Multiplies a prime elliptic curve point by an integer. Computes R = kP. + * + * @param[out] R - the result. + * @param[in] P - the point to multiply. + * @param[in] K - the integer. + */ +#if EP_MUL == BASIC +#define ep_mul(R, P, K) ep_mul_basic(R, P, K) +#elif EP_MUL == SLIDE +#define ep_mul(R, P, K) ep_mul_slide(R, P, K) +#elif EP_MUL == MONTY +#define ep_mul(R, P, K) ep_mul_monty(R, P, K) +#elif EP_MUL == LWNAF +#define ep_mul(R, P, K) ep_mul_lwnaf(R, P, K) +#elif EP_MUL == LWREG +#define ep_mul(R, P, K) ep_mul_lwreg(R, P, K) +#endif + +/** + * Builds a precomputation table for multiplying a fixed prime elliptic point. + * + * @param[out] T - the precomputation table. + * @param[in] P - the point to multiply. + */ +#if EP_FIX == BASIC +#define ep_mul_pre(T, P) ep_mul_pre_basic(T, P) +#elif EP_FIX == COMBS +#define ep_mul_pre(T, P) ep_mul_pre_combs(T, P) +#elif EP_FIX == COMBD +#define ep_mul_pre(T, P) ep_mul_pre_combd(T, P) +#elif EP_FIX == LWNAF +#define ep_mul_pre(T, P) ep_mul_pre_lwnaf(T, P) +#endif + +/** + * Multiplies a fixed prime elliptic point using a precomputation table. + * Computes R = kP. + * + * @param[out] R - the result. + * @param[in] T - the precomputation table. + * @param[in] K - the integer. + */ +#if EP_FIX == BASIC +#define ep_mul_fix(R, T, K) ep_mul_fix_basic(R, T, K) +#elif EP_FIX == COMBS +#define ep_mul_fix(R, T, K) ep_mul_fix_combs(R, T, K) +#elif EP_FIX == COMBD +#define ep_mul_fix(R, T, K) ep_mul_fix_combd(R, T, K) +#elif EP_FIX == LWNAF +#define ep_mul_fix(R, T, K) ep_mul_fix_lwnaf(R, T, K) +#endif + +/** + * Multiplies and adds two prime elliptic curve points simultaneously. Computes + * R = kP + mQ. + * + * @param[out] R - the result. + * @param[in] P - the first point to multiply. + * @param[in] K - the first integer. + * @param[in] Q - the second point to multiply. + * @param[in] M - the second integer, + */ +#if EP_SIM == BASIC +#define ep_mul_sim(R, P, K, Q, M) ep_mul_sim_basic(R, P, K, Q, M) +#elif EP_SIM == TRICK +#define ep_mul_sim(R, P, K, Q, M) ep_mul_sim_trick(R, P, K, Q, M) +#elif EP_SIM == INTER +#define ep_mul_sim(R, P, K, Q, M) ep_mul_sim_inter(R, P, K, Q, M) +#elif EP_SIM == JOINT +#define ep_mul_sim(R, P, K, Q, M) ep_mul_sim_joint(R, P, K, Q, M) +#endif + +/*============================================================================*/ +/* Function prototypes */ +/*============================================================================*/ + +/** + * Initializes the prime elliptic curve arithmetic module. + */ +void ep_curve_init(void); + +/** + * Finalizes the prime elliptic curve arithmetic module. + */ +void ep_curve_clean(void); + +/** + * Returns the 'a' coefficient of the currently configured prime elliptic curve. + * + * @return the 'a' coefficient of the elliptic curve. + */ +dig_t *ep_curve_get_a(void); + +/** + * Returns the 'b' coefficient of the currently configured prime elliptic curve. + * + * @return the 'b' coefficient of the elliptic curve. + */ +dig_t *ep_curve_get_b(void); + +/** + * Returns the efficient endormorphism associated with the prime curve. + */ +dig_t *ep_curve_get_beta(void); + +/** + * Returns the parameter V1 of the prime curve. + */ +void ep_curve_get_v1(bn_t v[]); + +/** + * Returns the parameter V2 of the prime curve. + */ +void ep_curve_get_v2(bn_t v[]); + +/** + * Returns a optimization identifier based on the 'a' coefficient of the curve. + * + * @return the optimization identifier. + */ +int ep_curve_opt_a(void); + +/** + * Returns a optimization identifier based on the 'b' coefficient of the curve. + * + * @return the optimization identifier. + */ +int ep_curve_opt_b(void); + +/** + * Tests if the configured prime elliptic curve is a Koblitz curve. + * + * @return 1 if the prime elliptic curve is a Koblitz curve, 0 otherwise. + */ +int ep_curve_is_endom(void); + +/** + * Tests if the configured prime elliptic curve is supersingular. + * + * @return 1 if the prime elliptic curve is supersingular, 0 otherwise. + */ +int ep_curve_is_super(void); + +/** + * Tests if the configured prime elliptic curve is pairing-friendly. + * + * @return 0 if the prime elliptic curve is not pairing-friendly, and the + * family identifier otherwise. + */ +int ep_curve_is_pairf(void); + +/** + * Tests if the current curve should use an isogeny map for the SSWU map. + * + * @return 1 if the curve uses an isogeny, and 0 otherwise. + */ +int ep_curve_is_ctmap(void); + +/** + * Returns the generator of the group of points in the prime elliptic curve. + * + * @param[out] g - the returned generator. + */ +void ep_curve_get_gen(ep_t g); + +/** + * Returns the precomputation table for the generator. + * + * @return the table. + */ +const ep_t *ep_curve_get_tab(void); + +/** + * Returns the order of the group of points in the prime elliptic curve. + * + * @param[out] r - the returned order. + */ +void ep_curve_get_ord(bn_t n); + +/** + * Returns the cofactor of the binary elliptic curve. + * + * @param[out] n - the returned cofactor. + */ +void ep_curve_get_cof(bn_t h); + +/** + * Returns the isogeny map coefficients for use with the SSWU map. + */ +iso_t ep_curve_get_iso(void); + +/** + * Configures a prime elliptic curve without endomorphisms by its coefficients + * and generator. + * + * @param[in] a - the 'a' coefficient of the curve. + * @param[in] b - the 'b' coefficient of the curve. + * @param[in] g - the generator. + * @param[in] r - the order of the group of points. + * @param[in] h - the cofactor of the group order. + * @param[in] u - the non-square used for hashing to this curve. + * @param[in] ctmap - true if this curve will use an isogeny for mapping. + */ +void ep_curve_set_plain(const fp_t a, const fp_t b, const ep_t g, const bn_t r, + const bn_t h, const fp_t u, int ctmap); + +/** + * Configures a supersingular prime elliptic curve by its coefficients and + * generator. + * + * @param[in] a - the 'a' coefficient of the curve. + * @param[in] b - the 'b' coefficient of the curve. + * @param[in] g - the generator. + * @param[in] r - the order of the group of points. + * @param[in] h - the cofactor of the group order. + * @param[in] u - the non-square used for hashing to this curve. + * @param[in] ctmap - true if this curve will use an isogeny for mapping. + */ +void ep_curve_set_super(const fp_t a, const fp_t b, const ep_t g, const bn_t r, + const bn_t h, const fp_t u, int ctmap); + +/** + * Configures a prime elliptic curve with endomorphisms by its coefficients and + * generator. + * + * @param[in] a - the 'a' coefficient of the curve. + * @param[in] b - the 'b' coefficient of the curve. + * @param[in] g - the generator. + * @param[in] r - the order of the group of points. + * @param[in] beta - the constant associated with the endomorphism. + * @param[in] l - the exponent corresponding to the endomorphism. + * @param[in] h - the cofactor of the group order. + * @param[in] u - the non-square used for hashing to this curve. + * @param[in] ctmap - true if this curve will use an isogeny for mapping. + */ +void ep_curve_set_endom(const fp_t a, const fp_t b, const ep_t g, const bn_t r, + const bn_t h, const fp_t beta, const bn_t l, const fp_t u, int ctmap); + +/** + * Configures a prime elliptic curve by its parameter identifier. + * + * @param - the parameter identifier. + */ +void ep_param_set(int param); + +/** + * Configures some set of curve parameters for the current security level. + */ +int ep_param_set_any(void); + +/** + * Configures some set of ordinary curve parameters for the current security + * level. + * + * @return RLC_OK if there is a curve at this security level, RLC_ERR otherwise. + */ +int ep_param_set_any_plain(void); + +/** + * Configures some set of Koblitz curve parameters for the current security + * level. + * + * @return RLC_OK if there is a curve at this security level, RLC_ERR otherwise. + */ +int ep_param_set_any_endom(void); + +/** + * Configures some set of supersingular curve parameters for the current + * security level. + * + * @return RLC_OK if there is a curve at this security level, RLC_ERR otherwise. + */ +int ep_param_set_any_super(void); + +/** + * Configures some set of pairing-friendly curve parameters for the current + * security level. + * + * @return RLC_OK if there is a curve at this security level, RLC_ERR otherwise. + */ +int ep_param_set_any_pairf(void); + +/** + * Returns the parameter identifier of the currently configured prime elliptic + * curve. + * + * @return the parameter identifier. + */ +int ep_param_get(void); + +/** + * Prints the current configured prime elliptic curve. + */ +void ep_param_print(void); + +/** + * Returns the current security level. + */ +int ep_param_level(void); + +/** + * Returns the embedding degree of the currently configured elliptic curve. + */ +int ep_param_embed(void); + +/** + * Tests if a point on a prime elliptic curve is at the infinity. + * + * @param[in] p - the point to test. + * @return 1 if the point is at infinity, 0 otherise. + */ +int ep_is_infty(const ep_t p); + +/** + * Assigns a prime elliptic curve point to a point at the infinity. + * + * @param[out] p - the point to assign. + */ +void ep_set_infty(ep_t p); + +/** + * Copies the second argument to the first argument. + * + * @param[out] q - the result. + * @param[in] p - the prime elliptic curve point to copy. + */ +void ep_copy(ep_t r, const ep_t p); + +/** + * Compares two prime elliptic curve points. + * + * @param[in] p - the first prime elliptic curve point. + * @param[in] q - the second prime elliptic curve point. + * @return RLC_EQ if p == q and RLC_NE if p != q. + */ +int ep_cmp(const ep_t p, const ep_t q); + +/** + * Assigns a random value to a prime elliptic curve point. + * + * @param[out] p - the prime elliptic curve point to assign. + */ +void ep_rand(ep_t p); + +/** + * Computes the right-hand side of the elliptic curve equation at a certain + * prime elliptic curve point. + * + * @param[out] rhs - the result. + * @param[in] p - the point. + */ +void ep_rhs(fp_t rhs, const ep_t p); + +/** + * Tests if a point is in the curve. + * + * @param[in] p - the point to test. + */ +int ep_is_valid(const ep_t p); + +/** + * Builds a precomputation table for multiplying a random prime elliptic point. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + * @param[in] w - the window width. + */ +void ep_tab(ep_t *t, const ep_t p, int w); + +/** + * Prints a prime elliptic curve point. + * + * @param[in] p - the prime elliptic curve point to print. + */ +void ep_print(const ep_t p); + +/** + * Returns the number of bytes necessary to store a prime elliptic curve point + * with optional point compression. + * + * @param[in] a - the prime field element. + * @param[in] pack - the flag to indicate compression. + * @return the number of bytes. + */ +int ep_size_bin(const ep_t a, int pack); + +/** + * Reads a prime elliptic curve point from a byte vector in big-endian format. + * + * @param[out] a - the result. + * @param[in] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @throw ERR_NO_VALID - if the encoded point is invalid. + * @throw ERR_NO_BUFFER - if the buffer capacity is invalid. + */ +void ep_read_bin(ep_t a, const uint8_t *bin, int len); + +/** + * Writes a prime elliptic curve point to a byte vector in big-endian format + * with optional point compression. + * + * @param[out] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @param[in] a - the prime elliptic curve point to write. + * @param[in] pack - the flag to indicate point compression. + * @throw ERR_NO_BUFFER - if the buffer capacity is invalid. + */ +void ep_write_bin(uint8_t *bin, int len, const ep_t a, int pack); + +/** + * Negates a prime elliptic curve point represented by affine coordinates. + * + * @param[out] r - the result. + * @param[in] p - the point to negate. + */ +void ep_neg_basic(ep_t r, const ep_t p); + +/** + * Negates a prime elliptic curve point represented by projective coordinates. + * + * @param[out] r - the result. + * @param[in] p - the point to negate. + */ +void ep_neg_projc(ep_t r, const ep_t p); + +/** + * Adds two prime elliptic curve points represented in affine coordinates. + * + * @param[out] r - the result. + * @param[in] p - the first point to add. + * @param[in] q - the second point to add. + */ +void ep_add_basic(ep_t r, const ep_t p, const ep_t q); + +/** + * Adds two prime elliptic curve points represented in affine coordinates and + * returns the computed slope. + * + * @param[out] r - the result. + * @param[out] s - the slope. + * @param[in] p - the first point to add. + * @param[in] q - the second point to add. + */ +void ep_add_slp_basic(ep_t r, fp_t s, const ep_t p, const ep_t q); + +/** + * Adds two prime elliptic curve points represented in projective coordinates. + * + * @param[out] r - the result. + * @param[in] p - the first point to add. + * @param[in] q - the second point to add. + */ +void ep_add_projc(ep_t r, const ep_t p, const ep_t q); + +/** + * Subtracts a prime elliptic curve point from another, both points represented + * in affine coordinates. + * + * @param[out] r - the result. + * @param[in] p - the first point. + * @param[in] q - the second point. + */ +void ep_sub_basic(ep_t r, const ep_t p, const ep_t q); + +/** + * Subtracts a prime elliptic curve point from another, both points represented + * in projective coordinates. + * + * @param[out] r - the result. + * @param[in] p - the first point. + * @param[in] q - the second point. + */ +void ep_sub_projc(ep_t r, const ep_t p, const ep_t q); + +/** + * Doubles a prime elliptic curve point represented in affine coordinates. + * + * @param[out] r - the result. + * @param[in] p - the point to double. + */ +void ep_dbl_basic(ep_t r, const ep_t p); + +/** + * Doubles a prime elliptic curve point represented in affine coordinates and + * returns the computed slope. + * + * @param[out] r - the result. + * @param[out] s - the slope. + * @param[in] p - the point to double. + */ +void ep_dbl_slp_basic(ep_t r, fp_t s, const ep_t p); + +/** + * Doubles a prime elliptic curve point represented in projective coordinates. + * + * @param[out] r - the result. + * @param[in] p - the point to double. + */ +void ep_dbl_projc(ep_t r, const ep_t p); + +/** + * Multiplies a prime elliptic point by an integer using the binary method. + * + * @param[out] r - the result. + * @param[in] p - the point to multiply. + * @param[in] k - the integer. + */ +void ep_mul_basic(ep_t r, const ep_t p, const bn_t k); + +/** + * Multiplies a prime elliptic point by an integer using the sliding window + * method. + * + * @param[out] r - the result. + * @param[in] p - the point to multiply. + * @param[in] k - the integer. + */ +void ep_mul_slide(ep_t r, const ep_t p, const bn_t k); + +/** + * Multiplies a prime elliptic point by an integer using the constant-time + * Montgomery laddering point multiplication method. + * + * @param[out] r - the result. + * @param[in] p - the point to multiply. + * @param[in] k - the integer. + */ +void ep_mul_monty(ep_t r, const ep_t p, const bn_t k); + +/** + * Multiplies a prime elliptic point by an integer using the w-NAF method. + * + * @param[out] r - the result. + * @param[in] p - the point to multiply. + * @param[in] k - the integer. + */ +void ep_mul_lwnaf(ep_t r, const ep_t p, const bn_t k); + +/** + * Multiplies a prime elliptic point by an integer using a regular method. + * + * @param[out] r - the result. + * @param[in] p - the point to multiply. + * @param[in] k - the integer. + */ +void ep_mul_lwreg(ep_t r, const ep_t p, const bn_t k); + +/** + * Multiplies the generator of a prime elliptic curve by an integer. + * + * @param[out] r - the result. + * @param[in] k - the integer. + */ +void ep_mul_gen(ep_t r, const bn_t k); + +/** + * Multiplies a prime elliptic point by a small positive integer. + * + * @param[out] r - the result. + * @param[in] p - the point to multiply. + * @param[in] k - the integer. + */ +void ep_mul_dig(ep_t r, const ep_t p, dig_t k); + +/** + * Builds a precomputation table for multiplying a fixed prime elliptic point + * using the binary method. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + */ +void ep_mul_pre_basic(ep_t *t, const ep_t p); + +/** + * Builds a precomputation table for multiplying a fixed prime elliptic point + * using Yao's windowing method. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + */ +void ep_mul_pre_yaowi(ep_t *t, const ep_t p); + +/** + * Builds a precomputation table for multiplying a fixed prime elliptic point + * using the NAF windowing method. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + */ +void ep_mul_pre_nafwi(ep_t *t, const ep_t p); + +/** + * Builds a precomputation table for multiplying a fixed prime elliptic point + * using the single-table comb method. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + */ +void ep_mul_pre_combs(ep_t *t, const ep_t p); + +/** + * Builds a precomputation table for multiplying a fixed prime elliptic point + * using the double-table comb method. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + */ +void ep_mul_pre_combd(ep_t *t, const ep_t p); + +/** + * Builds a precomputation table for multiplying a fixed prime elliptic point + * using the w-(T)NAF method. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + */ +void ep_mul_pre_lwnaf(ep_t *t, const ep_t p); + +/** + * Multiplies a fixed prime elliptic point using a precomputation table and + * the binary method. + * + * @param[out] r - the result. + * @param[in] t - the precomputation table. + * @param[in] k - the integer. + */ +void ep_mul_fix_basic(ep_t r, const ep_t *t, const bn_t k); + +/** + * Multiplies a fixed prime elliptic point using a precomputation table and + * Yao's windowing method + * + * @param[out] r - the result. + * @param[in] t - the precomputation table. + * @param[in] k - the integer. + */ +void ep_mul_fix_yaowi(ep_t r, const ep_t *t, const bn_t k); + +/** + * Multiplies a fixed prime elliptic point using a precomputation table and + * the w-(T)NAF method. + * + * @param[out] r - the result. + * @param[in] t - the precomputation table. + * @param[in] k - the integer. + */ +void ep_mul_fix_nafwi(ep_t r, const ep_t *t, const bn_t k); + +/** + * Multiplies a fixed prime elliptic point using a precomputation table and + * the single-table comb method. + * + * @param[out] r - the result. + * @param[in] t - the precomputation table. + * @param[in] k - the integer. + */ +void ep_mul_fix_combs(ep_t r, const ep_t *t, const bn_t k); + +/** + * Multiplies a fixed prime elliptic point using a precomputation table and + * the double-table comb method. + * + * @param[out] r - the result. + * @param[in] t - the precomputation table. + * @param[in] k - the integer. + */ +void ep_mul_fix_combd(ep_t r, const ep_t *t, const bn_t k); + +/** + * Multiplies a fixed prime elliptic point using a precomputation table and + * the w-(T)NAF method. + * + * @param[out] r - the result. + * @param[in] t - the precomputation table. + * @param[in] k - the integer. + */ +void ep_mul_fix_lwnaf(ep_t r, const ep_t *t, const bn_t k); + +/** + * Multiplies and adds two prime elliptic curve points simultaneously using + * scalar multiplication and point addition. + * + * @param[out] r - the result. + * @param[in] p - the first point to multiply. + * @param[in] k - the first integer. + * @param[in] q - the second point to multiply. + * @param[in] m - the second integer, + */ +void ep_mul_sim_basic(ep_t r, const ep_t p, const bn_t k, const ep_t q, + const bn_t m); + +/** + * Multiplies and adds two prime elliptic curve points simultaneously using + * shamir's trick. + * + * @param[out] r - the result. + * @param[in] p - the first point to multiply. + * @param[in] k - the first integer. + * @param[in] q - the second point to multiply. + * @param[in] m - the second integer, + */ +void ep_mul_sim_trick(ep_t r, const ep_t p, const bn_t k, const ep_t q, + const bn_t m); + +/** + * Multiplies and adds two prime elliptic curve points simultaneously using + * interleaving of NAFs. + * + * @param[out] r - the result. + * @param[in] p - the first point to multiply. + * @param[in] k - the first integer. + * @param[in] q - the second point to multiply. + * @param[in] m - the second integer, + */ +void ep_mul_sim_inter(ep_t r, const ep_t p, const bn_t k, const ep_t q, + const bn_t m); + +/** + * Multiplies and adds two prime elliptic curve points simultaneously using + * Solinas' Joint Sparse Form. + * + * @param[out] r - the result. + * @param[in] p - the first point to multiply. + * @param[in] k - the first integer. + * @param[in] q - the second point to multiply. + * @param[in] m - the second integer, + */ +void ep_mul_sim_joint(ep_t r, const ep_t p, const bn_t k, const ep_t q, + const bn_t m); + +/** + * Multiplies and adds the generator and a prime elliptic curve point + * simultaneously. Computes R = kG + mQ. + * + * @param[out] r - the result. + * @param[in] k - the first integer. + * @param[in] q - the second point to multiply. + * @param[in] m - the second integer. + */ +void ep_mul_sim_gen(ep_t r, const bn_t k, const ep_t q, const bn_t m); + +/** + * Multiplies prime elliptic curve points by small scalars. + * Computes R = \sum k_iP_i. + * + * @param[out] r - the result. + * @param[in] p - the points to multiply. + * @param[in] k - the small scalars. + * @param[in] len - the number of points to multiply. + */ +void ep_mul_sim_dig(ep_t r, const ep_t p[], const dig_t k[], int len); + +/** + * Converts a point to affine coordinates. + * + * @param[out] r - the result. + * @param[in] p - the point to convert. + */ +void ep_norm(ep_t r, const ep_t p); + +/** + * Converts multiple points to affine coordinates. + * + * @param[out] r - the result. + * @param[in] t - the points to convert. + * @param[in] n - the number of points. + */ +void ep_norm_sim(ep_t *r, const ep_t *t, int n); + +/** + * Maps a byte array to a point in a prime elliptic curve. + * + * @param[out] p - the result. + * @param[in] msg - the byte array to map. + * @param[in] len - the array length in bytes. + */ +void ep_map(ep_t p, const uint8_t *msg, int len); + +/** + * Maps a byte array to a point in a prime elliptic curve with specified + * domain separation tag (aka personalization string). + * + * @param[out] p - the result. + * @param[in] msg - the byte array to map. + * @param[in] len - the array length in bytes. + * @param[in] dst - the domain separation tag. + * @param[in] dst_len - the domain separation tag length in bytes. + */ +void ep_map_dst(ep_t p, const uint8_t *msg, int len, const uint8_t *dst, int dst_len); + +/** + * Compresses a point. + * + * @param[out] r - the result. + * @param[in] p - the point to compress. + */ +void ep_pck(ep_t r, const ep_t p); + +/** + * Decompresses a point. + * + * @param[out] r - the result. + * @param[in] p - the point to decompress. + * @return a boolean value indicating if the decompression was successful. + */ +int ep_upk(ep_t r, const ep_t p); + +#endif /* !RLC_EP_H */ diff --git a/bls/contrib/relic/include/relic_epx.h b/bls/contrib/relic/include/relic_epx.h new file mode 100644 index 00000000..419a2a3a --- /dev/null +++ b/bls/contrib/relic/include/relic_epx.h @@ -0,0 +1,1022 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @defgroup epx Elliptic curves defined over extensions of prime fields. + */ + +/** + * @file + * + * Interface of the module for arithmetic on prime elliptic curves defined over + * extension fields. + * + * @ingroup epx + */ + +#ifndef RLC_EPX_H +#define RLC_EPX_H + +#include "relic_fpx.h" +#include "relic_ep.h" +#include "relic_types.h" + +/*============================================================================*/ +/* Constant definitions */ +/*============================================================================*/ + +/** + * Size of a precomputation table using the binary method. + */ +#define RLC_EPX_TABLE_BASIC (2 * RLC_FP_BITS + 1) + +/** + * Size of a precomputation table using the single-table comb method. + */ +#define RLC_EPX_TABLE_COMBS (1 << EP_DEPTH) + +/** + * Size of a precomputation table using the double-table comb method. + */ +#define RLC_EPX_TABLE_COMBD (1 << (EP_DEPTH + 1)) + +/** + * Size of a precomputation table using the w-(T)NAF method. + */ +#define RLC_EPX_TABLE_LWNAF (1 << (EP_DEPTH - 2)) + +/** + * Size of a precomputation table using the chosen algorithm. + */ +#if EP_FIX == BASIC +#define RLC_EPX_TABLE RLC_EPX_TABLE_BASIC +#elif EP_FIX == COMBS +#define RLC_EPX_TABLE RLC_EPX_TABLE_COMBS +#elif EP_FIX == COMBD +#define RLC_EPX_TABLE RLC_EPX_TABLE_COMBD +#elif EP_FIX == LWNAF +#define RLC_EPX_TABLE RLC_EPX_TABLE_LWNAF +#endif + +/** + * Maximum size of a precomputation table. + */ +#ifdef STRIP +#define RLC_EPX_TABLE_MAX RLC_EPX_TABLE +#else +#define RLC_EPX_TABLE_MAX RLC_MAX(RLC_EPX_TABLE_BASIC, RLC_EPX_TABLE_COMBD) +#endif + +/** + * Maximum number of coefficients of an isogeny map polynomial. + * 4 is sufficient for a degree-3 isogeny polynomial. + */ +#define RLC_EPX_CTMAP_MAX 4 + +/*============================================================================*/ +/* Type definitions */ +/*============================================================================*/ + +/** + * Represents an elliptic curve point over a quadratic extension over a prime + * field. + */ +typedef struct { + /** The first coordinate. */ + fp2_t x; + /** The second coordinate. */ + fp2_t y; + /** The third coordinate (projective representation). */ + fp2_t z; + /** Flag to indicate that this point is normalized. */ + int norm; +} ep2_st; + +/** + * Pointer to an elliptic curve point. + */ +#if ALLOC == AUTO +typedef ep2_st ep2_t[1]; +#else +typedef ep2_st *ep2_t; +#endif + +/** + * Represents an elliptic curve point over a cubic extension over a prime + * field. + */ +typedef struct { + /** The first coordinate. */ + fp3_t x; + /** The second coordinate. */ + fp3_t y; + /** The third coordinate (projective representation). */ + fp3_t z; + /** Flag to indicate that this point is normalized. */ + int norm; +} ep3_st; + +/** + * Pointer to an elliptic curve point. + */ +#if ALLOC == AUTO +typedef ep3_st ep3_t[1]; +#else +typedef ep3_st *ep3_t; +#endif + +/** + * Coefficients of an isogeny map for a curve over a quadratic extension. + */ +typedef struct { + /** The a-coefficient of the isogenous curve used for SSWU mapping. */ + fp2_t a; + /** The b-coefficient of the isogenous curve used for SSWU mapping. */ + fp2_t b; + /** Degree of x numerator */ + int deg_xn; + /** Degree of x denominator */ + int deg_xd; + /** Degree of y numerator */ + int deg_yn; + /** Degree of y denominator */ + int deg_yd; + /** x numerator coefficients */ + fp2_t xn[RLC_EPX_CTMAP_MAX]; + /** x denominator coefficients */ + fp2_t xd[RLC_EPX_CTMAP_MAX]; + /** y numerator coefficients */ + fp2_t yn[RLC_EPX_CTMAP_MAX]; + /** y denominator coefficients */ + fp2_t yd[RLC_EPX_CTMAP_MAX]; +#if ALLOC == STACK + /** In case of stack allocation, storage for the values in this struct. */ + /* a, b, and the elms in xn, xd, yn, yd */ + fp2_st storage[2 + 4 * RLC_EPX_CTMAP_MAX]; +#endif /* ALLOC == DYNAMIC or STACK */ +} iso2_st; + +/** + * Pointer to isogeny map coefficients. + */ +typedef iso2_st *iso2_t; + +/*============================================================================*/ +/* Macro definitions */ +/*============================================================================*/ + +/** + * Initializes a point on a elliptic curve with a null value. + * + * @param[out] A - the point to initialize. + */ +#if ALLOC == AUTO +#define ep2_null(A) /* empty */ +#else +#define ep2_null(A) A = NULL +#endif + +/** + * Calls a function to allocate a point on a elliptic curve. + * + * @param[out] A - the new point. + * @throw ERR_NO_MEMORY - if there is no available memory. + */ +#if ALLOC == DYNAMIC +#define ep2_new(A) \ + A = (ep2_t)calloc(1, sizeof(ep2_st)); \ + if (A == NULL) { \ + THROW(ERR_NO_MEMORY); \ + } \ + fp2_null((A)->x); \ + fp2_null((A)->y); \ + fp2_null((A)->z); \ + fp2_new((A)->x); \ + fp2_new((A)->y); \ + fp2_new((A)->z); \ + +#elif ALLOC == AUTO +#define ep2_new(A) /* empty */ + +#elif ALLOC == STACK +#define ep2_new(A) \ + A = (ep2_t)alloca(sizeof(ep2_st)); \ + fp2_new((A)->x); \ + fp2_new((A)->y); \ + fp2_new((A)->z); \ + +#endif + +/** + * Calls a function to clean and free a point on a elliptic curve. + * + * @param[out] A - the point to free. + */ +#if ALLOC == DYNAMIC +#define ep2_free(A) \ + if (A != NULL) { \ + fp2_free((A)->x); \ + fp2_free((A)->y); \ + fp2_free((A)->z); \ + free(A); \ + A = NULL; \ + } \ + +#elif ALLOC == AUTO +#define ep2_free(A) /* empty */ +#elif ALLOC == STACK +#define ep2_free(A) A = NULL; +#endif + +/** + * Negates a point in an elliptic curve over a quadratic extension field. + * Computes R = -P. + * + * @param[out] R - the result. + * @param[in] P - the point to negate. + */ +#if EP_ADD == BASIC +#define ep2_neg(R, P) ep2_neg_basic(R, P) +#elif EP_ADD == PROJC +#define ep2_neg(R, P) ep2_neg_projc(R, P) +#endif + +/** + * Adds two points in an elliptic curve over a quadratic extension field. + * Computes R = P + Q. + * + * @param[out] R - the result. + * @param[in] P - the first point to add. + * @param[in] Q - the second point to add. + */ +#if EP_ADD == BASIC +#define ep2_add(R, P, Q) ep2_add_basic(R, P, Q); +#elif EP_ADD == PROJC +#define ep2_add(R, P, Q) ep2_add_projc(R, P, Q); +#endif + +/** + * Subtracts a point in an elliptic curve over a quadratic extension field from + * another point in this curve. Computes R = P - Q. + * + * @param[out] R - the result. + * @param[in] P - the first point. + * @param[in] Q - the second point. + */ +#if EP_ADD == BASIC +#define ep2_sub(R, P, Q) ep2_sub_basic(R, P, Q) +#elif EP_ADD == PROJC +#define ep2_sub(R, P, Q) ep2_sub_projc(R, P, Q) +#endif + +/** + * Doubles a point in an elliptic curve over a quadratic extension field. + * Computes R = 2P. + * + * @param[out] R - the result. + * @param[in] P - the point to double. + */ +#if EP_ADD == BASIC +#define ep2_dbl(R, P) ep2_dbl_basic(R, P); +#elif EP_ADD == PROJC +#define ep2_dbl(R, P) ep2_dbl_projc(R, P); +#endif + +/** + * Multiplies a point in an elliptic curve over a quadratic extension field. + * Computes R = kP. + * + * @param[out] R - the result. + * @param[in] P - the point to multiply. + * @param[in] K - the integer. + */ +#if EP_MUL == BASIC +#define ep2_mul(R, P, K) ep2_mul_basic(R, P, K) +#elif EP_MUL == SLIDE +#define ep2_mul(R, P, K) ep2_mul_slide(R, P, K) +#elif EP_MUL == MONTY +#define ep2_mul(R, P, K) ep2_mul_monty(R, P, K) +#elif EP_MUL == LWNAF || EP2_MUL == LWREG +#define ep2_mul(R, P, K) ep2_mul_lwnaf(R, P, K) +#endif + +/** + * Builds a precomputation table for multiplying a fixed prime elliptic point + * over a quadratic extension. + * + * @param[out] T - the precomputation table. + * @param[in] P - the point to multiply. + */ +#if EP_FIX == BASIC +#define ep2_mul_pre(T, P) ep2_mul_pre_basic(T, P) +#elif EP_FIX == COMBS +#define ep2_mul_pre(T, P) ep2_mul_pre_combs(T, P) +#elif EP_FIX == COMBD +#define ep2_mul_pre(T, P) ep2_mul_pre_combd(T, P) +#elif EP_FIX == LWNAF +#define ep2_mul_pre(T, P) ep2_mul_pre_lwnaf(T, P) +#elif EP_FIX == GLV +//TODO: implement ep2_mul_pre_glv +#define ep2_mul_pre(T, P) ep2_mul_pre_lwnaf(T, P) +#endif + +/** + * Multiplies a fixed prime elliptic point over a quadratic extension using a + * precomputation table. Computes R = kP. + * + * @param[out] R - the result. + * @param[in] T - the precomputation table. + * @param[in] K - the integer. + */ +#if EP_FIX == BASIC +#define ep2_mul_fix(R, T, K) ep2_mul_fix_basic(R, T, K) +#elif EP_FIX == COMBS +#define ep2_mul_fix(R, T, K) ep2_mul_fix_combs(R, T, K) +#elif EP_FIX == COMBD +#define ep2_mul_fix(R, T, K) ep2_mul_fix_combd(R, T, K) +#elif EP_FIX == LWNAF +#define ep2_mul_fix(R, T, K) ep2_mul_fix_lwnaf(R, T, K) +#elif EP_FIX == GLV +//TODO: implement ep2_mul_pre_glv +#define ep2_mul_fix(R, T, K) ep2_mul_fix_lwnaf(R, T, K) +#endif + +/** + * Multiplies and adds two prime elliptic curve points simultaneously. Computes + * R = kP + lQ. + * + * @param[out] R - the result. + * @param[in] P - the first point to multiply. + * @param[in] K - the first integer. + * @param[in] Q - the second point to multiply. + * @param[in] M - the second integer, + */ +#if EP_SIM == BASIC +#define ep2_mul_sim(R, P, K, Q, M) ep2_mul_sim_basic(R, P, K, Q, M) +#elif EP_SIM == TRICK +#define ep2_mul_sim(R, P, K, Q, M) ep2_mul_sim_trick(R, P, K, Q, M) +#elif EP_SIM == INTER +#define ep2_mul_sim(R, P, K, Q, M) ep2_mul_sim_inter(R, P, K, Q, M) +#elif EP_SIM == JOINT +#define ep2_mul_sim(R, P, K, Q, M) ep2_mul_sim_joint(R, P, K, Q, M) +#endif + +/*============================================================================*/ +/* Function prototypes */ +/*============================================================================*/ + +/** + * Initializes the elliptic curve over quadratic extension. + */ +void ep2_curve_init(void); + +/** + * Finalizes the elliptic curve over quadratic extension. + */ +void ep2_curve_clean(void); + +/** + * Returns the 'a' coefficient of the currently configured elliptic curve. + * + * @return the 'a' coefficient of the elliptic curve. + */ +fp_t *ep2_curve_get_a(void); + +/** + * Returns the 'b' coefficient of the currently configured elliptic curve. + * + * @param[out] b - the 'b' coefficient of the elliptic curve. + */ +fp_t *ep2_curve_get_b(void); + +/** + * Returns the vector of coefficients required to perform GLV method. + * + * @param[out] b - the vector of coefficients. + */ +void ep2_curve_get_vs(bn_t *v); + +/** + * Returns a optimization identifier based on the 'a' coefficient of the curve. + * + * @return the optimization identifier. + */ +int ep2_curve_opt_a(void); + +/** + * Returns b optimization identifier based on the 'b' coefficient of the curve. + * + * @return the optimization identifier. + */ +int ep2_curve_opt_b(void); + +/** + * Tests if the configured elliptic curve is a twist. + * + * @return the type of the elliptic curve twist, 0 if non-twisted curve. + */ +int ep2_curve_is_twist(void); + +/** + * Tests if the current curve should use an isogeny map for the SSWU map. + * + * @return 1 if the curve uses an isogeny, and 0 otherwise. + */ +int ep2_curve_is_ctmap(void); + +/** + * Returns the generator of the group of points in the elliptic curve. + * + * @param[out] g - the returned generator. + */ +void ep2_curve_get_gen(ep2_t g); + +/** + * Returns the precomputation table for the generator. + * + * @return the table. + */ +ep2_t *ep2_curve_get_tab(void); + +/** + * Returns the order of the group of points in the elliptic curve. + * + * @param[out] n - the returned order. + */ +void ep2_curve_get_ord(bn_t n); + +/** + * Returns the cofactor of the group order in the elliptic curve. + * + * @param[out] h - the returned cofactor. + */ +void ep2_curve_get_cof(bn_t h); + +/** + * Returns the sqrt(-3) mod q in the curve, where q is the prime. + * + * @param[out] h - the returned cofactor. + */ +void ep2_curve_get_s3(bn_t s3); + +/** + * Returns the (sqrt(-3) - 1) / 2 mod q in the curve, where q is the prime. + * + * @param[out] h - the returned cofactor. + */ +void ep2_curve_get_s32(bn_t s32); + +/** + * Returns the isogeny map coefficients for use with the SSWU map. + */ +iso2_t ep2_curve_get_iso(void); + +/** + * Configures an elliptic curve over a quadratic extension by its coefficients. + * + * @param[in] a - the 'a' coefficient of the curve. + * @param[in] b - the 'b' coefficient of the curve. + * @param[in] g - the generator. + * @param[in] r - the order of the group of points. + * @param[in] h - the cofactor of the group order. + */ +void ep2_curve_set(fp2_t a, fp2_t b, ep2_t g, bn_t r, bn_t h); + +/** + * Configures an elliptic curve by twisting the curve over the base prime field. + * + * @param - the type of twist (multiplicative or divisive) + */ +void ep2_curve_set_twist(int type); + +/** + * Tests if a point on a elliptic curve is at the infinity. + * + * @param[in] p - the point to test. + * @return 1 if the point is at infinity, 0 otherise. + */ +int ep2_is_infty(ep2_t p); + +/** + * Assigns a elliptic curve point to a point at the infinity. + * + * @param[out] p - the point to assign. + */ +void ep2_set_infty(ep2_t p); + +/** + * Copies the second argument to the first argument. + * + * @param[out] q - the result. + * @param[in] p - the elliptic curve point to copy. + */ +void ep2_copy(ep2_t r, ep2_t p); + +/** + * Compares two elliptic curve points. + * + * @param[in] p - the first elliptic curve point. + * @param[in] q - the second elliptic curve point. + * @return RLC_EQ if p == q and RLC_NE if p != q. + */ +int ep2_cmp(ep2_t p, ep2_t q); + +/** + * Assigns a random value to an elliptic curve point. + * + * @param[out] p - the elliptic curve point to assign. + */ +void ep2_rand(ep2_t p); + +/** + * Computes the right-hand side of the elliptic curve equation at a certain + * elliptic curve point. + * + * @param[out] rhs - the result. + * @param[in] p - the point. + */ +void ep2_rhs(fp2_t rhs, ep2_t p); + +/** + * Tests if a point is in the curve. + * + * @param[in] p - the point to test. + */ +int ep2_is_valid(ep2_t p); + +/** + * Builds a precomputation table for multiplying a random prime elliptic point. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + * @param[in] w - the window width. + */ +void ep2_tab(ep2_t *t, ep2_t p, int w); + +/** + * Prints a elliptic curve point. + * + * @param[in] p - the elliptic curve point to print. + */ +void ep2_print(ep2_t p); + +/** + * Returns the number of bytes necessary to store a prime elliptic curve point + * over a quadratic extension with optional point compression. + * + * @param[in] a - the prime field element. + * @param[in] pack - the flag to indicate compression. + * @return the number of bytes. + */ +int ep2_size_bin(ep2_t a, int pack); + +/** + * Reads a prime elliptic curve point over a quadratic extension from a byte + * vector in big-endian format. + * + * @param[out] a - the result. + * @param[in] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @throw ERR_NO_VALID - if the encoded point is invalid. + * @throw ERR_NO_BUFFER - if the buffer capacity is invalid. + */ +void ep2_read_bin(ep2_t a, const uint8_t *bin, int len); + +/** + * Writes a prime elliptic curve pointer over a quadratic extension to a byte + * vector in big-endian format with optional point compression. + * + * @param[out] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @param[in] a - the prime elliptic curve point to write. + * @param[in] pack - the flag to indicate point compression. + * @throw ERR_NO_BUFFER - if the buffer capacity is invalid. + */ +void ep2_write_bin(uint8_t *bin, int len, ep2_t a, int pack); + +/** + * Negates a point represented in affine coordinates in an elliptic curve over + * a quadratic extension. + * + * @param[out] r - the result. + * @param[out] p - the point to negate. + */ +void ep2_neg_basic(ep2_t r, ep2_t p); + +/** + * Negates a point represented in projective coordinates in an elliptic curve + * over a quadratic exyension. + * + * @param[out] r - the result. + * @param[out] p - the point to negate. + */ +void ep2_neg_projc(ep2_t r, ep2_t p); + +/** + * Adds to points represented in affine coordinates in an elliptic curve over a + * quadratic extension. + * + * @param[out] r - the result. + * @param[in] p - the first point to add. + * @param[in] q - the second point to add. + */ +void ep2_add_basic(ep2_t r, ep2_t p, ep2_t q); + +/** + * Adds to points represented in affine coordinates in an elliptic curve over a + * quadratic extension and returns the computed slope. + * + * @param[out] r - the result. + * @param[out] s - the slope. + * @param[in] p - the first point to add. + * @param[in] q - the second point to add. + */ +void ep2_add_slp_basic(ep2_t r, fp2_t s, ep2_t p, ep2_t q); + +/** + * Subtracts a points represented in affine coordinates in an elliptic curve + * over a quadratic extension from another point. + * + * @param[out] r - the result. + * @param[in] p - the first point. + * @param[in] q - the point to subtract. + */ +void ep2_sub_basic(ep2_t r, ep2_t p, ep2_t q); + +/** + * Adds two points represented in projective coordinates in an elliptic curve + * over a quadratic extension. + * + * @param[out] r - the result. + * @param[in] p - the first point to add. + * @param[in] q - the second point to add. + */ +void ep2_add_projc(ep2_t r, ep2_t p, ep2_t q); + +/** + * Subtracts a points represented in projective coordinates in an elliptic curve + * over a quadratic extension from another point. + * + * @param[out] r - the result. + * @param[in] p - the first point. + * @param[in] q - the point to subtract. + */ +void ep2_sub_projc(ep2_t r, ep2_t p, ep2_t q); + +/** + * Doubles a points represented in affine coordinates in an elliptic curve over + * a quadratic extension. + * + * @param[out] r - the result. + * @param[int] p - the point to double. + */ +void ep2_dbl_basic(ep2_t r, ep2_t p); + +/** + * Doubles a points represented in affine coordinates in an elliptic curve over + * a quadratic extension and returns the computed slope. + * + * @param[out] r - the result. + * @param[out] s - the slope. + * @param[in] p - the point to double. + */ +void ep2_dbl_slp_basic(ep2_t r, fp2_t s, ep2_t p); + +/** + * Doubles a points represented in projective coordinates in an elliptic curve + * over a quadratic extension. + * + * @param[out] r - the result. + * @param[in] p - the point to double. + */ +void ep2_dbl_projc(ep2_t r, ep2_t p); + +/** + * Multiplies a prime elliptic point by an integer using the binary method. + * + * @param[out] r - the result. + * @param[in] p - the point to multiply. + * @param[in] k - the integer. + */ +void ep2_mul_basic(ep2_t r, ep2_t p, const bn_t k); + +/** + * Multiplies a prime elliptic point by an integer using the sliding window + * method. + * + * @param[out] r - the result. + * @param[in] p - the point to multiply. + * @param[in] k - the integer. + */ +void ep2_mul_slide(ep2_t r, ep2_t p, const bn_t k); + +/** + * Multiplies a prime elliptic point by an integer using the constant-time + * Montgomery laddering point multiplication method. + * + * @param[out] r - the result. + * @param[in] p - the point to multiply. + * @param[in] k - the integer. + */ +void ep2_mul_monty(ep2_t r, ep2_t p, const bn_t k); + +/** + * Multiplies a prime elliptic point by an integer using the w-NAF method. + * + * @param[out] r - the result. + * @param[in] p - the point to multiply. + * @param[in] k - the integer. + */ +void ep2_mul_lwnaf(ep2_t r, ep2_t p, const bn_t k); + +/** + * Multiplies a prime elliptic point by an integer using a regular method. + * + * @param[out] r - the result. + * @param[in] p - the point to multiply. + * @param[in] k - the integer. + */ +void ep2_mul_lwreg(ep2_t r, ep2_t p, const bn_t k); + +/** + * Multiplies the generator of an elliptic curve over a qaudratic extension. + * + * @param[out] r - the result. + * @param[in] k - the integer. + */ +void ep2_mul_gen(ep2_t r, bn_t k); + +/** + * Multiplies a prime elliptic point by a small integer. + * + * @param[out] r - the result. + * @param[in] p - the point to multiply. + * @param[in] k - the integer. + */ +void ep2_mul_dig(ep2_t r, ep2_t p, dig_t k); + +/** + * Builds a precomputation table for multiplying a fixed prime elliptic point + * using the binary method. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + */ +void ep2_mul_pre_basic(ep2_t *t, ep2_t p); + +/** + * Builds a precomputation table for multiplying a fixed prime elliptic point + * using Yao's windowing method. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + */ +void ep2_mul_pre_yaowi(ep2_t *t, ep2_t p); + +/** + * Builds a precomputation table for multiplying a fixed prime elliptic point + * using the NAF windowing method. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + */ +void ep2_mul_pre_nafwi(ep2_t *t, ep2_t p); + +/** + * Builds a precomputation table for multiplying a fixed prime elliptic point + * using the single-table comb method. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + */ +void ep2_mul_pre_combs(ep2_t *t, ep2_t p); + +/** + * Builds a precomputation table for multiplying a fixed prime elliptic point + * using the double-table comb method. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + */ +void ep2_mul_pre_combd(ep2_t *t, ep2_t p); + +/** + * Builds a precomputation table for multiplying a fixed prime elliptic point + * using the w-(T)NAF method. + * + * @param[out] t - the precomputation table. + * @param[in] p - the point to multiply. + */ +void ep2_mul_pre_lwnaf(ep2_t *t, ep2_t p); + +/** + * Multiplies a fixed prime elliptic point using a precomputation table and + * the binary method. + * + * @param[out] r - the result. + * @param[in] t - the precomputation table. + * @param[in] k - the integer. + */ +void ep2_mul_fix_basic(ep2_t r, ep2_t *t, bn_t k); + +/** + * Multiplies a fixed prime elliptic point using a precomputation table and + * Yao's windowing method + * + * @param[out] r - the result. + * @param[in] t - the precomputation table. + * @param[in] k - the integer. + */ +void ep2_mul_fix_yaowi(ep2_t r, ep2_t *t, bn_t k); + +/** + * Multiplies a fixed prime elliptic point using a precomputation table and + * the w-(T)NAF method. + * + * @param[out] r - the result. + * @param[in] t - the precomputation table. + * @param[in] k - the integer. + */ +void ep2_mul_fix_nafwi(ep2_t r, ep2_t *t, bn_t k); + +/** + * Multiplies a fixed prime elliptic point using a precomputation table and + * the single-table comb method. + * + * @param[out] r - the result. + * @param[in] t - the precomputation table. + * @param[in] k - the integer. + */ +void ep2_mul_fix_combs(ep2_t r, ep2_t *t, bn_t k); + +/** + * Multiplies a fixed prime elliptic point using a precomputation table and + * the double-table comb method. + * + * @param[out] r - the result. + * @param[in] t - the precomputation table. + * @param[in] k - the integer. + */ +void ep2_mul_fix_combd(ep2_t r, ep2_t *t, bn_t k); + +/** + * Multiplies a fixed prime elliptic point using a precomputation table and + * the w-(T)NAF method. + * + * @param[out] r - the result. + * @param[in] t - the precomputation table. + * @param[in] k - the integer. + */ +void ep2_mul_fix_lwnaf(ep2_t r, ep2_t *t, bn_t k); + +/** + * Multiplies and adds two prime elliptic curve points simultaneously using + * scalar multiplication and point addition. + * + * @param[out] r - the result. + * @param[in] p - the first point to multiply. + * @param[in] k - the first integer. + * @param[in] q - the second point to multiply. + * @param[in] m - the second integer, + */ +void ep2_mul_sim_basic(ep2_t r, ep2_t p, bn_t k, ep2_t q, bn_t m); + +/** + * Multiplies and adds two prime elliptic curve points simultaneously using + * shamir's trick. + * + * @param[out] r - the result. + * @param[in] p - the first point to multiply. + * @param[in] k - the first integer. + * @param[in] q - the second point to multiply. + * @param[in] m - the second integer, + */ +void ep2_mul_sim_trick(ep2_t r, ep2_t p, bn_t k, ep2_t q, bn_t m); + +/** + * Multiplies and adds two prime elliptic curve points simultaneously using + * interleaving of NAFs. + * + * @param[out] r - the result. + * @param[in] p - the first point to multiply. + * @param[in] k - the first integer. + * @param[in] q - the second point to multiply. + * @param[in] m - the second integer, + */ +void ep2_mul_sim_inter(ep2_t r, ep2_t p, bn_t k, ep2_t q, bn_t m); + +/** + * Multiplies and adds two prime elliptic curve points simultaneously using + * Solinas' Joint Sparse Form. + * + * @param[out] r - the result. + * @param[in] p - the first point to multiply. + * @param[in] k - the first integer. + * @param[in] q - the second point to multiply. + * @param[in] m - the second integer, + */ +void ep2_mul_sim_joint(ep2_t r, ep2_t p, bn_t k, ep2_t q, bn_t m); + +/** + * Multiplies and adds the generator and a prime elliptic curve point + * simultaneously. Computes R = kG + lQ. + * + * @param[out] r - the result. + * @param[in] k - the first integer. + * @param[in] q - the second point to multiply. + * @param[in] m - the second integer, + */ +void ep2_mul_sim_gen(ep2_t r, bn_t k, ep2_t q, bn_t m); + +/** + * Multiplies prime elliptic curve points by small scalars. + * Computes R = \sum k_iP_i. + * + * @param[out] r - the result. + * @param[in] p - the points to multiply. + * @param[in] k - the small scalars. + * @param[in] len - the number of points to multiply. + */ +void ep2_mul_sim_dig(ep2_t r, ep2_t p[], dig_t k[], int len); + +/** + * Converts a point to affine coordinates. + * + * @param[out] r - the result. + * @param[in] p - the point to convert. + */ +void ep2_norm(ep2_t r, ep2_t p); + +/** + * Converts multiple points to affine coordinates. + * + * @param[out] r - the result. + * @param[in] t - the points to convert. + * @param[in] n - the number of points. + */ +void ep2_norm_sim(ep2_t *r, ep2_t *t, int n); + +/** + * Maps a byte array to a point in a prime elliptic curve. The + * algorithm implemented is the Fouque-Tibouchi algorithm from the + * paper "Indifferentiable Hashing to Barreto-Naehrig curves" for + * the BLS12-381 curve. + * + * @param[out] p - the result. + * @param[in] msg - the byte array to map. + * @param[in] len - the array length in bytes. + */ +void ep2_map(ep2_t p, const uint8_t *msg, int len, int performHash); + +/** + * Computes a power of the Gailbraith-Lin-Scott homomorphism of a point + * represented in affine coordinates on a twisted elliptic curve over a + * quadratic exension. That is, Psi^i(P) = Twist(P)(Frob^i(unTwist(P)). + * On the trace-zero group of a quadratic twist, consists of a power of the + * Frobenius map of a point represented in affine coordinates in an elliptic + * curve over a quadratic exension. Computes Frob^i(P) = (p^i)P. + * + * @param[out] r - the result in affine coordinates. + * @param[in] p - a point in affine coordinates. + * @param[in] i - the power of the Frobenius map. + */ +void ep2_frb(ep2_t r, ep2_t p, int i); + +/** + * Compresses a point in an elliptic curve over a quadratic extension. + * + * @param[out] r - the result. + * @param[in] p - the point to compress. + */ +void ep2_pck(ep2_t r, ep2_t p); + +/** + * Decompresses a point in an elliptic curve over a quadratic extension. + * + * @param[out] r - the result. + * @param[in] p - the point to decompress. + * @return if the decompression was successful + */ +int ep2_upk(ep2_t r, ep2_t p); + +#endif /* !RLC_EPX_H */ diff --git a/bls/contrib/relic/include/relic_err.h b/bls/contrib/relic/include/relic_err.h new file mode 100644 index 00000000..559afbbf --- /dev/null +++ b/bls/contrib/relic/include/relic_err.h @@ -0,0 +1,340 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @file + * + * Interface of the error-handling functions. + * + * @ingroup relic + */ + +#ifndef RLC_ERR_H +#define RLC_ERR_H + +#include +#include +#include +#include +#include + +#include "relic_core.h" +#include "relic_conf.h" +#include "relic_util.h" +#include "relic_label.h" + +/*============================================================================*/ +/* Constant definitions */ +/*============================================================================*/ + +/** + * List of possible errors generated by the library. + */ +enum errors { + /** Constant to indicate the first an error already catched. */ + ERR_CAUGHT = 1, + /** Occurs when memory-allocating functions fail. */ + ERR_NO_MEMORY, + /** Occcurs when the library precision is not sufficient. */ + ERR_NO_PRECI, + /** Occurs when a file is not found. */ + ERR_NO_FILE, + /** Occurs when the specified number of bytes cannot be read from source. */ + ERR_NO_READ, + /** Occurs when an invalid value is passed as input. */ + ERR_NO_VALID, + /** Occurs when a buffer capacity is insufficient. */ + ERR_NO_BUFFER, + /** Occurs when there is not a supported field in the security level. */ + ERR_NO_FIELD, + /** Occurs when there is not a supported curve in the security level. */ + ERR_NO_CURVE, + /** Occurs when the library configuration is incorrect. */ + ERR_NO_CONFIG, + /** Constant to indicate the number of errors. */ + ERR_MAX +}; + +/** Truncate file name if verbosity is turned off. */ +#ifdef VERBS +#define ERR_FILE RLC_STR(__FILE__) +#else +#define ERR_FILE \ + ((strrchr(RLC_STR(__FILE__), '/') ? : RLC_STR(__FILE__) - 1) + 1) +#endif + +/*============================================================================*/ +/* Type definitions */ +/*============================================================================*/ + +/** + * Type that represents an error. + */ +typedef int err_t; + +/** + * Type that describes an error status, including the error code and the program + * location where the error occurred. + */ +typedef struct _sts_t { + /** Error occurred. */ + err_t *error; + /** Pointer to the program location where the error occurred. */ + jmp_buf addr; + /** Flag to tell if there is a surrounding try-catch block. */ + int block; +} sts_t; + +/*============================================================================*/ +/* Macro definitions */ +/*============================================================================*/ + +/** + * Implements the TRY clause of the error-handling routines. + * + * This macro copies the last error from the current library context to + * a temporary variable and handles the current error. The loop is used so + * the CATCH facility is called first to store the address of the error + * being caught. The setjmp() function is then called to store the current + * program location in the current error field. The program block can now be + * executed. If an error is thrown inside the program block, the setjmp() + * function is called again and the return value is non-zero. + */ +#define ERR_TRY \ + { \ + sts_t *_last, _this; \ + ctx_t *_ctx = core_get(); \ + _last = _ctx->last; \ + _this.block = 1; \ + _ctx->last = &_this; \ + for (int _z = 0; ; _z = 1) \ + if (_z) { \ + if (setjmp(_this.addr) == 0) { \ + if (1) \ + +/** + * Implements the CATCH clause of the error-handling routines. + * + * First, the address of the error is stored and the execution resumes + * on the ERR_TRY macro. If an error is thrown inside the program block, + * the caught flag is updated and the last error is restored. If some error + * was caught, the execution is resumed inside the CATCH block. + * + * @param[in] ADDR - the address of the exception being caught + */ +#define ERR_CATCH(ADDR) \ + else { } \ + _ctx->caught = 0; \ + } else { \ + _ctx->caught = 1; \ + } \ + _ctx->last = _last; \ + break; \ + } else { \ + _this.error = ADDR; \ + } \ + } \ + for (int _z = 0; _z < 2; _z++) \ + if (_z == 1 && core_get()->caught) \ + +/** + * Implements the THROW clause of the error-handling routines. + * + * If the error pointer is not NULL but there is no surrounding TRY-CATCH + * block, then the code threw an exception after an exception was thrown. + * In this case, we finish execution. + * + * If the error pointer is NULL, the error was thrown outside of a TRY-CATCH + * block. An error message is printed and the function returns. + * + * If the error pointer is valid, the longjmp() function is called to return to + * the program location where setjmp() was last called. An error message + * respective to the error is then printed and the current error pointer is + * updated to store the error. + * + * @param[in] E - the exception being caught. + */ +#define ERR_THROW(E) \ + { \ + ctx_t *_ctx = core_get(); \ + _ctx->code = RLC_ERR; \ + if (_ctx->last != NULL && _ctx->last->block == 0) { \ + exit(E); \ + } \ + if (_ctx->last == NULL) { \ + _ctx->last = &(_ctx->error); \ + _ctx->error.error = &(_ctx->number); \ + _ctx->error.block = 0; \ + _ctx->number = E; \ + ERR_PRINT(E); \ + } else { \ + for (; ; longjmp(_ctx->last->addr, 1)) { \ + ERR_PRINT(E); \ + if (_ctx->last->error) { \ + if (E != ERR_CAUGHT) { \ + *(_ctx->last->error) = E; \ + } \ + } \ + } \ + } \ + } \ + +#ifdef CHECK +/** + * Implements a TRY clause. + */ +#define TRY ERR_TRY +#else +/** + * Stub for the TRY clause. + */ +#define TRY if (1) +#endif + +#ifdef CHECK +/** + * Implements a CATCH clause. + */ +#define CATCH(E) ERR_CATCH(&(E)) +#else +/** + * Stub for the CATCH clause. + */ +#define CATCH(E) else +#endif + +#ifdef CHECK +/** + * Implements a CATCH clause for any possible error. + * + * If this macro is used the error type is not available inside the CATCH + * block. + */ +#define CATCH_ANY ERR_CATCH(NULL) +#else +/** + * Stub for the CATCH_ANY clause. + */ +#define CATCH_ANY if (0) +#endif + +#ifdef CHECK +/** + * Implements a FINALLY clause. + */ +#define FINALLY else if (_z == 0) +#else +#define FINALLY if (1) +#endif + +#ifdef CHECK +/** + * Implements a THROW clause. + */ +#define THROW ERR_THROW +#else +/** + * Stub for the THROW clause. + */ +#ifdef QUIET +#define THROW(E) core_get()->code = RLC_ERR; +#else +#define THROW(E) \ + core_get()->code = RLC_ERR; \ + util_print("FATAL ERROR in %s:%d\n", ERR_FILE, __LINE__); \ + +#endif +#endif + +/** + * Treats an error jumping to the argument. + * + * @param[in] LABEL - the label to jump + */ +#define ERROR(LABEL) goto LABEL + +#ifdef VERBS + +/** + * Prints the current error message. + * + * @param[in] ERROR - the error code. + */ +#define ERR_PRINT(ERROR) \ + err_full_msg(__func__, ERR_FILE, __LINE__, ERROR) \ + +#else + +/** + * Prints the current error message. + * + * @param[in] ERROR - the error code. + */ +#define ERR_PRINT(ERROR) \ + err_simple_msg(ERROR) \ + +#endif + +/*============================================================================*/ +/* Function prototypes */ +/*============================================================================*/ + +#ifdef CHECK + +/** + * Prints the error message with little information. + * + * @param[in] error - the error code. + */ +void err_simple_msg(int error); + +/** + * Prints the error message with detailed information. + * + * @param[in] function - the function where the error occurred. + * @param[in] file - the source file where the error occurred. + * @param[in] line - the line in the file where the error occurred. + * @param[in] error - the error code. + */ +void err_full_msg(const char *function, const char *file, + int line, int error); + +/** + * Prints the error message respective to an error code. + * + * @param[out] e - the error occurred. + * @param[out] msg - the error message. + */ +void err_get_msg(err_t *e, char **msg); + +#endif + +/** + * Returns the code returned by the last function call and resets the current + * code. + * + * @returns ERR_OK if no errors occurred in the function, ERR_ERR otherwise. + */ +int err_get_code(void); + +#endif /* !RLC_ERR_H */ diff --git a/bls/contrib/relic/include/relic_fb.h b/bls/contrib/relic/include/relic_fb.h new file mode 100644 index 00000000..d8c593c6 --- /dev/null +++ b/bls/contrib/relic/include/relic_fb.h @@ -0,0 +1,995 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @defgroup fb Binary field arithmetic + */ + +/** + * @file + * + * Interface of module for binary field arithmetic. + * + * @ingroup fb + */ + +#ifndef RLC_FB_H +#define RLC_FB_H + +#include "relic_bn.h" +#include "relic_dv.h" +#include "relic_conf.h" +#include "relic_types.h" + +/*============================================================================*/ +/* Constant definitions */ +/*============================================================================*/ + +/** + * Precision in bits of a binary field element. + */ +#define RLC_FB_BITS ((int)FB_POLYN) + +/** + * Size in digits of a block sufficient to store a binary field element. + */ +#define RLC_FB_DIGS ((int)RLC_CEIL(RLC_FB_BITS, RLC_DIG)) + +/** + * Size in bytes of a block sufficient to store a binary field element. + */ +#define RLC_FB_BYTES ((int)RLC_CEIL(RLC_FB_BITS, 8)) + +/** + * Finite field identifiers. + */ +enum { + /** AES pentaonimal. */ + PENTA_8 = 1, + /** Toy pentanomial. */ + PENTA_64, + /** Hankerson's trinomial for GLS curves. */ + TRINO_113, + /** Hankerson's trinomial for GLS curves. */ + TRINO_127, + /** GCM pentanomial */ + PENTA_128, + /** Pentanomial for ECC2K-130 challenge. */ + PENTA_131, + /** NIST 163-bit fast reduction polynomial. */ + NIST_163, + /** Square-root friendly 163-bit polynomial. */ + SQRT_163, + /** Example with 193 bits for Itoh-Tsuji. */ + TRINO_193, + /** NIST 233-bit fast reduction polynomial. */ + NIST_233, + /** Square-root friendly 233-bit polynomial. */ + SQRT_233, + /** SECG 239-bit fast reduction polynomial. */ + SECG_239, + /** Square-root friendly 239-bit polynomial. */ + SQRT_239, + /** Square-root friendly 251-bit polynomial. */ + SQRT_251, + /** eBATS curve_2_251 pentanomial. */ + PENTA_251, + /** Hankerson's trinomial for halving curve. */ + TRINO_257, + /** Scott's 271-bit pairing-friendly trinomial. */ + TRINO_271, + /** Scott's 271-bit pairing-friendly pentanomial. */ + PENTA_271, + /** NIST 283-bit fast reduction polynomial. */ + NIST_283, + /** Square-root friendly 283-bit polynomial. */ + SQRT_283, + /** Scott's 271-bit pairing-friendly trinomial. */ + TRINO_353, + /** Detrey's trinomial for genus 2 curves. */ + TRINO_367, + /** NIST 409-bit fast reduction polynomial. */ + NIST_409, + /** Hankerson's trinomial for genus 2 curves. */ + TRINO_439, + /** NIST 571-bit fast reduction polynomial. */ + NIST_571, + /** Square-root friendly 571-bit polynomial. */ + SQRT_571, + /** Scott's 1223-bit pairing-friendly trinomial. */ + TRINO_1223 +}; + +/** + * Size of a precomputation table for repeated squaring/square-root using the + * trivial approach. + */ +#define RLC_FB_TABLE_BASIC (1) + +/** + * Size of a precomputation table for repeated squaring/square-root using the + * faster approach. + */ +#define RLC_FB_TABLE_QUICK ((RLC_DIG / 4) * RLC_FB_DIGS * 16) + +/** + * Size of a precomputation table for repeated squaring/square-root using the + * chosen algorithm. + */ +#if FB_ITR == BASIC +#define RLC_FB_TABLE RLC_FB_TABLE_BASIC +#else +#define RLC_FB_TABLE RLC_FB_TABLE_QUICK +#endif + +/** + * Maximum size of a precomputation table. + */ +#ifdef STRIP +#define RLC_FB_TABLE_MAX RLC_FB_TABLE +#else +#define RLC_FB_TABLE_MAX RLC_FB_TABLE_QUICK +#endif + +/*============================================================================*/ +/* Type definitions */ +/*============================================================================*/ + +/** + * Represents a binary field element. + */ +#if ALLOC == AUTO +typedef rlc_align dig_t fb_t[RLC_FB_DIGS + RLC_PAD(RLC_FB_BYTES) / (RLC_DIG / 8)]; +#else +typedef dig_t *fb_t; +#endif + +/** + * Represents a binary field element with automatic memory allocation. + */ +typedef rlc_align dig_t fb_st[RLC_FB_DIGS + RLC_PAD(RLC_FB_BYTES) / (RLC_DIG / 8)]; + +/*============================================================================*/ +/* Macro definitions */ +/*============================================================================*/ + +/** + * Initializes a binary field element with a null value. + * + * @param[out] A - the binary field element to initialize. + */ +#if ALLOC == AUTO +#define fb_null(A) /* empty */ +#else +#define fb_null(A) A = NULL; +#endif + +/** + * Calls a function to allocate a binary field element. + * + * @param[out] A - the new binary field element. + * @throw ERR_NO_MEMORY - if there is no available memory. + */ +#if ALLOC == DYNAMIC +#define fb_new(A) dv_new_dynam((dv_t *)&(A), RLC_FB_DIGS) +#elif ALLOC == AUTO +#define fb_new(A) /* empty */ +#elif ALLOC == STACK +#define fb_new(A) \ + A = (dig_t *)alloca(RLC_FB_BYTES + RLC_PAD(RLC_FB_BYTES)); \ + A = (dig_t *)RLC_ALIGN(A); \ + +#endif + +/** + * Calls a function to free a binary field element. + * + * @param[out] A - the binary field element to clean and free. + */ +#if ALLOC == DYNAMIC +#define fb_free(A) dv_free_dynam((dv_t *)&(A)) +#elif ALLOC == AUTO +#define fb_free(A) /* empty */ +#elif ALLOC == STACK +#define fb_free(A) A = NULL; +#endif + +/** + * Multiples two binary field elements. Computes c = a * b. + * + * @param[out] C - the result. + * @param[in] A - the first binary field element to multiply. + * @param[in] B - the second binary field element to multiply. + */ +#if FB_KARAT > 0 +#define fb_mul(C, A, B) fb_mul_karat(C, A, B) +#elif FB_MUL == BASIC +#define fb_mul(C, A, B) fb_mul_basic(C, A, B) +#elif FB_MUL == INTEG +#define fb_mul(C, A, B) fb_mul_integ(C, A, B) +#elif FB_MUL == LODAH +#define fb_mul(C, A, B) fb_mul_lodah(C, A, B) +#endif + +/** + * Squares a binary field element. Computes c = a * a. + * + * @param[out] C - the result. + * @param[in] A - the binary field element to square. + */ +#if FB_SQR == BASIC +#define fb_sqr(C, A) fb_sqr_basic(C, A) +#elif FB_SQR == QUICK +#define fb_sqr(C, A) fb_sqr_quick(C, A) +#elif FB_SQR == INTEG +#define fb_sqr(C, A) fb_sqr_integ(C, A) +#endif + +/** + * Extracts the square root of a binary field element. Computes c = a^(1/2). + * + * @param[out] C - the result. + * @param[in] A - the binary field element. + */ +#if FB_SRT == BASIC +#define fb_srt(C, A) fb_srt_basic(C, A) +#elif FB_SRT == QUICK +#define fb_srt(C, A) fb_srt_quick(C, A) +#endif + +/** + * Reduces a multiplication result modulo a binary irreducible polynomial. + * Computes c = a mod f(z). + * + * @param[out] C - the result. + * @param[in] A - the multiplication result to reduce. + */ +#if FB_RDC == BASIC +#define fb_rdc(C, A) fb_rdc_basic(C, A) +#elif FB_RDC == QUICK +#define fb_rdc(C, A) fb_rdc_quick(C, A) +#endif + +/** + * Compute the trace of a binary field element. Computes c = Tr(a). + * + * @param[in] A - the binary field element. + * @return the trace of the binary field element. + */ +#if FB_TRC == BASIC +#define fb_trc(A) fb_trc_basic(A) +#elif FB_TRC == QUICK +#define fb_trc(A) fb_trc_quick(A) +#endif + +/** + * Solves a quadratic equation for c, Tr(a) = 0. Computes c such that + * c^2 + c = a. + * + * @param[out] C - the result. + * @param[in] A - the binary field element. + */ +#if FB_SLV == BASIC +#define fb_slv(C, A) fb_slv_basic(C, A) +#elif FB_SLV == QUICK +#define fb_slv(C, A) fb_slv_quick(C, A) +#endif + +/** + * Inverts a binary field element. Computes c = a^{-1}. + * + * @param[out] C - the result. + * @param[in] A - the binary field element to invert. + */ +#if FB_INV == BASIC +#define fb_inv(C, A) fb_inv_basic(C, A) +#elif FB_INV == BINAR +#define fb_inv(C, A) fb_inv_binar(C, A) +#elif FB_INV == EXGCD +#define fb_inv(C, A) fb_inv_exgcd(C, A) +#elif FB_INV == ALMOS +#define fb_inv(C, A) fb_inv_almos(C, A) +#elif FB_INV == ITOHT +#define fb_inv(C, A) fb_inv_itoht(C, A) +#elif FB_INV == BRUCH +#define fb_inv(C, A) fb_inv_bruch(C, A) +#elif FB_INV == CTAIA +#define fb_inv(C, A) fb_inv_ctaia(C, A) +#elif FB_INV == LOWER +#define fb_inv(C, A) fb_inv_lower(C, A) +#endif + +/** + * Exponentiates a binary field element. Computes c = a^b. + * + * @param[out] C - the result. + * @param[in] A - the basis. + * @param[in] B - the exponent. + */ +#if FB_EXP == BASIC +#define fb_exp(C, A, B) fb_exp_basic(C, A, B) +#elif FB_EXP == SLIDE +#define fb_exp(C, A, B) fb_exp_slide(C, A, B) +#elif FB_EXP == MONTY +#define fb_exp(C, A, B) fb_exp_monty(C, A, B) +#endif + +/** + * Precomputed the table for repeated squaring/square-root. + * + * @param[out] T - the table. + * @param[in] B - the exponent. + */ +#if FB_ITR == BASIC +#define fb_itr_pre(T, B) (void)(T), (void)(B) +#elif FB_ITR == QUICK +#define fb_itr_pre(T, B) fb_itr_pre_quick(T, B) +#endif + +/** + * Computes the repeated Frobenius (squaring) or inverse Frobenius (square-root) + * of a binary field element. If the number of arguments is 3, then simple + * consecutive squaring/square-root is used. If the number of arguments if 4, + * then a table-based method is used and the fourth argument is + * a pointer fo the precomputed table. The variant with 4 arguments + * should be used when several 2^k/2^-k powers are computed with the same + * k. Computes c = a^(2^b), where b can be positive or negative. + * + * @param[out] C - the result. + * @param[in] A - the binary field element to exponentiate. + * @param[in] B - the exponent. + * @param[in] ... - the modulus and an optional argument. + */ +#define fb_itr(C, A, ...) RLC_CAT(fb_itr, RLC_OPT(__VA_ARGS__)) (C, A, __VA_ARGS__) + +/** + * Reduces a multiple precision integer modulo another integer. This macro + * should not be called directly. Use bn_mod() with 4 arguments instead. + * + * @param[out] C - the result. + * @param[in] A - the binary field element to exponentiate. + * @param[in] B - the exponent. + * @param[in] T - the precomputed table for the exponent. + */ +#if FB_ITR == BASIC +#define fb_itr_imp(C, A, B, T) fb_itr_basic(C, A, B) +#elif FB_ITR == QUICK +#define fb_itr_imp(C, A, B, T) fb_itr_quick(C, A, T) +#endif +/*============================================================================*/ + /* Function prototypes */ +/*============================================================================*/ +/** + * Initializes the binary field arithmetic layer. + */ +void fb_poly_init(void); + +/** + * Finalizes the binary field arithmetic layer. + */ +void fb_poly_clean(void); + +/** + * Returns the irreducible polynomial f(z) configured for the binary field. + * + * @return the irreducible polynomial. + */ +dig_t *fb_poly_get(void); + +/** + * Configures the irreducible polynomial of the binary field as a dense + * polynomial. + * + * @param[in] f - the new irreducible polynomial. + */ +void fb_poly_set_dense(const fb_t f); + +/** + * Configures a trinomial as the irreducible polynomial by its non-zero + * coefficients. The other coefficients are RLC_FB_BITS and 0. + * + * @param[in] a - the second coefficient. + */ +void fb_poly_set_trino(int a); + +/** + * Configures a pentanomial as the binary field modulo by its non-zero + * coefficients. The other coefficients are RLC_FB_BITS and 0. + * + * @param[in] a - the second coefficient. + * @param[in] b - the third coefficient. + * @param[in] c - the fourth coefficient. + */ +void fb_poly_set_penta(int a, int b, int c); + +/** + * Returns the square root of z. + * + * @return the square root of z. + */ +dig_t *fb_poly_get_srz(void); + +/** + * Returns sqrt(z) * (i represented as a polynomial). + * + * @return the precomputed result. + */ +const dig_t *fb_poly_tab_srz(int i); + +/** + * Returns a table for accelerating repeated squarings. + * + * @param the number of the table. + * @return the precomputed result. + */ +const fb_t *fb_poly_tab_sqr(int i); + +/** + * Returns an addition chain for (RLC_FB_BITS - 1). + * + * @param[out] len - the number of elements in the addition chain. + * + * @return a pointer to the addition chain. + */ +const int *fb_poly_get_chain(int *len); + +/** + * Returns the non-zero coefficients of the configured trinomial or pentanomial. + * If b is -1, the irreducible polynomial configured is a trinomial. + * The other coefficients are RLC_FB_BITS and 0. + * + * @param[out] a - the second coefficient. + * @param[out] b - the third coefficient. + * @param[out] c - the fourth coefficient. + */ +void fb_poly_get_rdc(int *a, int *b, int *c); + +/** + * Returns the non-zero bits used to compute the trace function. The -1 + * coefficient is the last coefficient. + * + * @param[out] a - the first coefficient. + * @param[out] b - the second coefficient. + * @param[out] c - the third coefficient. + */ +void fb_poly_get_trc(int *a, int *b, int *c); + +/** + * Returns the table of precomputed half-traces. + * + * @return the table of half-traces. + */ +const dig_t *fb_poly_get_slv(void); + +/** + * Assigns a standard irreducible polynomial as modulo of the binary field. + * + * @param[in] param - the standardized polynomial identifier. + */ +void fb_param_set(int param); + +/** + * Configures some finite field parameters for the current security level. + */ +void fb_param_set_any(void); + +/** + * Prints the currently configured irreducible polynomial. + */ +void fb_param_print(void); + +/** + * Adds a binary field element and the irreducible polynomial. Computes + * c = a + f(z). + * + * @param[out] c - the destination. + * @param[in] a - the binary field element. + */ +void fb_poly_add(fb_t c, const fb_t a); + +/** + * Copies the second argument to the first argument. + * + * @param[out] c - the result. + * @param[in] a - the binary field element to copy. + */ +void fb_copy(fb_t c, const fb_t a); + +/** + * Negates a binary field element. + * + * @param[out] c - the result. + * @param[out] a - the binary field element to negate. + */ +void fb_neg(fb_t c, const fb_t a); + +/** + * Assigns zero to a binary field element. + * + * @param[out] a - the binary field element to assign. + */ +void fb_zero(fb_t a); + +/** + * Tests if a binary field element is zero or not. + * + * @param[in] a - the binary field element to test. + * @return 1 if the argument is zero, 0 otherwise. + */ +int fb_is_zero(const fb_t a); + +/** + * Reads the bit stored in the given position on a binary field element. + * + * @param[in] a - the binary field element. + * @param[in] bit - the bit position. + * @return the bit value. + */ +int fb_get_bit(const fb_t a, int bit); + +/** + * Stores a bit in a given position on a binary field element. + * + * @param[out] a - the binary field element. + * @param[in] bit - the bit position. + * @param[in] value - the bit value. + */ +void fb_set_bit(fb_t a, int bit, int value); + +/** + * Assigns a small positive polynomial to a binary field element. + * + * The degree of the polynomial must be smaller than RLC_DIG. + * + * @param[out] c - the result. + * @param[in] a - the small polynomial to assign. + */ +void fb_set_dig(fb_t c, dig_t a); + +/** + * Returns the number of bits of a binary field element. + * + * @param[in] a - the binary field element. + * @return the number of bits. + */ +int fb_bits(const fb_t a); + +/** + * Assigns a random value to a binary field element. + * + * @param[out] a - the binary field element to assign. + */ +void fb_rand(fb_t a); + +/** + * Prints a binary field element to standard output. + * + * @param[in] a - the binary field element to print. + */ +void fb_print(const fb_t a); + +/** + * Returns the number of digits in radix necessary to store a binary field + * element. The radix must be a power of 2 included in the interval [2, 64]. + * + * @param[in] a - the binary field element. + * @param[in] radix - the radix. + * @throw ERR_NO_VALID - if the radix is invalid. + * @return the number of digits in the given radix. + */ +int fb_size_str(const fb_t a, int radix); + +/** + * Reads a binary field element from a string in a given radix. The radix must + * be a power of 2 included in the interval [2, 64]. + * + * @param[out] a - the result. + * @param[in] str - the string. + * @param[in] len - the size of the string. + * @param[in] radix - the radix. + * @throw ERR_NO_VALID - if the radix is invalid. + * @throw ERR_NO_BUFFER - if the string is too long. + */ +void fb_read_str(fb_t a, const char *str, int len, int radix); + +/** + * Writes a binary field element to a string in a given radix. The radix must + * be a power of 2 included in the interval [2, 64]. + * + * @param[out] str - the string. + * @param[in] len - the buffer capacity. + * @param[in] a - the binary field element to write. + * @param[in] radix - the radix. + * @throw ERR_NO_VALID - if the radix is invalid. + * @throw ERR_NO_BUFFER - if the buffer capacity is insufficient. + */ +void fb_write_str(char *str, int len, const fb_t a, int radix); + +/** + * Reads a binary field element from a byte vector in big-endian format. + * + * @param[out] a - the result. + * @param[in] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @throw ERR_NO_BUFFER - if the buffer capacity is not RLC_FP_BYTES. + */ +void fb_read_bin(fb_t a, const uint8_t *bin, int len); + +/** + * Writes a binary field element to a byte vector in big-endian format. + * + * @param[out] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @param[in] a - the binary field element to write. + * @throw ERR_NO_BUFFER - if the buffer capacity is not RLC_FP_BYTES. + */ +void fb_write_bin(uint8_t *bin, int len, const fb_t a); + +/** + * Returns the result of a comparison between two binary field elements. + * + * @param[in] a - the first binary field element. + * @param[in] b - the second binary field element. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fb_cmp(const fb_t a, const fb_t b); + +/** + * Returns the result of a comparison between a binary field element + * and a small binary field element. + * + * @param[in] a - the binary field element. + * @param[in] b - the small binary field element. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fb_cmp_dig(const fb_t a, dig_t b); + +/** + * Adds two binary field elements. Computes c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the first binary field element to add. + * @param[in] b - the second binary field element to add. + */ +void fb_add(fb_t c, const fb_t a, const fb_t b); + +/** + * Adds a binary field element and a small binary field element. + * Computes c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the binary field element to add. + * @param[in] b - the small binary field element to add. + */ +void fb_add_dig(fb_t c, const fb_t a, dig_t b); + +/** + * Multiples two binary field elements using Shift-and-add multiplication. + * + * @param[out] c - the result. + * @param[in] a - the first binary field element to multiply. + * @param[in] b - the second binary field element to multiply. + */ +void fb_mul_basic(fb_t c, const fb_t a, const fb_t b); + +/** + * Multiples two binary field elements using multiplication integrated with + * modular reduction. + * + * @param[out] c - the result. + * @param[in] a - the first binary field element to multiply. + * @param[in] b - the second binary field element to multiply. + */ +void fb_mul_integ(fb_t c, const fb_t a, const fb_t b); + +/** + * Multiples two binary field elements using Lopez-Dahab multiplication. + * + * @param[out] c - the result. + * @param[in] a - the first binary field element to multiply. + * @param[in] b - the second binary field element to multiply. + */ +void fb_mul_lodah(fb_t c, const fb_t a, const fb_t b); + +/** + * Multiplies a binary field element by a small binary field element. + * + * @param[out] c - the result. + * @param[in] a - the binary field element. + * @param[in] b - the small binary field element to multiply. + */ +void fb_mul_dig(fb_t c, const fb_t a, dig_t b); + +/** + * Multiples two binary field elements using Karatsuba multiplication. + * + * @param[out] c - the result. + * @param[in] a - the first binary field element. + * @param[in] b - the second binary field element. + */ +void fb_mul_karat(fb_t c, const fb_t a, const fb_t b); + +/** + * Squares a binary field element using bit-manipulation squaring. + * + * @param[out] c - the result. + * @param[in] a - the binary field element to square. + */ +void fb_sqr_basic(fb_t c, const fb_t a); + +/** + * Squares a binary field element with integrated modular reduction. + * + * @param[out] c - the result. + * @param[in] a - the binary field element to square. + */ +void fb_sqr_integ(fb_t c, const fb_t a); + +/** + * Squares a binary field element using table-based squaring. + * + * @param[out] c - the result. + * @param[in] a - the binary field element to square. + */ +void fb_sqr_quick(fb_t c, const fb_t a); + +/** + * Shifts a binary field element to the left. Computes c = a * z^bits mod f(z). + * + * @param[out] c - the result. + * @param[in] a - the binary field element to shift. + * @param[in] bits - the number of bits to shift. + */ +void fb_lsh(fb_t c, const fb_t a, int bits); + +/** +* Shifts a binary field element to the right. Computes c = a / (z^bits). + * + * @param[out] c - the result. + * @param[in] a - the binary field element to shift. + * @param[in] bits - the number of bits to shift. + */ +void fb_rsh(fb_t c, const fb_t a, int bits); + +/** + * Reduces a multiplication result modulo an irreducible polynomial using + * shift-and-add modular reduction. + * + * @param[out] c - the result. + * @param[in] a - the multiplication result to reduce. + */ +void fb_rdc_basic(fb_t c, dv_t a); + +/** + * Reduces a multiplication result modulo a trinomial or pentanomial. + * + * @param[out] c - the result. + * @param[in] a - the multiplication result to reduce. + */ +void fb_rdc_quick(fb_t c, dv_t a); + +/** + * Extracts the square root of a binary field element using repeated squaring. + * Computes c = a^{1/2}. + * + * @param[out] c - the result. + * @param[in] a - the binary field element to take a square root. + */ +void fb_srt_basic(fb_t c, const fb_t a); + +/** + * Extracts the square root of a binary field element using a fast square root + * extraction algorithm. + * + * @param[out] c - the result. + * @param[in] a - the binary field element to take a square root. + */ +void fb_srt_quick(fb_t c, const fb_t a); + +/** + * Computes the trace of a binary field element using repeated squaring. + * Returns Tr(a). + * + * @param[in] a - the binary field element. + * @return the trace of the binary field element. + */ +dig_t fb_trc_basic(const fb_t a); + +/** + * Computes the trace of a binary field element using a fast trace computation + * algorithm. Returns Tr(a). + * + * @param[in] a - the binary field element. + * @return the trace of the binary field element. + */ +dig_t fb_trc_quick(const fb_t a); + +/** + * Inverts a binary field element using Fermat's Little Theorem. + * + * @param[out] c - the result. + * @param[in] a - the binary field element to invert. + * @throw ERR_NO_VALID - if the field element is not invertible. + */ +void fb_inv_basic(fb_t c, const fb_t a); + +/** + * Inverts a binary field element using the binary method. + * + * @param[out] c - the result. + * @param[in] a - the binary field element to invert. + * @throw ERR_NO_VALID - if the field element is not invertible. + */ +void fb_inv_binar(fb_t c, const fb_t a); + +/** + * Inverts a binary field element using the Extended Euclidean algorithm. + * + * @param[out] c - the result. + * @param[in] a - the binary field element to invert. + * @throw ERR_NO_VALID - if the field element is not invertible. + */ +void fb_inv_exgcd(fb_t c, const fb_t a); + +/** + * Inverts a binary field element using the Almost Inverse algorithm. + * + * @param[out] c - the result. + * @param[in] a - the binary field element to invert. + * @throw ERR_NO_VALID - if the field element is not invertible. + */ +void fb_inv_almos(fb_t c, const fb_t a); + +/** + * Inverts a binary field element using Itoh-Tsuji inversion. + * + * @param[out] c - the result. + * @param[in] a - the binary field element to invert. + * @throw ERR_NO_VALID - if the field element is not invertible. + */ +void fb_inv_itoht(fb_t c, const fb_t a); + +/** + * Inverts a binary field element using the hardware-friendly + * Brunner-Curiger-Hofstetter algorithm. + * + * @param[out] c - the result. + * @param[in] a - the binary field element to invert. + * @throw ERR_NO_VALID - if the field element is not invertible. + */ +void fb_inv_bruch(fb_t c, const fb_t a); + +/** + * Inverts a binary field element in constant-time using + * the Wu-Wu-Shieh-Hwang algorithm. + * + * @param[out] c - the result. + * @param[in] a - the binary field element to invert. + * @throw ERR_NO_VALID - if the field element is not invertible. + */ +void fb_inv_ctaia(fb_t c, const fb_t a); + +/** + * Inverts a binary field element using a direct call to the lower layer. + * + * @param[out] c - the result. + * @param[in] a - the binary field element to invert. + * @throw ERR_NO_VALID - if the field element is not invertible. + */ +void fb_inv_lower(fb_t c, const fb_t a); + +/** + * Inverts multiple binary field elements. + * + * @param[out] c - the result. + * @param[in] a - the binary field elements to invert. + * @param[in] n - the number of elements. + */ +void fb_inv_sim(fb_t *c, const fb_t *a, int n); + +/** + * Exponentiates a binary field element through consecutive squaring. Computes + * c = a^(2^b). + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent. + */ +void fb_exp_2b(fb_t c, const fb_t a, int b); + +/** + * Exponentiates a binary field element using the binary + * method. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent. + */ +void fb_exp_basic(fb_t c, const fb_t a, const bn_t b); + +/** + * Exponentiates a binary field element using the sliding window method. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent. + */ +void fb_exp_slide(fb_t c, const fb_t a, const bn_t b); + +/** + * Exponentiates a binary field element using the constant-time Montgomery + * powering ladder method. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent. + */ +void fb_exp_monty(fb_t c, const fb_t a, const bn_t b); + +/** + * Solves a quadratic equation for a, Tr(a) = 0 by repeated squarings and + * additions. + * + * @param[out] c - the result. + * @param[in] a - the binary field element to solve. + */ +void fb_slv_basic(fb_t c, const fb_t a); + +/** + * Solves a quadratic equation for a, Tr(a) = 0 with precomputed half-traces. + * + * @param[out] c - the result. + * @param[in] a - the binary field element to solve. + */ +void fb_slv_quick(fb_t c, const fb_t a); + +/** + * Computes the iterated squaring/square-root of a binary field element by + * consecutive squaring/square-root. Computes c = a^(2^b). + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent. + */ +void fb_itr_basic(fb_t c, const fb_t a, int b); + +/** + * Precomputes a table for iterated squaring/square-root of a binary field + * element. + * + * @param[out] t - the precomputed table. + * @param[in] b - the exponent. + */ +void fb_itr_pre_quick(fb_t *t, int b); + +/** + * Computes the iterated squaring/square-root of a binary field element by + * a table based method. Computes c = a^(2^b). + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] t - the precomputed table. + */ +void fb_itr_quick(fb_t c, const fb_t a, const fb_t *t); + +#endif /* !RLC_FB_H */ diff --git a/bls/contrib/relic/include/relic_fbx.h b/bls/contrib/relic/include/relic_fbx.h new file mode 100644 index 00000000..8b125522 --- /dev/null +++ b/bls/contrib/relic/include/relic_fbx.h @@ -0,0 +1,204 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @defgroup fbx Binary field extensions. + */ + +/** + * @file + * + * Interface of the module for extension field arithmetic over binary fields. + * + * @ingroup fbx + */ + +#ifndef RLC_FBX_H +#define RLC_FBX_H + +#include "relic_fb.h" +#include "relic_types.h" + +/*============================================================================*/ +/* Type definitions */ +/*============================================================================*/ + +/** + * Represents a quadratic extension binary field element. + * + * This extension field is constructed with the basis {1, s}, where s is a + * quadratic non-residue in the binary field. + */ +typedef fb_t fb2_t[2]; + +/*============================================================================*/ +/* Macro definitions */ +/*============================================================================*/ + +/** + * Initializes a quadratic extension binary field with a null value. + * + * @param[out] A - the quadratic extension element to initialize. + */ +#define fb2_null(A) \ + fb_null(A[0]); fb_null(A[1]); \ + +/** + * Calls a function to allocate a quadratic extension binary field element. + * + * @param[out] A - the new quadratic extension field element. + */ +#define fb2_new(A) \ + fb_new(A[0]); fb_new(A[1]); \ + +/** + * Calls a function to free a quadratic extension binary field element. + * + * @param[out] A - the quadratic extension field element to free. + */ +#define fb2_free(A) \ + fb_free(A[0]); fb_free(A[1]); \ + +/** + * Copies the second argument to the first argument. + * + * @param[out] C - the result. + * @param[in] A - the quadratic extension field element to copy. + */ +#define fb2_copy(C, A) \ + fb_copy(C[0], A[0]); fb_copy(C[1], A[1]); \ + +/** + * Negates a quadratic extension field element. + * + * f@param[out] C - the result. + * @param[out] A - the quadratic extension field element to negate. + */ +#define fb2_neg(C, A) \ + fb_neg(C[0], A[0]); fb_neg(C[1], A[1]); \ + +/** + * Assigns zero to a quadratic extension field element. + * + * @param[out] A - the quadratic extension field element to zero. + */ +#define fb2_zero(A) \ + fb_zero(A[0]); fb_zero(A[1]); \ + +/** + * Tests if a quadratic extension field element is zero or not. + * + * @param[in] A - the quadratic extension field element to test. + * @return 1 if the argument is zero, 0 otherwise. + */ +#define fb2_is_zero(A) \ + (fb_is_zero(A[0]) && fb_is_zero(A[1])) \ + +/** + * Assigns a random value to a quadratic extension field element. + * + * @param[out] A - the quadratic extension field element to assign. + */ +#define fb2_rand(A) \ + fb_rand(A[0]); fb_rand(A[1]); \ + +/** + * Prints a quadratic extension field element to standard output. + * + * @param[in] A - the quadratic extension field element to print. + */ +#define fb2_print(A) \ + fb_print(A[0]); fb_print(A[1]); \ + +/** + * Returns the result of a comparison between two quadratic extension field + * elements + * + * @param[in] A - the first quadratic extension field element. + * @param[in] B - the second quadratic extension field element. + * @return RLC_NE if a != b, RLC_EQ if a == b. + */ +#define fb2_cmp(A, B) \ + ((fb_cmp(A[0], B[0]) == RLC_EQ) && (fb_cmp(A[1], B[1]) == RLC_EQ) \ + ? RLC_EQ : RLC_NE) \ + +/** + * Adds two quadratic extension field elements. Computes c = a + b. + * + * @param[out] C - the result. + * @param[in] A - the first quadratic extension field element. + * @param[in] B - the second quadratic extension field element. + */ +#define fb2_add(C, A, B) \ + fb_add(C[0], A[0], B[0]); fb_add(C[1], A[1], B[1]); \ + +/*============================================================================*/ +/* Function prototypes */ +/*============================================================================*/ + +/** + * Multiples two quadratic extension field elements. Computes c = a * b. + * + * @param[out] c - the result. + * @param[in] a - the quadratic extension binary field element. + * @param[in] b - the quadratic extension binary field element. + */ +void fb2_mul(fb2_t c, fb2_t a, fb2_t b); + + /** + * Multiples a quadratic extension field element by a quadratic non-residue. + * Computes c = a * s. + * + * @param[out] c - the result. + * @param[in] a - the quadratic extension binary field element. + * @param[in] b - the quadratic extension binary field element. + */ + void fb2_mul_nor(fb2_t c, fb2_t a); + +/** + * Computes the square of a quadratic extension field element. Computes + * c = a * a. + * + * @param[out] c - the result. + * @param[in] a - the binary field element to square. + */ +void fb2_sqr(fb2_t c, fb2_t a); + +/** + * Solves a quadratic equation for c, Tr(a) = 0. Computes c such that + * c^2 + c = a. + * + * @param[out] c - the result. + * @param[in] a - the quadratic extension field element. + */ +void fb2_slv(fb2_t c, fb2_t a); + +/** + * Inverts a quadratic extension field element. Computes c = a^{-1}. + * + * @param[out] c - the result. + * @param[in] a - the quadratic extension field element to invert. + */ +void fb2_inv(fb2_t c, fb2_t a); + +#endif /* !RLC_FBX_H */ diff --git a/bls/contrib/relic/include/relic_fp.h b/bls/contrib/relic/include/relic_fp.h new file mode 100644 index 00000000..abdd090e --- /dev/null +++ b/bls/contrib/relic/include/relic_fp.h @@ -0,0 +1,1088 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @defgroup fp Prime field arithmetic + */ + +/** + * @file + * + * Interface of the module for prime field arithmetic. + * + * @ingroup fp + */ + +#ifndef RLC_FP_H +#define RLC_FP_H + +#include "relic_dv.h" +#include "relic_bn.h" +#include "relic_conf.h" +#include "relic_types.h" + +/*============================================================================*/ +/* Constant definitions */ +/*============================================================================*/ + +/** + * Precision in bits of a prime field element. + */ +#define RLC_FP_BITS ((int)FP_PRIME) + +/** + * Size in digits of a block sufficient to store a prime field element. + */ +#define RLC_FP_DIGS ((int)RLC_CEIL(RLC_FP_BITS, RLC_DIG)) + +/** + * Size in bytes of a block sufficient to store a binary field element. + */ +#define RLC_FP_BYTES ((int)RLC_CEIL(RLC_FP_BITS, 8)) + +/* + * Finite field identifiers. + */ +enum { + /** SECG 160-bit fast reduction prime. */ + SECG_160 = 1, + /** SECG 160-bit denser reduction prime. */ + SECG_160D, + /** NIST 192-bit fast reduction prime. */ + NIST_192, + /** SECG 192-bit denser reduction prime. */ + SECG_192, + /** Curve22103 221-bit prime modulus. */ + PRIME_22103, + /** NIST 224-bit fast reduction polynomial. */ + NIST_224, + /** SECG 224-bit denser reduction prime. */ + SECG_224, + /** Curve4417 226-bit prime modulus. */ + PRIME_22605, + /* Curve1174 251-bit prime modulus. */ + PRIME_25109, + /** Curve25519 255-bit prime modulus. */ + PRIME_25519, + /** NIST 256-bit fast reduction polynomial. */ + NIST_256, + /** Brainpool random 256-bit prime. */ + BSI_256, + /** SECG 256-bit denser reduction prime. */ + SECG_256, + /** Curve67254 382-bit prime modulus. */ + PRIME_382105, + /** Curve383187 383-bit prime modulus. */ + PRIME_383187, + /** NIST 384-bit fast reduction polynomial. */ + NIST_384, + /** Curve511187 511-bit prime modulus. */ + PRIME_511187, + /** NIST 521-bit fast reduction polynomial. */ + NIST_521, + /** 158-bit prime for BN curve. */ + BN_158, + /** 254-bit prime provided in Nogami et al. for BN curves. */ + BN_254, + /** 256-bit prime provided in Barreto et al. for BN curves. */ + BN_256, + /** 381-bit prime for BLS curve of embedding degree 12 (Zcash). */ + B12_381, + /** 382-bit prime provided by Barreto for BN curve. */ + BN_382, + /** 446-bit prime provided by Barreto for BN curve. */ + BN_446, + /** 446-bit prime for BLS curve of embedding degree 12. */ + B12_446, + /** 455-bit prime for BLS curve of embedding degree 12. */ + B12_455, + /** 477-bit prime for BLS curve of embedding degree 24. */ + B24_477, + /** 508-bit prime for KSS16 curve. */ + KSS_508, + /** 511-bit prime for Optimal TNFS-secure curve. */ + OT_511, + /** Random 544-bit prime for Cocks-Pinch curve with embedding degree 8. */ + CP8_544, + /** 569-bit prime for KSS curve with embedding degree 54. */ + K54_569, + /** 575-bit prime for BLS curve with embedding degree 48. */ + B48_575, + /** 638-bit prime provided in Barreto et al. for BN curve. */ + BN_638, + /** 638-bit prime for BLS curve with embedding degree 12. */ + B12_638, + /** 1536-bit prime for supersingular curve with embedding degree k = 2. */ + SS_1536, +}; + +/** + * Constant used to indicate that there's some room left in the storage of + * prime field elements. This can be used to avoid carries. + */ +#if ((FP_PRIME % WSIZE) != 0) && ((FP_PRIME % WSIZE) <= (WSIZE - 2)) +#if ((2 * FP_PRIME % WSIZE) != 0) && ((2 * FP_PRIME % WSIZE) <= (WSIZE - 2)) +#define RLC_FP_ROOM +#else +#undef RLC_FP_ROOM +#endif +#else +#undef RLC_FP_ROOM +#endif + +/*============================================================================*/ +/* Type definitions */ +/*============================================================================*/ + +/** + * Represents a prime field element. + * + * A field element is represented as a digit vector. These digits are organized + * in little-endian format, that is, the least significant digits are + * stored in the first positions of the vector. + */ +#if ALLOC == AUTO +typedef rlc_align dig_t fp_t[RLC_FP_DIGS + RLC_PAD(RLC_FP_BYTES)/(RLC_DIG / 8)]; +#else +typedef dig_t *fp_t; +#endif + +/** + * Represents a prime field element with automatic memory allocation. + */ +typedef rlc_align dig_t fp_st[RLC_FP_DIGS + RLC_PAD(RLC_FP_BYTES)/(RLC_DIG / 8)]; + +/*============================================================================*/ +/* Macro definitions */ +/*============================================================================*/ + +/** + * Initializes a binary field element with a null value. + * + * @param[out] A - the binary field element to initialize. + */ +#if ALLOC == AUTO +#define fp_null(A) /* empty */ +#else +#define fp_null(A) A = NULL; +#endif + +/** + * Calls a function to allocate and initialize a prime field element. + * + * @param[out] A - the new prime field element. + */ +#if ALLOC == DYNAMIC +#define fp_new(A) dv_new_dynam((dv_t *)&(A), RLC_FP_DIGS) +#elif ALLOC == AUTO +#define fp_new(A) /* empty */ +#elif ALLOC == STACK +#define fp_new(A) \ + A = (dig_t *)alloca(RLC_FP_BYTES + RLC_PAD(RLC_FP_BYTES)); \ + A = (dig_t *)RLC_ALIGN(A); \ + +#endif + +/** + * Calls a function to clean and free a prime field element. + * + * @param[out] A - the prime field element to clean and free. + */ +#if ALLOC == DYNAMIC +#define fp_free(A) dv_free_dynam((dv_t *)&(A)) +#elif ALLOC == AUTO +#define fp_free(A) /* empty */ +#elif ALLOC == STACK +#define fp_free(A) A = NULL; +#endif + +/** + * Adds two prime field elements. Computes c = a + b. + * + * @param[out] C - the result. + * @param[in] A - the first prime field element. + * @param[in] B - the second prime field element. + */ +#if FP_ADD == BASIC +#define fp_add(C, A, B) fp_add_basic(C, A, B) +#elif FP_ADD == INTEG +#define fp_add(C, A, B) fp_add_integ(C, A, B) +#endif + +/** + * Subtracts a prime field element from another. Computes C = A - B. + * + * @param[out] C - the result. + * @param[in] A - the first prime field element. + * @param[in] B - the second prime field element. + */ +#if FP_ADD == BASIC +#define fp_sub(C, A, B) fp_sub_basic(C, A, B) +#elif FP_ADD == INTEG +#define fp_sub(C, A, B) fp_sub_integ(C, A, B) +#endif + +/** + * Negates a prime field element from another. Computes C = -A. + * + * @param[out] C - the result. + * @param[in] A - the prime field element to negate. + */ +#if FP_ADD == BASIC +#define fp_neg(C, A) fp_neg_basic(C, A) +#elif FP_ADD == INTEG +#define fp_neg(C, A) fp_neg_integ(C, A) +#endif + +/** + * Doubles a prime field element. Computes C = A + A. + * + * @param[out] C - the result. + * @param[in] A - the first prime field element. + */ +#if FP_ADD == BASIC +#define fp_dbl(C, A) fp_dbl_basic(C, A) +#elif FP_ADD == INTEG +#define fp_dbl(C, A) fp_dbl_integ(C, A) +#endif + +/** + * Halves a prime field element. Computes C = A/2. + * + * @param[out] C - the result. + * @param[in] A - the first prime field element. + */ +#if FP_ADD == BASIC +#define fp_hlv(C, A) fp_hlv_basic(C, A) +#elif FP_ADD == INTEG +#define fp_hlv(C, A) fp_hlv_integ(C, A) +#endif + +/** + * Multiples two prime field elements. Computes C = A * B. + * + * @param[out] C - the result. + * @param[in] A - the first prime field element. + * @param[in] B - the second prime field element. + */ +#if FP_KARAT > 0 +#define fp_mul(C, A, B) fp_mul_karat(C, A, B) +#elif FP_MUL == BASIC +#define fp_mul(C, A, B) fp_mul_basic(C, A, B) +#elif FP_MUL == COMBA +#define fp_mul(C, A, B) fp_mul_comba(C, A, B) +#elif FP_MUL == INTEG +#define fp_mul(C, A, B) fp_mul_integ(C, A, B) +#endif + +/** + * Squares a prime field element. Computes C = A * A. + * + * @param[out] C - the result. + * @param[in] A - the prime field element to square. + */ +#if FP_KARAT > 0 +#define fp_sqr(C, A) fp_sqr_karat(C, A) +#elif FP_SQR == BASIC +#define fp_sqr(C, A) fp_sqr_basic(C, A) +#elif FP_SQR == COMBA +#define fp_sqr(C, A) fp_sqr_comba(C, A) +#elif FP_SQR == MULTP +#define fp_sqr(C, A) fp_mul(C, A, A) +#elif FP_SQR == INTEG +#define fp_sqr(C, A) fp_sqr_integ(C, A) +#endif + +/** + * Reduces a multiplication result modulo a prime field order. Computes + * C = A mod p. + * + * @param[out] C - the result. + * @param[in] A - the multiplication result to reduce. + */ +#if FP_RDC == BASIC +#define fp_rdc(C, A) fp_rdc_basic(C, A) +#elif FP_RDC == MONTY +#define fp_rdc(C, A) fp_rdc_monty(C, A) +#elif FP_RDC == QUICK +#define fp_rdc(C, A) fp_rdc_quick(C, A) +#endif + +/** + * Reduces a multiplication result modulo a prime field order using Montgomery + * modular reduction. + * + * @param[out] C - the result. + * @param[in] A - the multiplication result to reduce. + */ +#if FP_MUL == BASIC +#define fp_rdc_monty(C, A) fp_rdc_monty_basic(C, A) +#else +#define fp_rdc_monty(C, A) fp_rdc_monty_comba(C, A) +#endif + +/** + * Inverts a prime field element. Computes C = A^{-1}. + * + * @param[out] C - the result. + * @param[in] A - the prime field element to invert. + */ +#if FP_INV == BASIC +#define fp_inv(C, A) fp_inv_basic(C, A) +#elif FP_INV == BINAR +#define fp_inv(C, A) fp_inv_binar(C, A) +#elif FP_INV == MONTY +#define fp_inv(C, A) fp_inv_monty(C, A) +#elif FP_INV == EXGCD +#define fp_inv(C, A) fp_inv_exgcd(C, A) +#elif FP_INV == DIVST +#define fp_inv(C, A) fp_inv_divst(C, A) +#elif FP_INV == LOWER +#define fp_inv(C, A) fp_inv_lower(C, A) +#endif + +/** + * Exponentiates a prime field element. Computes C = A^B (mod p). + * + * @param[out] C - the result. + * @param[in] A - the basis. + * @param[in] B - the exponent. + */ +#if FP_EXP == BASIC +#define fp_exp(C, A, B) fp_exp_basic(C, A, B) +#elif FP_EXP == SLIDE +#define fp_exp(C, A, B) fp_exp_slide(C, A, B) +#elif FP_EXP == MONTY +#define fp_exp(C, A, B) fp_exp_monty(C, A, B) +#endif + +/*============================================================================*/ +/* Function prototypes */ +/*============================================================================*/ + +/** + * Initializes the prime field arithmetic layer. + */ +void fp_prime_init(void); + +/** + * Finalizes the prime field arithmetic layer. + */ +void fp_prime_clean(void); + +/** + * Returns the order of the prime field. + * + * @return the order of the prime field. + */ +const dig_t *fp_prime_get(void); + +/** + * Returns the additional value used for modular reduction. + * + * @return the additional value used for modular reduction. + */ +const dig_t *fp_prime_get_rdc(void); + +/** + * Returns the additional value used for conversion from multiple precision + * integer to prime field element. + * + * @return the additional value used for importing integers. + */ +const dig_t *fp_prime_get_conv(void); + +/** + * Returns the result of prime order mod 8. + * + * @return the result of prime order mod 8. + */ +dig_t fp_prime_get_mod8(void); + +/** + * Returns the prime stored in special form. The most significant bit is + * RLC_FP_BITS. + * + * @param[out] len - the number of returned bits, can be NULL. + * + * @return the prime represented by it non-zero bits. + */ +const int *fp_prime_get_sps(int *len); + +/** + * Returns a non-quadratic residue in the prime field. + * + * @return the non-quadratic residue. + */ +int fp_prime_get_qnr(void); + +/** + * Returns a non-cubic residue in the prime field. + * + * @return the non-cubic residue. + */ +int fp_prime_get_cnr(void); + +/** + * Returns the 2-adicity of the prime modulus. + * + * @return the 2-adicity of the modulus. + */ +int fp_prime_get_2ad(void); + +/** + * Returns the prime field parameter identifier. + * + * @return the parameter identifier. + */ +int fp_param_get(void); + +/** + * Assigns the prime field modulus to a non-sparse prime. + * + * @param[in] p - the new prime field modulus. + */ +void fp_prime_set_dense(const bn_t p); + +/** + * Assigns the prime field modulus to a special form sparse prime. + * + * @param[in] spars - the list of powers of 2 describing the prime. + * @param[in] len - the number of powers. + */ +void fp_prime_set_pmers(const int *spars, int len); + +/** +* Assigns the prime field modulus to a parametrization from a family of + * pairing-friendly curves. + */ +void fp_prime_set_pairf(const bn_t x, int pairf); + +/** + * Computes the constants needed for evaluating Frobenius maps in higher + * extension fields. + */ +void fp_prime_calc(void); + +/** + * Imports a multiple precision integer as a prime field element, doing the + * necessary conversion. + * + * @param[out] c - the result. + * @param[in] a - the multiple precision integer to import. + */ +void fp_prime_conv(fp_t c, const bn_t a); + +/** + * Imports a single digit as a prime field element, doing the necessary + * conversion. + * + * @param[out] c - the result. + * @param[in] a - the digit to import. + */ +void fp_prime_conv_dig(fp_t c, dig_t a); + +/** + * Exports a prime field element as a multiple precision integer, doing the + * necessary conversion. + * + * @param[out] c - the result. + * @param[in] a - the prime field element to export. + */ +void fp_prime_back(bn_t c, const fp_t a); + +/** + * Assigns a prime modulus based on its identifier. + */ +void fp_param_set(int param); + +/** + * Assigns any pre-defined parameter as the prime modulus. + * + * @return RLC_OK if no errors occurred; RLC_ERR otherwise. + */ +int fp_param_set_any(void); + +/** + * Assigns the order of the prime field to any non-sparse prime. + * + * @return RLC_OK if no errors occurred; RLC_ERR otherwise. + */ +int fp_param_set_any_dense(void); + +/** + * Assigns the order of the prime field to any sparse prime. + * + * @return RLC_OK if no errors occurred; RLC_ERR otherwise. + */ +int fp_param_set_any_pmers(void); + +/** + * Assigns the order of the prime field to any towering-friendly prime. + * + * @return RLC_OK if no errors occurred; RLC_ERR otherwise. + */ +int fp_param_set_any_tower(void); + +/** + * Prints the currently configured prime modulus. + */ +void fp_param_print(void); + +/** + * Returns the variable used to parametrize the given prime modulus. + * + * @param[out] x - the integer parameter. + */ +void fp_prime_get_par(bn_t x); + +/** + * Returns the absolute value of the variable used to parameterize the given + * prime modulus in sparse form. + * + * @param[out] len - the length of the representation. + */ +const int *fp_prime_get_par_sps(int *len); + +/** + * Returns the absolute value of the variable used to parameterize the currently + * configured prime modulus in sparse form. The first argument must be an array + * of size (RLC_TERMS + 1). + * + * @param[out] s - the parameter in sparse form. + * @param[out] len - the length of the parameter in sparse form. + * @throw ERR_NO_BUFFER - if the buffer capacity is insufficient. + * @throw ERR_NO_VALID - if the current configuration is invalid. + * @return the integer parameter in sparse form. + */ +void fp_param_get_sps(int *s, int *len); + +/** + * Copies the second argument to the first argument. + * + * @param[out] c - the result. + * @param[in] a - the prime field element to copy. + */ +void fp_copy(fp_t c, const fp_t a); + +/** + * Assigns zero to a prime field element. + * + * @param[out] a - the prime field element to asign. + */ +void fp_zero(fp_t a); + +/** + * Tests if a prime field element is zero or not. + * + * @param[in] a - the prime field element to test. + * @return 1 if the argument is zero, 0 otherwise. + */ +int fp_is_zero(const fp_t a); + +/** + * Tests if a prime field element is even or odd. + * + * @param[in] a - the prime field element to test. + * @return 1 if the argument is even, 0 otherwise. + */ +int fp_is_even(const fp_t a); + +/** + * Reads the bit stored in the given position on a prime field element. + * + * @param[in] a - the prime field element. + * @param[in] bit - the bit position. + * @return the bit value. + */ +int fp_get_bit(const fp_t a, int bit); + +/** + * Stores a bit in a given position on a prime field element. + * + * @param[out] a - the prime field element. + * @param[in] bit - the bit position. + * @param[in] value - the bit value. + */ +void fp_set_bit(fp_t a, int bit, int value); + +/** + * Assigns a small positive constant to a prime field element. + * + * The constant must fit on a multiple precision digit, or dig_t type using + * only the number of bits specified on RLC_DIG. + * + * @param[out] c - the result. + * @param[in] a - the constant to assign. + */ +void fp_set_dig(fp_t c, dig_t a); + +/** + * Returns the number of bits of a prime field element. + * + * @param[in] a - the prime field element. + * @return the number of bits. + */ +int fp_bits(const fp_t a); + +/** + * Assigns a random value to a prime field element. + * + * @param[out] a - the prime field element to assign. + */ +void fp_rand(fp_t a); + +/** + * Prints a prime field element to standard output. + * + * @param[in] a - the prime field element to print. + */ +void fp_print(const fp_t a); + +/** + * Returns the number of digits in radix necessary to store a multiple precision + * integer. The radix must be a power of 2 included in the interval [2, 64]. + * + * @param[in] a - the prime field element. + * @param[in] radix - the radix. + * @throw ERR_NO_VALID - if the radix is invalid. + * @return the number of digits in the given radix. + */ +int fp_size_str(const fp_t a, int radix); + +/** + * Reads a prime field element from a string in a given radix. The radix must + * be a power of 2 included in the interval [2, 64]. + * + * @param[out] a - the result. + * @param[in] str - the string. + * @param[in] len - the size of the string. + * @param[in] radix - the radix. + * @throw ERR_NO_VALID - if the radix is invalid. + */ +void fp_read_str(fp_t a, const char *str, int len, int radix); + +/** + * Writes a prime field element to a string in a given radix. The radix must + * be a power of 2 included in the interval [2, 64]. + * + * @param[out] str - the string. + * @param[in] len - the buffer capacity. + * @param[in] a - the prime field element to write. + * @param[in] radix - the radix. + * @throw ERR_BUFFER - if the buffer capacity is insufficient. + * @throw ERR_NO_VALID - if the radix is invalid. + */ +void fp_write_str(char *str, int len, const fp_t a, int radix); + +/** + * Reads a prime field element from a byte vector in big-endian format. + * + * @param[out] a - the result. + * @param[in] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @throw ERR_NO_BUFFER - if the buffer capacity is not RLC_FP_BYTES. + */ +void fp_read_bin(fp_t a, const uint8_t *bin, int len); + +/** + * Writes a prime field element to a byte vector in big-endian format. + * + * @param[out] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @param[in] a - the prime field element to write. + * @throw ERR_NO_BUFFER - if the buffer capacity is not RLC_FP_BYTES. + */ +void fp_write_bin(uint8_t *bin, int len, const fp_t a); + +/** + * Returns the result of a comparison between two prime field elements. + * + * @param[in] a - the first prime field element. + * @param[in] b - the second prime field element. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fp_cmp(const fp_t a, const fp_t b); + +/** + * Returns the result of a signed comparison between a prime field element + * and a digit. + * + * @param[in] a - the prime field element. + * @param[in] b - the digit. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fp_cmp_dig(const fp_t a, dig_t b); + +/** + * Adds two prime field elements using basic addition. Computes c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the first prime field element to add. + * @param[in] b - the second prime field element to add. + */ +void fp_add_basic(fp_t c, const fp_t a, const fp_t b); + +/** + * Adds two prime field elements with integrated modular reduction. Computes + * c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the first prime field element to add. + * @param[in] b - the second prime field element to add. + */ +void fp_add_integ(fp_t c, const fp_t a, const fp_t b); + +/** + * Adds a prime field element and a digit. Computes c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the first prime field element to add. + * @param[in] b - the digit to add. + */ +void fp_add_dig(fp_t c, const fp_t a, dig_t b); + +/** + * Subtracts a prime field element from another using basic subtraction. + * Computes c = a - b. + * + * @param[out] c - the result. + * @param[in] a - the prime field element. + * @param[in] b - the prime field element to subtract. + */ +void fp_sub_basic(fp_t c, const fp_t a, const fp_t b); + +/** + * Subtracts a prime field element from another with integrated modular + * reduction. Computes c = a - b. + * + * @param[out] c - the result. + * @param[in] a - the prime field element. + * @param[in] b - the prime field element to subtract. + */ +void fp_sub_integ(fp_t c, const fp_t a, const fp_t b); + +/** + * Subtracts a digit from a prime field element. Computes c = a - b. + * + * @param[out] c - the result. + * @param[in] a - the prime field element. + * @param[in] b - the digit to subtract. + */ +void fp_sub_dig(fp_t c, const fp_t a, dig_t b); + +/** + * Negates a prime field element using basic negation. + * + * @param[out] c - the result. + * @param[out] a - the prime field element to negate. + */ +void fp_neg_basic(fp_t c, const fp_t a); + +/** + * Negates a prime field element using integrated negation. + * + * @param[out] c - the result. + * @param[out] a - the prime field element to negate. + */ +void fp_neg_integ(fp_t c, const fp_t a); + +/** + * Doubles a prime field element using basic addition. + * + * @param[out] c - the result. + * @param[in] a - the first prime field element to add. + */ +void fp_dbl_basic(fp_t c, const fp_t a); + +/** + * Doubles a prime field element with integrated modular reduction. + * + * @param[out] c - the result. + * @param[in] a - the first prime field element to add. + */ +void fp_dbl_integ(fp_t c, const fp_t a); + +/** + * Halves a prime field element. + * + * @param[out] c - the result. + * @param[in] a - the prime field element to halve. + */ +void fp_hlv_basic(fp_t c, const fp_t a); + +/** + * Halves a prime field element with integrated modular reduction. + * + * @param[out] c - the result. + * @param[in] a - the prime field element to halve. + */ +void fp_hlv_integ(fp_t c, const fp_t a); + +/** + * Multiples two prime field elements using Schoolbook multiplication. + * + * @param[out] c - the result. + * @param[in] a - the first prime field element to multiply. + * @param[in] b - the second prime field element to multiply. + */ +void fp_mul_basic(fp_t c, const fp_t a, const fp_t b); + +/** + * Multiples two prime field elements using Comba multiplication. + * + * @param[out] c - the result. + * @param[in] a - the first prime field element to multiply. + * @param[in] b - the second prime field element to multiply. + */ +void fp_mul_comba(fp_t c, const fp_t a, const fp_t b); + +/** + * Multiples two prime field elements using multiplication integrated with + * modular reduction. + * + * @param[out] c - the result. + * @param[in] a - the first prime field element to multiply. + * @param[in] b - the second prime field element to multiply. + */ +void fp_mul_integ(fp_t c, const fp_t a, const fp_t b); + +/** + * Multiples two prime field elements using Karatsuba multiplication. + * + * @param[out] c - the result. + * @param[in] a - the first prime field element to multiply. + * @param[in] b - the second prime field element to multiply. + */ +void fp_mul_karat(fp_t c, const fp_t a, const fp_t b); + +/** + * Multiplies a prime field element by a digit. Computes c = a * b. + * + * @param[out] c - the result. + * @param[in] a - the prime field element. + * @param[in] b - the digit to multiply. + */ +void fp_mul_dig(fp_t c, const fp_t a, dig_t b); + +/** + * Squares a prime field element using Schoolbook squaring. + * + * @param[out] c - the result. + * @param[in] a - the prime field element to square. + */ +void fp_sqr_basic(fp_t c, const fp_t a); + +/** + * Squares a prime field element using Comba squaring. + * + * @param[out] c - the result. + * @param[in] a - the prime field element to square. + */ +void fp_sqr_comba(fp_t c, const fp_t a); + +/** + * Squares two prime field elements using squaring integrated with + * modular reduction. + * + * @param[out] c - the result. + * @param[in] a - the binary field element to square. + */ +void fp_sqr_integ(fp_t c, const fp_t a); + +/** + * Squares a prime field element using Karatsuba squaring. + * + * @param[out] c - the result. + * @param[in] a - the prime field element to square. + */ +void fp_sqr_karat(fp_t c, const fp_t a); + +/** + * Shifts a prime field element number to the left. Computes + * c = a * 2^bits. + * + * @param[out] c - the result. + * @param[in] a - the prime field element to shift. + * @param[in] bits - the number of bits to shift. + */ +void fp_lsh(fp_t c, const fp_t a, int bits); + +/** + * Shifts a prime field element to the right. Computes c = floor(a / 2^bits). + * + * @param[out] c - the result. + * @param[in] a - the prime field element to shift. + * @param[in] bits - the number of bits to shift. + */ +void fp_rsh(fp_t c, const fp_t a, int bits); + +/** + * Reduces a multiplication result modulo the prime field modulo using + * division-based reduction. + * + * @param[out] c - the result. + * @param[in] a - the multiplication result to reduce. + */ +void fp_rdc_basic(fp_t c, dv_t a); + +/** + * Reduces a multiplication result modulo the prime field order using Shoolbook + * Montgomery reduction. + * + * @param[out] c - the result. + * @param[in] a - the multiplication result to reduce. + */ +void fp_rdc_monty_basic(fp_t c, dv_t a); + +/** + * Reduces a multiplication result modulo the prime field order using Comba + * Montgomery reduction. + * + * @param[out] c - the result. + * @param[in] a - the multiplication result to reduce. + */ +void fp_rdc_monty_comba(fp_t c, dv_t a); + +/** + * Reduces a multiplication result modulo the prime field modulo using + * fast reduction. + * + * @param[out] c - the result. + * @param[in] a - the multiplication result to reduce. + */ +void fp_rdc_quick(fp_t c, dv_t a); + +/** + * Inverts a prime field element using Fermat's Little Theorem. + * + * @param[out] c - the result. + * @param[in] a - the prime field element to invert. + * @throw ERR_NO_VALID - if the field element is not invertible. + */ +void fp_inv_basic(fp_t c, const fp_t a); + +/** + * Inverts a prime field element using the binary method. + * + * @param[out] c - the result. + * @param[in] a - the prime field element to invert. + * @throw ERR_NO_VALID - if the field element is not invertible. + */ +void fp_inv_binar(fp_t c, const fp_t a); + +/** + * Inverts a prime field element using Montgomery inversion. + * + * @param[out] c - the result. + * @param[in] a - the prime field element to invert. + * @throw ERR_NO_VALID - if the field element is not invertible. + */ +void fp_inv_monty(fp_t c, const fp_t a); + +/** + * Inverts a prime field element using the Euclidean Extended Algorithm. + * + * @param[out] c - the result. + * @param[in] a - the prime field element to invert. + * @throw ERR_NO_VALID - if the field element is not invertible. + */ +void fp_inv_exgcd(fp_t c, const fp_t a); + +/** + * Inverts a prime field element using the Euclidean Extended Algorithm, + * using bns and a custum prime modulus. + * + * @param[out] c - the result. + * @param[in] a - the prime field element to invert. + */ +void fp_inv_exgcd_bn(bn_t c, const bn_t u, const bn_t p); + +/** + * Inverts a prime field element using the constant-time division step approach + * by Bernstein and Bo-Yin Yang. + * + * @param[out] c - the result. + * @param[in] a - the prime field element to invert. + * @throw ERR_NO_VALID - if the field element is not invertible. + */ +void fp_inv_divst(fp_t c, const fp_t a); + +/** + * Inverts a prime field element using a direct call to the lower layer. + * + * @param[out] c - the result. + * @param[in] a - the prime field element to invert. + * @throw ERR_NO_VALID - if the field element is not invertible. + */ +void fp_inv_lower(fp_t c, const fp_t a); + +/** + * Inverts multiple prime field elements simultaneously. + * + * @param[out] c - the result. + * @param[in] a - the prime field elements to invert. + * @param[in] n - the number of elements. + */ +void fp_inv_sim(fp_t *c, const fp_t *a, int n); + +/** + * Exponentiates a prime field element using the binary + * method. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent. + */ +void fp_exp_basic(fp_t c, const fp_t a, const bn_t b); + +/** + * Exponentiates a prime field element using the sliding window method. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent. + */ +void fp_exp_slide(fp_t c, const fp_t a, const bn_t b); + +/** + * Exponentiates a prime field element using the constant-time Montgomery + * powering ladder method. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent. + */ +void fp_exp_monty(fp_t c, const fp_t a, const bn_t b); + +/** + * Extracts the square root of a prime field element. Computes c = sqrt(a). The + * other square root is the negation of c. + * + * @param[out] c - the result. + * @param[in] a - the prime field element. + * @return - 1 if there is a square root, 0 otherwise. + */ +int fp_srt(fp_t c, const fp_t a); + +#endif /* !RLC_FP_H */ diff --git a/bls/contrib/relic/include/relic_fpx.h b/bls/contrib/relic/include/relic_fpx.h new file mode 100644 index 00000000..7e46fa69 --- /dev/null +++ b/bls/contrib/relic/include/relic_fpx.h @@ -0,0 +1,4497 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @defgroup fpx Prime field extensions. + */ + +/** + * @file + * + * Interface of the module for prime extension field arithmetic. + * + * @ingroup fpx + */ + +#ifndef RLC_FPX_H +#define RLC_FPX_H + +#include "relic_fp.h" +#include "relic_types.h" + +/*============================================================================*/ +/* Type definitions */ +/*============================================================================*/ + +/** + * Represents a quadratic extension prime field element. + * + * This extension is constructed with the basis {1, i}, where i is an adjoined + * square root in the prime field. + */ +typedef fp_t fp2_t[2]; + +/** + * Represents a double-precision quadratic extension field element. + */ +typedef dv_t dv2_t[2]; + +/** + * Represents a quadratic extension field element with automatic memory + * allocation. + */ +typedef fp_st fp2_st[2]; + +/** + * Represents a cubic extension prime field element. + * + * This extension is constructed with the basis {1, j}, where j is an adjoined + * cube root in the prime field. + */ +typedef fp_t fp3_t[3]; + +/** + * Represents a double-precision cubic extension field element. + */ +typedef dv_t dv3_t[3]; + +/** + * Represents a cubic extension field element with automatic memory + * allocation. + */ +typedef fp_st fp3_st[3]; + +/** + * Represents a quartic extension prime field element. + * + * This extension is constructed with the basis {1, v}, where v^2 = E is an + * adjoined root in the underlying quadratic extension. + */ +typedef fp2_t fp4_t[2]; + +/** + * Represents a double-precision quartic extension field element. + */ +typedef dv2_t dv4_t[2]; + +/** + * Represents a quartic extension field element with automatic memory + * allocation. + */ +typedef fp2_st fp4_st[2]; + +/** + * Represents a sextic extension field element. + * + * This extension is constructed with the basis {1, v, v^2}, where v^3 = E is an + * adjoined root in the underlying quadratic extension. + */ +typedef fp2_t fp6_t[3]; + +/** + * Represents a double-precision sextic extension field element. + */ +typedef dv2_t dv6_t[3]; + +/** + * Represents an octic extension prime field element. + * + * This extension is constructed with the basis {1, w}, where w^2 = v is an + * adjoined root in the underlying quadratic extension. + */ +typedef fp4_t fp8_t[2]; + +/** + * Represents a double-precision octic extension field element. + */ +typedef dv4_t dv8_t[2]; + +/** + * Represents an octic extension field element with automatic memory + * allocation. + */ +typedef fp4_st fp8_st[2]; + +/** + * Represents an octic extension prime field element. + * + * This extension is constructed with the basis {1, w, w^2}, where w^3 = v is an + * adjoined root in the underlying quadratic extension. + */ +typedef fp3_t fp9_t[3]; + +/** + * Represents a double-precision octic extension field element. + */ +typedef dv3_t dv9_t[3]; + +/** + * Represents an octic extension field element with automatic memory + * allocation. + */ +typedef fp3_st fp9_st[3]; + +/** + * Represents a double-precision dodecic extension field element. + */ +typedef dv6_t dv12_t[2]; + +/** + * Represents a dodecic extension field element. + * + * This extension is constructed with the basis {1, w}, where w^2 = v is an + * adjoined root in the underlying sextic extension. + */ +typedef fp6_t fp12_t[2]; + +/** + * Represents a double-precision octdecic extension field element. + */ +typedef dv9_t dv18_t[2]; + +/** + * Represents an octdecic extension field element. + * + * This extension is constructed with the basis {1, w}, where w^2 = v is an + * adjoined root in the underlying sextic extension. + */ +typedef fp9_t fp18_t[2]; + +/** + * Represents a double-precision 24-degree extension field element. + */ +typedef dv8_t dv24_t[3]; + +/** + * Represents a 24-degree extension field element. + * + * This extension is constructed with the basis {1, t, t^2}, where t^3 = w is an + * adjoined root in the underlying dodecic extension. + */ +typedef fp8_t fp24_t[3]; + +/** + * Represents a double-precision 48-degree extension field element. + */ +typedef dv24_t dv48_t[2]; + +/** + * Represents a 48-degree extension field element. + * + * This extension is constructed with the basis {1, u}, where u^2 = t is an + * adjoined root in the underlying dodecic extension. + */ +typedef fp24_t fp48_t[2]; + +/** + * Represents a double-precision 48-degree extension field element. + */ +typedef dv18_t dv54_t[3]; + +/** + * Represents a 54-degree extension field element. + * + * This extension is constructed with the basis {1, t, t^2}, where u^3 = w is an + * adjoined root in the underlying dodecic extension. + */ +typedef fp18_t fp54_t[3]; + +/*============================================================================*/ +/* Macro definitions */ +/*============================================================================*/ + +/** + * Initializes a double-precision quadratic extension field element with null. + * +* @param[out] A - the quadratic extension element to initialize. + */ +#define dv2_null(A) \ + dv_null(A[0]); dv_null(A[1]); \ + + +/** + * Allocates a double-precision quadratic extension field element. + * + * @param[out] A - the new quadratic extension field element. + */ +#define dv2_new(A) \ + dv_new(A[0]); dv_new(A[1]); \ + +/** + * Frees a double-precision quadratic extension field element. + * + * @param[out] A - the quadratic extension field element to free. + */ +#define dv2_free(A) \ + dv_free(A[0]); dv_free(A[1]); \ + +/** + * Initializes a quadratic extension field element with null. + * +* @param[out] A - the quadratic extension element to initialize. + */ +#define fp2_null(A) \ + fp_null(A[0]); fp_null(A[1]); \ + +/** + * Allocates a quadratic extension field element. + * + * @param[out] A - the new quadratic extension field element. + */ +#define fp2_new(A) \ + fp_new(A[0]); fp_new(A[1]); \ + +/** + * Frees a quadratic extension field element. + * + * @param[out] A - the quadratic extension field element to free. + */ +#define fp2_free(A) \ + fp_free(A[0]); fp_free(A[1]); \ + +/** + * Adds two quadratic extension field elements. Computes C = A + B. + * + * @param[out] C - the result. + * @param[in] A - the first quadratic extension field element. + * @param[in] B - the second quadratic extension field element. + */ +#if FPX_QDR == BASIC +#define fp2_add(C, A, B) fp2_add_basic(C, A, B) +#elif FPX_QDR == INTEG +#define fp2_add(C, A, B) fp2_add_integ(C, A, B) +#endif + +/** + * Subtracts a quadratic extension field element from another. + * Computes C = A - B. + * + * @param[out] C - the result. + * @param[in] A - the first quadratic extension field element. + * @param[in] B - the second quadratic extension field element. + */ +#if FPX_QDR == BASIC +#define fp2_sub(C, A, B) fp2_sub_basic(C, A, B) +#elif FPX_QDR == INTEG +#define fp2_sub(C, A, B) fp2_sub_integ(C, A, B) +#endif + +/** + * Doubles a quadratic extension field element. Computes C = A + A. + * + * @param[out] C - the result. + * @param[in] A - the quadratic extension field element. + */ +#if FPX_QDR == BASIC +#define fp2_dbl(C, A) fp2_dbl_basic(C, A) +#elif FPX_QDR == INTEG +#define fp2_dbl(C, A) fp2_dbl_integ(C, A) +#endif + +/** + * Adds a quadratic extension field element and a digit. Computes c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the quadratic extension field element. + * @param[in] b - the digit to add. + */ +void fp2_add_dig(fp2_t c, const fp2_t a, dig_t b); + +/** + * Subtracts a quadratic extension field element and a digit. Computes c = a - b. + * + * @param[out] c - the result. + * @param[in] a - the quadratic extension field element. + * @param[in] b - the digit to subtract. + */ +void fp2_sub_dig(fp2_t c, const fp2_t a, dig_t b); + +/** + * Multiplies two quadratic extension field elements. Computes C = A * B. + * + * @param[out] C - the result. + * @param[in] A - the first quadratic extension field element. + * @param[in] B - the second quadratic extension field element. + */ +#if FPX_QDR == BASIC +#define fp2_mul(C, A, B) fp2_mul_basic(C, A, B) +#elif FPX_QDR == INTEG +#define fp2_mul(C, A, B) fp2_mul_integ(C, A, B) +#endif + +/** + * Multiplies a quadratic extension field by the quadratic/cubic non-residue. + * Computes C = A * E, where E is a non-square/non-cube in the quadratic + * extension. + * + * @param[out] C - the result. + * @param[in] A - the quadratic extension field element to multiply. + */ +#if FPX_QDR == BASIC +#define fp2_mul_nor(C, A) fp2_mul_nor_basic(C, A) +#elif FPX_QDR == INTEG +#define fp2_mul_nor(C, A) fp2_mul_nor_integ(C, A) +#endif + +/** + * Squares a quadratic extension field element. Computes C = A * A. + * + * @param[out] C - the result. + * @param[in] A - the quadratic extension field element to square. + */ +#if FPX_QDR == BASIC +#define fp2_sqr(C, A) fp2_sqr_basic(C, A) +#elif FPX_QDR == INTEG +#define fp2_sqr(C, A) fp2_sqr_integ(C, A) +#endif + +/** + * Initializes a double-precision cubic extension field element with a null + * value. + * +* @param[out] A - the cubic extension element to initialize. + */ +#define dv3_null(A) \ + dv_null(A[0]); dv_null(A[1]); dv_null(A[2]); \ + +/** + * Allocates a double-precision cubic extension field element. + * + * @param[out] A - the new cubic extension field element. + */ +#define dv3_new(A) \ + dv_new(A[0]); dv_new(A[1]); dv_new(A[2]); \ + +/** + * Frees a double-precision cubic extension field element. + * + * @param[out] A - the cubic extension field element to free. + */ +#define dv3_free(A) \ + dv_free(A[0]); dv_free(A[1]); dv_free(A[2]); \ + +/** + * Initializes a cubic extension field element with null. + * +* @param[out] A - the cubic extension element to initialize. + */ +#define fp3_null(A) \ + fp_null(A[0]); fp_null(A[1]); fp_null(A[2]); \ + +/** + * Allocates a cubic extension field element. + * + * @param[out] A - the new cubic extension field element. + */ +#define fp3_new(A) \ + fp_new(A[0]); fp_new(A[1]); fp_new(A[2]); \ + +/** + * Frees a cubic extension field element. + * + * @param[out] A - the cubic extension field element to free. + */ +#define fp3_free(A) \ + fp_free(A[0]); fp_free(A[1]); fp_free(A[2]); \ + +/** + * Adds two cubic extension field elements. Computes C = A + B. + * + * @param[out] C - the result. + * @param[in] A - the first cubic extension field element. + * @param[in] B - the second cubic extension field element. + */ +#if FPX_CBC == BASIC +#define fp3_add(C, A, B) fp3_add_basic(C, A, B) +#elif FPX_CBC == INTEG +#define fp3_add(C, A, B) fp3_add_integ(C, A, B) +#endif + +/** + * Subtracts a cubic extension field element from another. + * Computes C = A - B. + * + * @param[out] C - the result. + * @param[in] A - the first cubic extension field element. + * @param[in] B - the second cubic extension field element. + */ +#if FPX_CBC == BASIC +#define fp3_sub(C, A, B) fp3_sub_basic(C, A, B) +#elif FPX_CBC == INTEG +#define fp3_sub(C, A, B) fp3_sub_integ(C, A, B) +#endif + +/** + * Doubles a cubic extension field element. Computes C = A + A. + * + * @param[out] C - the result. + * @param[in] A - the cubic extension field element. + */ +#if FPX_CBC == BASIC +#define fp3_dbl(C, A) fp3_dbl_basic(C, A) +#elif FPX_CBC == INTEG +#define fp3_dbl(C, A) fp3_dbl_integ(C, A) +#endif + +/** + * Multiplies two cubic extension field elements. Computes C = A * B. + * + * @param[out] C - the result. + * @param[in] A - the first cubic extension field element. + * @param[in] B - the second cubic extension field element. + */ +#if FPX_CBC == BASIC +#define fp3_mul(C, A, B) fp3_mul_basic(C, A, B) +#elif FPX_CBC == INTEG +#define fp3_mul(C, A, B) fp3_mul_integ(C, A, B) +#endif + +/** + * Squares a cubic extension field element. Computes C = A * A. + * + * @param[out] C - the result. + * @param[in] A - the cubic extension field element to square. + */ +#if FPX_CBC == BASIC +#define fp3_sqr(C, A) fp3_sqr_basic(C, A) +#elif FPX_CBC == INTEG +#define fp3_sqr(C, A) fp3_sqr_integ(C, A) +#endif + +/** + * Initializes a double-precision quartic extension field with null. + * + * @param[out] A - the quartic extension element to initialize. + */ +#define dv4_null(A) \ + dv2_null(A[0]); dv2_null(A[1]); \ + +/** + * Allocates a double-precision quartic extension field element. + * + * @param[out] A - the new quartic extension field element. + */ +#define dv4_new(A) \ + dv2_new(A[0]); dv2_new(A[1]); \ + +/** + * Frees a double-precision quartic extension field element. + * + * @param[out] A - the quartic extension field element to free. + */ +#define dv4_free(A) \ + dv2_free(A[0]); dv2_free(A[1]); \ + +/** + * Initializes a quartic extension field with null. + * + * @param[out] A - the quartic extension element to initialize. + */ +#define fp4_null(A) \ + fp2_null(A[0]); fp2_null(A[1]); \ + +/** + * Allocates a quartic extension field element. + * + * @param[out] A - the new quartic extension field element. + */ +#define fp4_new(A) \ + fp2_new(A[0]); fp2_new(A[1]); \ + +/** + * Frees a quartic extension field element. + * + * @param[out] A - the quartic extension field element to free. + */ +#define fp4_free(A) \ + fp2_free(A[0]); fp2_free(A[1]); \ + +/** + * Multiplies two quartic extension field elements. Computes C = A * B. + * + * @param[out] C - the result. + * @param[in] A - the first quartic extension field element. + * @param[in] B - the second quartic extension field element. + */ +#if FPX_RDC == BASIC +#define fp4_mul(C, A, B) fp4_mul_basic(C, A, B) +#elif FPX_RDC == LAZYR +#define fp4_mul(C, A, B) fp4_mul_lazyr(C, A, B) +#endif + +/** + * Squares a quartic extension field element. Computes C = A * A. + * + * @param[out] C - the result. + * @param[in] A - the quartic extension field element to square. + */ +#if FPX_RDC == BASIC +#define fp4_sqr(C, A) fp4_sqr_basic(C, A) +#elif FPX_RDC == LAZYR +#define fp4_sqr(C, A) fp4_sqr_lazyr(C, A) +#endif + +/** + * Initializes a double-precision sextic extension field with null. + * + * @param[out] A - the sextic extension element to initialize. + */ +#define dv6_null(A) \ + dv2_null(A[0]); dv2_null(A[1]); dv2_null(A[2]); \ + +/** + * Allocates a double-precision sextic extension field element. + * + * @param[out] A - the new sextic extension field element. + */ +#define dv6_new(A) \ + dv2_new(A[0]); dv2_new(A[1]); dv2_new(A[2]); \ + +/** + * Frees a double-precision sextic extension field element. + * + * @param[out] A - the sextic extension field element to free. + */ +#define dv6_free(A) \ + dv2_free(A[0]); dv2_free(A[1]); dv2_free(A[2]); \ + +/** + * Initializes a sextic extension field with null. + * + * @param[out] A - the sextic extension element to initialize. + */ +#define fp6_null(A) \ + fp2_null(A[0]); fp2_null(A[1]); fp2_null(A[2]); \ + +/** + * Allocates a sextic extension field element. + * + * @param[out] A - the new sextic extension field element. + */ +#define fp6_new(A) \ + fp2_new(A[0]); fp2_new(A[1]); fp2_new(A[2]); \ + +/** + * Frees a sextic extension field element. + * + * @param[out] A - the sextic extension field element to free. + */ +#define fp6_free(A) \ + fp2_free(A[0]); fp2_free(A[1]); fp2_free(A[2]); \ + +/** + * Multiplies two sextic extension field elements. Computes C = A * B. + * + * @param[out] C - the result. + * @param[in] A - the first sextic extension field element. + * @param[in] B - the second sextic extension field element. + */ +#if FPX_RDC == BASIC +#define fp6_mul(C, A, B) fp6_mul_basic(C, A, B) +#elif FPX_RDC == LAZYR +#define fp6_mul(C, A, B) fp6_mul_lazyr(C, A, B) +#endif + +/** + * Squares a sextic extension field element. Computes C = A * A. + * + * @param[out] C - the result. + * @param[in] A - the sextic extension field element to square. + */ +#if FPX_RDC == BASIC +#define fp6_sqr(C, A) fp6_sqr_basic(C, A) +#elif FPX_RDC == LAZYR +#define fp6_sqr(C, A) fp6_sqr_lazyr(C, A) +#endif + +/** + * Initializes a double-precision octic extension field with null. + * + * @param[out] A - the octic extension element to initialize. + */ +#define dv8_null(A) \ + dv4_null(A[0]); dv4_null(A[1]); \ + +/** + * Allocates a double-precision octic extension field element. + * + * @param[out] A - the new octic extension field element. + */ +#define dv8_new(A) \ + dv4_new(A[0]); dv4_new(A[1]); \ + +/** + * Frees a double-precision octic extension field element. + * + * @param[out] A - the octic extension field element to free. + */ +#define dv8_free(A) \ + dv4_free(A[0]); dv4_free(A[1]); \ + +/** + * Initializes an octic extension field with null. + * + * @param[out] A - the octic extension element to initialize. + */ +#define fp8_null(A) \ + fp4_null(A[0]); fp4_null(A[1]); \ + +/** + * Allocates an octic extension field element. + * + * @param[out] A - the new octic extension field element. + */ +#define fp8_new(A) \ + fp4_new(A[0]); fp4_new(A[1]); \ + +/** + * Frees an octic extension field element. + * + * @param[out] A - the octic extension field element to free. + */ +#define fp8_free(A) \ + fp4_free(A[0]); fp4_free(A[1]); \ + +/** + * Multiplies two octic extension field elements. Computes C = A * B. + * + * @param[out] C - the result. + * @param[in] A - the first octic extension field element. + * @param[in] B - the second octic extension field element. + */ +#if FPX_RDC == BASIC +#define fp8_mul(C, A, B) fp8_mul_basic(C, A, B) +#elif FPX_RDC == LAZYR +#define fp8_mul(C, A, B) fp8_mul_lazyr(C, A, B) +#endif + +/** + * Squares an octic extension field element. Computes C = A * A. + * + * @param[out] C - the result. + * @param[in] A - the octic extension field element to square. + */ +#if FPX_RDC == BASIC +#define fp8_sqr(C, A) fp8_sqr_basic(C, A) +#elif FPX_RDC == LAZYR +#define fp8_sqr(C, A) fp8_sqr_lazyr(C, A) +#endif + +/** + * Initializes a double-precision nonic extension field with null. + * + * @param[out] A - the octic extension element to initialize. + */ +#define dv9_null(A) \ + dv3_null(A[0]); dv3_null(A[1]); dv3_null(A[2]); \ + +/** + * Allocates a double-precision nonic extension field element. + * + * @param[out] A - the new nonic extension field element. + */ +#define dv9_new(A) \ + dv3_new(A[0]); dv3_new(A[1]); dv3_new(A[2]); \ + +/** + * Frees a double-precision nonic extension field element. + * + * @param[out] A - the nonic extension field element to free. + */ +#define dv9_free(A) \ + dv3_free(A[0]); dv3_free(A[1]); dv3_free(A[2]); \ + +/** + * Initializes a nonic extension field with null. + * + * @param[out] A - the nonic extension element to initialize. + */ +#define fp9_null(A) \ + fp3_null(A[0]); fp3_null(A[1]); fp3_null(A[2]); \ + +/** + * Allocates a nonic extension field element. + * + * @param[out] A - the new nonic extension field element. + */ +#define fp9_new(A) \ + fp3_new(A[0]); fp3_new(A[1]); fp3_new(A[2]); \ + +/** + * Frees a nonic extension field element. + * + * @param[out] A - the nonic extension field element to free. + */ +#define fp9_free(A) \ + fp3_free(A[0]); fp3_free(A[1]); fp3_free(A[2]); \ + +/** + * Multiplies two nonic extension field elements. Computes C = A * B. + * + * @param[out] C - the result. + * @param[in] A - the first nonic extension field element. + * @param[in] B - the second nonic extension field element. + */ +#if FPX_RDC == BASIC +#define fp9_mul(C, A, B) fp9_mul_basic(C, A, B) +#elif FPX_RDC == LAZYR +#define fp9_mul(C, A, B) fp9_mul_lazyr(C, A, B) +#endif + +/** + * Squares a nonic extension field element. Computes C = A * A. + * + * @param[out] C - the result. + * @param[in] A - the nonic extension field element to square. + */ +#if FPX_RDC == BASIC +#define fp9_sqr(C, A) fp9_sqr_basic(C, A) +#elif FPX_RDC == LAZYR +#define fp9_sqr(C, A) fp9_sqr_lazyr(C, A) +#endif + +/** + * Initializes a double-precision dodecic extension field with null. + * + * @param[out] A - the dodecic extension element to initialize. + */ +#define dv12_null(A) \ + dv6_null(A[0]); dv6_null(A[1]); \ + +/** + * Allocates a double-precision dodecic extension field element. + * + * @param[out] A - the new dodecic extension field element. + */ +#define dv12_new(A) \ + dv6_new(A[0]); dv6_new(A[1]); \ + +/** + * Frees a double-precision dodecic extension field element. + * + * @param[out] A - the dodecic extension field element to free. + */ +#define dv12_free(A) \ + dv6_free(A[0]); dv6_free(A[1]); \ + +/** + * Initializes a dodecic extension field with null. + * + * @param[out] A - the dodecic extension element to initialize. + */ +#define fp12_null(A) \ + fp6_null(A[0]); fp6_null(A[1]); \ + +/** + * Allocates a dodecic extension field element. + * + * @param[out] A - the new dodecic extension field element. + */ +#define fp12_new(A) \ + fp6_new(A[0]); fp6_new(A[1]); \ + +/** + * Frees a dodecic extension field element. + * + * @param[out] A - the dodecic extension field element to free. + */ +#define fp12_free(A) \ + fp6_free(A[0]); fp6_free(A[1]); \ + +/** + * Multiplies two dodecic extension field elements. Computes C = A * B. + * + * @param[out] C - the result. + * @param[in] A - the first dodecic extension field element. + * @param[in] B - the second dodecic extension field element. + */ +#if FPX_RDC == BASIC +#define fp12_mul(C, A, B) fp12_mul_basic(C, A, B) +#elif FPX_RDC == LAZYR +#define fp12_mul(C, A, B) fp12_mul_lazyr(C, A, B) +#endif + +/** + * Multiplies a dense and a sparse dodecic extension field elements. Computes + * C = A * B. + * + * @param[out] C - the result. + * @param[in] A - the dense dodecic extension field element. + * @param[in] B - the sparse dodecic extension field element. + */ +#if FPX_RDC == BASIC +#define fp12_mul_dxs(C, A, B) fp12_mul_dxs_basic(C, A, B) +#elif FPX_RDC == LAZYR +#define fp12_mul_dxs(C, A, B) fp12_mul_dxs_lazyr(C, A, B) +#endif + +/** + * Squares a dodecic extension field element. Computes C = A * A. + * + * @param[out] C - the result. + * @param[in] A - the dodecic extension field element to square. + */ +#if FPX_RDC == BASIC +#define fp12_sqr(C, A) fp12_sqr_basic(C, A) +#elif FPX_RDC == LAZYR +#define fp12_sqr(C, A) fp12_sqr_lazyr(C, A) +#endif + +/** + * Squares a dodecic extension field element in the cyclotomic subgroup. + * Computes C = A * A. + * + * @param[out] C - the result. + * @param[in] A - the dodecic extension field element to square. + */ +#if FPX_RDC == BASIC +#define fp12_sqr_cyc(C, A) fp12_sqr_cyc_basic(C, A) +#elif FPX_RDC == LAZYR +#define fp12_sqr_cyc(C, A) fp12_sqr_cyc_lazyr(C, A) +#endif + +/** + * Squares a dodecic extension field element in the cyclotomic subgroup in + * compressed form. Computes C = A * A. + * + * @param[out] C - the result. + * @param[in] A - the dodecic extension field element to square. + */ +#if FPX_RDC == BASIC +#define fp12_sqr_pck(C, A) fp12_sqr_pck_basic(C, A) +#elif FPX_RDC == LAZYR +#define fp12_sqr_pck(C, A) fp12_sqr_pck_lazyr(C, A) +#endif + +/** + * Initializes a double-precision sextic extension field with null. + * + * @param[out] A - the sextic extension element to initialize. + */ +#define dv18_null(A) \ + dv9_null(A[0]); dv9_null(A[1]); \ + +/** + * Allocates a double-precision sextic extension field element. + * + * @param[out] A - the new sextic extension field element. + */ +#define dv18_new(A) \ + dv9_new(A[0]); dv9_new(A[1]); \ + +/** + * Frees a double-precision sextic extension field element. + * + * @param[out] A - the sextic extension field element to free. + */ +#define dv18_free(A) \ + dv9_free(A[0]); dv9_free(A[1]); \ + +/** + * Initializes an octdecic extension field with null. + * + * @param[out] A - the octdecic extension element to initialize. + */ +#define fp18_null(A) \ + fp9_null(A[0]); fp9_null(A[1]); \ + +/** + * Allocates an octdecic extension field element. + * + * @param[out] A - the new octdecic extension field element. + */ +#define fp18_new(A) \ + fp9_new(A[0]); fp9_new(A[1]); \ + +/** + * Frees an octdecic extension field element. + * + * @param[out] A - the octdecic extension field element to free. + */ +#define fp18_free(A) \ + fp9_free(A[0]); fp9_free(A[1]); \ + +/** + * Multiplies two octdecic extension field elements. Computes C = A * B. + * + * @param[out] C - the result. + * @param[in] A - the first octdecic extension field element. + * @param[in] B - the second octdecic extension field element. + */ +#if FPX_RDC == BASIC +#define fp18_mul(C, A, B) fp18_mul_basic(C, A, B) +#elif FPX_RDC == LAZYR +#define fp18_mul(C, A, B) fp18_mul_lazyr(C, A, B) +#endif + +/** + * Multiplies a dense and a sparse octdecic extension field elements. Computes + * C = A * B. + * + * @param[out] C - the result. + * @param[in] A - the dense octdecic extension field element. + * @param[in] B - the sparse octdecic extension field element. + */ +#if FPX_RDC == BASIC +#define fp18_mul_dxs(C, A, B) fp18_mul_dxs_basic(C, A, B) +#elif FPX_RDC == LAZYR +#define fp18_mul_dxs(C, A, B) fp18_mul_dxs_lazyr(C, A, B) +#endif + +/** + * Squares an octdecic extension field element. Computes C = A * A. + * + * @param[out] C - the result. + * @param[in] A - the octdecic extension field element to square. + */ +#if FPX_RDC == BASIC +#define fp18_sqr(C, A) fp18_sqr_basic(C, A) +#elif FPX_RDC == LAZYR +#define fp18_sqr(C, A) fp18_sqr_lazyr(C, A) +#endif + +/** + * Initializes a double-precision 24-degree extension field with null. + * + * @param[out] A - the 24-degree extension element to initialize. + */ +#define dv24_null(A) \ + dv8_null(A[0]); dv8_null(A[1]); dv8_null(A[2]); \ + +/** + * Allocates a double-precision 24-degree extension field element. + * + * @param[out] A - the new 24-degree extension field element. + */ +#define dv24_new(A) \ + dv8_new(A[0]); dv8_new(A[1]); dv8_new(A[2]); \ + +/** + * Frees a double-precision 24-degree extension field element. + * + * @param[out] A - the 24-degree extension field element to free. + */ +#define dv24_free(A) \ + dv8_free(A[0]); dv8_free(A[1]); dv8_free(A[2]); \ + +/** + * Initializes a 24-degree extension field with null. + * + * @param[out] A - the 24-degree extension element to initialize. + */ +#define fp24_null(A) \ + fp8_null(A[0]); fp8_null(A[1]); fp8_null(A[2]); \ + +/** + * Allocates a 24-degree extension field element. + * + * @param[out] A - the new 24-degree extension field element. + */ +#define fp24_new(A) \ + fp8_new(A[0]); fp8_new(A[1]); fp8_new(A[2]); \ + +/** + * Frees a 24-degree extension field element. + * + * @param[out] A - the 24-degree extension field element to free. + */ +#define fp24_free(A) \ + fp8_free(A[0]); fp8_free(A[1]); fp8_free(A[2]); \ + +/** + * Multiplies two 24-degree extension field elements. Computes C = A * B. + * + * @param[out] C - the result. + * @param[in] A - the first 24-degree extension field element. + * @param[in] B - the second 24-degree extension field element. + */ +#if FPX_RDC == BASIC +#define fp24_mul(C, A, B) fp24_mul_basic(C, A, B) +#elif FPX_RDC == LAZYR +#define fp24_mul(C, A, B) fp24_mul_lazyr(C, A, B) +#endif + +/** + * Squares a 24-degree extension field element. Computes C = A * A. + * + * @param[out] C - the result. + * @param[in] A - the 24-degree extension field element to square. + */ +#if FPX_RDC == BASIC +#define fp24_sqr(C, A) fp24_sqr_basic(C, A) +#elif FPX_RDC == LAZYR +#define fp24_sqr(C, A) fp24_sqr_lazyr(C, A) +#endif + +/** + * Initializes a double-precision 48-degree extension field with null. + * + * @param[out] A - the 48-degree extension element to initialize. + */ +#define dv48_null(A) \ + dv24_null(A[0]); dv24_null(A[1]); \ + +/** + * Allocates a double-precision 48-degree extension field element. + * + * @param[out] A - the new 48-degree extension field element. + */ +#define dv48_new(A) \ + dv24_new(A[0]); dv24_new(A[1]); \ + +/** + * Frees a double-precision 48-degree extension field element. + * + * @param[out] A - the 48-degree extension field element to free. + */ +#define dv48_free(A) \ + dv24_free(A[0]); dv24_free(A[1]); \ + +/** + * Initializes a 48-degree extension field with null. + * + * @param[out] A - the 48-degree extension element to initialize. + */ +#define fp48_null(A) \ + fp24_null(A[0]); fp24_null(A[1]); \ + +/** + * Allocates a 48-degree extension field element. + * + * @param[out] A - the new 48-degree extension field element. + */ +#define fp48_new(A) \ + fp24_new(A[0]); fp24_new(A[1]); \ + +/** + * Frees a 48-degree extension field element. + * + * @param[out] A - the 48-degree extension field element to free. + */ +#define fp48_free(A) \ + fp24_free(A[0]); fp24_free(A[1]); \ + +/** + * Multiplies two 48-degree extension field elements. Computes C = A * B. + * + * @param[out] C - the result. + * @param[in] A - the first 48-degree extension field element. + * @param[in] B - the second 48-degree extension field element. + */ +#if FPX_RDC == BASIC +#define fp48_mul(C, A, B) fp48_mul_basic(C, A, B) +#elif FPX_RDC == LAZYR +#define fp48_mul(C, A, B) fp48_mul_lazyr(C, A, B) +#endif + +/** + * Squares a 48-degree extension field element. Computes C = A * A. + * + * @param[out] C - the result. + * @param[in] A - the 48-degree extension field element to square. + */ +#if FPX_RDC == BASIC +#define fp48_sqr(C, A) fp48_sqr_basic(C, A) +#elif FPX_RDC == LAZYR +#define fp48_sqr(C, A) fp48_sqr_lazyr(C, A) +#endif + +/** + * Squares a 48-degree extension field element in the cyclotomic subgroup. + * Computes C = A * A. + * + * @param[out] C - the result. + * @param[in] A - the 48-degree extension field element to square. + */ +#if FPX_RDC == BASIC +#define fp48_sqr_cyc(C, A) fp48_sqr_cyc_basic(C, A) +#elif FPX_RDC == LAZYR +#define fp48_sqr_cyc(C, A) fp48_sqr_cyc_lazyr(C, A) +#endif + +/** + * Squares a 48-degree extension field element in the cyclotomic subgroup in + * compressed form. Computes C = A * A. + * + * @param[out] C - the result. + * @param[in] A - the 48-degree extension field element to square. + */ +#if FPX_RDC == BASIC +#define fp48_sqr_pck(C, A) fp48_sqr_pck_basic(C, A) +#elif FPX_RDC == LAZYR +#define fp48_sqr_pck(C, A) fp48_sqr_pck_lazyr(C, A) +#endif + +/** + * Initializes a double-precision 54-degree extension field with null. + * + * @param[out] A - the 54-degree extension element to initialize. + */ +#define dv54_null(A) \ + dv18_null(A[0]); dv18_null(A[1]); dv18_null(A[2]); \ + +/** + * Allocates a double-precision 54-degree extension field element. + * + * @param[out] A - the new 54-degree extension field element. + */ +#define dv54_new(A) \ + dv18_new(A[0]); dv18_new(A[1]); dv18_new(A[2]); \ + +/** + * Frees a double-precision 54-degree extension field element. + * + * @param[out] A - the 54-degree extension field element to free. + */ +#define dv54_free(A) \ + dv18_free(A[0]); dv18_free(A[1]); dv18_free(A[2]); \ + +/** + * Initializes a 54-degree extension field with null. + * + * @param[out] A - the 54-degree extension element to initialize. + */ +#define fp54_null(A) \ + fp18_null(A[0]); fp18_null(A[1]); fp18_null(A[2]); \ + +/** + * Allocates a 54-degree extension field element. + * + * @param[out] A - the new 54-degree extension field element. + */ +#define fp54_new(A) \ + fp18_new(A[0]); fp18_new(A[1]); fp18_new(A[2]); \ + +/** + * Frees a 54-degree extension field element. + * + * @param[out] A - the 54-degree extension field element to free. + */ +#define fp54_free(A) \ + fp18_free(A[0]); fp18_free(A[1]); fp18_free(A[2]); \ + +/** + * Multiplies two 54-degree extension field elements. Computes C = A * B. + * + * @param[out] C - the result. + * @param[in] A - the first 54-degree extension field element. + * @param[in] B - the second 54-degree extension field element. + */ +#if FPX_RDC == BASIC +#define fp54_mul(C, A, B) fp54_mul_basic(C, A, B) +#elif FPX_RDC == LAZYR +#define fp54_mul(C, A, B) fp54_mul_lazyr(C, A, B) +#endif + +/** + * Squares a 54-degree extension field element. Computes C = A * A. + * + * @param[out] C - the result. + * @param[in] A - the 54-degree extension field element to square. + */ +#if FPX_RDC == BASIC +#define fp54_sqr(C, A) fp54_sqr_basic(C, A) +#elif FPX_RDC == LAZYR +#define fp54_sqr(C, A) fp54_sqr_lazyr(C, A) +#endif + +/** + * Squares a 54-degree extension field element in the cyclotomic subgroup. + * Computes C = A * A. + * + * @param[out] C - the result. + * @param[in] A - the 54-degree extension field element to square. + */ +#if FPX_RDC == BASIC +#define fp54_sqr_cyc(C, A) fp54_sqr_cyc_basic(C, A) +#elif FPX_RDC == LAZYR +#define fp54_sqr_cyc(C, A) fp54_sqr_cyc_lazyr(C, A) +#endif + +/** + * Squares a 54-degree extension field element in the cyclotomic subgroup in + * compressed form. Computes C = A * A. + * + * @param[out] C - the result. + * @param[in] A - the 54-degree extension field element to square. + */ +#if FPX_RDC == BASIC +#define fp54_sqr_pck(C, A) fp54_sqr_pck_basic(C, A) +#elif FPX_RDC == LAZYR +#define fp54_sqr_pck(C, A) fp54_sqr_pck_lazyr(C, A) +#endif + +/*============================================================================*/ +/* Function prototypes */ +/*============================================================================*/ + +/** + * Initializes the quadratic extension field arithmetic module. + */ +void fp2_field_init(void); + +/** + * Return the integer part (u) of the quadratic non-residue (i + u). + */ +int fp2_field_get_qnr(void); + +/** + * Copies the second argument to the first argument. + * + * @param[out] C - the result. + * @param[in] A - the quadratic extension field element to copy. + */ +void fp2_copy(fp2_t c, fp2_t a); + +/** + * Assigns zero to a quadratic extension field element. + * + * @param[out] A - the quadratic extension field element to zero. + */ +void fp2_zero(fp2_t a); + +/** + * Tests if a quadratic extension field element is zero or not. + * + * @param[in] A - the quadratic extension field element to test. + * @return 1 if the argument is zero, 0 otherwise. + */ +int fp2_is_zero(fp2_t a); + +/** + * Assigns a random value to a quadratic extension field element. + * + * @param[out] A - the quadratic extension field element to assign. + */ +void fp2_rand(fp2_t a); + +/** + * Prints a quadratic extension field element to standard output. + * + * @param[in] A - the quadratic extension field element to print. + */ +void fp2_print(fp2_t a); + +/** + * Returns the number of bytes necessary to store a quadratic extension field + * element. + * + * @param[in] a - the extension field element. + * @param[in] pack - the flag to indicate compression. + * @return the number of bytes. + */ +int fp2_size_bin(fp2_t a, int pack); + +/** + * Reads a quadratic extension field element from a byte vector in big-endian + * format. + * + * @param[out] a - the result. + * @param[in] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @throw ERR_NO_BUFFER - if the buffer capacity is not correct. + */ +void fp2_read_bin(fp2_t a, const uint8_t *bin, int len); + +/** + * Writes a quadratic extension field element to a byte vector in big-endian + * format. + * + * @param[out] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @param[in] a - the extension field element to write. + * @param[in] pack - the flag to indicate compression. + * @throw ERR_NO_BUFFER - if the buffer capacity is not correct. + */ +void fp2_write_bin(uint8_t *bin, int len, fp2_t a, int pack); + +/** + * Returns the result of a comparison between two quadratic extension field + * elements. + * + * @param[in] A - the first quadratic extension field element. + * @param[in] B - the second quadratic extension field element. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fp2_cmp(fp2_t a, fp2_t b); + +/** + * Returns the result of a signed comparison between a quadratic extension field + * element and a digit. + * + * @param[in] a - the quadratic extension field element. + * @param[in] b - the digit. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fp2_cmp_dig(fp2_t a, dig_t b); + +/** + * Assigns a quadratic extension field element to a digit. + * + * @param[in] a - the quadratic extension field element. + * @param[in] b - the digit. + */ +void fp2_set_dig(fp2_t a, dig_t b); + +/** + * Adds two quadratic extension field elements using basic arithmetic. + * + * @param[out] c - the result. + * @param[in] a - the first quadratic extension field element. + * @param[in] b - the second quadratic extension field element. + */ +void fp2_add_basic(fp2_t c, fp2_t a, fp2_t b); + +/** + * Adds two quadratic extension field elements using integrated modular + * reduction. + * + * @param[out] c - the result. + * @param[in] a - the first quadratic extension field element. + * @param[in] b - the second quadratic extension field element. + */ +void fp2_add_integ(fp2_t c, fp2_t a, fp2_t b); + +/** + * Subtracts a quadratic extension field element from another using basic + * arithmetic. + * + * @param[out] C - the result. + * @param[in] A - the first quadratic extension field element. + * @param[in] B - the second quadratic extension field element. + */ +void fp2_sub_basic(fp2_t c, fp2_t a, fp2_t b); + +/** + * Subtracts a quadratic extension field element from another using integrated + * modular reduction. + * + * @param[out] C - the result. + * @param[in] A - the first quadratic extension field element. + * @param[in] B - the second quadratic extension field element. + */ +void fp2_sub_integ(fp2_t c, fp2_t a, fp2_t b); + +/** + * Negates a quadratic extension field element. + * + * @param[out] C - the result. + * @param[out] A - the quadratic extension field element to negate. + */ +void fp2_neg(fp2_t c, fp2_t a); + +/** + * Doubles a quadratic extension field element using basic arithmetic. + * + * @param[out] c - the result. + * @param[in] a - the quadratic extension field element to double. + */ +void fp2_dbl_basic(fp2_t c, fp2_t a); + +/** + * Doubles a quadratic extension field element using integrated modular + * reduction. + * + * @param[out] c - the result. + * @param[in] a - the quadratic extension field element to double. + */ +void fp2_dbl_integ(fp2_t c, fp2_t a); + +/** + * Multiples two quadratic extension field elements using basic arithmetic. + * + * @param[out] c - the result. + * @param[in] a - the first quadratic extension field element. + * @param[in] b - the second quadratic extension field element. + */ +void fp2_mul_basic(fp2_t c, fp2_t a, fp2_t b); + +/** + * Multiples two quadratic extension field elements using integrated modular + * reduction. + * + * @param[out] c - the result. + * @param[in] a - the first quadratic extension field element. + * @param[in] b - the second quadratic extension field element. + */ +void fp2_mul_integ(fp2_t c, fp2_t a, fp2_t b); + +/** + * Multiplies a quadratic extension field element by the adjoined root. + * Computes c = a * u. + * + * @param[out] c - the result. + * @param[in] a - the quadratic extension field element to multiply. + */ +void fp2_mul_art(fp2_t c, fp2_t a); + +/** + * Multiplies a quadratic extension field element by a quadratic/cubic + * non-residue. + * + * @param[out] c - the result. + * @param[in] a - the quadratic extension field element to multiply. + */ +void fp2_mul_nor_basic(fp2_t c, fp2_t a); + +/** + * Multiplies a quadratic extension field element by a quadratic/cubic + * non-residue using integrated modular reduction. + * + * @param[out] c - the result. + * @param[in] a - the quadratic extension field element to multiply. + */ +void fp2_mul_nor_integ(fp2_t c, fp2_t a); + +/** + * Multiplies a quadratic extension field element by a power of the constant + * needed to compute a power of the Frobenius map. + * + * @param[out] c - the result. + * @param[in] a - the field element to multiply. + * @param[in] i - the power of the Frobenius map. + * @param[in] j - the power of the constant. + */ +void fp2_mul_frb(fp2_t c, fp2_t a, int i, int j); + +/** + * Multiplies a quadratic extension field element by a digit. Computes c = a * b. + * + * @param[out] c - the result. + * @param[in] a - the quadratic extension field element. + * @param[in] b - the digit to multiply. + */ +void fp2_mul_dig(fp2_t c, const fp2_t a, dig_t b); + +/** + * Computes the square of a quadratic extension field element using basic + * arithmetic. + * + * @param[out] c - the result. + * @param[in] a - the quadratic extension field element to square. + */ +void fp2_sqr_basic(fp2_t c, fp2_t a); + +/** + * Computes the square of a quadratic extension field element using integrated + * modular reduction. + * + * @param[out] c - the result. + * @param[in] a - the quadratic extension field element to square. + */ +void fp2_sqr_integ(fp2_t c, fp2_t a); + +/** + * Inverts a quadratic extension field element. Computes c = 1/a. + * + * @param[out] c - the result. + * @param[in] a - the quadratic extension field element to invert. + */ +void fp2_inv(fp2_t c, fp2_t a); + +/** + * Computes the inverse of a cyclotomic quadratic extension field element. + * + * @param[out] c - the result. + * @param[in] a - the quadratic extension field element to invert. + */ +void fp2_inv_cyc(fp2_t c, fp2_t a); + +/** + * Inverts multiple quadratic extension field elements simultaneously. + * + * @param[out] c - the result. + * @param[in] a - the quadratic extension field elements to invert. + * @param[in] n - the number of elements. + */ +void fp2_inv_sim(fp2_t *c, fp2_t *a, int n); + +/** + * Tests if a quadratic extension field element is cyclotomic. + * + * @param[in] a - the quadratic extension field element to test. + * @return 1 if the extension field element is cyclotomic, 0 otherwise. + */ +int fp2_test_cyc(fp2_t a); + +/** + * Converts a quadratic extension field element to a cyclotomic element. + * Computes c = a^(p - 1). + * + * @param[out] c - the result. + * @param[in] a - the quadratic extension field element. + */ +void fp2_conv_cyc(fp2_t c, fp2_t a); + +/** + * Computes a power of a quadratic extension field element. + * + * @param[out] c - the result. + * @param[in] a - the quadratic extension element to exponentiate. + * @param[in] b - the exponent. + */ +void fp2_exp(fp2_t c, fp2_t a, bn_t b); + +/** + * Computes a power of a quadratic extension field element by a small exponent. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent. + */ +void fp2_exp_dig(fp2_t c, fp2_t a, dig_t b); + +/** + * Computes a power of a cyclotomic quadratic extension field element. + * + * @param[out] c - the result. + * @param[in] a - the cyclotomic element to exponentiate. + * @param[in] b - the exponent. + */ +void fp2_exp_cyc(fp2_t c, fp2_t a, bn_t b); + +/** + * Computes a power of the Frobenius map of a quadratic extension field element. + * When i is odd, this is the same as computing the conjugate of the extension + * field element. + * + * @param[out] c - the result. + * @param[in] a - the quadratic extension element to conjugate. + * @param[in] i - the power of the Frobenius map. + */ +void fp2_frb(fp2_t c, fp2_t a, int i); + +/** + * Extracts the square root of a quadratic extension field element. Computes + * c = sqrt(a). The other square root is the negation of c. + * + * @param[out] c - the result. + * @param[in] a - the extension field element. + * @return - 1 if there is a square root, 0 otherwise. + */ +int fp2_srt(fp2_t c, fp2_t a); + +/** + * Compresses an extension field element. + * + * @param[out] r - the result. + * @param[in] p - the extension field element to compress. + */ +void fp2_pck(fp2_t c, fp2_t a); + +/** + * Decompresses a quadratic extension field element. + * + * @param[out] r - the result. + * @param[in] p - the quadratic extension field element. + * @return if the decompression was successful + */ +int fp2_upk(fp2_t c, fp2_t a); + +/** + * Initializes the cubic extension field arithmetic module. + */ +void fp3_field_init(void); + +/** + * Copies the second argument to the first argument. + * + * @param[out] C - the result. + * @param[in] A - the cubic extension field element to copy. + */ +void fp3_copy(fp3_t c, fp3_t a); + +/** + * Assigns zero to a cubic extension field element. + * + * @param[out] A - the cubic extension field element to zero. + */ +void fp3_zero(fp3_t a); + +/** + * Tests if a cubic extension field element is zero or not. + * + * @param[in] A - the cubic extension field element to test. + * @return 1 if the argument is zero, 0 otherwise. + */ +int fp3_is_zero(fp3_t a); + +/** + * Assigns a random value to a cubic extension field element. + * + * @param[out] A - the cubic extension field element to assign. + */ +void fp3_rand(fp3_t a); + +/** + * Prints a cubic extension field element to standard output. + * + * @param[in] A - the cubic extension field element to print. + */ +void fp3_print(fp3_t a); + +/** + * Returns the number of bytes necessary to store a cubic extension field + * element. + * + * @param[out] size - the result. + * @param[in] a - the extension field element. + */ +int fp3_size_bin(fp3_t a); + +/** + * Reads a cubic extension field element from a byte vector in big-endian + * format. + * + * @param[out] a - the result. + * @param[in] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @throw ERR_NO_BUFFER - if the buffer capacity is not correct. + */ +void fp3_read_bin(fp3_t a, const uint8_t *bin, int len); + +/** + * Writes a cubic extension field element to a byte vector in big-endian + * format. + * + * @param[out] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @param[in] a - the extension field element to write. + * @throw ERR_NO_BUFFER - if the buffer capacity is not correct. + */ +void fp3_write_bin(uint8_t *bin, int len, fp3_t a); + +/** + * Returns the result of a comparison between two cubic extension field + * elements. + * + * @param[in] A - the first cubic extension field element. + * @param[in] B - the second cubic extension field element. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fp3_cmp(fp3_t a, fp3_t b); + +/** + * Returns the result of a signed comparison between a cubic extension field + * element and a digit. + * + * @param[in] a - the cubic extension field element. + * @param[in] b - the digit. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fp3_cmp_dig(fp3_t a, dig_t b); + +/** + * Assigns a cubic extension field element to a digit. + * + * @param[in] a - the cubic extension field element. + * @param[in] b - the digit. + */ +void fp3_set_dig(fp3_t a, dig_t b); + +/** + * Adds two cubic extension field elements using basic arithmetic. + * + * @param[out] c - the result. + * @param[in] a - the first cubic extension field element. + * @param[in] b - the second cubic extension field element. + */ +void fp3_add_basic(fp3_t c, fp3_t a, fp3_t b); + +/** + * Adds two cubic extension field elements using integrated modular reduction. + * + * @param[out] c - the result. + * @param[in] a - the first cubic extension field element. + * @param[in] b - the second cubic extension field element. + */ +void fp3_add_integ(fp3_t c, fp3_t a, fp3_t b); + +/** + * Subtracts a cubic extension field element from another using basic + * arithmetic. + * + * @param[out] C - the result. + * @param[in] A - the first cubic extension field element. + * @param[in] B - the second cubic extension field element. + */ +void fp3_sub_basic(fp3_t c, fp3_t a, fp3_t b); + +/** + * Subtracts a cubic extension field element from another using integrated + * modular reduction. + * + * @param[out] C - the result. + * @param[in] A - the first cubic extension field element. + * @param[in] B - the second cubic extension field element. + */ +void fp3_sub_integ(fp3_t c, fp3_t a, fp3_t b); + +/** + * Negates a cubic extension field element. Computes c = -a. + * + * @param[out] C - the result. + * @param[out] A - the cubic extension field element to negate. + */ +void fp3_neg(fp3_t c, fp3_t a); + +/** + * Doubles a cubic extension field element using basic arithmetic. + * + * @param[out] c - the result. + * @param[in] a - the cubic extension field element to double. + */ +void fp3_dbl_basic(fp3_t c, fp3_t a); + +/** + * Doubles a cubic extension field element using integrated modular reduction. + * + * @param[out] c - the result. + * @param[in] a - the cubic extension field element to double. + */ +void fp3_dbl_integ(fp3_t c, fp3_t a); + +/** + * Multiples two cubic extension field elements using basic arithmetic. + * + * @param[out] c - the result. + * @param[in] a - the first cubic extension field element. + * @param[in] b - the second cubic extension field element. + */ +void fp3_mul_basic(fp3_t c, fp3_t a, fp3_t b); + +/** + * Multiples two cubic extension field elements using integrated modular + * reduction. + * + * @param[out] c - the result. + * @param[in] a - the first cubic extension field element. + * @param[in] b - the second cubic extension field element. + */ +void fp3_mul_integ(fp3_t c, fp3_t a, fp3_t b); + +/** + * Multiplies a cubic extension field element by a cubic non-residue. + * + * @param[out] c - the result. + * @param[in] a - the cubic extension field element to multiply. + */ +void fp3_mul_nor(fp3_t c, fp3_t a); + +/** + * Multiplies a cubic extension field element by a power of the constant + * needed to compute a power of the Frobenius map. If the flag is zero, the map + * is computed on the cubic extension directly; otherwise the map is computed on + * a higher extension. + * + * @param[out] c - the result. + * @param[in] a - the field element to multiply. + * @param[in] i - the power of the Frobenius map. + * @param[in] j - the power of the constant. + */ +void fp3_mul_frb(fp3_t c, fp3_t a, int i, int j); + +/** + * Computes the square of a cubic extension field element using basic + * arithmetic. + * + * @param[out] c - the result. + * @param[in] a - the cubic extension field element to square. + */ +void fp3_sqr_basic(fp3_t c, fp3_t a); + +/** + * Computes the square of a cubic extension field element using integrated + * modular reduction. + * + * @param[out] c - the result. + * @param[in] a - the cubic extension field element to square. + */ +void fp3_sqr_integ(fp3_t c, fp3_t a); + +/** + * Inverts a cubic extension field element. Computes c = 1/a. + * + * @param[out] c - the result. + * @param[in] a - the cubic extension field element to invert. + */ +void fp3_inv(fp3_t c, fp3_t a); + +/** + * Inverts multiple cubic extension field elements simultaneously. + * + * @param[out] c - the result. + * @param[in] a - the cubic extension field elements to invert. + * @param[in] n - the number of elements. + */ +void fp3_inv_sim(fp3_t *c, fp3_t *a, int n); + +/** + * Computes a power of a cubic extension field element. Computes c = a^b. + * + * @param[out] c - the result. + * @param[in] a - the cubic extension element to exponentiate. + * @param[in] b - the exponent. + */ +void fp3_exp(fp3_t c, fp3_t a, bn_t b); + +/** + * Computes a power of the Frobenius map of a cubic extension field element. + * + * @param[out] c - the result. + * @param[in] a - the cubic extension element to exponentiate. + * @param[in] i - the power of the Frobenius map. + */ +void fp3_frb(fp3_t c, fp3_t a, int i); + +/** + * Extracts the square root of a cubic extension field element. Computes + * c = sqrt(a). The other square root is the negation of c. + * + * @param[out] c - the result. + * @param[in] a - the extension field element. + * @return - 1 if there is a square root, 0 otherwise. + */ +int fp3_srt(fp3_t c, fp3_t a); + +/** + * Copies the second argument to the first argument. + * + * @param[out] C - the result. + * @param[in] A - the sextic extension field element to copy. + */ +void fp4_copy(fp4_t c, fp4_t a); + +/** + * Assigns zero to a quartic extension field element. + * + * @param[out] A - the quartic extension field element to zero. + */ +void fp4_zero(fp4_t a); + +/** + * Tests if a quartic extension field element is zero or not. + * + * @param[in] A - the quartic extension field element to test. + * @return 1 if the argument is zero, 0 otherwise. + */ +int fp4_is_zero(fp4_t a); + +/** + * Assigns a random value to a quartic extension field element. + * + * @param[out] A - the quartic extension field element to assign. + */ +void fp4_rand(fp4_t a); + +/** + * Prints a quartic extension field element to standard output. + * + * @param[in] A - the quartic extension field element to print. + */ +void fp4_print(fp4_t a); + +/** + * Returns the number of bytes necessary to store a quartic extension field + * element. + * + * @param[out] size - the result. + * @param[in] a - the extension field element. + */ +int fp4_size_bin(fp4_t a); + +/** + * Reads a quartic extension field element from a byte vector in big-endian + * format. + * + * @param[out] a - the result. + * @param[in] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @throw ERR_NO_BUFFER - if the buffer capacity is not correct. + */ +void fp4_read_bin(fp4_t a, const uint8_t *bin, int len); + +/** + * Writes a quartic extension field element to a byte vector in big-endian + * format. + * + * @param[out] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @param[in] a - the extension field element to write. + * @throw ERR_NO_BUFFER - if the buffer capacity is not correct. + */ +void fp4_write_bin(uint8_t *bin, int len, fp4_t a); + +/** + * Returns the result of a comparison between two quartic extension field + * elements. + * + * @param[in] A - the first quartic extension field element. + * @param[in] B - the second quartic extension field element. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fp4_cmp(fp4_t a, fp4_t b); + +/** + * Returns the result of a signed comparison between a quartic extension field + * element and a digit. + * + * @param[in] a - the quartic extension field element. + * @param[in] b - the digit. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fp4_cmp_dig(fp4_t a, dig_t b); + +/** + * Assigns a quartic extension field element to a digit. + * + * @param[in] a - the quartic extension field element. + * @param[in] b - the digit. + */ +void fp4_set_dig(fp4_t a, dig_t b); + +/** + * Adds two quartic extension field elements. Computes c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the first quartic extension field element. + * @param[in] b - the second quartic extension field element. + */ +void fp4_add(fp4_t c, fp4_t a, fp4_t b); + +/** + * Subtracts a quartic extension field element from another. Computes + * c = a - b. + * + * @param[out] c - the result. + * @param[in] a - the quartic extension field element. + * @param[in] b - the quartic extension field element. + */ +void fp4_sub(fp4_t c, fp4_t a, fp4_t b); + +/** + * Negates a quartic extension field element. Computes c = -a. + * + * @param[out] C - the result. + * @param[out] A - the quartic extension field element to negate. + */ +void fp4_neg(fp4_t c, fp4_t a); + +/** + * Doubles a quartic extension field element. Computes c = 2 * a. + * + * @param[out] c - the result. + * @param[in] a - the quartic extension field element to double. + */ +void fp4_dbl(fp4_t c, fp4_t a); + +/** + * Multiples two quartic extension field elements without performing modular + * reduction. + * + * @param[out] c - the result. + * @param[in] a - the quartic extension field element. + * @param[in] b - the quartic extension field element. + */ +void fp4_mul_unr(dv4_t c, fp4_t a, fp4_t b); + +/** + * Multiples two quartic extension field elements. + * + * @param[out] c - the result. + * @param[in] a - the quartic extension field element. + * @param[in] b - the quartic extension field element. + */ +void fp4_mul_basic(fp4_t c, fp4_t a, fp4_t b); + +/** + * Multiples two quartic extension field elements using lazy reduction. + * + * @param[out] c - the result. + * @param[in] a - the quartic extension field element. + * @param[in] b - the quartic extension field element. + */ +void fp4_mul_lazyr(fp4_t c, fp4_t a, fp4_t b); + +/** + * Multiplies a quartic extension field element by the adjoined root. + * + * @param[out] c - the result. + * @param[in] a - the quartic extension field element to multiply. + */ +void fp4_mul_art(fp4_t c, fp4_t a); + +/** + * Multiples a dense quartic extension field element by a sparse element. + * + * @param[out] c - the result. + * @param[in] a - a quartic extension field element. + * @param[in] b - a sparse quartic extension field element. + */ +void fp4_mul_dxs(fp4_t c, fp4_t a, fp4_t b); + +/** + * Computes the square of a quartic extension field element without performing + * modular reduction. + * + * @param[out] c - the result. + * @param[in] a - the quartic extension field element to square. + */ +void fp4_sqr_unr(dv6_t c, fp4_t a); + +/** + * Computes the squares of a quartic extension field element using basic + * arithmetic. + * + * @param[out] c - the result. + * @param[in] a - the quartic extension field element to square. + */ +void fp4_sqr_basic(fp4_t c, fp4_t a); + +/** + * Computes the square of a quartic extension field element using lazy reduction. + * + * @param[out] c - the result. + * @param[in] a - the quartic extension field element to square. + */ +void fp4_sqr_lazyr(fp4_t c, fp4_t a); + +/** + * Inverts a quartic extension field element. Computes c = 1/a. + * + * @param[out] c - the result. + * @param[in] a - the quartic extension field element to invert. + */ +void fp4_inv(fp4_t c, fp4_t a); + +/** + * Computes the inverse of a cyclotomic quartic extension field element. + * + * For cyclotomic elements, this is equivalent to computing the conjugate. + * A cyclotomic element is one previously raised to the (p^2 - 1)-th power. + * + * @param[out] c - the result. + * @param[in] a - the quartic extension field element to invert. + */ +void fp4_inv_cyc(fp4_t c, fp4_t a); + +/** + * Computes a power of a quartic extension field element. Computes c = a^b. + * + * @param[out] c - the result. + * @param[in] a - the quartic extension element to exponentiate. + * @param[in] b - the exponent. + */ +void fp4_exp(fp4_t c, fp4_t a, bn_t b); + +/** + * Computes a power of the Frobenius endomorphism of a quartic extension field + * element. Computes c = a^p^i. + * + * @param[out] c - the result. + * @param[in] a - a quartic extension field element. + * @param[in] i - the power of the Frobenius map. + */ +void fp4_frb(fp4_t c, fp4_t a, int i); + +/** + * Copies the second argument to the first argument. + * + * @param[out] C - the result. + * @param[in] A - the sextic extension field element to copy. + */ +void fp6_copy(fp6_t c, fp6_t a); + +/** + * Assigns zero to a sextic extension field element. + * + * @param[out] A - the sextic extension field element to zero. + */ +void fp6_zero(fp6_t a); + +/** + * Tests if a sextic extension field element is zero or not. + * + * @param[in] A - the sextic extension field element to test. + * @return 1 if the argument is zero, 0 otherwise. + */ +int fp6_is_zero(fp6_t a); + +/** + * Assigns a random value to a sextic extension field element. + * + * @param[out] A - the sextic extension field element to assign. + */ +void fp6_rand(fp6_t a); + +/** + * Prints a sextic extension field element to standard output. + * + * @param[in] A - the sextic extension field element to print. + */ +void fp6_print(fp6_t a); + +/** + * Returns the number of bytes necessary to store a quadratic extension field + * element. + * + * @param[out] size - the result. + * @param[in] a - the extension field element. + */ +int fp6_size_bin(fp6_t a); + +/** + * Reads a quadratic extension field element from a byte vector in big-endian + * format. + * + * @param[out] a - the result. + * @param[in] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @throw ERR_NO_BUFFER - if the buffer capacity is not correct. + */ +void fp6_read_bin(fp6_t a, const uint8_t *bin, int len); + +/** + * Writes a sextic extension field element to a byte vector in big-endian + * format. + * + * @param[out] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @param[in] a - the extension field element to write. + * @throw ERR_NO_BUFFER - if the buffer capacity is not correct. + */ +void fp6_write_bin(uint8_t *bin, int len, fp6_t a); + +/** + * Returns the result of a comparison between two sextic extension field + * elements. + * + * @param[in] A - the first sextic extension field element. + * @param[in] B - the second sextic extension field element. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fp6_cmp(fp6_t a, fp6_t b); + +/** + * Returns the result of a signed comparison between a sextic extension field + * element and a digit. + * + * @param[in] a - the sextic extension field element. + * @param[in] b - the digit. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fp6_cmp_dig(fp6_t a, dig_t b); + +/** + * Assigns a sextic extension field element to a digit. + * + * @param[in] a - the sextic extension field element. + * @param[in] b - the digit. + */ +void fp6_set_dig(fp6_t a, dig_t b); + +/** + * Adds two sextic extension field elements. Computes c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the first sextic extension field element. + * @param[in] b - the second sextic extension field element. + */ +void fp6_add(fp6_t c, fp6_t a, fp6_t b); + +/** + * Subtracts a sextic extension field element from another. Computes + * c = a - b. + * + * @param[out] c - the result. + * @param[in] a - the sextic extension field element. + * @param[in] b - the sextic extension field element. + */ +void fp6_sub(fp6_t c, fp6_t a, fp6_t b); + +/** + * Negates a sextic extension field element. Computes c = -a. + * + * @param[out] C - the result. + * @param[out] A - the sextic extension field element to negate. + */ +void fp6_neg(fp6_t c, fp6_t a); + +/** + * Doubles a sextic extension field element. Computes c = 2 * a. + * + * @param[out] c - the result. + * @param[in] a - the sextic extension field element to double. + */ +void fp6_dbl(fp6_t c, fp6_t a); + +/** + * Multiples two sextic extension field elements without performing modular + * reduction. + * + * @param[out] c - the result. + * @param[in] a - the sextic extension field element. + * @param[in] b - the sextic extension field element. + */ +void fp6_mul_unr(dv6_t c, fp6_t a, fp6_t b); + +/** + * Multiples two sextic extension field elements. + * + * @param[out] c - the result. + * @param[in] a - the sextic extension field element. + * @param[in] b - the sextic extension field element. + */ +void fp6_mul_basic(fp6_t c, fp6_t a, fp6_t b); + +/** + * Multiples two sextic extension field elements using lazy reduction. + * + * @param[out] c - the result. + * @param[in] a - the sextic extension field element. + * @param[in] b - the sextic extension field element. + */ +void fp6_mul_lazyr(fp6_t c, fp6_t a, fp6_t b); + +/** + * Multiplies a sextic extension field element by the adjoined root. + * + * @param[out] c - the result. + * @param[in] a - the sextic extension field element to multiply. + */ +void fp6_mul_art(fp6_t c, fp6_t a); + +/** + * Multiples a dense sextic extension field element by a sparse element. + * + * @param[out] c - the result. + * @param[in] a - a sextic extension field element. + * @param[in] b - a sparse sextic extension field element. + */ +void fp6_mul_dxs(fp6_t c, fp6_t a, fp6_t b); + +/** + * Computes the square of a sextic extension field element without performing + * modular reduction. + * + * @param[out] c - the result. + * @param[in] a - the sextic extension field element to square. + */ +void fp6_sqr_unr(dv6_t c, fp6_t a); + +/** + * Computes the squares of a sextic extension field element using basic + * arithmetic. + * + * @param[out] c - the result. + * @param[in] a - the sextic extension field element to square. + */ +void fp6_sqr_basic(fp6_t c, fp6_t a); + +/** + * Computes the square of a sextic extension field element using lazy reduction. + * + * @param[out] c - the result. + * @param[in] a - the sextic extension field element to square. + */ +void fp6_sqr_lazyr(fp6_t c, fp6_t a); + +/** + * Inverts a sextic extension field element. Computes c = 1/a. + * + * @param[out] c - the result. + * @param[in] a - the sextic extension field element to invert. + */ +void fp6_inv(fp6_t c, fp6_t a); + +/** + * Computes a power of a sextic extension field element. Computes c = a^b. + * + * @param[out] c - the result. + * @param[in] a - the sextic extension element to exponentiate. + * @param[in] b - the exponent. + */ +void fp6_exp(fp6_t c, fp6_t a, bn_t b); + +/** + * Computes a power of the Frobenius endomorphism of a sextic extension field + * element. Computes c = a^p^i. + * + * @param[out] c - the result. + * @param[in] a - a sextic extension field element. + * @param[in] i - the power of the Frobenius map. + */ +void fp6_frb(fp6_t c, fp6_t a, int i); + +/** + * Copies the second argument to the first argument. + * + * @param[out] C - the result. + * @param[in] A - the octic extension field element to copy. + */ +void fp8_copy(fp8_t c, fp8_t a); + +/** + * Assigns zero to an octic extension field element. + * + * @param[out] A - the octic extension field element to zero. + */ +void fp8_zero(fp8_t a); + +/** + * Tests if an octic extension field element is zero or not. + * + * @param[in] A - the octic extension field element to test. + * @return 1 if the argument is zero, 0 otherwise. + */ +int fp8_is_zero(fp8_t a); + +/** + * Assigns a random value to an octic extension field element. + * + * @param[out] A - the octic extension field element to assign. + */ +void fp8_rand(fp8_t a); + +/** + * Prints an octic extension field element to standard output. + * + * @param[in] A - the octic extension field element to print. + */ +void fp8_print(fp8_t a); + +/** + * Returns the number of bytes necessary to store an octic extension field + * element. + * + * @param[in] a - the extension field element. + * @param[in] pack - the flag to indicate compression. + * @return the number of bytes. + */ +int fp8_size_bin(fp8_t a, int pack); + +/** + * Reads an octic extension field element from a byte vector in big-endian + * format. + * + * @param[out] a - the result. + * @param[in] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @throw ERR_NO_BUFFER - if the buffer capacity is not correct. + */ +void fp8_read_bin(fp8_t a, const uint8_t *bin, int len); + +/** + * Writes an octic extension field element to a byte vector in big-endian + * format. + * + * @param[out] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @param[in] a - the extension field element to write. + * @throw ERR_NO_BUFFER - if the buffer capacity is not correct. + */ +void fp8_write_bin(uint8_t *bin, int len, fp8_t a); + +/** + * Returns the result of a comparison between two octic extension field + * elements. + * + * @param[in] A - the first octic extension field element. + * @param[in] B - the second octic extension field element. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fp8_cmp(fp8_t a, fp8_t b); + +/** + * Returns the result of a signed comparison between an octic extension field + * element and a digit. + * + * @param[in] a - the octic extension field element. + * @param[in] b - the digit. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fp8_cmp_dig(fp8_t a, dig_t b); + +/** + * Assigns an octic extension field element to a digit. + * + * @param[in] a - the octic extension field element. + * @param[in] b - the digit. + */ +void fp8_set_dig(fp8_t a, dig_t b); + +/** + * Adds two octic extension field elements. Computes c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the first octic extension field element. + * @param[in] b - the second octic extension field element. + */ +void fp8_add(fp8_t c, fp8_t a, fp8_t b); + +/** + * Subtracts an octic extension field element from another. Computes + * c = a - b. + * + * @param[out] c - the result. + * @param[in] a - the octic extension field element. + * @param[in] b - the octic extension field element. + */ +void fp8_sub(fp8_t c, fp8_t a, fp8_t b); + +/** + * Negates an octic extension field element. Computes c = -a. + * + * @param[out] C - the result. + * @param[out] A - the octic extension field element to negate. + */ +void fp8_neg(fp8_t c, fp8_t a); + +/** + * Doubles an octic extension field element. Computes c = 2 * a. + * + * @param[out] c - the result. + * @param[in] a - the octic extension field element to double. + */ +void fp8_dbl(fp8_t c, fp8_t a); + +/** + * Multiples two octic extension field elements without performing modular + * reduction. + * + * @param[out] c - the result. + * @param[in] a - the octic extension field element. + * @param[in] b - the octic extension field element. + */ +void fp8_mul_unr(dv8_t c, fp8_t a, fp8_t b); + +/** + * Multiples two octic extension field elements. + * + * @param[out] c - the result. + * @param[in] a - the octic extension field element. + * @param[in] b - the octic extension field element. + */ +void fp8_mul_basic(fp8_t c, fp8_t a, fp8_t b); + +/** + * Multiples two octic extension field elements using lazy reduction. + * + * @param[out] c - the result. + * @param[in] a - the octic extension field element. + * @param[in] b - the octic extension field element. + */ +void fp8_mul_lazyr(fp8_t c, fp8_t a, fp8_t b); + +/** + * Multiplies an octic extension field element by the adjoined root. + * + * @param[out] c - the result. + * @param[in] a - the octic extension field element to multiply. + */ +void fp8_mul_art(fp8_t c, fp8_t a); + +/** + * Multiples a dense octic extension field element by a sparse element. + * + * @param[out] c - the result. + * @param[in] a - an octic extension field element. + * @param[in] b - a sparse octic extension field element. + */ +void fp8_mul_dxs(fp8_t c, fp8_t a, fp8_t b); + +/** + * Computes the square of an octic extension field element without performing + * modular reduction. + * + * @param[out] c - the result. + * @param[in] a - the octic extension field element to square. + */ +void fp8_sqr_unr(dv8_t c, fp8_t a); + +/** + * Computes the squares of an octic extension field element using basic + * arithmetic. + * + * @param[out] c - the result. + * @param[in] a - the octic extension field element to square. + */ +void fp8_sqr_basic(fp8_t c, fp8_t a); + +/** + * Computes the square of an octic extension field element using lazy reduction. + * + * @param[out] c - the result. + * @param[in] a - the octic extension field element to square. + */ +void fp8_sqr_lazyr(fp8_t c, fp8_t a); + +/** + * Computes the square of a cyclotomic octic extension field element. + * + * @param[out] c - the result. + * @param[in] a - the cyclotomic extension element to square. + */ +void fp8_sqr_cyc(fp8_t c, fp8_t a); + +/** + * Inverts an octic extension field element. Computes c = 1/a. + * + * @param[out] c - the result. + * @param[in] a - the octic extension field element to invert. + */ +void fp8_inv(fp8_t c, fp8_t a); + +/** + * Computes the inverse of a cyclotomic octic extension field element. + * + * For cyclotomic elements, this is equivalent to computing the conjugate. + * A cyclotomic element is one previously raised to the (p^4 - 1)-th power. + * + * @param[out] c - the result. + * @param[in] a - the octic extension field element to invert. + */ +void fp8_inv_cyc(fp8_t c, fp8_t a); + +/** + * Inverts multiple octic extension field elements simultaneously. + * + * @param[out] c - the result. + * @param[in] a - the octic extension field elements to invert. + * @param[in] n - the number of elements. + */ +void fp8_inv_sim(fp8_t *c, fp8_t *a, int n); + +/** + * Tests if an octic extension field element is cyclotomic. + * + * @param[in] a - the octic extension field element to test. + * @return 1 if the extension field element is cyclotomic, 0 otherwise. + */ +int fp8_test_cyc(fp8_t a); + +/** + * Converts an octic extension field element to a cyclotomic element. Computes + * c = a^(p^4 - 1). + * + * @param[out] c - the result. + * @param[in] a - the octic extension field element. + */ +void fp8_conv_cyc(fp8_t c, fp8_t a); + +/** + * Computes a power of an octic extension field element. Computes c = a^b. + * + * @param[out] c - the result. + * @param[in] a - the octic extension element to exponentiate. + * @param[in] b - the exponent. + */ +void fp8_exp(fp8_t c, fp8_t a, bn_t b); + +/** + * Computes a power of a cyclotomic octic extension field element. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent. + */ +void fp8_exp_cyc(fp8_t c, fp8_t a, bn_t b); + +/** + * Computes a power of the Frobenius endomorphism of an octic extension field + * element. Computes c = a^p^i. + * + * @param[out] c - the result. + * @param[in] a - an octic extension field element. + * @param[in] i - the power of the Frobenius map. + */ +void fp8_frb(fp8_t c, fp8_t a, int i); + +/** + * Copies the second argument to the first argument. + * + * @param[out] C - the result. + * @param[in] A - the nonic extension field element to copy. + */ +void fp9_copy(fp9_t c, fp9_t a); + +/** + * Assigns zero to a nonic extension field element. + * + * @param[out] A - the nonic extension field element to zero. + */ +void fp9_zero(fp9_t a); + +/** + * Tests if a nonic extension field element is zero or not. + * + * @param[in] A - the nonic extension field element to test. + * @return 1 if the argument is zero, 0 otherwise. + */ +int fp9_is_zero(fp9_t a); + +/** + * Assigns a random value to a nonic extension field element. + * + * @param[out] A - the nonic extension field element to assign. + */ +void fp9_rand(fp9_t a); + +/** + * Prints a nonic extension field element to standard output. + * + * @param[in] A - the nonic extension field element to print. + */ +void fp9_print(fp9_t a); + +/** + * Returns the number of bytes necessary to store a quadratic extension field + * element. + * + * @param[out] size - the result. + * @param[in] a - the extension field element. + */ +int fp9_size_bin(fp9_t a); + +/** + * Reads a quadratic extension field element from a byte vector in big-endian + * format. + * + * @param[out] a - the result. + * @param[in] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @throw ERR_NO_BUFFER - if the buffer capacity is not correct. + */ +void fp9_read_bin(fp9_t a, const uint8_t *bin, int len); + +/** + * Writes a nonic extension field element to a byte vector in big-endian + * format. + * + * @param[out] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @param[in] a - the extension field element to write. + * @throw ERR_NO_BUFFER - if the buffer capacity is not correct. + */ +void fp9_write_bin(uint8_t *bin, int len, fp9_t a); + +/** + * Returns the result of a comparison between two nonic extension field + * elements. + * + * @param[in] A - the first nonic extension field element. + * @param[in] B - the second nonic extension field element. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fp9_cmp(fp9_t a, fp9_t b); + +/** + * Returns the result of a signed comparison between a nonic extension field + * element and a digit. + * + * @param[in] a - the nonic extension field element. + * @param[in] b - the digit. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fp9_cmp_dig(fp9_t a, dig_t b); + +/** + * Assigns a nonic extension field element to a digit. + * + * @param[in] a - the nonic extension field element. + * @param[in] b - the digit. + */ +void fp9_set_dig(fp9_t a, dig_t b); + +/** + * Adds two nonic extension field elements. Computes c = a + b. + * + * @param[out] c - the result. + * @param[in] a - the first nonic extension field element. + * @param[in] b - the second nonic extension field element. + */ +void fp9_add(fp9_t c, fp9_t a, fp9_t b); + +/** + * Subtracts a nonic extension field element from another. Computes + * c = a - b. + * + * @param[out] c - the result. + * @param[in] a - the nonic extension field element. + * @param[in] b - the nonic extension field element. + */ +void fp9_sub(fp9_t c, fp9_t a, fp9_t b); + +/** + * Negates a nonic extension field element. Computes c = -a. + * + * @param[out] C - the result. + * @param[out] A - the nonic extension field element to negate. + */ +void fp9_neg(fp9_t c, fp9_t a); + +/** + * Doubles a nonic extension field element. Computes c = 2 * a. + * + * @param[out] c - the result. + * @param[in] a - the nonic extension field element to double. + */ +void fp9_dbl(fp9_t c, fp9_t a); + +/** + * Multiples two nonic extension field elements without performing modular + * reduction. + * + * @param[out] c - the result. + * @param[in] a - the nonic extension field element. + * @param[in] b - the nonic extension field element. + */ +void fp9_mul_unr(dv9_t c, fp9_t a, fp9_t b); + +/** + * Multiples two nonic extension field elements. + * + * @param[out] c - the result. + * @param[in] a - the nonic extension field element. + * @param[in] b - the nonic extension field element. + */ +void fp9_mul_basic(fp9_t c, fp9_t a, fp9_t b); + +/** + * Multiples two nonic extension field elements using lazy reduction. + * + * @param[out] c - the result. + * @param[in] a - the nonic extension field element. + * @param[in] b - the nonic extension field element. + */ +void fp9_mul_lazyr(fp9_t c, fp9_t a, fp9_t b); + +/** + * Multiplies a nonic extension field element by the adjoined root. + * + * @param[out] c - the result. + * @param[in] a - the nonic extension field element to multiply. + */ +void fp9_mul_art(fp9_t c, fp9_t a); + +/** + * Multiples a dense nonic extension field element by a sparse element. + * + * @param[out] c - the result. + * @param[in] a - a nonic extension field element. + * @param[in] b - a sparse nonic extension field element. + */ +void fp9_mul_dxs(fp9_t c, fp9_t a, fp9_t b); + +/** + * Computes the square of a nonic extension field element without performing + * modular reduction. + * + * @param[out] c - the result. + * @param[in] a - the nonic extension field element to square. + */ +void fp9_sqr_unr(dv9_t c, fp9_t a); + +/** + * Computes the squares of a nonic extension field element using basic + * arithmetic. + * + * @param[out] c - the result. + * @param[in] a - the nonic extension field element to square. + */ +void fp9_sqr_basic(fp9_t c, fp9_t a); + +/** + * Computes the square of a nonic extension field element using lazy reduction. + * + * @param[out] c - the result. + * @param[in] a - the nonic extension field element to square. + */ +void fp9_sqr_lazyr(fp9_t c, fp9_t a); + +/** + * Inverts a nonic extension field element. Computes c = 1/a. + * + * @param[out] c - the result. + * @param[in] a - the nonic extension field element to invert. + */ +void fp9_inv(fp9_t c, fp9_t a); + +/** + * Inverts multiple noinc extension field elements simultaneously. + * + * @param[out] c - the result. + * @param[in] a - the nonic extension field elements to invert. + * @param[in] n - the number of elements. + */ +void fp9_inv_sim(fp9_t *c, fp9_t *a, int n); + +/** + * Computes a power of a nonic extension field element. Computes c = a^b. + * + * @param[out] c - the result. + * @param[in] a - the nonic extension element to exponentiate. + * @param[in] b - the exponent. + */ +void fp9_exp(fp9_t c, fp9_t a, bn_t b); + +/** + * Computes a power of the Frobenius endomorphism of a nonic extension field + * element. Computes c = a^p^i. + * + * @param[out] c - the result. + * @param[in] a - a nonic extension field element. + * @param[in] i - the power of the Frobenius map. + */ +void fp9_frb(fp9_t c, fp9_t a, int i); + +/** + * Copies the second argument to the first argument. + * + * @param[out] C - the result. + * @param[in] A - the dodecic extension field element to copy. + */ +void fp12_copy(fp12_t c, fp12_t a); + +/** + * Assigns zero to a dodecic extension field element. + * + * @param[out] A - the dodecic extension field element to zero. + */ +void fp12_zero(fp12_t a); + +/** + * Tests if a dodecic extension field element is zero or not. + * + * @param[in] A - the dodecic extension field element to test. + * @return 1 if the argument is zero, 0 otherwise. + */ +int fp12_is_zero(fp12_t a); + +/** + * Assigns a random value to a dodecic extension field element. + * + * @param[out] A - the dodecic extension field element to assign. + */ +void fp12_rand(fp12_t a); + +/** + * Prints a dodecic extension field element to standard output. + * + * @param[in] A - the dodecic extension field element to print. + */ +void fp12_print(fp12_t a); + +/** + * Returns the number of bytes necessary to store a dodecic extension field + * element. + * + * @param[in] a - the extension field element. + * @param[in] pack - the flag to indicate compression. + * @return the number of bytes. + */ +int fp12_size_bin(fp12_t a, int pack); + +/** + * Reads a dodecic extension field element from a byte vector in big-endian + * format. + * + * @param[out] a - the result. + * @param[in] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @throw ERR_NO_BUFFER - if the buffer capacity is not correct. + */ +void fp12_read_bin(fp12_t a, const uint8_t *bin, int len); + +/** + * Writes a dodecic extension field element to a byte vector in big-endian + * format. + * + * @param[out] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @param[in] a - the extension field element to write. + * @param[in] pack - the flag to indicate compression. + * @throw ERR_NO_BUFFER - if the buffer capacity is not correct. + */ +void fp12_write_bin(uint8_t *bin, int len, fp12_t a, int pack); + +/** + * Returns the result of a comparison between two dodecic extension field + * elements. + * + * @param[in] a - the first dodecic extension field element. + * @param[in] b - the second dodecic extension field element. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fp12_cmp(fp12_t a, fp12_t b); + +/** + * Returns the result of a signed comparison between a dodecic extension field + * element and a digit. + * + * @param[in] a - the dodecic extension field element. + * @param[in] b - the digit. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fp12_cmp_dig(fp12_t a, dig_t b); + +/** + * Assigns a dodecic extension field element to a digit. + * + * @param[in] a - the dodecic extension field element. + * @param[in] b - the digit. + */ +void fp12_set_dig(fp12_t a, dig_t b); + +/** + * Adds two dodecic extension field elements. Computes C = A + B. + * + * @param[out] C - the result. + * @param[in] A - the first dodecic extension field element. + * @param[in] B - the second dodecic extension field element. + */ +void fp12_add(fp12_t c, fp12_t a, fp12_t b); + +/** + * Subtracts a dodecic extension field element from another. Computes + * C = A - B. + * + * @param[out] C - the result. + * @param[in] A - the first dodecic extension field element. + * @param[in] B - the second dodecic extension field element. + */ +void fp12_sub(fp12_t c, fp12_t a, fp12_t b); + +/** + * Negates a dodecic extension field element. + * + * @param[out] C - the result. + * @param[out] A - the dodecic extension field element to negate. + */ +void fp12_neg(fp12_t c, fp12_t a); + +/** + * Doubles a dodecic extension field element. Computes c = 2 * a. + * + * @param[out] c - the result. + * @param[in] a - the dodecic extension field element to double. + */ +void fp12_dbl(fp12_t c, fp12_t a); + +/** + * Multiples two dodecic extension field elements without performing modular + * reduction. + * + * @param[out] c - the result. + * @param[in] a - the dodecic extension field element. + * @param[in] b - the dodecic extension field element. + */ +void fp12_mul_unr(dv12_t c, fp12_t a, fp12_t b); + +/** + * Multiples two dodecic extension field elements using basic arithmetic. + * + * @param[out] c - the result. + * @param[in] a - the dodecic extension field element. + * @param[in] b - the dodecic extension field element. + */ +void fp12_mul_basic(fp12_t c, fp12_t a, fp12_t b); + +/** + * Multiples two dodecic extension field elements using lazy reduction. + * + * @param[out] c - the result. + * @param[in] a - the dodecic extension field element. + * @param[in] b - the dodecic extension field element. + */ +void fp12_mul_lazyr(fp12_t c, fp12_t a, fp12_t b); + +/** + * Multiplies a dodecic extension field element by the adjoined root. + * + * @param[out] c - the result. + * @param[in] a - the dodecic extension field element to multiply. + */ +void fp12_mul_art(fp12_t c, fp12_t a); + +/** + * Multiples a dense dodecic extension field element by a sparse element using + * basic arithmetic. + * + * @param[out] c - the result. + * @param[in] a - the dense dodecic extension field element. + * @param[in] b - the sparse dodecic extension field element. + */ +void fp12_mul_dxs_basic(fp12_t c, fp12_t a, fp12_t b); + +/** + * Multiples a dense dodecic extension field element by a sparse element using + * lazy reduction. + * + * @param[out] c - the result. + * @param[in] a - the dense dodecic extension field element. + * @param[in] b - the sparse dodecic extension field element. + */ +void fp12_mul_dxs_lazyr(fp12_t c, fp12_t a, fp12_t b); + +/** + * Computes the square of a dodecic extension field element without performing + * modular reduction. + * + * @param[out] c - the result. + * @param[in] a - the dodecic extension field element to square. + */ +void fp12_sqr_unr(dv12_t c, fp12_t a); + +/** + * Computes the square of a dodecic extension field element using basic + * arithmetic. + * + * @param[out] c - the result. + * @param[in] a - the dodecic extension field element to square. + */ +void fp12_sqr_basic(fp12_t c, fp12_t a); + +/** + * Computes the square of a dodecic extension field element using lazy + * reduction. + * + * @param[out] c - the result. + * @param[in] a - the dodecic extension field element to square. + */ +void fp12_sqr_lazyr(fp12_t c, fp12_t a); + +/** + * Computes the square of a cyclotomic dodecic extension field element using + * basic arithmetic. + * + * A cyclotomic element is one raised to the (p^6 - 1)(p^2 + 1)-th power. + * + * @param[out] c - the result. + * @param[in] a - the cyclotomic extension element to square. + */ +void fp12_sqr_cyc_basic(fp12_t c, fp12_t a); + +/** + * Computes the square of a cyclotomic dodecic extension field element using + * lazy reduction. + * + * A cyclotomic element is one raised to the (p^6 - 1)(p^2 + 1)-th power. + * + * @param[out] c - the result. + * @param[in] a - the cyclotomic extension element to square. + */ +void fp12_sqr_cyc_lazyr(fp12_t c, fp12_t a); + +/** + * Computes the square of a compressed cyclotomic extension field element. + * + * A cyclotomic element is one raised to the (p^6 - 1)(p^2 + 1)-th power. + * + * @param[out] c - the result. + * @param[in] a - the cyclotomic extension element to square. + */ +void fp12_sqr_pck_basic(fp12_t c, fp12_t a); + +/** + * Computes the square of a compressed cyclotomic extension field element using + * lazy reduction. + * + * A cyclotomic element is one raised to the (p^6 - 1)(p^2 + 1)-th power. + * + * @param[out] c - the result. + * @param[in] a - the cyclotomic extension element to square. + */ +void fp12_sqr_pck_lazyr(fp12_t c, fp12_t a); + +/** + * Tests if a dodecic extension field element belongs to the cyclotomic + * subgroup. + * + * @param[in] a - the dodecic extension field element to test. + * @return 1 if the extension field element is in the subgroup, 0 otherwise. + */ +int fp12_test_cyc(fp12_t a); + +/** + * Converts a dodecic extension field element to a cyclotomic element. + * Computes c = a^(p^6 - 1)*(p^2 + 1). + * + * @param[out] c - the result. + * @param[in] a - a dodecic extension field element. + */ +void fp12_conv_cyc(fp12_t c, fp12_t a); + +/** + * Decompresses a compressed cyclotomic extension field element. + * + * @param[out] c - the result. + * @param[in] a - the dodecic extension field element to decompress. + */ +void fp12_back_cyc(fp12_t c, fp12_t a); + +/** + * Decompresses multiple compressed cyclotomic extension field elements. + * + * @param[out] c - the result. + * @param[in] a - the dodecic field elements to decompress. + * @param[in] n - the number of field elements to decompress. + */ +void fp12_back_cyc_sim(fp12_t *c, fp12_t *a, int n); + +/** + * Inverts a dodecic extension field element. Computes c = 1/a. + * + * @param[out] c - the result. + * @param[in] a - the dodecic extension field element to invert. + */ +void fp12_inv(fp12_t c, fp12_t a); + +/** + * Computes the inverse of a cyclotomic dodecic extension field element. + * For unitary elements, this is equivalent to computing the conjugate. + * A unitary element is one previously raised to the (p^6 - 1)-th power. + * + * @param[out] c - the result. + * @param[in] a - the dodecic extension field element to invert. + */ +void fp12_inv_cyc(fp12_t c, fp12_t a); + +/** + * Computes the Frobenius endomorphism of a dodecic extension element. + * Computes c = a^p. + * + * @param[out] c - the result. + * @param[in] a - a dodecic extension field element. + * @param[in] i - the power of the Frobenius map. + */ +void fp12_frb(fp12_t c, fp12_t a, int i); + +/** + * Computes a power of a dodecic extension field element. + * Faster formulas are used if the extension field element is cyclotomic. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent. + */ +void fp12_exp(fp12_t c, fp12_t a, bn_t b); + +/** + * Computes a power of a dodecic extension field element by a small exponent. + * Faster formulas are used if the extension field element is cyclotomic. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent. + */ +void fp12_exp_dig(fp12_t c, fp12_t a, dig_t b); + +/** + * Computes a power of a cyclotomic dodecic extension field element. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent. + */ +void fp12_exp_cyc(fp12_t c, fp12_t a, bn_t b); + +/** + * Computes a power of a cyclotomic dodecic extension field element. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent in sparse form. + * @param[in] l - the length of the exponent in sparse form. + * @param[in] s - the sign of the exponent. + */ +void fp12_exp_cyc_sps(fp12_t c, fp12_t a, const int *b, int l, int s); + +/** + * Compresses a dodecic extension field element. + * + * @param[out] r - the result. + * @param[in] p - the dodecic extension field element to compress. + */ +void fp12_pck(fp12_t c, fp12_t a); + +/** + * Decompresses a dodecic extension field element. + * + * @param[out] r - the result. + * @param[in] p - the dodecic extension field element to decompress. + * @return if the decompression was successful + */ +int fp12_upk(fp12_t c, fp12_t a); + +/** + * Copies the second argument to the first argument. + * + * @param[out] C - the result. + * @param[in] A - the octdecic extension field element to copy. + */ +void fp18_copy(fp18_t c, fp18_t a); + +/** + * Assigns zero to an octdecic extension field element. + * + * @param[out] A - the octdecic extension field element to zero. + */ +void fp18_zero(fp18_t a); + +/** + * Tests if an octdecic extension field element is zero or not. + * + * @param[in] A - the octdecic extension field element to test. + * @return 1 if the argument is zero, 0 otherwise. + */ +int fp18_is_zero(fp18_t a); + +/** + * Assigns a random value to an octdecic extension field element. + * + * @param[out] A - the octdecic extension field element to assign. + */ +void fp18_rand(fp18_t a); + +/** + * Prints an octdecic extension field element to standard output. + * + * @param[in] A - the octdecic extension field element to print. + */ +void fp18_print(fp18_t a); + +/** + * Returns the number of bytes necessary to store an octdecic extension field + * element. + * + * @param[in] a - the extension field element. + * @return the number of bytes. + */ +int fp18_size_bin(fp18_t a); + +/** + * Reads an octdecic extension field element from a byte vector in big-endian + * format. + * + * @param[out] a - the result. + * @param[in] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @throw ERR_NO_BUFFER - if the buffer capacity is not correct. + */ +void fp18_read_bin(fp18_t a, const uint8_t *bin, int len); + +/** + * Writes an octdecic extension field element to a byte vector in big-endian + * format. + * + * @param[out] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @param[in] a - the extension field element to write. + * @throw ERR_NO_BUFFER - if the buffer capacity is not correct. + */ +void fp18_write_bin(uint8_t *bin, int len, fp18_t a); + +/** + * Returns the result of a comparison between two octdecic extension field + * elements. + * + * @param[in] a - the first octdecic extension field element. + * @param[in] b - the second octdecic extension field element. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fp18_cmp(fp18_t a, fp18_t b); + +/** + * Returns the result of a signed comparison between an octdecic extension + * field element and a digit. + * + * @param[in] a - the octdecic extension field element. + * @param[in] b - the digit. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fp18_cmp_dig(fp18_t a, dig_t b); + +/** + * Assigns an octdecic extension field element to a digit. + * + * @param[in] a - the octdecic extension field element. + * @param[in] b - the digit. + */ +void fp18_set_dig(fp18_t a, dig_t b); + +/** + * Adds two octdecic extension field elements. Computes C = A + B. + * + * @param[out] C - the result. + * @param[in] A - the first octdecic extension field element. + * @param[in] B - the second octdecic extension field element. + */ +void fp18_add(fp18_t c, fp18_t a, fp18_t b); + +/** + * Subtracts an octdecic extension field element from another. Computes + * C = A - B. + * + * @param[out] C - the result. + * @param[in] A - the first octdecic extension field element. + * @param[in] B - the second octdecic extension field element. + */ +void fp18_sub(fp18_t c, fp18_t a, fp18_t b); + +/** + * Negates an octdecic extension field element. + * + * @param[out] C - the result. + * @param[out] A - the octdecic extension field element to negate. + */ +void fp18_neg(fp18_t c, fp18_t a); + +/** + * Doubles an octdecic extension field element. Computes c = 2 * a. + * + * @param[out] c - the result. + * @param[in] a - the octdecic extension field element to double. + */ +void fp18_dbl(fp18_t c, fp18_t a); + +/** + * Multiples two octdecic extension field elements without performing modular + * reduction. + * + * @param[out] c - the result. + * @param[in] a - the octdecic extension field element. + * @param[in] b - the octdecic extension field element. + */ +void fp18_mul_unr(dv18_t c, fp18_t a, fp18_t b); + +/** + * Multiples two octdecic extension field elements using basic arithmetic. + * + * @param[out] c - the result. + * @param[in] a - the octdecic extension field element. + * @param[in] b - the octdecic extension field element. + */ +void fp18_mul_basic(fp18_t c, fp18_t a, fp18_t b); + +/** + * Multiples two octdecic extension field elements using lazy reduction. + * + * @param[out] c - the result. + * @param[in] a - the octdecic extension field element. + * @param[in] b - the octdecic extension field element. + */ +void fp18_mul_lazyr(fp18_t c, fp18_t a, fp18_t b); + +/** + * Multiplies an octdecic extension field element by the adjoined root. + * + * @param[out] c - the result. + * @param[in] a - the octdecic extension field element to multiply. + */ +void fp18_mul_art(fp18_t c, fp18_t a); + +/** + * Multiples a dense octdecic extension field element by a sparse element using + * basic arithmetic. + * + * @param[out] c - the result. + * @param[in] a - the dense octdecic extension field element. + * @param[in] b - the sparse octdecic extension field element. + */ +void fp18_mul_dxs_basic(fp18_t c, fp18_t a, fp18_t b); + +/** + * Multiples a dense octdecic extension field element by a sparse element using + * lazy reduction. + * + * @param[out] c - the result. + * @param[in] a - the dense octdecic extension field element. + * @param[in] b - the sparse octdecic extension field element. + */ +void fp18_mul_dxs_lazyr(fp18_t c, fp18_t a, fp18_t b); + +/** + * Computes the square of an octdecic extension field element without performing + * modular reduction. + * + * @param[out] c - the result. + * @param[in] a - the octdecic extension field element to square. + */ +void fp18_sqr_unr(dv18_t c, fp18_t a); + +/** + * Computes the square of an octdecic extension field element using basic + * arithmetic. + * + * @param[out] c - the result. + * @param[in] a - the octdecic extension field element to square. + */ +void fp18_sqr_basic(fp18_t c, fp18_t a); + +/** + * Computes the square of an octdecic extension field element using lazy + * reduction. + * + * @param[out] c - the result. + * @param[in] a - the octdecic extension field element to square. + */ +void fp18_sqr_lazyr(fp18_t c, fp18_t a); + +/** + * Inverts an octdecic extension field element. Computes c = 1/a. + * + * @param[out] c - the result. + * @param[in] a - the octdecic extension field element to invert. + */ +void fp18_inv(fp18_t c, fp18_t a); + +/** + * Computes the inverse of a cyclotomic octdecic extension field element. + * For unitary elements, this is equivalent to computing the conjugate. + * A unitary element is one previously raised to the (p^9 - 1)-th power. + * + * @param[out] c - the result. + * @param[in] a - the octdecic extension field element to invert. + */ +void fp18_inv_cyc(fp18_t c, fp18_t a); + +/** + * Converts an octdecic extension field element to a cyclotomic element. + * Computes c = a^(p^9 - 1). + * + * @param[out] c - the result. + * @param[in] a - an octdecic extension field element. + */ +void fp18_conv_cyc(fp18_t c, fp18_t a); + +/** + * Computes the Frobenius endomorphism of an octdecic extension element. + * Computes c = a^(p^i). + * + * @param[out] c - the result. + * @param[in] a - an octdecic extension field element. + * @param[in] i - the power of the Frobenius map. + */ +void fp18_frb(fp18_t c, fp18_t a, int i); + +/** + * Computes a power of an octdecic extension field element. + * Faster formulas are used if the field element is cyclotomic. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent. + */ +void fp18_exp(fp18_t c, fp18_t a, bn_t b); + +/** + * Copies the second argument to the first argument. + * + * @param[out] C - the result. + * @param[in] A - the 24-degree extension field element to copy. + */ +void fp24_copy(fp24_t c, fp24_t a); + +/** + * Assigns zero to a 24-degree extension field element. + * + * @param[out] A - the 24-degree extension field element to zero. + */ +void fp24_zero(fp24_t a); + +/** + * Tests if a 24-degree extension field element is zero or not. + * + * @param[in] A - the 24-degree extension field element to test. + * @return 1 if the argument is zero, 0 otherwise. + */ +int fp24_is_zero(fp24_t a); + +/** + * Assigns a random value to a 24-degree extension field element. + * + * @param[out] A - the 24-degree extension field element to assign. + */ +void fp24_rand(fp24_t a); + +/** + * Prints a 24-degree extension field element to standard output. + * + * @param[in] A - the 24-degree extension field element to print. + */ +void fp24_print(fp24_t a); + +/** + * Returns the number of bytes necessary to store a 24-degree extension field + * element. + * + * @param[in] a - the extension field element. + * @return the number of bytes. + */ +int fp24_size_bin(fp24_t a); + +/** + * Reads a 24-degree extension field element from a byte vector in big-endian + * format. + * + * @param[out] a - the result. + * @param[in] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @throw ERR_NO_BUFFER - if the buffer capacity is not correct. + */ +void fp24_read_bin(fp24_t a, const uint8_t *bin, int len); + +/** + * Writes a 24-degree extension field element to a byte vector in big-endian + * format. + * + * @param[out] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @param[in] a - the extension field element to write. + * @throw ERR_NO_BUFFER - if the buffer capacity is not correct. + */ +void fp24_write_bin(uint8_t *bin, int len, fp24_t a); + +/** + * Returns the result of a comparison between two 24-degree extension field + * elements. + * + * @param[in] a - the first 24-degree extension field element. + * @param[in] b - the second 24-degree extension field element. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fp24_cmp(fp24_t a, fp24_t b); + +/** + * Returns the result of a signed comparison between a 24-degree extension field + * element and a digit. + * + * @param[in] a - the 24-degree extension field element. + * @param[in] b - the digit. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fp24_cmp_dig(fp24_t a, dig_t b); + +/** + * Assigns a 24-degree extension field element to a digit. + * + * @param[in] a - the 24-degree extension field element. + * @param[in] b - the digit. + */ +void fp24_set_dig(fp24_t a, dig_t b); + +/** + * Adds two 24-degree extension field elements. Computes C = A + B. + * + * @param[out] C - the result. + * @param[in] A - the first 24-degree extension field element. + * @param[in] B - the second 24-degree extension field element. + */ +void fp24_add(fp24_t c, fp24_t a, fp24_t b); + +/** + * Subtracts a 24-degree extension field element from another. Computes + * C = A - B. + * + * @param[out] C - the result. + * @param[in] A - the first 24-degree extension field element. + * @param[in] B - the second 24-degree extension field element. + */ +void fp24_sub(fp24_t c, fp24_t a, fp24_t b); + +/** + * Negates a 24-degree extension field element. + * + * @param[out] C - the result. + * @param[out] A - the 24-degree extension field element to negate. + */ +void fp24_neg(fp24_t c, fp24_t a); + +/** + * Doubles a 24-degree extension field element. Computes c = 2 * a. + * + * @param[out] c - the result. + * @param[in] a - the octic extension field element to double. + */ +void fp24_dbl(fp24_t c, fp24_t a); + +/** + * Multiples two 24-degree extension field elements without performing modular + * reduction. + * + * @param[out] c - the result. + * @param[in] a - the 24-degree extension field element. + * @param[in] b - the 24-degree extension field element. + */ +void fp24_mul_unr(dv24_t c, fp24_t a, fp24_t b); + +/** + * Multiples two 24-degree extension field elements using basic arithmetic. + * + * @param[out] c - the result. + * @param[in] a - the 24-degree extension field element. + * @param[in] b - the 24-degree extension field element. + */ +void fp24_mul_basic(fp24_t c, fp24_t a, fp24_t b); + +/** + * Multiples two 24-degree extension field elements using lazy reduction. + * + * @param[out] c - the result. + * @param[in] a - the 24-degree extension field element. + * @param[in] b - the 24-degree extension field element. + */ +void fp24_mul_lazyr(fp24_t c, fp24_t a, fp24_t b); + +/** + * Multiplies a 24-degree extension field element by the adjoined root. + * + * @param[out] c - the result. + * @param[in] a - the dodecic extension field element to multiply. + */ +void fp24_mul_art(fp24_t c, fp24_t a); + +/** + * Multiples a dense 24-degree extension field element by a sparse element. + * + * @param[out] c - the result. + * @param[in] a - a 24-degree extension field element. + * @param[in] b - a 24-degree quartic extension field element. + */ +void fp24_mul_dxs(fp24_t c, fp24_t a, fp24_t b); + +/** + * Computes the square of a 24-degree extension field element without performing + * modular reduction. + * + * @param[out] c - the result. + * @param[in] a - the 24-degree extension field element to square. + */ +void fp24_sqr_unr(dv24_t c, fp24_t a); + +/** + * Computes the square of a 24-degree extension field element using basic + * arithmetic. + * + * @param[out] c - the result. + * @param[in] a - the 24-degree extension field element to square. + */ +void fp24_sqr_basic(fp24_t c, fp24_t a); + +/** + * Computes the square of a 24-degree extension field element using lazy + * reduction. + * + * @param[out] c - the result. + * @param[in] a - the 24-degree extension field element to square. + */ +void fp24_sqr_lazyr(fp24_t c, fp24_t a); + +/** + * Inverts a 24-degree extension field element. Computes c = 1/a. + * + * @param[out] c - the result. + * @param[in] a - the 24-degree extension field element to invert. + */ +void fp24_inv(fp24_t c, fp24_t a); + +/** + * Computes the Frobenius endomorphism of a 24-degree extension element. + * Computes c = a^p. + * + * @param[out] c - the result. + * @param[in] a - a 24-degree extension field element. + * @param[in] i - the power of the Frobenius map. + */ +void fp24_frb(fp24_t c, fp24_t a, int i); + +/** + * Computes a power of a 24-degree extension field element. + * Faster formulas are used if the extension field element is cyclotomic. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent. + */ +void fp24_exp(fp24_t c, fp24_t a, bn_t b); + +/** + * Copies the second argument to the first argument. + * + * @param[out] C - the result. + * @param[in] A - the 48-extension field element to copy. + */ +void fp48_copy(fp48_t c, fp48_t a); + +/** + * Assigns zero to a 48-extension field element. + * + * @param[out] A - the 48-extension field element to zero. + */ +void fp48_zero(fp48_t a); + +/** + * Tests if a 48-extension field element is zero or not. + * + * @param[in] A - the 48-extension field element to test. + * @return 1 if the argument is zero, 0 otherwise. + */ +int fp48_is_zero(fp48_t a); + +/** + * Assigns a random value to a 48-extension field element. + * + * @param[out] A - the 48-extension field element to assign. + */ +void fp48_rand(fp48_t a); + +/** + * Prints a 48-extension field element to standard output. + * + * @param[in] A - the 48-extension field element to print. + */ +void fp48_print(fp48_t a); + +/** + * Returns the number of bytes necessary to store a 48-extension field + * element. + * + * @param[in] a - the extension field element. + * @param[in] pack - the flag to indicate compression. + * @return the number of bytes. + */ +int fp48_size_bin(fp48_t a, int pack); + +/** + * Reads a 48-extension field element from a byte vector in big-endian + * format. + * + * @param[out] a - the result. + * @param[in] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @throw ERR_NO_BUFFER - if the buffer capacity is not correct. + */ +void fp48_read_bin(fp48_t a, const uint8_t *bin, int len); + +/** + * Writes a 48-extension field element to a byte vector in big-endian + * format. + * + * @param[out] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @param[in] a - the extension field element to write. + * @param[in] pack - the flag to indicate compression. + * @throw ERR_NO_BUFFER - if the buffer capacity is not correct. + */ +void fp48_write_bin(uint8_t *bin, int len, fp48_t a, int pack); + +/** + * Returns the result of a comparison between two 48-extension field + * elements. + * + * @param[in] a - the first 48-extension field element. + * @param[in] b - the second 48-extension field element. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fp48_cmp(fp48_t a, fp48_t b); + +/** + * Returns the result of a signed comparison between a 48-extension field + * element and a digit. + * + * @param[in] a - the 48-extension field element. + * @param[in] b - the digit. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fp48_cmp_dig(fp48_t a, dig_t b); + +/** + * Assigns a 48-extension field element to a digit. + * + * @param[in] a - the 48-extension field element. + * @param[in] b - the digit. + */ +void fp48_set_dig(fp48_t a, dig_t b); + +/** + * Adds two 48-extension field elements. Computes C = A + B. + * + * @param[out] C - the result. + * @param[in] A - the first 48-extension field element. + * @param[in] B - the second 48-extension field element. + */ +void fp48_add(fp48_t c, fp48_t a, fp48_t b); + +/** + * Subtracts a 48-extension field element from another. Computes + * C = A - B. + * + * @param[out] C - the result. + * @param[in] A - the first 48-extension field element. + * @param[in] B - the second 48-extension field element. + */ +void fp48_sub(fp48_t c, fp48_t a, fp48_t b); + +/** + * Negates a 48-extension field element. + * + * @param[out] C - the result. + * @param[out] A - the 48-extension field element to negate. + */ +void fp48_neg(fp48_t c, fp48_t a); + +/** + * Doubles a 48-extension field element. Computes c = 2 * a. + * + * @param[out] c - the result. + * @param[in] a - the 48-extension field element to double. + */ +void fp48_dbl(fp48_t c, fp48_t a); + +/** + * Multiples two 48-extension field elements without performing modular + * reduction. + * + * @param[out] c - the result. + * @param[in] a - the 48-extension field element. + * @param[in] b - the 48-extension field element. + */ +void fp48_mul_unr(dv48_t c, fp48_t a, fp48_t b); + +/** + * Multiples two 48-extension field elements using basic arithmetic. + * + * @param[out] c - the result. + * @param[in] a - the 48-extension field element. + * @param[in] b - the 48-extension field element. + */ +void fp48_mul_basic(fp48_t c, fp48_t a, fp48_t b); + +/** + * Multiples two 48-extension field elements using lazy reduction. + * + * @param[out] c - the result. + * @param[in] a - the 48-extension field element. + * @param[in] b - the 48-extension field element. + */ +void fp48_mul_lazyr(fp48_t c, fp48_t a, fp48_t b); + +/** + * Multiplies a 48-extension field element by the adjoined root. + * + * @param[out] c - the result. + * @param[in] a - the 48-extension field element to multiply. + */ +void fp48_mul_art(fp48_t c, fp48_t a); + +/** + * Multiples a dense 48-extension field element by a sparse element using + * basic arithmetic. Computes C = A * B. + * + * @param[out] c - the result. + * @param[in] a - the dense 48-extension field element. + * @param[in] b - the sparse 48-extension field element. + */ +void fp48_mul_dxs(fp48_t c, fp48_t a, fp48_t b); + +/** + * Computes the square of a 48-extension field element without performing + * modular reduction. + * + * @param[out] c - the result. + * @param[in] a - the 48-extension field element to square. + */ +void fp48_sqr_unr(dv48_t c, fp48_t a); + +/** + * Computes the square of a 48-extension field element using basic + * arithmetic. + * + * @param[out] c - the result. + * @param[in] a - the 48-extension field element to square. + */ +void fp48_sqr_basic(fp48_t c, fp48_t a); + +/** + * Computes the square of a 48-extension field element using lazy + * reduction. + * + * @param[out] c - the result. + * @param[in] a - the 48-extension field element to square. + */ +void fp48_sqr_lazyr(fp48_t c, fp48_t a); + +/** + * Computes the square of a cyclotomic 48-extension field element using + * basic arithmetic. + * + * A cyclotomic element is one raised to the (p^6 - 1)(p^2 + 1)-th power. + * + * @param[out] c - the result. + * @param[in] a - the cyclotomic extension element to square. + */ +void fp48_sqr_cyc_basic(fp48_t c, fp48_t a); + +/** + * Computes the square of a cyclotomic 48-extension field element using + * lazy reduction. + * + * A cyclotomic element is one raised to the (p^6 - 1)(p^2 + 1)-th power. + * + * @param[out] c - the result. + * @param[in] a - the cyclotomic extension element to square. + */ +void fp48_sqr_cyc_lazyr(fp48_t c, fp48_t a); + +/** + * Computes the square of a compressed cyclotomic extension field element. + * + * A cyclotomic element is one raised to the (p^6 - 1)(p^2 + 1)-th power. + * + * @param[out] c - the result. + * @param[in] a - the cyclotomic extension element to square. + */ +void fp48_sqr_pck_basic(fp48_t c, fp48_t a); + +/** + * Computes the square of a compressed cyclotomic extension field element using + * lazy reduction. + * + * A cyclotomic element is one raised to the (p^6 - 1)(p^2 + 1)-th power. + * + * @param[out] c - the result. + * @param[in] a - the cyclotomic extension element to square. + */ +void fp48_sqr_pck_lazyr(fp48_t c, fp48_t a); + +/** + * Tests if a 48-extension field element belongs to the cyclotomic + * subgroup. + * + * @param[in] a - the 48-extension field element to test. + * @return 1 if the extension field element is in the subgroup, 0 otherwise. + */ +int fp48_test_cyc(fp48_t a); + +/** + * Converts a 48-extension field element to a cyclotomic element. + * Computes c = a^(p^6 - 1)*(p^2 + 1). + * + * @param[out] c - the result. + * @param[in] a - a 48-extension field element. + */ +void fp48_conv_cyc(fp48_t c, fp48_t a); + +/** + * Decompresses a compressed cyclotomic extension field element. + * + * @param[out] c - the result. + * @param[in] a - the 48-extension field element to decompress. + */ +void fp48_back_cyc(fp48_t c, fp48_t a); + +/** + * Decompresses multiple compressed cyclotomic extension field elements. + * + * @param[out] c - the result. + * @param[in] a - the 48 field elements to decompress. + * @param[in] n - the number of field elements to decompress. + */ +void fp48_back_cyc_sim(fp48_t *c, fp48_t *a, int n); + +/** + * Inverts a 48-extension field element. Computes c = 1/a. + * + * @param[out] c - the result. + * @param[in] a - the 48-extension field element to invert. + */ +void fp48_inv(fp48_t c, fp48_t a); + +/** + * Computes the inverse of a cyclotomic 48-extension field element. + * + * For unitary elements, this is equivalent to computing the conjugate. + * A unitary element is one previously raised to the (p^24 - 1)-th power. + * + * @param[out] c - the result. + * @param[in] a - the 48-extension field element to invert. + */ +void fp48_inv_cyc(fp48_t c, fp48_t a); + +/** + * Converts a 48-extension field element to a cyclotomic element. Computes + * c = a^(p^6 - 1). + * + * @param[out] c - the result. + * @param[in] a - the 48-extension field element. + */ +void fp48_conv_cyc(fp48_t c, fp48_t a); + +/** + * Computes the Frobenius endomorphism of a 48-extension element. + * Computes c = a^p. + * + * @param[out] c - the result. + * @param[in] a - a 48-extension field element. + * @param[in] i - the power of the Frobenius map. + */ +void fp48_frb(fp48_t c, fp48_t a, int i); + +/** + * Computes a power of a 48-extension field element. + * Faster formulas are used if the extension field element is cyclotomic. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent. + */ +void fp48_exp(fp48_t c, fp48_t a, bn_t b); + +/** + * Computes a power of a 48-extension field element by a small exponent. + * Faster formulas are used if the extension field element is cyclotomic. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent. + */ +void fp48_exp_dig(fp48_t c, fp48_t a, dig_t b); + +/** + * Computes a power of a cyclotomic 48-extension field element. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent. + */ +void fp48_exp_cyc(fp48_t c, fp48_t a, bn_t b); + +/** + * Computes a power of a cyclotomic 48-extension field element. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent in sparse form. + * @param[in] l - the length of the exponent in sparse form. + * @param[in] s - the sign of the exponent. + */ +void fp48_exp_cyc_sps(fp48_t c, fp48_t a, const int *b, int l, int s); + +/** + * Compresses a 48-extension field element. + * + * @param[out] r - the result. + * @param[in] p - the 48-extension field element to compress. + */ +void fp48_pck(fp48_t c, fp48_t a); + +/** + * Decompresses a 48-extension field element. + * + * @param[out] r - the result. + * @param[in] p - the 48-extension field element to decompress. + * @return if the decompression was successful + */ +int fp48_upk(fp48_t c, fp48_t a); + +/** + * Copies the second argument to the first argument. + * + * @param[out] C - the result. + * @param[in] A - the 54-extension field element to copy. + */ +void fp54_copy(fp54_t c, fp54_t a); + +/** + * Assigns zero to a 54-extension field element. + * + * @param[out] A - the 54-extension field element to zero. + */ +void fp54_zero(fp54_t a); + +/** + * Tests if a 54-extension field element is zero or not. + * + * @param[in] A - the 54-extension field element to test. + * @return 1 if the argument is zero, 0 otherwise. + */ +int fp54_is_zero(fp54_t a); + +/** + * Assigns a random value to a 54-extension field element. + * + * @param[out] A - the 54-extension field element to assign. + */ +void fp54_rand(fp54_t a); + +/** + * Prints a 54-extension field element to standard output. + * + * @param[in] A - the 54-extension field element to print. + */ +void fp54_print(fp54_t a); + +/** + * Returns the number of bytes necessary to store a 54-extension field + * element. + * + * @param[in] a - the extension field element. + * @param[in] pack - the flag to indicate compression. + * @return the number of bytes. + */ +int fp54_size_bin(fp54_t a, int pack); + +/** + * Reads a 54-extension field element from a byte vector in big-endian + * format. + * + * @param[out] a - the result. + * @param[in] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @throw ERR_NO_BUFFER - if the buffer capacity is not correct. + */ +void fp54_read_bin(fp54_t a, const uint8_t *bin, int len); + +/** + * Writes a 54-extension field element to a byte vector in big-endian + * format. + * + * @param[out] bin - the byte vector. + * @param[in] len - the buffer capacity. + * @param[in] a - the extension field element to write. + * @param[in] pack - the flag to indicate compression. + * @throw ERR_NO_BUFFER - if the buffer capacity is not correct. + */ +void fp54_write_bin(uint8_t *bin, int len, fp54_t a, int pack); + +/** + * Returns the result of a comparison between two 54-extension field + * elements. + * + * @param[in] a - the first 54-extension field element. + * @param[in] b - the second 54-extension field element. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fp54_cmp(fp54_t a, fp54_t b); + +/** + * Returns the result of a signed comparison between a 54-extension field + * element and a digit. + * + * @param[in] a - the 54-extension field element. + * @param[in] b - the digit. + * @return RLC_EQ if a == b, and RLC_NE otherwise. + */ +int fp54_cmp_dig(fp54_t a, dig_t b); + +/** + * Assigns a 54-extension field element to a digit. + * + * @param[in] a - the 54-extension field element. + * @param[in] b - the digit. + */ +void fp54_set_dig(fp54_t a, dig_t b); + +/** + * Adds two 54-extension field elements. Computes C = A + B. + * + * @param[out] C - the result. + * @param[in] A - the first 54-extension field element. + * @param[in] B - the second 54-extension field element. + */ +void fp54_add(fp54_t c, fp54_t a, fp54_t b); + +/** + * Subtracts a 54-extension field element from another. Computes + * C = A - B. + * + * @param[out] C - the result. + * @param[in] A - the first 54-extension field element. + * @param[in] B - the second 54-extension field element. + */ +void fp54_sub(fp54_t c, fp54_t a, fp54_t b); + +/** + * Negates a 54-extension field element. + * + * @param[out] C - the result. + * @param[out] A - the 54-extension field element to negate. + */ +void fp54_neg(fp54_t c, fp54_t a); + +/** + * Doubles a 54-extension field element. Computes c = 2 * a. + * + * @param[out] c - the result. + * @param[in] a - the 54-extension field element to double. + */ +void fp54_dbl(fp54_t c, fp54_t a); + +/** + * Multiples two 54-extension field elements without performing modular + * reduction. + * + * @param[out] c - the result. + * @param[in] a - the 54-extension field element. + * @param[in] b - the 54-extension field element. + */ +void fp54_mul_unr(dv54_t c, fp54_t a, fp54_t b); + +/** + * Multiples two 54-extension field elements using basic arithmetic. + * + * @param[out] c - the result. + * @param[in] a - the 54-extension field element. + * @param[in] b - the 54-extension field element. + */ +void fp54_mul_basic(fp54_t c, fp54_t a, fp54_t b); + +/** + * Multiples two 54-extension field elements using lazy reduction. + * + * @param[out] c - the result. + * @param[in] a - the 54-extension field element. + * @param[in] b - the 54-extension field element. + */ +void fp54_mul_lazyr(fp54_t c, fp54_t a, fp54_t b); + +/** + * Multiplies a 54-extension field element by the adjoined root. + * + * @param[out] c - the result. + * @param[in] a - the 54-extension field element to multiply. + */ +void fp54_mul_art(fp54_t c, fp54_t a); + +/** + * Multiples a dense 54-extension field element by a sparse element using + * basic arithmetic. Computes C = A * B. + * + * @param[out] c - the result. + * @param[in] a - the dense 54-extension field element. + * @param[in] b - the sparse 54-extension field element. + */ +void fp54_mul_dxs(fp54_t c, fp54_t a, fp54_t b); + +/** + * Computes the square of a 54-extension field element without performing + * modular reduction. + * + * @param[out] c - the result. + * @param[in] a - the 54-extension field element to square. + */ +void fp54_sqr_unr(dv54_t c, fp54_t a); + +/** + * Computes the square of a 54-extension field element using basic + * arithmetic. + * + * @param[out] c - the result. + * @param[in] a - the 54-extension field element to square. + */ +void fp54_sqr_basic(fp54_t c, fp54_t a); + +/** + * Computes the square of a 54-extension field element using lazy + * reduction. + * + * @param[out] c - the result. + * @param[in] a - the 54-extension field element to square. + */ +void fp54_sqr_lazyr(fp54_t c, fp54_t a); + +/** + * Computes the square of a cyclotomic 54-extension field element using + * basic arithmetic. + * + * A cyclotomic element is one raised to the (p^6 - 1)(p^2 + 1)-th power. + * + * @param[out] c - the result. + * @param[in] a - the cyclotomic extension element to square. + */ +void fp54_sqr_cyc_basic(fp54_t c, fp54_t a); + +/** + * Computes the square of a cyclotomic 54-extension field element using + * lazy reduction. + * + * A cyclotomic element is one raised to the (p^6 - 1)(p^2 + 1)-th power. + * + * @param[out] c - the result. + * @param[in] a - the cyclotomic extension element to square. + */ +void fp54_sqr_cyc_lazyr(fp54_t c, fp54_t a); + +/** + * Computes the square of a compressed cyclotomic extension field element. + * + * A cyclotomic element is one raised to the (p^6 - 1)(p^2 + 1)-th power. + * + * @param[out] c - the result. + * @param[in] a - the cyclotomic extension element to square. + */ +void fp54_sqr_pck_basic(fp54_t c, fp54_t a); + +/** + * Computes the square of a compressed cyclotomic extension field element using + * lazy reduction. + * + * A cyclotomic element is one raised to the (p^6 - 1)(p^2 + 1)-th power. + * + * @param[out] c - the result. + * @param[in] a - the cyclotomic extension element to square. + */ +void fp54_sqr_pck_lazyr(fp54_t c, fp54_t a); + +/** + * Tests if a 54-extension field element belongs to the cyclotomic + * subgroup. + * + * @param[in] a - the 54-extension field element to test. + * @return 1 if the extension field element is in the subgroup, 0 otherwise. + */ +int fp54_test_cyc(fp54_t a); + +/** + * Converts a 54-extension field element to a cyclotomic element. + * Computes c = a^(p^6 - 1)*(p^2 + 1). + * + * @param[out] c - the result. + * @param[in] a - a 54-extension field element. + */ +void fp54_conv_cyc(fp54_t c, fp54_t a); + +/** + * Decompresses a compressed cyclotomic extension field element. + * + * @param[out] c - the result. + * @param[in] a - the 54-extension field element to decompress. + */ +void fp54_back_cyc(fp54_t c, fp54_t a); + +/** + * Decompresses multiple compressed cyclotomic extension field elements. + * + * @param[out] c - the result. + * @param[in] a - the 54 field elements to decompress. + * @param[in] n - the number of field elements to decompress. + */ +void fp54_back_cyc_sim(fp54_t *c, fp54_t *a, int n); + +/** + * Inverts a 54-extension field element. Computes c = 1/a. + * + * @param[out] c - the result. + * @param[in] a - the 54-extension field element to invert. + */ +void fp54_inv(fp54_t c, fp54_t a); + +/** + * Computes the inverse of a cyclotomic 54-extension field element. + * + * For unitary elements, this is equivalent to computing the conjugate. + * A unitary element is one previously raised to the (p^24 - 1)-th power. + * + * @param[out] c - the result. + * @param[in] a - the 54-extension field element to invert. + */ +void fp54_inv_cyc(fp54_t c, fp54_t a); + +/** + * Converts a 54-extension field element to a cyclotomic element. Computes + * c = a^(p^6 - 1). + * + * @param[out] c - the result. + * @param[in] a - the 54-extension field element. + */ +void fp54_conv_cyc(fp54_t c, fp54_t a); + +/** + * Computes the Frobenius endomorphism of a 54-extension element. + * Computes c = a^p. + * + * @param[out] c - the result. + * @param[in] a - a 54-extension field element. + * @param[in] i - the power of the Frobenius map. + */ +void fp54_frb(fp54_t c, fp54_t a, int i); + +/** + * Computes a power of a 54-extension field element. + * Faster formulas are used if the extension field element is cyclotomic. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent. + */ +void fp54_exp(fp54_t c, fp54_t a, bn_t b); + +/** + * Computes a power of a 54-extension field element by a small exponent. + * Faster formulas are used if the extension field element is cyclotomic. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent. + */ +void fp54_exp_dig(fp54_t c, fp54_t a, dig_t b); + +/** + * Computes a power of a cyclotomic 54-extension field element. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent. + */ +void fp54_exp_cyc(fp54_t c, fp54_t a, bn_t b); + +/** + * Computes a power of a cyclotomic 54-extension field element. + * + * @param[out] c - the result. + * @param[in] a - the basis. + * @param[in] b - the exponent in sparse form. + * @param[in] l - the length of the exponent in sparse form. + * @param[in] s - the sign of the exponent. + */ +void fp54_exp_cyc_sps(fp54_t c, fp54_t a, const int *b, int l, int s); + +/** + * Compresses a 54-extension field element. + * + * @param[out] r - the result. + * @param[in] p - the 54-extension field element to compress. + */ +void fp54_pck(fp54_t c, fp54_t a); + +/** + * Decompresses a 54-extension field element. + * + * @param[out] r - the result. + * @param[in] p - the 54-extension field element to decompress. + * @return if the decompression was successful + */ +int fp54_upk(fp54_t c, fp54_t a); + +#endif /* !RLC_FPX_H */ diff --git a/bls/contrib/relic/include/relic_label.h b/bls/contrib/relic/include/relic_label.h new file mode 100644 index 00000000..959a3b3d --- /dev/null +++ b/bls/contrib/relic/include/relic_label.h @@ -0,0 +1,2667 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @file + * + * Symbol renaming to a#undef clashes when simultaneous linking multiple builds. + * + * @ingroup core + */ + +#ifndef RLC_LABEL_H +#define RLC_LABEL_H + +#include "relic_conf.h" + +#define PREFIX(F) _PREFIX(LABEL, F) +#define _PREFIX(A, B) __PREFIX(A, B) +#define __PREFIX(A, B) A ## _ ## B + +/*============================================================================*/ +/* Macro definitions */ +/*============================================================================*/ + +#ifdef LABEL + +#undef first_ctx +#define first_ctx PREFIX(first_ctx) +#undef core_ctx +#define core_ctx PREFIX(core_ctx) + +#undef core_init +#undef core_clean +#undef core_get +#undef core_set + +#define core_init PREFIX(core_init) +#define core_clean PREFIX(core_clean) +#define core_get PREFIX(core_get) +#define core_set PREFIX(core_set) + +#undef arch_init +#undef arch_clean +#undef arch_cycles +#undef arch_copy_rom + +#define arch_init PREFIX(arch_init) +#define arch_clean PREFIX(arch_clean) +#define arch_cycles PREFIX(arch_cycles) +#define arch_copy_rom PREFIX(arch_copy_rom) + +#undef bench_overhead +#undef bench_reset +#undef bench_before +#undef bench_after +#undef bench_compute +#undef bench_print +#undef bench_total + +#define bench_overhead PREFIX(bench_overhead) +#define bench_reset PREFIX(bench_reset) +#define bench_before PREFIX(bench_before) +#define bench_after PREFIX(bench_after) +#define bench_compute PREFIX(bench_compute) +#define bench_print PREFIX(bench_print) +#define bench_total PREFIX(bench_total) + +#undef err_simple_msg +#undef err_full_msg +#undef err_get_msg +#undef err_get_code + +#define err_simple_msg PREFIX(err_simple_msg) +#define err_full_msg PREFIX(err_full_msg) +#define err_get_msg PREFIX(err_get_msg) +#define err_get_code PREFIX(err_get_code) + +#undef rand_init +#undef rand_clean +#undef rand_seed +#undef rand_seed +#undef rand_bytes + +#define rand_init PREFIX(rand_init) +#define rand_clean PREFIX(rand_clean) +#define rand_seed PREFIX(rand_seed) +#define rand_seed PREFIX(rand_seed) +#define rand_bytes PREFIX(rand_bytes) + +#undef test_fail +#undef test_pass + +#define test_fail PREFIX(test_fail) +#define test_pass PREFIX(test_pass) + +#undef util_conv_endian +#undef util_conv_big +#undef util_conv_little +#undef util_conv_char +#undef util_bits_dig +#undef util_cmp_const +#undef util_printf +#undef util_print_dig + +#define util_conv_endian PREFIX(util_conv_endian) +#define util_conv_big PREFIX(util_conv_big) +#define util_conv_little PREFIX(util_conv_little) +#define util_conv_char PREFIX(util_conv_char) +#define util_bits_dig PREFIX(util_bits_dig) +#define util_cmp_const PREFIX(util_cmp_const) +#define util_printf PREFIX(util_printf) +#define util_print_dig PREFIX(util_print_dig) + +#undef conf_print +#define conf_print PREFIX(conf_print) + +#undef dv_t +#define dv_t PREFIX(dv_t) + +#undef dv_print +#undef dv_zero +#undef dv_copy +#undef dv_copy_cond +#undef dv_swap_cond +#undef dv_cmp +#undef dv_cmp_const +#undef dv_new_dynam +#undef dv_free_dynam + +#define dv_print PREFIX(dv_print) +#define dv_zero PREFIX(dv_zero) +#define dv_copy PREFIX(dv_copy) +#define dv_copy_cond PREFIX(dv_copy_cond) +#define dv_swap_cond PREFIX(dv_swap_cond) +#define dv_cmp PREFIX(dv_cmp) +#define dv_cmp_const PREFIX(dv_cmp_const) +#define dv_new_dynam PREFIX(dv_new_dynam) +#define dv_free_dynam PREFIX(dv_free_dynam) + + + +#undef bn_st +#undef bn_t +#define bn_st PREFIX(bn_st) +#define bn_t PREFIX(bn_t) + +#undef bn_init +#undef bn_clean +#undef bn_grow +#undef bn_trim +#undef bn_copy +#undef bn_abs +#undef bn_neg +#undef bn_sign +#undef bn_zero +#undef bn_is_zero +#undef bn_is_even +#undef bn_bits +#undef bn_get_bit +#undef bn_set_bit +#undef bn_ham +#undef bn_get_dig +#undef bn_set_dig +#undef bn_set_2b +#undef bn_rand +#undef bn_rand_mod +#undef bn_print +#undef bn_size_str +#undef bn_read_str +#undef bn_write_str +#undef bn_size_bin +#undef bn_read_bin +#undef bn_write_bin +#undef bn_size_raw +#undef bn_read_raw +#undef bn_write_raw +#undef bn_cmp_abs +#undef bn_cmp_dig +#undef bn_cmp +#undef bn_add +#undef bn_add_dig +#undef bn_sub +#undef bn_sub_dig +#undef bn_mul_dig +#undef bn_mul_basic +#undef bn_mul_comba +#undef bn_mul_karat +#undef bn_sqr_basic +#undef bn_sqr_comba +#undef bn_sqr_karat +#undef bn_dbl +#undef bn_hlv +#undef bn_lsh +#undef bn_rsh +#undef bn_div +#undef bn_div_rem +#undef bn_div_dig +#undef bn_div_rem_dig +#undef bn_mod_2b +#undef bn_mod_dig +#undef bn_mod_basic +#undef bn_mod_pre_barrt +#undef bn_mod_barrt +#undef bn_mod_pre_monty +#undef bn_mod_monty_conv +#undef bn_mod_monty_back +#undef bn_mod_monty_basic +#undef bn_mod_monty_comba +#undef bn_mod_pre_pmers +#undef bn_mod_pmers +#undef bn_mxp_basic +#undef bn_mxp_slide +#undef bn_mxp_monty +#undef bn_mxp_dig +#undef bn_srt +#undef bn_gcd_basic +#undef bn_gcd_lehme +#undef bn_gcd_stein +#undef bn_gcd_dig +#undef bn_gcd_ext_basic +#undef bn_gcd_ext_lehme +#undef bn_gcd_ext_stein +#undef bn_gcd_ext_mid +#undef bn_gcd_ext_dig +#undef bn_lcm +#undef bn_smb_leg +#undef bn_smb_jac +#undef bn_get_prime +#undef bn_is_prime +#undef bn_is_prime_basic +#undef bn_is_prime_rabin +#undef bn_is_prime_solov +#undef bn_gen_prime_basic +#undef bn_gen_prime_safep +#undef bn_gen_prime_stron +#undef bn_factor +#undef bn_is_factor +#undef bn_rec_win +#undef bn_rec_slw +#undef bn_rec_naf +#undef bn_rec_tnaf +#undef bn_rec_rtnaf +#undef bn_rec_tnaf_get +#undef bn_rec_tnaf_mod +#undef bn_rec_reg +#undef bn_rec_jsf +#undef bn_rec_glv + +#define bn_init PREFIX(bn_init) +#define bn_clean PREFIX(bn_clean) +#define bn_grow PREFIX(bn_grow) +#define bn_trim PREFIX(bn_trim) +#define bn_copy PREFIX(bn_copy) +#define bn_abs PREFIX(bn_abs) +#define bn_neg PREFIX(bn_neg) +#define bn_sign PREFIX(bn_sign) +#define bn_zero PREFIX(bn_zero) +#define bn_is_zero PREFIX(bn_is_zero) +#define bn_is_even PREFIX(bn_is_even) +#define bn_bits PREFIX(bn_bits) +#define bn_get_bit PREFIX(bn_get_bit) +#define bn_set_bit PREFIX(bn_set_bit) +#define bn_ham PREFIX(bn_ham) +#define bn_get_dig PREFIX(bn_get_dig) +#define bn_set_dig PREFIX(bn_set_dig) +#define bn_set_2b PREFIX(bn_set_2b) +#define bn_rand PREFIX(bn_rand) +#define bn_rand_mod PREFIX(bn_rand_mod) +#define bn_print PREFIX(bn_print) +#define bn_size_str PREFIX(bn_size_str) +#define bn_read_str PREFIX(bn_read_str) +#define bn_write_str PREFIX(bn_write_str) +#define bn_size_bin PREFIX(bn_size_bin) +#define bn_read_bin PREFIX(bn_read_bin) +#define bn_write_bin PREFIX(bn_write_bin) +#define bn_size_raw PREFIX(bn_size_raw) +#define bn_read_raw PREFIX(bn_read_raw) +#define bn_write_raw PREFIX(bn_write_raw) +#define bn_cmp_abs PREFIX(bn_cmp_abs) +#define bn_cmp_dig PREFIX(bn_cmp_dig) +#define bn_cmp PREFIX(bn_cmp) +#define bn_add PREFIX(bn_add) +#define bn_add_dig PREFIX(bn_add_dig) +#define bn_sub PREFIX(bn_sub) +#define bn_sub_dig PREFIX(bn_sub_dig) +#define bn_mul_dig PREFIX(bn_mul_dig) +#define bn_mul_basic PREFIX(bn_mul_basic) +#define bn_mul_comba PREFIX(bn_mul_comba) +#define bn_mul_karat PREFIX(bn_mul_karat) +#define bn_sqr_basic PREFIX(bn_sqr_basic) +#define bn_sqr_comba PREFIX(bn_sqr_comba) +#define bn_sqr_karat PREFIX(bn_sqr_karat) +#define bn_dbl PREFIX(bn_dbl) +#define bn_hlv PREFIX(bn_hlv) +#define bn_lsh PREFIX(bn_lsh) +#define bn_rsh PREFIX(bn_rsh) +#define bn_div PREFIX(bn_div) +#define bn_div_rem PREFIX(bn_div_rem) +#define bn_div_dig PREFIX(bn_div_dig) +#define bn_div_rem_dig PREFIX(bn_div_rem_dig) +#define bn_mod_2b PREFIX(bn_mod_2b) +#define bn_mod_dig PREFIX(bn_mod_dig) +#define bn_mod_basic PREFIX(bn_mod_basic) +#define bn_mod_pre_barrt PREFIX(bn_mod_pre_barrt) +#define bn_mod_barrt PREFIX(bn_mod_barrt) +#define bn_mod_pre_monty PREFIX(bn_mod_pre_monty) +#define bn_mod_monty_conv PREFIX(bn_mod_monty_conv) +#define bn_mod_monty_back PREFIX(bn_mod_monty_back) +#define bn_mod_monty_basic PREFIX(bn_mod_monty_basic) +#define bn_mod_monty_comba PREFIX(bn_mod_monty_comba) +#define bn_mod_pre_pmers PREFIX(bn_mod_pre_pmers) +#define bn_mod_pmers PREFIX(bn_mod_pmers) +#define bn_mxp_basic PREFIX(bn_mxp_basic) +#define bn_mxp_slide PREFIX(bn_mxp_slide) +#define bn_mxp_monty PREFIX(bn_mxp_monty) +#define bn_mxp_dig PREFIX(bn_mxp_dig) +#define bn_srt PREFIX(bn_srt) +#define bn_gcd_basic PREFIX(bn_gcd_basic) +#define bn_gcd_lehme PREFIX(bn_gcd_lehme) +#define bn_gcd_stein PREFIX(bn_gcd_stein) +#define bn_gcd_dig PREFIX(bn_gcd_dig) +#define bn_gcd_ext_basic PREFIX(bn_gcd_ext_basic) +#define bn_gcd_ext_lehme PREFIX(bn_gcd_ext_lehme) +#define bn_gcd_ext_stein PREFIX(bn_gcd_ext_stein) +#define bn_gcd_ext_mid PREFIX(bn_gcd_ext_mid) +#define bn_gcd_ext_dig PREFIX(bn_gcd_ext_dig) +#define bn_lcm PREFIX(bn_lcm) +#define bn_smb_leg PREFIX(bn_smb_leg) +#define bn_smb_jac PREFIX(bn_smb_jac) +#define bn_get_prime PREFIX(bn_get_prime) +#define bn_is_prime PREFIX(bn_is_prime) +#define bn_is_prime_basic PREFIX(bn_is_prime_basic) +#define bn_is_prime_rabin PREFIX(bn_is_prime_rabin) +#define bn_is_prime_solov PREFIX(bn_is_prime_solov) +#define bn_gen_prime_basic PREFIX(bn_gen_prime_basic) +#define bn_gen_prime_safep PREFIX(bn_gen_prime_safep) +#define bn_gen_prime_stron PREFIX(bn_gen_prime_stron) +#define bn_factor PREFIX(bn_factor) +#define bn_is_factor PREFIX(bn_is_factor) +#define bn_rec_win PREFIX(bn_rec_win) +#define bn_rec_slw PREFIX(bn_rec_slw) +#define bn_rec_naf PREFIX(bn_rec_naf) +#define bn_rec_tnaf PREFIX(bn_rec_tnaf) +#define bn_rec_rtnaf PREFIX(bn_rec_rtnaf) +#define bn_rec_tnaf_get PREFIX(bn_rec_tnaf_get) +#define bn_rec_tnaf_mod PREFIX(bn_rec_tnaf_mod) +#define bn_rec_reg PREFIX(bn_rec_reg) +#define bn_rec_jsf PREFIX(bn_rec_jsf) +#define bn_rec_glv PREFIX(bn_rec_glv) + +#undef bn_add1_low +#undef bn_addn_low +#undef bn_sub1_low +#undef bn_subn_low +#undef bn_cmp1_low +#undef bn_cmpn_low +#undef bn_lsh1_low +#undef bn_lshb_low +#undef bn_lshd_low +#undef bn_rsh1_low +#undef bn_rshb_low +#undef bn_rshd_low +#undef bn_mula_low +#undef bn_mul1_low +#undef bn_muln_low +#undef bn_muld_low +#undef bn_sqra_low +#undef bn_sqrn_low +#undef bn_divn_low +#undef bn_div1_low +#undef bn_modn_low + +#define bn_add1_low PREFIX(bn_add1_low) +#define bn_addn_low PREFIX(bn_addn_low) +#define bn_sub1_low PREFIX(bn_sub1_low) +#define bn_subn_low PREFIX(bn_subn_low) +#define bn_cmp1_low PREFIX(bn_cmp1_low) +#define bn_cmpn_low PREFIX(bn_cmpn_low) +#define bn_lsh1_low PREFIX(bn_lsh1_low) +#define bn_lshb_low PREFIX(bn_lshb_low) +#define bn_lshd_low PREFIX(bn_lshd_low) +#define bn_rsh1_low PREFIX(bn_rsh1_low) +#define bn_rshb_low PREFIX(bn_rshb_low) +#define bn_rshd_low PREFIX(bn_rshd_low) +#define bn_mula_low PREFIX(bn_mula_low) +#define bn_mul1_low PREFIX(bn_mul1_low) +#define bn_muln_low PREFIX(bn_muln_low) +#define bn_muld_low PREFIX(bn_muld_low) +#define bn_sqra_low PREFIX(bn_sqra_low) +#define bn_sqrn_low PREFIX(bn_sqrn_low) +#define bn_divn_low PREFIX(bn_divn_low) +#define bn_div1_low PREFIX(bn_div1_low) +#define bn_modn_low PREFIX(bn_modn_low) + +#undef fp_st +#undef fp_t +#define fp_st PREFIX(fp_st) +#define fp_t PREFIX(fp_t) + +#undef fp_prime_init +#undef fp_prime_clean +#undef fp_prime_get +#undef fp_prime_get_rdc +#undef fp_prime_get_conv +#undef fp_prime_get_mod8 +#undef fp_prime_get_sps +#undef fp_prime_get_qnr +#undef fp_prime_get_cnr +#undef fp_prime_get_2ad +#undef fp_param_get +#undef fp_prime_set_dense +#undef fp_prime_set_pmers +#undef fp_prime_set_pairf +#undef fp_prime_calc +#undef fp_prime_conv +#undef fp_prime_conv_dig +#undef fp_prime_back +#undef fp_param_set +#undef fp_param_set_any +#undef fp_param_set_any_dense +#undef fp_param_set_any_pmers +#undef fp_param_set_any_tower +#undef fp_param_print +#undef fp_prime_get_par +#undef fp_prime_get_par_sps +#undef fp_param_get_sps +#undef fp_copy +#undef fp_zero +#undef fp_is_zero +#undef fp_is_even +#undef fp_get_bit +#undef fp_set_bit +#undef fp_set_dig +#undef fp_bits +#undef fp_rand +#undef fp_print +#undef fp_size_str +#undef fp_read_str +#undef fp_write_str +#undef fp_read_bin +#undef fp_write_bin +#undef fp_cmp +#undef fp_cmp_dig +#undef fp_add_basic +#undef fp_add_integ +#undef fp_add_dig +#undef fp_sub_basic +#undef fp_sub_integ +#undef fp_sub_dig +#undef fp_neg_basic +#undef fp_neg_integ +#undef fp_dbl_basic +#undef fp_dbl_integ +#undef fp_hlv_basic +#undef fp_hlv_integ +#undef fp_mul_basic +#undef fp_mul_comba +#undef fp_mul_integ +#undef fp_mul_karat +#undef fp_mul_dig +#undef fp_sqr_basic +#undef fp_sqr_comba +#undef fp_sqr_integ +#undef fp_sqr_karat +#undef fp_lsh +#undef fp_rsh +#undef fp_rdc_basic +#undef fp_rdc_monty_basic +#undef fp_rdc_monty_comba +#undef fp_rdc_quick +#undef fp_inv_basic +#undef fp_inv_binar +#undef fp_inv_monty +#undef fp_inv_exgcd +#undef fp_inv_divst +#undef fp_inv_lower +#undef fp_inv_sim +#undef fp_exp_basic +#undef fp_exp_slide +#undef fp_exp_monty +#undef fp_srt + +#define fp_prime_init PREFIX(fp_prime_init) +#define fp_prime_clean PREFIX(fp_prime_clean) +#define fp_prime_get PREFIX(fp_prime_get) +#define fp_prime_get_rdc PREFIX(fp_prime_get_rdc) +#define fp_prime_get_conv PREFIX(fp_prime_get_conv) +#define fp_prime_get_mod8 PREFIX(fp_prime_get_mod8) +#define fp_prime_get_sps PREFIX(fp_prime_get_sps) +#define fp_prime_get_qnr PREFIX(fp_prime_get_qnr) +#define fp_prime_get_cnr PREFIX(fp_prime_get_cnr) +#define fp_prime_get_2ad PREFIX(fp_prime_get_2ad) +#define fp_param_get PREFIX(fp_param_get) +#define fp_prime_set_dense PREFIX(fp_prime_set_dense) +#define fp_prime_set_pmers PREFIX(fp_prime_set_pmers) +#define fp_prime_set_pairf PREFIX(fp_prime_set_pairf) +#define fp_prime_calc PREFIX(fp_prime_calc) +#define fp_prime_conv PREFIX(fp_prime_conv) +#define fp_prime_conv_dig PREFIX(fp_prime_conv_dig) +#define fp_prime_back PREFIX(fp_prime_back) +#define fp_param_set PREFIX(fp_param_set) +#define fp_param_set_any PREFIX(fp_param_set_any) +#define fp_param_set_any_dense PREFIX(fp_param_set_any_dense) +#define fp_param_set_any_pmers PREFIX(fp_param_set_any_pmers) +#define fp_param_set_any_tower PREFIX(fp_param_set_any_tower) +#define fp_param_print PREFIX(fp_param_print) +#define fp_prime_get_par PREFIX(fp_prime_get_par) +#define fp_prime_get_par_sps PREFIX(fp_prime_get_par_sps) +#define fp_param_get_sps PREFIX(fp_param_get_sps) +#define fp_copy PREFIX(fp_copy) +#define fp_zero PREFIX(fp_zero) +#define fp_is_zero PREFIX(fp_is_zero) +#define fp_is_even PREFIX(fp_is_even) +#define fp_get_bit PREFIX(fp_get_bit) +#define fp_set_bit PREFIX(fp_set_bit) +#define fp_set_dig PREFIX(fp_set_dig) +#define fp_bits PREFIX(fp_bits) +#define fp_rand PREFIX(fp_rand) +#define fp_print PREFIX(fp_print) +#define fp_size_str PREFIX(fp_size_str) +#define fp_read_str PREFIX(fp_read_str) +#define fp_write_str PREFIX(fp_write_str) +#define fp_read_bin PREFIX(fp_read_bin) +#define fp_write_bin PREFIX(fp_write_bin) +#define fp_cmp PREFIX(fp_cmp) +#define fp_cmp_dig PREFIX(fp_cmp_dig) +#define fp_add_basic PREFIX(fp_add_basic) +#define fp_add_integ PREFIX(fp_add_integ) +#define fp_add_dig PREFIX(fp_add_dig) +#define fp_sub_basic PREFIX(fp_sub_basic) +#define fp_sub_integ PREFIX(fp_sub_integ) +#define fp_sub_dig PREFIX(fp_sub_dig) +#define fp_neg_basic PREFIX(fp_neg_basic) +#define fp_neg_integ PREFIX(fp_neg_integ) +#define fp_dbl_basic PREFIX(fp_dbl_basic) +#define fp_dbl_integ PREFIX(fp_dbl_integ) +#define fp_hlv_basic PREFIX(fp_hlv_basic) +#define fp_hlv_integ PREFIX(fp_hlv_integ) +#define fp_mul_basic PREFIX(fp_mul_basic) +#define fp_mul_comba PREFIX(fp_mul_comba) +#define fp_mul_integ PREFIX(fp_mul_integ) +#define fp_mul_karat PREFIX(fp_mul_karat) +#define fp_mul_dig PREFIX(fp_mul_dig) +#define fp_sqr_basic PREFIX(fp_sqr_basic) +#define fp_sqr_comba PREFIX(fp_sqr_comba) +#define fp_sqr_integ PREFIX(fp_sqr_integ) +#define fp_sqr_karat PREFIX(fp_sqr_karat) +#define fp_lsh PREFIX(fp_lsh) +#define fp_rsh PREFIX(fp_rsh) +#define fp_rdc_basic PREFIX(fp_rdc_basic) +#define fp_rdc_monty_basic PREFIX(fp_rdc_monty_basic) +#define fp_rdc_monty_comba PREFIX(fp_rdc_monty_comba) +#define fp_rdc_quick PREFIX(fp_rdc_quick) +#define fp_inv_basic PREFIX(fp_inv_basic) +#define fp_inv_binar PREFIX(fp_inv_binar) +#define fp_inv_monty PREFIX(fp_inv_monty) +#define fp_inv_exgcd PREFIX(fp_inv_exgcd) +#define fp_inv_divst PREFIX(fp_inv_divst) +#define fp_inv_lower PREFIX(fp_inv_lower) +#define fp_inv_sim PREFIX(fp_inv_sim) +#define fp_exp_basic PREFIX(fp_exp_basic) +#define fp_exp_slide PREFIX(fp_exp_slide) +#define fp_exp_monty PREFIX(fp_exp_monty) +#define fp_srt PREFIX(fp_srt) + +#undef fp_add1_low +#undef fp_addn_low +#undef fp_addm_low +#undef fp_addd_low +#undef fp_addc_low +#undef fp_sub1_low +#undef fp_subn_low +#undef fp_subm_low +#undef fp_subd_low +#undef fp_subc_low +#undef fp_negm_low +#undef fp_dbln_low +#undef fp_dblm_low +#undef fp_hlvm_low +#undef fp_hlvd_low +#undef fp_lsh1_low +#undef fp_lshb_low +#undef fp_lshd_low +#undef fp_rsh1_low +#undef fp_rshb_low +#undef fp_rshd_low +#undef fp_mula_low +#undef fp_mul1_low +#undef fp_muln_low +#undef fp_mulm_low +#undef fp_sqrn_low +#undef fp_sqrm_low +#undef fp_rdcs_low +#undef fp_rdcn_low +#undef fp_invm_low + +#define fp_add1_low PREFIX(fp_add1_low) +#define fp_addn_low PREFIX(fp_addn_low) +#define fp_addm_low PREFIX(fp_addm_low) +#define fp_addd_low PREFIX(fp_addd_low) +#define fp_addc_low PREFIX(fp_addc_low) +#define fp_sub1_low PREFIX(fp_sub1_low) +#define fp_subn_low PREFIX(fp_subn_low) +#define fp_subm_low PREFIX(fp_subm_low) +#define fp_subd_low PREFIX(fp_subd_low) +#define fp_subc_low PREFIX(fp_subc_low) +#define fp_negm_low PREFIX(fp_negm_low) +#define fp_dbln_low PREFIX(fp_dbln_low) +#define fp_dblm_low PREFIX(fp_dblm_low) +#define fp_hlvm_low PREFIX(fp_hlvm_low) +#define fp_hlvd_low PREFIX(fp_hlvd_low) +#define fp_lsh1_low PREFIX(fp_lsh1_low) +#define fp_lshb_low PREFIX(fp_lshb_low) +#define fp_lshd_low PREFIX(fp_lshd_low) +#define fp_rsh1_low PREFIX(fp_rsh1_low) +#define fp_rshb_low PREFIX(fp_rshb_low) +#define fp_rshd_low PREFIX(fp_rshd_low) +#define fp_mula_low PREFIX(fp_mula_low) +#define fp_mul1_low PREFIX(fp_mul1_low) +#define fp_muln_low PREFIX(fp_muln_low) +#define fp_mulm_low PREFIX(fp_mulm_low) +#define fp_sqrn_low PREFIX(fp_sqrn_low) +#define fp_sqrm_low PREFIX(fp_sqrm_low) +#define fp_rdcs_low PREFIX(fp_rdcs_low) +#define fp_rdcn_low PREFIX(fp_rdcn_low) +#define fp_invm_low PREFIX(fp_invm_low) + +#undef fp_st +#undef fp_t +#define fp_st PREFIX(fp_st) +#define fp_t PREFIX(fp_t) + +#undef fb_poly_init +#undef fb_poly_clean +#undef fb_poly_get +#undef fb_poly_set_dense +#undef fb_poly_set_trino +#undef fb_poly_set_penta +#undef fb_poly_get_srz +#undef fb_poly_tab_srz +#undef fb_poly_tab_sqr +#undef fb_poly_get_chain +#undef fb_poly_get_rdc +#undef fb_poly_get_trc +#undef fb_poly_get_slv +#undef fb_param_set +#undef fb_param_set_any +#undef fb_param_print +#undef fb_poly_add +#undef fb_copy +#undef fb_neg +#undef fb_zero +#undef fb_is_zero +#undef fb_get_bit +#undef fb_set_bit +#undef fb_set_dig +#undef fb_bits +#undef fb_rand +#undef fb_print +#undef fb_size_str +#undef fb_read_str +#undef fb_write_str +#undef fb_read_bin +#undef fb_write_bin +#undef fb_cmp +#undef fb_cmp_dig +#undef fb_add +#undef fb_add_dig +#undef fb_mul_basic +#undef fb_mul_integ +#undef fb_mul_lodah +#undef fb_mul_dig +#undef fb_mul_karat +#undef fb_sqr_basic +#undef fb_sqr_integ +#undef fb_sqr_quick +#undef fb_lsh +#undef fb_rsh +#undef fb_rdc_basic +#undef fb_rdc_quick +#undef fb_srt_basic +#undef fb_srt_quick +#undef fb_trc_basic +#undef fb_trc_quick +#undef fb_inv_basic +#undef fb_inv_binar +#undef fb_inv_exgcd +#undef fb_inv_almos +#undef fb_inv_itoht +#undef fb_inv_bruch +#undef fb_inv_ctaia +#undef fb_inv_lower +#undef fb_inv_sim +#undef fb_exp_2b +#undef fb_exp_basic +#undef fb_exp_slide +#undef fb_exp_monty +#undef fb_slv_basic +#undef fb_slv_quick +#undef fb_itr_basic +#undef fb_itr_pre_quick +#undef fb_itr_quick + +#define fb_poly_init PREFIX(fb_poly_init) +#define fb_poly_clean PREFIX(fb_poly_clean) +#define fb_poly_get PREFIX(fb_poly_get) +#define fb_poly_set_dense PREFIX(fb_poly_set_dense) +#define fb_poly_set_trino PREFIX(fb_poly_set_trino) +#define fb_poly_set_penta PREFIX(fb_poly_set_penta) +#define fb_poly_get_srz PREFIX(fb_poly_get_srz) +#define fb_poly_tab_srz PREFIX(fb_poly_tab_srz) +#define fb_poly_tab_sqr PREFIX(fb_poly_tab_sqr) +#define fb_poly_get_chain PREFIX(fb_poly_get_chain) +#define fb_poly_get_rdc PREFIX(fb_poly_get_rdc) +#define fb_poly_get_trc PREFIX(fb_poly_get_trc) +#define fb_poly_get_slv PREFIX(fb_poly_get_slv) +#define fb_param_set PREFIX(fb_param_set) +#define fb_param_set_any PREFIX(fb_param_set_any) +#define fb_param_print PREFIX(fb_param_print) +#define fb_poly_add PREFIX(fb_poly_add) +#define fb_copy PREFIX(fb_copy) +#define fb_neg PREFIX(fb_neg) +#define fb_zero PREFIX(fb_zero) +#define fb_is_zero PREFIX(fb_is_zero) +#define fb_get_bit PREFIX(fb_get_bit) +#define fb_set_bit PREFIX(fb_set_bit) +#define fb_set_dig PREFIX(fb_set_dig) +#define fb_bits PREFIX(fb_bits) +#define fb_rand PREFIX(fb_rand) +#define fb_print PREFIX(fb_print) +#define fb_size_str PREFIX(fb_size_str) +#define fb_read_str PREFIX(fb_read_str) +#define fb_write_str PREFIX(fb_write_str) +#define fb_read_bin PREFIX(fb_read_bin) +#define fb_write_bin PREFIX(fb_write_bin) +#define fb_cmp PREFIX(fb_cmp) +#define fb_cmp_dig PREFIX(fb_cmp_dig) +#define fb_add PREFIX(fb_add) +#define fb_add_dig PREFIX(fb_add_dig) +#define fb_mul_basic PREFIX(fb_mul_basic) +#define fb_mul_integ PREFIX(fb_mul_integ) +#define fb_mul_lodah PREFIX(fb_mul_lodah) +#define fb_mul_dig PREFIX(fb_mul_dig) +#define fb_mul_karat PREFIX(fb_mul_karat) +#define fb_sqr_basic PREFIX(fb_sqr_basic) +#define fb_sqr_integ PREFIX(fb_sqr_integ) +#define fb_sqr_quick PREFIX(fb_sqr_quick) +#define fb_lsh PREFIX(fb_lsh) +#define fb_rsh PREFIX(fb_rsh) +#define fb_rdc_basic PREFIX(fb_rdc_basic) +#define fb_rdc_quick PREFIX(fb_rdc_quick) +#define fb_srt_basic PREFIX(fb_srt_basic) +#define fb_srt_quick PREFIX(fb_srt_quick) +#define fb_trc_basic PREFIX(fb_trc_basic) +#define fb_trc_quick PREFIX(fb_trc_quick) +#define fb_inv_basic PREFIX(fb_inv_basic) +#define fb_inv_binar PREFIX(fb_inv_binar) +#define fb_inv_exgcd PREFIX(fb_inv_exgcd) +#define fb_inv_almos PREFIX(fb_inv_almos) +#define fb_inv_itoht PREFIX(fb_inv_itoht) +#define fb_inv_bruch PREFIX(fb_inv_bruch) +#define fb_inv_ctaia PREFIX(fb_inv_ctaia) +#define fb_inv_lower PREFIX(fb_inv_lower) +#define fb_inv_sim PREFIX(fb_inv_sim) +#define fb_exp_2b PREFIX(fb_exp_2b) +#define fb_exp_basic PREFIX(fb_exp_basic) +#define fb_exp_slide PREFIX(fb_exp_slide) +#define fb_exp_monty PREFIX(fb_exp_monty) +#define fb_slv_basic PREFIX(fb_slv_basic) +#define fb_slv_quick PREFIX(fb_slv_quick) +#define fb_itr_basic PREFIX(fb_itr_basic) +#define fb_itr_pre_quick PREFIX(fb_itr_pre_quick) +#define fb_itr_quick PREFIX(fb_itr_quick) + +#undef fb_add1_low +#undef fb_addn_low +#undef fb_addd_low +#undef fb_lsh1_low +#undef fb_lshb_low +#undef fb_lshd_low +#undef fb_rsh1_low +#undef fb_rshb_low +#undef fb_rshd_low +#undef fb_lsha_low +#undef fb_mul1_low +#undef fb_muln_low +#undef fb_muld_low +#undef fb_mulm_low +#undef fb_sqrn_low +#undef fb_sqrl_low +#undef fb_sqrm_low +#undef fb_itrn_low +#undef fb_srtn_low +#undef fb_slvn_low +#undef fb_trcn_low +#undef fb_rdcn_low +#undef fb_rdc1_low +#undef fb_invn_low + +#define fb_add1_low PREFIX(fb_add1_low) +#define fb_addn_low PREFIX(fb_addn_low) +#define fb_addd_low PREFIX(fb_addd_low) +#define fb_lsh1_low PREFIX(fb_lsh1_low) +#define fb_lshb_low PREFIX(fb_lshb_low) +#define fb_lshd_low PREFIX(fb_lshd_low) +#define fb_rsh1_low PREFIX(fb_rsh1_low) +#define fb_rshb_low PREFIX(fb_rshb_low) +#define fb_rshd_low PREFIX(fb_rshd_low) +#define fb_lsha_low PREFIX(fb_lsha_low) +#define fb_mul1_low PREFIX(fb_mul1_low) +#define fb_muln_low PREFIX(fb_muln_low) +#define fb_muld_low PREFIX(fb_muld_low) +#define fb_mulm_low PREFIX(fb_mulm_low) +#define fb_sqrn_low PREFIX(fb_sqrn_low) +#define fb_sqrl_low PREFIX(fb_sqrl_low) +#define fb_sqrm_low PREFIX(fb_sqrm_low) +#define fb_itrn_low PREFIX(fb_itrn_low) +#define fb_srtn_low PREFIX(fb_srtn_low) +#define fb_slvn_low PREFIX(fb_slvn_low) +#define fb_trcn_low PREFIX(fb_trcn_low) +#define fb_rdcn_low PREFIX(fb_rdcn_low) +#define fb_rdc1_low PREFIX(fb_rdc1_low) +#define fb_invn_low PREFIX(fb_invn_low) + +#undef ep_st +#undef ep_t +#define ep_st PREFIX(ep_st) +#define ep_t PREFIX(ep_t) + +#undef ep_curve_init +#undef ep_curve_clean +#undef ep_curve_get_a +#undef ep_curve_get_b +#undef ep_curve_get_beta +#undef ep_curve_get_v1 +#undef ep_curve_get_v2 +#undef ep_curve_opt_a +#undef ep_curve_opt_b +#undef ep_curve_is_endom +#undef ep_curve_is_super +#undef ep_curve_is_pairf +#undef ep_curve_is_ctmap +#undef ep_curve_get_gen +#undef ep_curve_get_tab +#undef ep_curve_get_ord +#undef ep_curve_get_cof +#undef ep_curve_get_iso +#undef ep_curve_set_plain +#undef ep_curve_set_super +#undef ep_curve_set_endom +#undef ep_param_set +#undef ep_param_set_any +#undef ep_param_set_any_plain +#undef ep_param_set_any_endom +#undef ep_param_set_any_super +#undef ep_param_set_any_pairf +#undef ep_param_get +#undef ep_param_print +#undef ep_param_level +#undef ep_param_embed +#undef ep_is_infty +#undef ep_set_infty +#undef ep_copy +#undef ep_cmp +#undef ep_rand +#undef ep_rhs +#undef ep_is_valid +#undef ep_tab +#undef ep_print +#undef ep_size_bin +#undef ep_read_bin +#undef ep_write_bin +#undef ep_neg_basic +#undef ep_neg_projc +#undef ep_add_basic +#undef ep_add_slp_basic +#undef ep_add_projc +#undef ep_sub_basic +#undef ep_sub_projc +#undef ep_dbl_basic +#undef ep_dbl_slp_basic +#undef ep_dbl_projc +#undef ep_mul_basic +#undef ep_mul_slide +#undef ep_mul_monty +#undef ep_mul_lwnaf +#undef ep_mul_lwreg +#undef ep_mul_gen +#undef ep_mul_dig +#undef ep_mul_pre_basic +#undef ep_mul_pre_yaowi +#undef ep_mul_pre_nafwi +#undef ep_mul_pre_combs +#undef ep_mul_pre_combd +#undef ep_mul_pre_lwnaf +#undef ep_mul_fix_basic +#undef ep_mul_fix_yaowi +#undef ep_mul_fix_nafwi +#undef ep_mul_fix_combs +#undef ep_mul_fix_combd +#undef ep_mul_fix_lwnaf +#undef ep_mul_sim_basic +#undef ep_mul_sim_trick +#undef ep_mul_sim_inter +#undef ep_mul_sim_joint +#undef ep_mul_sim_gen +#undef ep_mul_sim_dig +#undef ep_norm +#undef ep_norm_sim +#undef ep_map +#undef ep_map_dst +#undef ep_pck +#undef ep_upk + +#define ep_curve_init PREFIX(ep_curve_init) +#define ep_curve_clean PREFIX(ep_curve_clean) +#define ep_curve_get_a PREFIX(ep_curve_get_a) +#define ep_curve_get_b PREFIX(ep_curve_get_b) +#define ep_curve_get_beta PREFIX(ep_curve_get_beta) +#define ep_curve_get_v1 PREFIX(ep_curve_get_v1) +#define ep_curve_get_v2 PREFIX(ep_curve_get_v2) +#define ep_curve_opt_a PREFIX(ep_curve_opt_a) +#define ep_curve_opt_b PREFIX(ep_curve_opt_b) +#define ep_curve_is_endom PREFIX(ep_curve_is_endom) +#define ep_curve_is_super PREFIX(ep_curve_is_super) +#define ep_curve_is_pairf PREFIX(ep_curve_is_pairf) +#define ep_curve_is_ctmap PREFIX(ep_curve_is_ctmap) +#define ep_curve_get_gen PREFIX(ep_curve_get_gen) +#define ep_curve_get_tab PREFIX(ep_curve_get_tab) +#define ep_curve_get_ord PREFIX(ep_curve_get_ord) +#define ep_curve_get_cof PREFIX(ep_curve_get_cof) +#define ep_curve_get_iso PREFIX(ep_curve_get_iso) +#define ep_curve_set_plain PREFIX(ep_curve_set_plain) +#define ep_curve_set_super PREFIX(ep_curve_set_super) +#define ep_curve_set_endom PREFIX(ep_curve_set_endom) +#define ep_param_set PREFIX(ep_param_set) +#define ep_param_set_any PREFIX(ep_param_set_any) +#define ep_param_set_any_plain PREFIX(ep_param_set_any_plain) +#define ep_param_set_any_endom PREFIX(ep_param_set_any_endom) +#define ep_param_set_any_super PREFIX(ep_param_set_any_super) +#define ep_param_set_any_pairf PREFIX(ep_param_set_any_pairf) +#define ep_param_get PREFIX(ep_param_get) +#define ep_param_print PREFIX(ep_param_print) +#define ep_param_level PREFIX(ep_param_level) +#define ep_param_embed PREFIX(ep_param_embed) +#define ep_is_infty PREFIX(ep_is_infty) +#define ep_set_infty PREFIX(ep_set_infty) +#define ep_copy PREFIX(ep_copy) +#define ep_cmp PREFIX(ep_cmp) +#define ep_rand PREFIX(ep_rand) +#define ep_rhs PREFIX(ep_rhs) +#define ep_is_valid PREFIX(ep_is_valid) +#define ep_tab PREFIX(ep_tab) +#define ep_print PREFIX(ep_print) +#define ep_size_bin PREFIX(ep_size_bin) +#define ep_read_bin PREFIX(ep_read_bin) +#define ep_write_bin PREFIX(ep_write_bin) +#define ep_neg_basic PREFIX(ep_neg_basic) +#define ep_neg_projc PREFIX(ep_neg_projc) +#define ep_add_basic PREFIX(ep_add_basic) +#define ep_add_slp_basic PREFIX(ep_add_slp_basic) +#define ep_add_projc PREFIX(ep_add_projc) +#define ep_sub_basic PREFIX(ep_sub_basic) +#define ep_sub_projc PREFIX(ep_sub_projc) +#define ep_dbl_basic PREFIX(ep_dbl_basic) +#define ep_dbl_slp_basic PREFIX(ep_dbl_slp_basic) +#define ep_dbl_projc PREFIX(ep_dbl_projc) +#define ep_mul_basic PREFIX(ep_mul_basic) +#define ep_mul_slide PREFIX(ep_mul_slide) +#define ep_mul_monty PREFIX(ep_mul_monty) +#define ep_mul_lwnaf PREFIX(ep_mul_lwnaf) +#define ep_mul_lwreg PREFIX(ep_mul_lwreg) +#define ep_mul_gen PREFIX(ep_mul_gen) +#define ep_mul_dig PREFIX(ep_mul_dig) +#define ep_mul_pre_basic PREFIX(ep_mul_pre_basic) +#define ep_mul_pre_yaowi PREFIX(ep_mul_pre_yaowi) +#define ep_mul_pre_nafwi PREFIX(ep_mul_pre_nafwi) +#define ep_mul_pre_combs PREFIX(ep_mul_pre_combs) +#define ep_mul_pre_combd PREFIX(ep_mul_pre_combd) +#define ep_mul_pre_lwnaf PREFIX(ep_mul_pre_lwnaf) +#define ep_mul_fix_basic PREFIX(ep_mul_fix_basic) +#define ep_mul_fix_yaowi PREFIX(ep_mul_fix_yaowi) +#define ep_mul_fix_nafwi PREFIX(ep_mul_fix_nafwi) +#define ep_mul_fix_combs PREFIX(ep_mul_fix_combs) +#define ep_mul_fix_combd PREFIX(ep_mul_fix_combd) +#define ep_mul_fix_lwnaf PREFIX(ep_mul_fix_lwnaf) +#define ep_mul_sim_basic PREFIX(ep_mul_sim_basic) +#define ep_mul_sim_trick PREFIX(ep_mul_sim_trick) +#define ep_mul_sim_inter PREFIX(ep_mul_sim_inter) +#define ep_mul_sim_joint PREFIX(ep_mul_sim_joint) +#define ep_mul_sim_gen PREFIX(ep_mul_sim_gen) +#define ep_mul_sim_dig PREFIX(ep_mul_sim_dig) +#define ep_norm PREFIX(ep_norm) +#define ep_norm_sim PREFIX(ep_norm_sim) +#define ep_map PREFIX(ep_map) +#define ep_map_dst PREFIX(ep_map_dst) +#define ep_pck PREFIX(ep_pck) +#define ep_upk PREFIX(ep_upk) + +#undef ed_st +#undef ed_t +#define ed_st PREFIX(ed_st) +#define ed_t PREFIX(ed_t) + +#undef ed_param_set +#undef ed_param_set_any +#undef ed_param_get +#undef ed_curve_get_ord +#undef ed_curve_get_gen +#undef ed_curve_get_tab +#undef ed_curve_get_cof +#undef ed_param_print +#undef ed_param_level +#undef ed_projc_to_extnd +#undef ed_rand +#undef ed_rhs +#undef ed_copy +#undef ed_cmp +#undef ed_set_infty +#undef ed_is_infty +#undef ed_neg_basic +#undef ed_neg_projc +#undef ed_add_basic +#undef ed_add_projc +#undef ed_add_extnd +#undef ed_sub_basic +#undef ed_sub_projc +#undef ed_sub_extnd +#undef ed_dbl_basic +#undef ed_dbl_projc +#undef ed_dbl_extnd +#undef ed_norm +#undef ed_norm_sim +#undef ed_map +#undef ed_curve_init +#undef ed_curve_clean +#undef ed_mul_pre_basic +#undef ed_mul_pre_yaowi +#undef ed_mul_pre_nafwi +#undef ed_mul_pre_combs +#undef ed_mul_pre_combd +#undef ed_mul_pre_lwnaf +#undef ed_mul_fix_basic +#undef ed_mul_fix_yaowi +#undef ed_mul_fix_nafwi +#undef ed_mul_fix_combs +#undef ed_mul_fix_combd +#undef ed_mul_fix_lwnaf +#undef ed_mul_fix_lwnaf_mixed +#undef ed_mul_gen +#undef ed_mul_dig +#undef ed_mul_sim_basic +#undef ed_mul_sim_trick +#undef ed_mul_sim_inter +#undef ed_mul_sim_joint +#undef ed_mul_sim_gen +#undef ed_tab +#undef ed_print +#undef ed_is_valid +#undef ed_size_bin +#undef ed_read_bin +#undef ed_write_bin +#undef ed_mul_basic +#undef ed_mul_slide +#undef ed_mul_monty +#undef ed_mul_lwnaf +#undef ed_mul_lwreg +#undef ed_pck +#undef ed_upk + +#define ed_param_set PREFIX(ed_param_set) +#define ed_param_set_any PREFIX(ed_param_set_any) +#define ed_param_get PREFIX(ed_param_get) +#define ed_curve_get_ord PREFIX(ed_curve_get_ord) +#define ed_curve_get_gen PREFIX(ed_curve_get_gen) +#define ed_curve_get_tab PREFIX(ed_curve_get_tab) +#define ed_curve_get_cof PREFIX(ed_curve_get_cof) +#define ed_param_print PREFIX(ed_param_print) +#define ed_param_level PREFIX(ed_param_level) +#define ed_projc_to_extnd PREFIX(ed_projc_to_extnd) +#define ed_rand PREFIX(ed_rand) +#define ed_rhs PREFIX(ed_rhs) +#define ed_copy PREFIX(ed_copy) +#define ed_cmp PREFIX(ed_cmp) +#define ed_set_infty PREFIX(ed_set_infty) +#define ed_is_infty PREFIX(ed_is_infty) +#define ed_neg_basic PREFIX(ed_neg_basic) +#define ed_neg_projc PREFIX(ed_neg_projc) +#define ed_add_basic PREFIX(ed_add_basic) +#define ed_add_projc PREFIX(ed_add_projc) +#define ed_add_extnd PREFIX(ed_add_extnd) +#define ed_sub_basic PREFIX(ed_sub_basic) +#define ed_sub_projc PREFIX(ed_sub_projc) +#define ed_sub_extnd PREFIX(ed_sub_extnd) +#define ed_dbl_basic PREFIX(ed_dbl_basic) +#define ed_dbl_projc PREFIX(ed_dbl_projc) +#define ed_dbl_extnd PREFIX(ed_dbl_extnd) +#define ed_norm PREFIX(ed_norm) +#define ed_norm_sim PREFIX(ed_norm_sim) +#define ed_map PREFIX(ed_map) +#define ed_curve_init PREFIX(ed_curve_init) +#define ed_curve_clean PREFIX(ed_curve_clean) +#define ed_mul_pre_basic PREFIX(ed_mul_pre_basic) +#define ed_mul_pre_yaowi PREFIX(ed_mul_pre_yaowi) +#define ed_mul_pre_nafwi PREFIX(ed_mul_pre_nafwi) +#define ed_mul_pre_combs PREFIX(ed_mul_pre_combs) +#define ed_mul_pre_combd PREFIX(ed_mul_pre_combd) +#define ed_mul_pre_lwnaf PREFIX(ed_mul_pre_lwnaf) +#define ed_mul_fix_basic PREFIX(ed_mul_fix_basic) +#define ed_mul_fix_yaowi PREFIX(ed_mul_fix_yaowi) +#define ed_mul_fix_nafwi PREFIX(ed_mul_fix_nafwi) +#define ed_mul_fix_combs PREFIX(ed_mul_fix_combs) +#define ed_mul_fix_combd PREFIX(ed_mul_fix_combd) +#define ed_mul_fix_lwnaf PREFIX(ed_mul_fix_lwnaf) +#define ed_mul_fix_lwnaf_mixed PREFIX(ed_mul_fix_lwnaf_mixed) +#define ed_mul_gen PREFIX(ed_mul_gen) +#define ed_mul_dig PREFIX(ed_mul_dig) +#define ed_mul_sim_basic PREFIX(ed_mul_sim_basic) +#define ed_mul_sim_trick PREFIX(ed_mul_sim_trick) +#define ed_mul_sim_inter PREFIX(ed_mul_sim_inter) +#define ed_mul_sim_joint PREFIX(ed_mul_sim_joint) +#define ed_mul_sim_gen PREFIX(ed_mul_sim_gen) +#define ed_tab PREFIX(ed_tab) +#define ed_print PREFIX(ed_print) +#define ed_is_valid PREFIX(ed_is_valid) +#define ed_size_bin PREFIX(ed_size_bin) +#define ed_read_bin PREFIX(ed_read_bin) +#define ed_write_bin PREFIX(ed_write_bin) +#define ed_mul_basic PREFIX(ed_mul_basic) +#define ed_mul_slide PREFIX(ed_mul_slide) +#define ed_mul_monty PREFIX(ed_mul_monty) +#define ed_mul_lwnaf PREFIX(ed_mul_lwnaf) +#define ed_mul_lwreg PREFIX(ed_mul_lwreg) +#define ed_pck PREFIX(ed_pck) +#define ed_upk PREFIX(ed_upk) + +#undef eb_st +#undef eb_t +#define eb_st PREFIX(eb_st) +#define eb_t PREFIX(eb_t) + +#undef eb_curve_init +#undef eb_curve_clean +#undef eb_curve_get_a +#undef eb_curve_get_b +#undef eb_curve_opt_a +#undef eb_curve_opt_b +#undef eb_curve_is_kbltz +#undef eb_curve_get_gen +#undef eb_curve_get_tab +#undef eb_curve_get_ord +#undef eb_curve_get_cof +#undef eb_curve_set +#undef eb_param_set +#undef eb_param_set_any +#undef eb_param_set_any_plain +#undef eb_param_set_any_kbltz +#undef eb_param_get +#undef eb_param_print +#undef eb_param_level +#undef eb_is_infty +#undef eb_set_infty +#undef eb_copy +#undef eb_cmp +#undef eb_rand +#undef eb_rhs +#undef eb_is_valid +#undef eb_tab +#undef eb_print +#undef eb_size_bin +#undef eb_read_bin +#undef eb_write_bin +#undef eb_neg_basic +#undef eb_neg_projc +#undef eb_add_basic +#undef eb_add_projc +#undef eb_sub_basic +#undef eb_sub_projc +#undef eb_dbl_basic +#undef eb_dbl_projc +#undef eb_hlv +#undef eb_frb_basic +#undef eb_frb_projc +#undef eb_mul_basic +#undef eb_mul_lodah +#undef eb_mul_lwnaf +#undef eb_mul_rwnaf +#undef eb_mul_halve +#undef eb_mul_gen +#undef eb_mul_dig +#undef eb_mul_pre_basic +#undef eb_mul_pre_yaowi +#undef eb_mul_pre_nafwi +#undef eb_mul_pre_combs +#undef eb_mul_pre_combd +#undef eb_mul_pre_lwnaf +#undef eb_mul_fix_basic +#undef eb_mul_fix_yaowi +#undef eb_mul_fix_nafwi +#undef eb_mul_fix_combs +#undef eb_mul_fix_combd +#undef eb_mul_fix_lwnaf +#undef eb_mul_sim_basic +#undef eb_mul_sim_trick +#undef eb_mul_sim_inter +#undef eb_mul_sim_joint +#undef eb_mul_sim_gen +#undef eb_norm +#undef eb_norm_sim +#undef eb_map +#undef eb_pck +#undef eb_upk + +#define eb_curve_init PREFIX(eb_curve_init) +#define eb_curve_clean PREFIX(eb_curve_clean) +#define eb_curve_get_a PREFIX(eb_curve_get_a) +#define eb_curve_get_b PREFIX(eb_curve_get_b) +#define eb_curve_opt_a PREFIX(eb_curve_opt_a) +#define eb_curve_opt_b PREFIX(eb_curve_opt_b) +#define eb_curve_is_kbltz PREFIX(eb_curve_is_kbltz) +#define eb_curve_get_gen PREFIX(eb_curve_get_gen) +#define eb_curve_get_tab PREFIX(eb_curve_get_tab) +#define eb_curve_get_ord PREFIX(eb_curve_get_ord) +#define eb_curve_get_cof PREFIX(eb_curve_get_cof) +#define eb_curve_set PREFIX(eb_curve_set) +#define eb_param_set PREFIX(eb_param_set) +#define eb_param_set_any PREFIX(eb_param_set_any) +#define eb_param_set_any_plain PREFIX(eb_param_set_any_plain) +#define eb_param_set_any_kbltz PREFIX(eb_param_set_any_kbltz) +#define eb_param_get PREFIX(eb_param_get) +#define eb_param_print PREFIX(eb_param_print) +#define eb_param_level PREFIX(eb_param_level) +#define eb_is_infty PREFIX(eb_is_infty) +#define eb_set_infty PREFIX(eb_set_infty) +#define eb_copy PREFIX(eb_copy) +#define eb_cmp PREFIX(eb_cmp) +#define eb_rand PREFIX(eb_rand) +#define eb_rhs PREFIX(eb_rhs) +#define eb_is_valid PREFIX(eb_is_valid) +#define eb_tab PREFIX(eb_tab) +#define eb_print PREFIX(eb_print) +#define eb_size_bin PREFIX(eb_size_bin) +#define eb_read_bin PREFIX(eb_read_bin) +#define eb_write_bin PREFIX(eb_write_bin) +#define eb_neg_basic PREFIX(eb_neg_basic) +#define eb_neg_projc PREFIX(eb_neg_projc) +#define eb_add_basic PREFIX(eb_add_basic) +#define eb_add_projc PREFIX(eb_add_projc) +#define eb_sub_basic PREFIX(eb_sub_basic) +#define eb_sub_projc PREFIX(eb_sub_projc) +#define eb_dbl_basic PREFIX(eb_dbl_basic) +#define eb_dbl_projc PREFIX(eb_dbl_projc) +#define eb_hlv PREFIX(eb_hlv) +#define eb_frb_basic PREFIX(eb_frb_basic) +#define eb_frb_projc PREFIX(eb_frb_projc) +#define eb_mul_basic PREFIX(eb_mul_basic) +#define eb_mul_lodah PREFIX(eb_mul_lodah) +#define eb_mul_lwnaf PREFIX(eb_mul_lwnaf) +#define eb_mul_rwnaf PREFIX(eb_mul_rwnaf) +#define eb_mul_halve PREFIX(eb_mul_halve) +#define eb_mul_gen PREFIX(eb_mul_gen) +#define eb_mul_dig PREFIX(eb_mul_dig) +#define eb_mul_pre_basic PREFIX(eb_mul_pre_basic) +#define eb_mul_pre_yaowi PREFIX(eb_mul_pre_yaowi) +#define eb_mul_pre_nafwi PREFIX(eb_mul_pre_nafwi) +#define eb_mul_pre_combs PREFIX(eb_mul_pre_combs) +#define eb_mul_pre_combd PREFIX(eb_mul_pre_combd) +#define eb_mul_pre_lwnaf PREFIX(eb_mul_pre_lwnaf) +#define eb_mul_fix_basic PREFIX(eb_mul_fix_basic) +#define eb_mul_fix_yaowi PREFIX(eb_mul_fix_yaowi) +#define eb_mul_fix_nafwi PREFIX(eb_mul_fix_nafwi) +#define eb_mul_fix_combs PREFIX(eb_mul_fix_combs) +#define eb_mul_fix_combd PREFIX(eb_mul_fix_combd) +#define eb_mul_fix_lwnaf PREFIX(eb_mul_fix_lwnaf) +#define eb_mul_sim_basic PREFIX(eb_mul_sim_basic) +#define eb_mul_sim_trick PREFIX(eb_mul_sim_trick) +#define eb_mul_sim_inter PREFIX(eb_mul_sim_inter) +#define eb_mul_sim_joint PREFIX(eb_mul_sim_joint) +#define eb_mul_sim_gen PREFIX(eb_mul_sim_gen) +#define eb_norm PREFIX(eb_norm) +#define eb_norm_sim PREFIX(eb_norm_sim) +#define eb_map PREFIX(eb_map) +#define eb_pck PREFIX(eb_pck) +#define eb_upk PREFIX(eb_upk) + +#undef ep2_st +#undef ep2_t +#define ep2_st PREFIX(ep2_st) +#define ep2_t PREFIX(ep2_t) + +#undef ep2_curve_init +#undef ep2_curve_clean +#undef ep2_curve_get_a +#undef ep2_curve_get_b +#undef ep2_curve_get_vs +#undef ep2_curve_opt_a +#undef ep2_curve_opt_b +#undef ep2_curve_is_twist +#undef ep2_curve_is_ctmap +#undef ep2_curve_get_gen +#undef ep2_curve_get_tab +#undef ep2_curve_get_ord +#undef ep2_curve_get_cof +#undef ep2_curve_get_iso +#undef ep2_curve_set +#undef ep2_curve_set_twist +#undef ep2_is_infty +#undef ep2_set_infty +#undef ep2_copy +#undef ep2_cmp +#undef ep2_rand +#undef ep2_rhs +#undef ep2_is_valid +#undef ep2_tab +#undef ep2_print +#undef ep2_size_bin +#undef ep2_read_bin +#undef ep2_write_bin +#undef ep2_neg_basic +#undef ep2_neg_projc +#undef ep2_add_basic +#undef ep2_add_slp_basic +#undef ep2_sub_basic +#undef ep2_add_projc +#undef ep2_sub_projc +#undef ep2_dbl_basic +#undef ep2_dbl_slp_basic +#undef ep2_dbl_projc +#undef ep2_mul_basic +#undef ep2_mul_slide +#undef ep2_mul_monty +#undef ep2_mul_lwnaf +#undef ep2_mul_lwreg +#undef ep2_mul_gen +#undef ep2_mul_dig +#undef ep2_mul_pre_basic +#undef ep2_mul_pre_yaowi +#undef ep2_mul_pre_nafwi +#undef ep2_mul_pre_combs +#undef ep2_mul_pre_combd +#undef ep2_mul_pre_lwnaf +#undef ep2_mul_fix_basic +#undef ep2_mul_fix_yaowi +#undef ep2_mul_fix_nafwi +#undef ep2_mul_fix_combs +#undef ep2_mul_fix_combd +#undef ep2_mul_fix_lwnaf +#undef ep2_mul_sim_basic +#undef ep2_mul_sim_trick +#undef ep2_mul_sim_inter +#undef ep2_mul_sim_joint +#undef ep2_mul_sim_gen +#undef ep2_mul_sim_dig +#undef ep2_norm +#undef ep2_norm_sim +#undef ep2_map +#undef ep2_frb +#undef ep2_pck +#undef ep2_upk + +#define ep2_curve_init PREFIX(ep2_curve_init) +#define ep2_curve_clean PREFIX(ep2_curve_clean) +#define ep2_curve_get_a PREFIX(ep2_curve_get_a) +#define ep2_curve_get_b PREFIX(ep2_curve_get_b) +#define ep2_curve_get_vs PREFIX(ep2_curve_get_vs) +#define ep2_curve_opt_a PREFIX(ep2_curve_opt_a) +#define ep2_curve_opt_b PREFIX(ep2_curve_opt_b) +#define ep2_curve_is_twist PREFIX(ep2_curve_is_twist) +#define ep2_curve_is_ctmap PREFIX(ep2_curve_is_ctmap) +#define ep2_curve_get_gen PREFIX(ep2_curve_get_gen) +#define ep2_curve_get_tab PREFIX(ep2_curve_get_tab) +#define ep2_curve_get_ord PREFIX(ep2_curve_get_ord) +#define ep2_curve_get_cof PREFIX(ep2_curve_get_cof) +#define ep2_curve_get_iso PREFIX(ep2_curve_get_iso) +#define ep2_curve_set PREFIX(ep2_curve_set) +#define ep2_curve_set_twist PREFIX(ep2_curve_set_twist) +#define ep2_is_infty PREFIX(ep2_is_infty) +#define ep2_set_infty PREFIX(ep2_set_infty) +#define ep2_copy PREFIX(ep2_copy) +#define ep2_cmp PREFIX(ep2_cmp) +#define ep2_rand PREFIX(ep2_rand) +#define ep2_rhs PREFIX(ep2_rhs) +#define ep2_is_valid PREFIX(ep2_is_valid) +#define ep2_tab PREFIX(ep2_tab) +#define ep2_print PREFIX(ep2_print) +#define ep2_size_bin PREFIX(ep2_size_bin) +#define ep2_read_bin PREFIX(ep2_read_bin) +#define ep2_write_bin PREFIX(ep2_write_bin) +#define ep2_neg_basic PREFIX(ep2_neg_basic) +#define ep2_neg_projc PREFIX(ep2_neg_projc) +#define ep2_add_basic PREFIX(ep2_add_basic) +#define ep2_add_slp_basic PREFIX(ep2_add_slp_basic) +#define ep2_sub_basic PREFIX(ep2_sub_basic) +#define ep2_add_projc PREFIX(ep2_add_projc) +#define ep2_sub_projc PREFIX(ep2_sub_projc) +#define ep2_dbl_basic PREFIX(ep2_dbl_basic) +#define ep2_dbl_slp_basic PREFIX(ep2_dbl_slp_basic) +#define ep2_dbl_projc PREFIX(ep2_dbl_projc) +#define ep2_mul_basic PREFIX(ep2_mul_basic) +#define ep2_mul_slide PREFIX(ep2_mul_slide) +#define ep2_mul_monty PREFIX(ep2_mul_monty) +#define ep2_mul_lwnaf PREFIX(ep2_mul_lwnaf) +#define ep2_mul_lwreg PREFIX(ep2_mul_lwreg) +#define ep2_mul_gen PREFIX(ep2_mul_gen) +#define ep2_mul_dig PREFIX(ep2_mul_dig) +#define ep2_mul_pre_basic PREFIX(ep2_mul_pre_basic) +#define ep2_mul_pre_yaowi PREFIX(ep2_mul_pre_yaowi) +#define ep2_mul_pre_nafwi PREFIX(ep2_mul_pre_nafwi) +#define ep2_mul_pre_combs PREFIX(ep2_mul_pre_combs) +#define ep2_mul_pre_combd PREFIX(ep2_mul_pre_combd) +#define ep2_mul_pre_lwnaf PREFIX(ep2_mul_pre_lwnaf) +#define ep2_mul_fix_basic PREFIX(ep2_mul_fix_basic) +#define ep2_mul_fix_yaowi PREFIX(ep2_mul_fix_yaowi) +#define ep2_mul_fix_nafwi PREFIX(ep2_mul_fix_nafwi) +#define ep2_mul_fix_combs PREFIX(ep2_mul_fix_combs) +#define ep2_mul_fix_combd PREFIX(ep2_mul_fix_combd) +#define ep2_mul_fix_lwnaf PREFIX(ep2_mul_fix_lwnaf) +#define ep2_mul_sim_basic PREFIX(ep2_mul_sim_basic) +#define ep2_mul_sim_trick PREFIX(ep2_mul_sim_trick) +#define ep2_mul_sim_inter PREFIX(ep2_mul_sim_inter) +#define ep2_mul_sim_joint PREFIX(ep2_mul_sim_joint) +#define ep2_mul_sim_gen PREFIX(ep2_mul_sim_gen) +#define ep2_mul_sim_dig PREFIX(ep2_mul_sim_dig) +#define ep2_norm PREFIX(ep2_norm) +#define ep2_norm_sim PREFIX(ep2_norm_sim) +#define ep2_map PREFIX(ep2_map) +#define ep2_frb PREFIX(ep2_frb) +#define ep2_pck PREFIX(ep2_pck) +#define ep2_upk PREFIX(ep2_upk) + +#undef fp2_st +#undef fp2_t +#undef dv2_t +#define fp2_st PREFIX(fp2_st) +#define fp2_t PREFIX(fp2_t) +#define dv2_t PREFIX(dv2_t) +#undef fp3_st +#undef fp3_t +#undef dv3_t +#define fp3_st PREFIX(fp3_st) +#define fp3_t PREFIX(fp3_t) +#define dv3_t PREFIX(dv3_t) +#undef fp6_st +#undef fp6_t +#undef dv6_t +#define fp6_st PREFIX(fp6_st) +#define fp6_t PREFIX(fp6_t) +#define dv6_t PREFIX(dv6_t) +#undef fp9_st +#undef fp8_t +#undef dv8_t +#define fp8_st PREFIX(fp8_st) +#define fp8_t PREFIX(fp8_t) +#define dv8_t PREFIX(dv8_t) +#undef fp9_st +#undef fp9_t +#undef dv9_t +#define fp9_st PREFIX(fp9_st) +#define fp9_t PREFIX(fp9_t) +#define dv9_t PREFIX(dv9_t) +#undef fp12_st +#undef fp12_t +#undef dv12_t +#define fp12_st PREFIX(fp12_st) +#define fp12_t PREFIX(fp12_t) +#define dv12_t PREFIX(dv12_t) +#undef fp18_st +#undef fp18_t +#undef dv18_t +#define fp18_st PREFIX(fp18_st) +#define fp18_t PREFIX(fp18_t) +#define dv18_t PREFIX(dv18_t) +#undef fp24_st +#undef fp24_t +#undef dv24_t +#define fp24_st PREFIX(fp24_st) +#define fp24_t PREFIX(fp24_t) +#define dv24_t PREFIX(dv24_t) +#undef fp48_st +#undef fp48_t +#undef dv48_t +#define fp48_st PREFIX(fp48_st) +#define fp48_t PREFIX(fp48_t) +#define dv48_t PREFIX(dv48_t) +#undef fp54_st +#undef fp54_t +#undef dv54_t +#define fp54_st PREFIX(fp54_st) +#define fp54_t PREFIX(fp54_t) +#define dv54_t PREFIX(dv54_t) + +#undef fp2_field_init +#undef fp2_field_get_qnr +#undef fp2_copy +#undef fp2_zero +#undef fp2_is_zero +#undef fp2_rand +#undef fp2_print +#undef fp2_size_bin +#undef fp2_read_bin +#undef fp2_write_bin +#undef fp2_cmp +#undef fp2_cmp_dig +#undef fp2_set_dig +#undef fp2_add_basic +#undef fp2_add_integ +#undef fp2_add_dig +#undef fp2_sub_basic +#undef fp2_sub_integ +#undef fpt_sub_dig +#undef fp2_neg +#undef fp2_dbl_basic +#undef fp2_dbl_integ +#undef fp2_mul_basic +#undef fp2_mul_integ +#undef fp2_mul_art +#undef fp2_mul_nor_basic +#undef fp2_mul_nor_integ +#undef fp2_mul_frb +#undef fp2_mul_dig +#undef fp2_sqr_basic +#undef fp2_sqr_integ +#undef fp2_inv +#undef fp2_inv_cyc +#undef fp2_inv_sim +#undef fp2_test_cyc +#undef fp2_conv_cyc +#undef fp2_exp +#undef fp2_exp_dig +#undef fp2_exp_cyc +#undef fp2_frb +#undef fp2_srt +#undef fp2_pck +#undef fp2_upk + +#define fp2_field_init PREFIX(fp2_field_init) +#define fp2_field_get_qnr PREFIX(fp2_field_get_qnr) +#define fp2_copy PREFIX(fp2_copy) +#define fp2_zero PREFIX(fp2_zero) +#define fp2_is_zero PREFIX(fp2_is_zero) +#define fp2_rand PREFIX(fp2_rand) +#define fp2_print PREFIX(fp2_print) +#define fp2_size_bin PREFIX(fp2_size_bin) +#define fp2_read_bin PREFIX(fp2_read_bin) +#define fp2_write_bin PREFIX(fp2_write_bin) +#define fp2_cmp PREFIX(fp2_cmp) +#define fp2_cmp_dig PREFIX(fp2_cmp_dig) +#define fp2_set_dig PREFIX(fp2_set_dig) +#define fp2_add_basic PREFIX(fp2_add_basic) +#define fp2_add_integ PREFIX(fp2_add_integ) +#define fp2_add_dig PREFIX(fp2_add_dig) +#define fp2_sub_basic PREFIX(fp2_sub_basic) +#define fp2_sub_integ PREFIX(fp2_sub_integ) +#define fp2_sub_dig PREFIX(fp2_sub_dig) +#define fp2_neg PREFIX(fp2_neg) +#define fp2_dbl_basic PREFIX(fp2_dbl_basic) +#define fp2_dbl_integ PREFIX(fp2_dbl_integ) +#define fp2_mul_basic PREFIX(fp2_mul_basic) +#define fp2_mul_integ PREFIX(fp2_mul_integ) +#define fp2_mul_art PREFIX(fp2_mul_art) +#define fp2_mul_nor_basic PREFIX(fp2_mul_nor_basic) +#define fp2_mul_nor_integ PREFIX(fp2_mul_nor_integ) +#define fp2_mul_frb PREFIX(fp2_mul_frb) +#define fp2_mul_dig PREFIX(fp2_mul_dig) +#define fp2_sqr_basic PREFIX(fp2_sqr_basic) +#define fp2_sqr_integ PREFIX(fp2_sqr_integ) +#define fp2_inv PREFIX(fp2_inv) +#define fp2_inv_cyc PREFIX(fp2_inv_cyc) +#define fp2_inv_sim PREFIX(fp2_inv_sim) +#define fp2_test_cyc PREFIX(fp2_test_cyc) +#define fp2_conv_cyc PREFIX(fp2_conv_cyc) +#define fp2_exp PREFIX(fp2_exp) +#define fp2_exp_dig PREFIX(fp2_exp_dig) +#define fp2_exp_cyc PREFIX(fp2_exp_cyc) +#define fp2_frb PREFIX(fp2_frb) +#define fp2_srt PREFIX(fp2_srt) +#define fp2_pck PREFIX(fp2_pck) +#define fp2_upk PREFIX(fp2_upk) + +#undef fp2_addn_low +#undef fp2_addm_low +#undef fp2_addd_low +#undef fp2_addc_low +#undef fp2_subn_low +#undef fp2_subm_low +#undef fp2_subd_low +#undef fp2_subc_low +#undef fp2_dbln_low +#undef fp2_dblm_low +#undef fp2_norm_low +#undef fp2_norh_low +#undef fp2_nord_low +#undef fp2_muln_low +#undef fp2_mulc_low +#undef fp2_mulm_low +#undef fp2_sqrn_low +#undef fp2_sqrm_low +#undef fp2_rdcn_low + +#define fp2_addn_low PREFIX(fp2_addn_low) +#define fp2_addm_low PREFIX(fp2_addm_low) +#define fp2_addd_low PREFIX(fp2_addd_low) +#define fp2_addc_low PREFIX(fp2_addc_low) +#define fp2_subn_low PREFIX(fp2_subn_low) +#define fp2_subm_low PREFIX(fp2_subm_low) +#define fp2_subd_low PREFIX(fp2_subd_low) +#define fp2_subc_low PREFIX(fp2_subc_low) +#define fp2_dbln_low PREFIX(fp2_dbln_low) +#define fp2_dblm_low PREFIX(fp2_dblm_low) +#define fp2_norm_low PREFIX(fp2_norm_low) +#define fp2_norh_low PREFIX(fp2_norh_low) +#define fp2_nord_low PREFIX(fp2_nord_low) +#define fp2_muln_low PREFIX(fp2_muln_low) +#define fp2_mulc_low PREFIX(fp2_mulc_low) +#define fp2_mulm_low PREFIX(fp2_mulm_low) +#define fp2_sqrn_low PREFIX(fp2_sqrn_low) +#define fp2_sqrm_low PREFIX(fp2_sqrm_low) +#define fp2_rdcn_low PREFIX(fp2_rdcn_low) + +#undef fp3_field_init +#undef fp3_copy +#undef fp3_zero +#undef fp3_is_zero +#undef fp3_rand +#undef fp3_print +#undef fp3_size_bin +#undef fp3_read_bin +#undef fp3_write_bin +#undef fp3_cmp +#undef fp3_cmp_dig +#undef fp3_set_dig +#undef fp3_add_basic +#undef fp3_add_integ +#undef fp3_sub_basic +#undef fp3_sub_integ +#undef fp3_neg +#undef fp3_dbl_basic +#undef fp3_dbl_integ +#undef fp3_mul_basic +#undef fp3_mul_integ +#undef fp3_mul_nor +#undef fp3_mul_frb +#undef fp3_sqr_basic +#undef fp3_sqr_integ +#undef fp3_inv +#undef fp3_inv_sim +#undef fp3_exp +#undef fp3_frb +#undef fp3_srt + +#define fp3_field_init PREFIX(fp3_field_init) +#define fp3_copy PREFIX(fp3_copy) +#define fp3_zero PREFIX(fp3_zero) +#define fp3_is_zero PREFIX(fp3_is_zero) +#define fp3_rand PREFIX(fp3_rand) +#define fp3_print PREFIX(fp3_print) +#define fp3_size_bin PREFIX(fp3_size_bin) +#define fp3_read_bin PREFIX(fp3_read_bin) +#define fp3_write_bin PREFIX(fp3_write_bin) +#define fp3_cmp PREFIX(fp3_cmp) +#define fp3_cmp_dig PREFIX(fp3_cmp_dig) +#define fp3_set_dig PREFIX(fp3_set_dig) +#define fp3_add_basic PREFIX(fp3_add_basic) +#define fp3_add_integ PREFIX(fp3_add_integ) +#define fp3_sub_basic PREFIX(fp3_sub_basic) +#define fp3_sub_integ PREFIX(fp3_sub_integ) +#define fp3_neg PREFIX(fp3_neg) +#define fp3_dbl_basic PREFIX(fp3_dbl_basic) +#define fp3_dbl_integ PREFIX(fp3_dbl_integ) +#define fp3_mul_basic PREFIX(fp3_mul_basic) +#define fp3_mul_integ PREFIX(fp3_mul_integ) +#define fp3_mul_nor PREFIX(fp3_mul_nor) +#define fp3_mul_frb PREFIX(fp3_mul_frb) +#define fp3_sqr_basic PREFIX(fp3_sqr_basic) +#define fp3_sqr_integ PREFIX(fp3_sqr_integ) +#define fp3_inv PREFIX(fp3_inv) +#define fp3_inv_sim PREFIX(fp3_inv_sim) +#define fp3_exp PREFIX(fp3_exp) +#define fp3_frb PREFIX(fp3_frb) +#define fp3_srt PREFIX(fp3_srt) + +#undef fp3_addn_low +#undef fp3_addm_low +#undef fp3_addd_low +#undef fp3_addc_low +#undef fp3_subn_low +#undef fp3_subm_low +#undef fp3_subd_low +#undef fp3_subc_low +#undef fp3_dbln_low +#undef fp3_dblm_low +#undef fp3_nord_low +#undef fp3_muln_low +#undef fp3_mulc_low +#undef fp3_mulm_low +#undef fp3_sqrn_low +#undef fp3_sqrm_low +#undef fp3_rdcn_low + +#define fp3_addn_low PREFIX(fp3_addn_low) +#define fp3_addm_low PREFIX(fp3_addm_low) +#define fp3_addd_low PREFIX(fp3_addd_low) +#define fp3_addc_low PREFIX(fp3_addc_low) +#define fp3_subn_low PREFIX(fp3_subn_low) +#define fp3_subm_low PREFIX(fp3_subm_low) +#define fp3_subd_low PREFIX(fp3_subd_low) +#define fp3_subc_low PREFIX(fp3_subc_low) +#define fp3_dbln_low PREFIX(fp3_dbln_low) +#define fp3_dblm_low PREFIX(fp3_dblm_low) +#define fp3_nord_low PREFIX(fp3_nord_low) +#define fp3_muln_low PREFIX(fp3_muln_low) +#define fp3_mulc_low PREFIX(fp3_mulc_low) +#define fp3_mulm_low PREFIX(fp3_mulm_low) +#define fp3_sqrn_low PREFIX(fp3_sqrn_low) +#define fp3_sqrm_low PREFIX(fp3_sqrm_low) +#define fp3_rdcn_low PREFIX(fp3_rdcn_low) + +#undef fp4_copy +#undef fp4_zero +#undef fp4_is_zero +#undef fp4_rand +#undef fp4_print +#undef fp4_size_bin +#undef fp4_read_bin +#undef fp4_write_bin +#undef fp4_cmp +#undef fp4_cmp_dig +#undef fp4_set_dig +#undef fp4_add +#undef fp4_sub +#undef fp4_neg +#undef fp4_dbl +#undef fp4_mul_unr +#undef fp4_mul_basic +#undef fp4_mul_lazyr +#undef fp4_mul_art +#undef fp4_mul_dxs +#undef fp4_sqr_unr +#undef fp4_sqr_basic +#undef fp4_sqr_lazyr +#undef fp4_inv +#undef fp4_inv_cyc +#undef fp4_exp +#undef fp4_frb + +#define fp4_copy PREFIX(fp4_copy) +#define fp4_zero PREFIX(fp4_zero) +#define fp4_is_zero PREFIX(fp4_is_zero) +#define fp4_rand PREFIX(fp4_rand) +#define fp4_print PREFIX(fp4_print) +#define fp4_size_bin PREFIX(fp4_size_bin) +#define fp4_read_bin PREFIX(fp4_read_bin) +#define fp4_write_bin PREFIX(fp4_write_bin) +#define fp4_cmp PREFIX(fp4_cmp) +#define fp4_cmp_dig PREFIX(fp4_cmp_dig) +#define fp4_set_dig PREFIX(fp4_set_dig) +#define fp4_add PREFIX(fp4_add) +#define fp4_sub PREFIX(fp4_sub) +#define fp4_neg PREFIX(fp4_neg) +#define fp4_dbl PREFIX(fp4_dbl) +#define fp4_mul_unr PREFIX(fp4_mul_unr) +#define fp4_mul_basic PREFIX(fp4_mul_basic) +#define fp4_mul_lazyr PREFIX(fp4_mul_lazyr) +#define fp4_mul_art PREFIX(fp4_mul_art) +#define fp4_mul_dxs PREFIX(fp4_mul_dxs) +#define fp4_sqr_unr PREFIX(fp4_sqr_unr) +#define fp4_sqr_basic PREFIX(fp4_sqr_basic) +#define fp4_sqr_lazyr PREFIX(fp4_sqr_lazyr) +#define fp4_inv PREFIX(fp4_inv) +#define fp4_inv_cyc PREFIX(fp4_inv_cyc) +#define fp4_exp PREFIX(fp4_exp) +#define fp4_frb PREFIX(fp4_frb) + +#undef fp6_copy +#undef fp6_zero +#undef fp6_is_zero +#undef fp6_rand +#undef fp6_print +#undef fp6_size_bin +#undef fp6_read_bin +#undef fp6_write_bin +#undef fp6_cmp +#undef fp6_cmp_dig +#undef fp6_set_dig +#undef fp6_add +#undef fp6_sub +#undef fp6_neg +#undef fp6_dbl +#undef fp6_mul_unr +#undef fp6_mul_basic +#undef fp6_mul_lazyr +#undef fp6_mul_art +#undef fp6_mul_dxs +#undef fp6_sqr_unr +#undef fp6_sqr_basic +#undef fp6_sqr_lazyr +#undef fp6_inv +#undef fp6_exp +#undef fp6_frb + +#define fp6_copy PREFIX(fp6_copy) +#define fp6_zero PREFIX(fp6_zero) +#define fp6_is_zero PREFIX(fp6_is_zero) +#define fp6_rand PREFIX(fp6_rand) +#define fp6_print PREFIX(fp6_print) +#define fp6_size_bin PREFIX(fp6_size_bin) +#define fp6_read_bin PREFIX(fp6_read_bin) +#define fp6_write_bin PREFIX(fp6_write_bin) +#define fp6_cmp PREFIX(fp6_cmp) +#define fp6_cmp_dig PREFIX(fp6_cmp_dig) +#define fp6_set_dig PREFIX(fp6_set_dig) +#define fp6_add PREFIX(fp6_add) +#define fp6_sub PREFIX(fp6_sub) +#define fp6_neg PREFIX(fp6_neg) +#define fp6_dbl PREFIX(fp6_dbl) +#define fp6_mul_unr PREFIX(fp6_mul_unr) +#define fp6_mul_basic PREFIX(fp6_mul_basic) +#define fp6_mul_lazyr PREFIX(fp6_mul_lazyr) +#define fp6_mul_art PREFIX(fp6_mul_art) +#define fp6_mul_dxs PREFIX(fp6_mul_dxs) +#define fp6_sqr_unr PREFIX(fp6_sqr_unr) +#define fp6_sqr_basic PREFIX(fp6_sqr_basic) +#define fp6_sqr_lazyr PREFIX(fp6_sqr_lazyr) +#define fp6_inv PREFIX(fp6_inv) +#define fp6_exp PREFIX(fp6_exp) +#define fp6_frb PREFIX(fp6_frb) + +#undef fp8_copy +#undef fp8_zero +#undef fp8_is_zero +#undef fp8_rand +#undef fp8_print +#undef fp8_size_bin +#undef fp8_read_bin +#undef fp8_write_bin +#undef fp8_cmp +#undef fp8_cmp_dig +#undef fp8_set_dig +#undef fp8_add +#undef fp8_sub +#undef fp8_neg +#undef fp8_dbl +#undef fp8_mul_unr +#undef fp8_mul_basic +#undef fp8_mul_lazyr +#undef fp8_mul_art +#undef fp8_mul_dxs +#undef fp8_sqr_unr +#undef fp8_sqr_basic +#undef fp8_sqr_lazyr +#undef fp8_sqr_cyc +#undef fp8_inv +#undef fp8_inv_cyc +#undef fp8_inv_sim +#undef fp8_test_cyc +#undef fp8_conv_cyc +#undef fp8_exp +#undef fp8_exp_cyc +#undef fp8_frb + +#define fp8_copy PREFIX(fp8_copy) +#define fp8_zero PREFIX(fp8_zero) +#define fp8_is_zero PREFIX(fp8_is_zero) +#define fp8_rand PREFIX(fp8_rand) +#define fp8_print PREFIX(fp8_print) +#define fp8_size_bin PREFIX(fp8_size_bin) +#define fp8_read_bin PREFIX(fp8_read_bin) +#define fp8_write_bin PREFIX(fp8_write_bin) +#define fp8_cmp PREFIX(fp8_cmp) +#define fp8_cmp_dig PREFIX(fp8_cmp_dig) +#define fp8_set_dig PREFIX(fp8_set_dig) +#define fp8_add PREFIX(fp8_add) +#define fp8_sub PREFIX(fp8_sub) +#define fp8_neg PREFIX(fp8_neg) +#define fp8_dbl PREFIX(fp8_dbl) +#define fp8_mul_unr PREFIX(fp8_mul_unr) +#define fp8_mul_basic PREFIX(fp8_mul_basic) +#define fp8_mul_lazyr PREFIX(fp8_mul_lazyr) +#define fp8_mul_art PREFIX(fp8_mul_art) +#define fp8_mul_dxs PREFIX(fp8_mul_dxs) +#define fp8_sqr_unr PREFIX(fp8_sqr_unr) +#define fp8_sqr_basic PREFIX(fp8_sqr_basic) +#define fp8_sqr_lazyr PREFIX(fp8_sqr_lazyr) +#define fp8_sqr_cyc PREFIX(fp8_sqr_cyc) +#define fp8_inv PREFIX(fp8_inv) +#define fp8_inv_cyc PREFIX(fp8_inv_cyc) +#define fp8_inv_sim PREFIX(fp8_inv_sim) +#define fp8_test_cyc PREFIX(fp8_test_cyc) +#define fp8_conv_cyc PREFIX(fp8_conv_cyc) +#define fp8_exp PREFIX(fp8_exp) +#define fp8_exp_cyc PREFIX(fp8_exp_cyc) +#define fp8_frb PREFIX(fp8_frb) + +#undef fp9_copy +#undef fp9_zero +#undef fp9_is_zero +#undef fp9_rand +#undef fp9_print +#undef fp9_size_bin +#undef fp9_read_bin +#undef fp9_write_bin +#undef fp9_cmp +#undef fp9_cmp_dig +#undef fp9_set_dig +#undef fp9_add +#undef fp9_sub +#undef fp9_neg +#undef fp9_dbl +#undef fp9_mul_unr +#undef fp9_mul_basic +#undef fp9_mul_lazyr +#undef fp9_mul_art +#undef fp9_mul_dxs +#undef fp9_sqr_unr +#undef fp9_sqr_basic +#undef fp9_sqr_lazyr +#undef fp9_inv +#undef fp9_inv_sim +#undef fp9_exp +#undef fp9_frb + +#define fp9_copy PREFIX(fp9_copy) +#define fp9_zero PREFIX(fp9_zero) +#define fp9_is_zero PREFIX(fp9_is_zero) +#define fp9_rand PREFIX(fp9_rand) +#define fp9_print PREFIX(fp9_print) +#define fp9_size_bin PREFIX(fp9_size_bin) +#define fp9_read_bin PREFIX(fp9_read_bin) +#define fp9_write_bin PREFIX(fp9_write_bin) +#define fp9_cmp PREFIX(fp9_cmp) +#define fp9_cmp_dig PREFIX(fp9_cmp_dig) +#define fp9_set_dig PREFIX(fp9_set_dig) +#define fp9_add PREFIX(fp9_add) +#define fp9_sub PREFIX(fp9_sub) +#define fp9_neg PREFIX(fp9_neg) +#define fp9_dbl PREFIX(fp9_dbl) +#define fp9_mul_unr PREFIX(fp9_mul_unr) +#define fp9_mul_basic PREFIX(fp9_mul_basic) +#define fp9_mul_lazyr PREFIX(fp9_mul_lazyr) +#define fp9_mul_art PREFIX(fp9_mul_art) +#define fp9_mul_dxs PREFIX(fp9_mul_dxs) +#define fp9_sqr_unr PREFIX(fp9_sqr_unr) +#define fp9_sqr_basic PREFIX(fp9_sqr_basic) +#define fp9_sqr_lazyr PREFIX(fp9_sqr_lazyr) +#define fp9_inv PREFIX(fp9_inv) +#define fp9_inv_sim PREFIX(fp9_inv_sim) +#define fp9_exp PREFIX(fp9_exp) +#define fp9_frb PREFIX(fp9_frb) + +#undef fp12_copy +#undef fp12_zero +#undef fp12_is_zero +#undef fp12_rand +#undef fp12_print +#undef fp12_size_bin +#undef fp12_read_bin +#undef fp12_write_bin +#undef fp12_cmp +#undef fp12_cmp_dig +#undef fp12_set_dig +#undef fp12_add +#undef fp12_sub +#undef fp12_neg +#undef fp12_dbl +#undef fp12_mul_unr +#undef fp12_mul_basic +#undef fp12_mul_lazyr +#undef fp12_mul_art +#undef fp12_mul_dxs_basic +#undef fp12_mul_dxs_lazyr +#undef fp12_sqr_unr +#undef fp12_sqr_basic +#undef fp12_sqr_lazyr +#undef fp12_sqr_cyc_basic +#undef fp12_sqr_cyc_lazyr +#undef fp12_sqr_pck_basic +#undef fp12_sqr_pck_lazyr +#undef fp12_test_cyc +#undef fp12_conv_cyc +#undef fp12_back_cyc +#undef fp12_back_cyc_sim +#undef fp12_inv +#undef fp12_inv_cyc +#undef fp12_frb +#undef fp12_exp +#undef fp12_exp_dig +#undef fp12_exp_cyc +#undef fp12_exp_cyc_sps +#undef fp12_pck +#undef fp12_upk + +#define fp12_copy PREFIX(fp12_copy) +#define fp12_zero PREFIX(fp12_zero) +#define fp12_is_zero PREFIX(fp12_is_zero) +#define fp12_rand PREFIX(fp12_rand) +#define fp12_print PREFIX(fp12_print) +#define fp12_size_bin PREFIX(fp12_size_bin) +#define fp12_read_bin PREFIX(fp12_read_bin) +#define fp12_write_bin PREFIX(fp12_write_bin) +#define fp12_cmp PREFIX(fp12_cmp) +#define fp12_cmp_dig PREFIX(fp12_cmp_dig) +#define fp12_set_dig PREFIX(fp12_set_dig) +#define fp12_add PREFIX(fp12_add) +#define fp12_sub PREFIX(fp12_sub) +#define fp12_neg PREFIX(fp12_neg) +#define fp12_dbl PREFIX(fp12_dbl) +#define fp12_mul_unr PREFIX(fp12_mul_unr) +#define fp12_mul_basic PREFIX(fp12_mul_basic) +#define fp12_mul_lazyr PREFIX(fp12_mul_lazyr) +#define fp12_mul_art PREFIX(fp12_mul_art) +#define fp12_mul_dxs_basic PREFIX(fp12_mul_dxs_basic) +#define fp12_mul_dxs_lazyr PREFIX(fp12_mul_dxs_lazyr) +#define fp12_sqr_unr PREFIX(fp12_sqr_unr) +#define fp12_sqr_basic PREFIX(fp12_sqr_basic) +#define fp12_sqr_lazyr PREFIX(fp12_sqr_lazyr) +#define fp12_sqr_cyc_basic PREFIX(fp12_sqr_cyc_basic) +#define fp12_sqr_cyc_lazyr PREFIX(fp12_sqr_cyc_lazyr) +#define fp12_sqr_pck_basic PREFIX(fp12_sqr_pck_basic) +#define fp12_sqr_pck_lazyr PREFIX(fp12_sqr_pck_lazyr) +#define fp12_test_cyc PREFIX(fp12_test_cyc) +#define fp12_conv_cyc PREFIX(fp12_conv_cyc) +#define fp12_back_cyc PREFIX(fp12_back_cyc) +#define fp12_back_cyc_sim PREFIX(fp12_back_cyc_sim) +#define fp12_inv PREFIX(fp12_inv) +#define fp12_inv_cyc PREFIX(fp12_inv_cyc) +#define fp12_frb PREFIX(fp12_frb) +#define fp12_exp PREFIX(fp12_exp) +#define fp12_exp_dig PREFIX(fp12_exp_dig) +#define fp12_exp_cyc PREFIX(fp12_exp_cyc) +#define fp12_exp_cyc_sps PREFIX(fp12_exp_cyc_sps) +#define fp12_pck PREFIX(fp12_pck) +#define fp12_upk PREFIX(fp12_upk) + +#undef fp18_copy +#undef fp18_zero +#undef fp18_is_zero +#undef fp18_rand +#undef fp18_print +#undef fp18_size_bin +#undef fp18_read_bin +#undef fp18_write_bin +#undef fp18_cmp +#undef fp18_cmp_dig +#undef fp18_set_dig +#undef fp18_add +#undef fp18_sub +#undef fp18_neg +#undef fp18_dbl +#undef fp18_mul_unr +#undef fp18_mul_basic +#undef fp18_mul_lazyr +#undef fp18_mul_art +#undef fp18_mul_dxs_basic +#undef fp18_mul_dxs_lazyr +#undef fp18_sqr_unr +#undef fp18_sqr_basic +#undef fp18_sqr_lazyr +#undef fp18_inv +#undef fp18_inv_cyc +#undef fp18_conv_cyc +#undef fp18_frb +#undef fp18_exp + +#define fp18_copy PREFIX(fp18_copy) +#define fp18_zero PREFIX(fp18_zero) +#define fp18_is_zero PREFIX(fp18_is_zero) +#define fp18_rand PREFIX(fp18_rand) +#define fp18_print PREFIX(fp18_print) +#define fp18_size_bin PREFIX(fp18_size_bin) +#define fp18_read_bin PREFIX(fp18_read_bin) +#define fp18_write_bin PREFIX(fp18_write_bin) +#define fp18_cmp PREFIX(fp18_cmp) +#define fp18_cmp_dig PREFIX(fp18_cmp_dig) +#define fp18_set_dig PREFIX(fp18_set_dig) +#define fp18_add PREFIX(fp18_add) +#define fp18_sub PREFIX(fp18_sub) +#define fp18_neg PREFIX(fp18_neg) +#define fp18_dbl PREFIX(fp18_dbl) +#define fp18_mul_unr PREFIX(fp18_mul_unr) +#define fp18_mul_basic PREFIX(fp18_mul_basic) +#define fp18_mul_lazyr PREFIX(fp18_mul_lazyr) +#define fp18_mul_art PREFIX(fp18_mul_art) +#define fp18_mul_dxs_basic PREFIX(fp18_mul_dxs_basic) +#define fp18_mul_dxs_lazyr PREFIX(fp18_mul_dxs_lazyr) +#define fp18_sqr_unr PREFIX(fp18_sqr_unr) +#define fp18_sqr_basic PREFIX(fp18_sqr_basic) +#define fp18_sqr_lazyr PREFIX(fp18_sqr_lazyr) +#define fp18_inv PREFIX(fp18_inv) +#define fp18_inv_cyc PREFIX(fp18_inv_cyc) +#define fp18_conv_cyc PREFIX(fp18_conv_cyc) +#define fp18_frb PREFIX(fp18_frb) +#define fp18_exp PREFIX(fp18_exp) + +#undef fp24_copy +#undef fp24_zero +#undef fp24_is_zero +#undef fp24_rand +#undef fp24_print +#undef fp24_size_bin +#undef fp24_read_bin +#undef fp24_write_bin +#undef fp24_cmp +#undef fp24_cmp_dig +#undef fp24_set_dig +#undef fp24_add +#undef fp24_sub +#undef fp24_neg +#undef fp24_dbl +#undef fp24_mul_unr +#undef fp24_mul_basic +#undef fp24_mul_lazyr +#undef fp24_mul_art +#undef fp24_mul_dxs +#undef fp24_sqr_unr +#undef fp24_sqr_basic +#undef fp24_sqr_lazyr +#undef fp24_inv +#undef fp24_frb +#undef fp24_exp + +#define fp24_copy PREFIX(fp24_copy) +#define fp24_zero PREFIX(fp24_zero) +#define fp24_is_zero PREFIX(fp24_is_zero) +#define fp24_rand PREFIX(fp24_rand) +#define fp24_print PREFIX(fp24_print) +#define fp24_size_bin PREFIX(fp24_size_bin) +#define fp24_read_bin PREFIX(fp24_read_bin) +#define fp24_write_bin PREFIX(fp24_write_bin) +#define fp24_cmp PREFIX(fp24_cmp) +#define fp24_cmp_dig PREFIX(fp24_cmp_dig) +#define fp24_set_dig PREFIX(fp24_set_dig) +#define fp24_add PREFIX(fp24_add) +#define fp24_sub PREFIX(fp24_sub) +#define fp24_neg PREFIX(fp24_neg) +#define fp24_dbl PREFIX(fp24_dbl) +#define fp24_mul_unr PREFIX(fp24_mul_unr) +#define fp24_mul_basic PREFIX(fp24_mul_basic) +#define fp24_mul_lazyr PREFIX(fp24_mul_lazyr) +#define fp24_mul_art PREFIX(fp24_mul_art) +#define fp24_mul_dxs PREFIX(fp24_mul_dxs) +#define fp24_sqr_unr PREFIX(fp24_sqr_unr) +#define fp24_sqr_basic PREFIX(fp24_sqr_basic) +#define fp24_sqr_lazyr PREFIX(fp24_sqr_lazyr) +#define fp24_inv PREFIX(fp24_inv) +#define fp24_frb PREFIX(fp24_frb) +#define fp24_exp PREFIX(fp24_exp) + +#undef fp48_copy +#undef fp48_zero +#undef fp48_is_zero +#undef fp48_rand +#undef fp48_print +#undef fp48_size_bin +#undef fp48_read_bin +#undef fp48_write_bin +#undef fp48_cmp +#undef fp48_cmp_dig +#undef fp48_set_dig +#undef fp48_add +#undef fp48_sub +#undef fp48_neg +#undef fp48_dbl +#undef fp48_mul_unr +#undef fp48_mul_basic +#undef fp48_mul_lazyr +#undef fp48_mul_art +#undef fp48_mul_dxs +#undef fp48_sqr_unr +#undef fp48_sqr_basic +#undef fp48_sqr_lazyr +#undef fp48_sqr_cyc_basic +#undef fp48_sqr_cyc_lazyr +#undef fp48_sqr_pck_basic +#undef fp48_sqr_pck_lazyr +#undef fp48_test_cyc +#undef fp48_conv_cyc +#undef fp48_back_cyc +#undef fp48_back_cyc_sim +#undef fp48_inv +#undef fp48_inv_cyc +#undef fp48_conv_cyc +#undef fp48_frb +#undef fp48_exp +#undef fp48_exp_dig +#undef fp48_exp_cyc +#undef fp48_exp_cyc_sps +#undef fp48_pck +#undef fp48_upk + +#define fp48_copy PREFIX(fp48_copy) +#define fp48_zero PREFIX(fp48_zero) +#define fp48_is_zero PREFIX(fp48_is_zero) +#define fp48_rand PREFIX(fp48_rand) +#define fp48_print PREFIX(fp48_print) +#define fp48_size_bin PREFIX(fp48_size_bin) +#define fp48_read_bin PREFIX(fp48_read_bin) +#define fp48_write_bin PREFIX(fp48_write_bin) +#define fp48_cmp PREFIX(fp48_cmp) +#define fp48_cmp_dig PREFIX(fp48_cmp_dig) +#define fp48_set_dig PREFIX(fp48_set_dig) +#define fp48_add PREFIX(fp48_add) +#define fp48_sub PREFIX(fp48_sub) +#define fp48_neg PREFIX(fp48_neg) +#define fp48_dbl PREFIX(fp48_dbl) +#define fp48_mul_unr PREFIX(fp48_mul_unr) +#define fp48_mul_basic PREFIX(fp48_mul_basic) +#define fp48_mul_lazyr PREFIX(fp48_mul_lazyr) +#define fp48_mul_art PREFIX(fp48_mul_art) +#define fp48_mul_dxs PREFIX(fp48_mul_dxs) +#define fp48_sqr_unr PREFIX(fp48_sqr_unr) +#define fp48_sqr_basic PREFIX(fp48_sqr_basic) +#define fp48_sqr_lazyr PREFIX(fp48_sqr_lazyr) +#define fp48_sqr_cyc_basic PREFIX(fp48_sqr_cyc_basic) +#define fp48_sqr_cyc_lazyr PREFIX(fp48_sqr_cyc_lazyr) +#define fp48_sqr_pck_basic PREFIX(fp48_sqr_pck_basic) +#define fp48_sqr_pck_lazyr PREFIX(fp48_sqr_pck_lazyr) +#define fp48_test_cyc PREFIX(fp48_test_cyc) +#define fp48_conv_cyc PREFIX(fp48_conv_cyc) +#define fp48_back_cyc PREFIX(fp48_back_cyc) +#define fp48_back_cyc_sim PREFIX(fp48_back_cyc_sim) +#define fp48_inv PREFIX(fp48_inv) +#define fp48_inv_cyc PREFIX(fp48_inv_cyc) +#define fp48_conv_cyc PREFIX(fp48_conv_cyc) +#define fp48_frb PREFIX(fp48_frb) +#define fp48_exp PREFIX(fp48_exp) +#define fp48_exp_dig PREFIX(fp48_exp_dig) +#define fp48_exp_cyc PREFIX(fp48_exp_cyc) +#define fp48_exp_cyc_sps PREFIX(fp48_exp_cyc_sps) +#define fp48_pck PREFIX(fp48_pck) +#define fp48_upk PREFIX(fp48_upk) + +#undef fp54_copy +#undef fp54_zero +#undef fp54_is_zero +#undef fp54_rand +#undef fp54_print +#undef fp54_size_bin +#undef fp54_read_bin +#undef fp54_write_bin +#undef fp54_cmp +#undef fp54_cmp_dig +#undef fp54_set_dig +#undef fp54_add +#undef fp54_sub +#undef fp54_neg +#undef fp54_dbl +#undef fp54_mul_unr +#undef fp54_mul_basic +#undef fp54_mul_lazyr +#undef fp54_mul_art +#undef fp54_mul_dxs +#undef fp54_sqr_unr +#undef fp54_sqr_basic +#undef fp54_sqr_lazyr +#undef fp54_sqr_cyc_basic +#undef fp54_sqr_cyc_lazyr +#undef fp54_sqr_pck_basic +#undef fp54_sqr_pck_lazyr +#undef fp54_test_cyc +#undef fp54_conv_cyc +#undef fp54_back_cyc +#undef fp54_back_cyc_sim +#undef fp54_inv +#undef fp54_inv_cyc +#undef fp54_conv_cyc +#undef fp54_frb +#undef fp54_exp +#undef fp54_exp_dig +#undef fp54_exp_cyc +#undef fp54_exp_cyc_sps +#undef fp54_pck +#undef fp54_upk + +#define fp54_copy PREFIX(fp54_copy) +#define fp54_zero PREFIX(fp54_zero) +#define fp54_is_zero PREFIX(fp54_is_zero) +#define fp54_rand PREFIX(fp54_rand) +#define fp54_print PREFIX(fp54_print) +#define fp54_size_bin PREFIX(fp54_size_bin) +#define fp54_read_bin PREFIX(fp54_read_bin) +#define fp54_write_bin PREFIX(fp54_write_bin) +#define fp54_cmp PREFIX(fp54_cmp) +#define fp54_cmp_dig PREFIX(fp54_cmp_dig) +#define fp54_set_dig PREFIX(fp54_set_dig) +#define fp54_add PREFIX(fp54_add) +#define fp54_sub PREFIX(fp54_sub) +#define fp54_neg PREFIX(fp54_neg) +#define fp54_dbl PREFIX(fp54_dbl) +#define fp54_mul_unr PREFIX(fp54_mul_unr) +#define fp54_mul_basic PREFIX(fp54_mul_basic) +#define fp54_mul_lazyr PREFIX(fp54_mul_lazyr) +#define fp54_mul_art PREFIX(fp54_mul_art) +#define fp54_mul_dxs PREFIX(fp54_mul_dxs) +#define fp54_sqr_unr PREFIX(fp54_sqr_unr) +#define fp54_sqr_basic PREFIX(fp54_sqr_basic) +#define fp54_sqr_lazyr PREFIX(fp54_sqr_lazyr) +#define fp54_sqr_cyc_basic PREFIX(fp54_sqr_cyc_basic) +#define fp54_sqr_cyc_lazyr PREFIX(fp54_sqr_cyc_lazyr) +#define fp54_sqr_pck_basic PREFIX(fp54_sqr_pck_basic) +#define fp54_sqr_pck_lazyr PREFIX(fp54_sqr_pck_lazyr) +#define fp54_test_cyc PREFIX(fp54_test_cyc) +#define fp54_conv_cyc PREFIX(fp54_conv_cyc) +#define fp54_back_cyc PREFIX(fp54_back_cyc) +#define fp54_back_cyc_sim PREFIX(fp54_back_cyc_sim) +#define fp54_inv PREFIX(fp54_inv) +#define fp54_inv_cyc PREFIX(fp54_inv_cyc) +#define fp54_conv_cyc PREFIX(fp54_conv_cyc) +#define fp54_frb PREFIX(fp54_frb) +#define fp54_exp PREFIX(fp54_exp) +#define fp54_exp_dig PREFIX(fp54_exp_dig) +#define fp54_exp_cyc PREFIX(fp54_exp_cyc) +#define fp54_exp_cyc_sps PREFIX(fp54_exp_cyc_sps) +#define fp54_pck PREFIX(fp54_pck) +#define fp54_upk PREFIX(fp54_upk) + +#undef fb2_mul + #undef fb2_mul_nor +#undef fb2_sqr +#undef fb2_slv +#undef fb2_inv + +#define fb2_mul PREFIX(fb2_mul) + #define fb2_mul_nor PREFIX(fb2_mul_nor) +#define fb2_sqr PREFIX(fb2_sqr) +#define fb2_slv PREFIX(fb2_slv) +#define fb2_inv PREFIX(fb2_inv) + + + +#undef pp_map_init +#undef pp_map_clean +#undef pp_add_k2_basic +#undef pp_add_k2_projc_basic +#undef pp_add_k2_projc_lazyr +#undef pp_add_k8_basic +#undef pp_add_k8_projc_basic +#undef pp_add_k8_projc_lazyr +#undef pp_add_k12_basic +#undef pp_add_k12_projc_basic +#undef pp_add_k12_projc_lazyr +#undef pp_add_lit_k12 +#undef pp_add_k48_basic +#undef pp_add_k48_projc +#undef pp_add_k54_basic +#undef pp_add_k54_projc +#undef pp_dbl_k2_basic +#undef pp_dbl_k2_projc_basic +#undef pp_dbl_k2_projc_lazyr +#undef pp_dbl_k8_basic +#undef pp_dbl_k8_projc_basic +#undef pp_dbl_k8_projc_lazyr +#undef pp_dbl_k12_basic +#undef pp_dbl_k12_projc_basic +#undef pp_dbl_k12_projc_lazyr +#undef pp_dbl_k48_basic +#undef pp_dbl_k48_projc +#undef pp_dbl_k54_basic +#undef pp_dbl_k54_projc +#undef pp_dbl_lit_k12 +#undef pp_exp_k2 +#undef pp_exp_k8 +#undef pp_exp_k12 +#undef pp_exp_k48 +#undef pp_exp_k54 +#undef pp_norm_k2 +#undef pp_norm_k8 +#undef pp_norm_k12 +#undef pp_map_tatep_k2 +#undef pp_map_sim_tatep_k2 +#undef pp_map_weilp_k2 +#undef pp_map_oatep_k8 +#undef pp_map_sim_weilp_k2 +#undef pp_map_tatep_k12 +#undef pp_map_sim_tatep_k12 +#undef pp_map_weilp_k12 +#undef pp_map_sim_weilp_k12 +#undef pp_map_oatep_k12 +#undef pp_map_sim_oatep_k12 +#undef pp_map_k48 +#undef pp_map_k54 + +#define pp_map_init PREFIX(pp_map_init) +#define pp_map_clean PREFIX(pp_map_clean) +#define pp_add_k2_basic PREFIX(pp_add_k2_basic) +#define pp_add_k2_projc_basic PREFIX(pp_add_k2_projc_basic) +#define pp_add_k2_projc_lazyr PREFIX(pp_add_k2_projc_lazyr) +#define pp_add_k8_basic PREFIX(pp_add_k8_basic) +#define pp_add_k8_projc_basic PREFIX(pp_add_k8_projc_basic) +#define pp_add_k8_projc_lazyr PREFIX(pp_add_k8_projc_lazyr) +#define pp_add_k12_basic PREFIX(pp_add_k12_basic) +#define pp_add_k12_projc_basic PREFIX(pp_add_k12_projc_basic) +#define pp_add_k12_projc_lazyr PREFIX(pp_add_k12_projc_lazyr) +#define pp_add_lit_k12 PREFIX(pp_add_lit_k12) +#define pp_add_k48_basic PREFIX(pp_add_k48_basic) +#define pp_add_k48_projc PREFIX(pp_add_k48_projc) +#define pp_add_k54_basic PREFIX(pp_add_k54_basic) +#define pp_add_k54_projc PREFIX(pp_add_k54_projc) +#define pp_dbl_k2_basic PREFIX(pp_dbl_k2_basic) +#define pp_dbl_k2_projc_basic PREFIX(pp_dbl_k2_projc_basic) +#define pp_dbl_k2_projc_lazyr PREFIX(pp_dbl_k2_projc_lazyr) +#define pp_dbl_k8_basic PREFIX(pp_dbl_k8_basic) +#define pp_dbl_k8_projc_basic PREFIX(pp_dbl_k8_projc_basic) +#define pp_dbl_k8_projc_lazyr PREFIX(pp_dbl_k8_projc_lazyr) +#define pp_dbl_k12_basic PREFIX(pp_dbl_k12_basic) +#define pp_dbl_k12_projc_basic PREFIX(pp_dbl_k12_projc_basic) +#define pp_dbl_k12_projc_lazyr PREFIX(pp_dbl_k12_projc_lazyr) +#define pp_dbl_k48_basic PREFIX(pp_dbl_k48_basic) +#define pp_dbl_k48_projc PREFIX(pp_dbl_k48_projc) +#define pp_dbl_k54_basic PREFIX(pp_dbl_k54_basic) +#define pp_dbl_k54_projc PREFIX(pp_dbl_k54_projc) +#define pp_dbl_lit_k12 PREFIX(pp_dbl_lit_k12) +#define pp_exp_k2 PREFIX(pp_exp_k2) +#define pp_exp_k8 PREFIX(pp_exp_k8) +#define pp_exp_k12 PREFIX(pp_exp_k12) +#define pp_exp_k48 PREFIX(pp_exp_k48) +#define pp_exp_k54 PREFIX(pp_exp_k54) +#define pp_norm_k2 PREFIX(pp_norm_k2) +#define pp_norm_k8 PREFIX(pp_norm_k8) +#define pp_norm_k12 PREFIX(pp_norm_k12) +#define pp_map_tatep_k2 PREFIX(pp_map_tatep_k2) +#define pp_map_sim_tatep_k2 PREFIX(pp_map_sim_tatep_k2) +#define pp_map_weilp_k2 PREFIX(pp_map_weilp_k2) +#define pp_map_oatep_k8 PREFIX(pp_map_oatep_k8) +#define pp_map_sim_weilp_k2 PREFIX(pp_map_sim_weilp_k2) +#define pp_map_tatep_k12 PREFIX(pp_map_tatep_k12) +#define pp_map_sim_tatep_k12 PREFIX(pp_map_sim_tatep_k12) +#define pp_map_weilp_k12 PREFIX(pp_map_weilp_k12) +#define pp_map_sim_weilp_k12 PREFIX(pp_map_sim_weilp_k12) +#define pp_map_oatep_k12 PREFIX(pp_map_oatep_k12) +#define pp_map_sim_oatep_k12 PREFIX(pp_map_sim_oatep_k12) +#define pp_map_k48 PREFIX(pp_map_k48) +#define pp_map_k54 PREFIX(pp_map_k54) + +#undef rsa_t +#undef rabin_t +#undef bdpe_t +#undef sokaka_t +#define rsa_t PREFIX(rsa_t) +#define rabin_t PREFIX(rabin_t) +#define bdpe_t PREFIX(bdpe_t) +#define sokaka_t PREFIX(sokaka_t) + +#undef cp_rsa_gen_basic +#undef cp_rsa_gen_quick +#undef cp_rsa_enc +#undef cp_rsa_dec_basic +#undef cp_rsa_dec_quick +#undef cp_rsa_sig_basic +#undef cp_rsa_sig_quick +#undef cp_rsa_ver +#undef cp_rabin_gen +#undef cp_rabin_enc +#undef cp_rabin_dec +#undef cp_bdpe_gen +#undef cp_bdpe_enc +#undef cp_bdpe_dec +#undef cp_phpe_gen +#undef cp_phpe_enc +#undef cp_phpe_dec +#undef cp_ecdh_gen +#undef cp_ecdh_key +#undef cp_ecmqv_gen +#undef cp_ecmqv_key +#undef cp_ecies_gen +#undef cp_ecies_enc +#undef cp_ecies_dec +#undef cp_ecdsa_gen +#undef cp_ecdsa_sig +#undef cp_ecdsa_ver +#undef cp_ecss_gen +#undef cp_ecss_sig +#undef cp_ecss_ver +#undef cp_sokaka_gen +#undef cp_sokaka_gen_prv +#undef cp_sokaka_key +#undef cp_bgn_gen +#undef cp_bgn_enc1 +#undef cp_bgn_dec1 +#undef cp_bgn_enc2 +#undef cp_bgn_dec2 +#undef cp_bgn_add +#undef cp_bgn_mul +#undef cp_bgn_dec +#undef cp_ibe_gen +#undef cp_ibe_gen_prv +#undef cp_ibe_enc +#undef cp_ibe_dec +#undef cp_bls_gen +#undef cp_bls_sig +#undef cp_bls_ver +#undef cp_bbs_gen +#undef cp_bbs_sig +#undef cp_bbs_ver +#undef cp_cls_gen +#undef cp_cls_sig +#undef cp_cls_ver +#undef cp_cli_gen +#undef cp_cli_sig +#undef cp_cli_ver +#undef cp_clb_gen +#undef cp_clb_sig +#undef cp_clb_ver +#undef cp_pss_gen +#undef cp_pss_sig +#undef cp_pss_ver +#undef cp_psb_gen +#undef cp_psb_sig +#undef cp_psb_ver +#undef cp_zss_gen +#undef cp_zss_sig +#undef cp_zss_ver +#undef cp_vbnn_gen +#undef cp_vbnn_gen_prv +#undef cp_vbnn_sig +#undef cp_vbnn_ver +#undef cp_cmlhs_init +#undef cp_cmlhs_gen +#undef cp_cmlhs_sig +#undef cp_cmlhs_fun +#undef cp_cmlhs_evl +#undef cp_cmlhs_ver +#undef cp_mklhs_gen +#undef cp_mklhs_sig +#undef cp_mklhs_fun +#undef cp_mklhs_evl +#undef cp_mklhs_ver +#undef cp_mklhs_off +#undef cp_mklhs_onv + +#define cp_rsa_gen_basic PREFIX(cp_rsa_gen_basic) +#define cp_rsa_gen_quick PREFIX(cp_rsa_gen_quick) +#define cp_rsa_enc PREFIX(cp_rsa_enc) +#define cp_rsa_dec_basic PREFIX(cp_rsa_dec_basic) +#define cp_rsa_dec_quick PREFIX(cp_rsa_dec_quick) +#define cp_rsa_sig_basic PREFIX(cp_rsa_sig_basic) +#define cp_rsa_sig_quick PREFIX(cp_rsa_sig_quick) +#define cp_rsa_ver PREFIX(cp_rsa_ver) +#define cp_rabin_gen PREFIX(cp_rabin_gen) +#define cp_rabin_enc PREFIX(cp_rabin_enc) +#define cp_rabin_dec PREFIX(cp_rabin_dec) +#define cp_bdpe_gen PREFIX(cp_bdpe_gen) +#define cp_bdpe_enc PREFIX(cp_bdpe_enc) +#define cp_bdpe_dec PREFIX(cp_bdpe_dec) +#define cp_phpe_gen PREFIX(cp_phpe_gen) +#define cp_phpe_enc PREFIX(cp_phpe_enc) +#define cp_phpe_dec PREFIX(cp_phpe_dec) +#define cp_ecdh_gen PREFIX(cp_ecdh_gen) +#define cp_ecdh_key PREFIX(cp_ecdh_key) +#define cp_ecmqv_gen PREFIX(cp_ecmqv_gen) +#define cp_ecmqv_key PREFIX(cp_ecmqv_key) +#define cp_ecies_gen PREFIX(cp_ecies_gen) +#define cp_ecies_enc PREFIX(cp_ecies_enc) +#define cp_ecies_dec PREFIX(cp_ecies_dec) +#define cp_ecdsa_gen PREFIX(cp_ecdsa_gen) +#define cp_ecdsa_sig PREFIX(cp_ecdsa_sig) +#define cp_ecdsa_ver PREFIX(cp_ecdsa_ver) +#define cp_ecss_gen PREFIX(cp_ecss_gen) +#define cp_ecss_sig PREFIX(cp_ecss_sig) +#define cp_ecss_ver PREFIX(cp_ecss_ver) +#define cp_sokaka_gen PREFIX(cp_sokaka_gen) +#define cp_sokaka_gen_prv PREFIX(cp_sokaka_gen_prv) +#define cp_sokaka_key PREFIX(cp_sokaka_key) +#define cp_bgn_gen PREFIX(cp_bgn_gen) +#define cp_bgn_enc1 PREFIX(cp_bgn_enc1) +#define cp_bgn_dec1 PREFIX(cp_bgn_dec1) +#define cp_bgn_enc2 PREFIX(cp_bgn_enc2) +#define cp_bgn_dec2 PREFIX(cp_bgn_dec2) +#define cp_bgn_add PREFIX(cp_bgn_add) +#define cp_bgn_mul PREFIX(cp_bgn_mul) +#define cp_bgn_dec PREFIX(cp_bgn_dec) +#define cp_ibe_gen PREFIX(cp_ibe_gen) +#define cp_ibe_gen_prv PREFIX(cp_ibe_gen_prv) +#define cp_ibe_enc PREFIX(cp_ibe_enc) +#define cp_ibe_dec PREFIX(cp_ibe_dec) +#define cp_bls_gen PREFIX(cp_bls_gen) +#define cp_bls_sig PREFIX(cp_bls_sig) +#define cp_bls_ver PREFIX(cp_bls_ver) +#define cp_bbs_gen PREFIX(cp_bbs_gen) +#define cp_bbs_sig PREFIX(cp_bbs_sig) +#define cp_bbs_ver PREFIX(cp_bbs_ver) +#define cp_cls_gen PREFIX(cp_cls_gen) +#define cp_cls_sig PREFIX(cp_cls_sig) +#define cp_cls_ver PREFIX(cp_cls_ver) +#define cp_cli_gen PREFIX(cp_cli_gen) +#define cp_cli_sig PREFIX(cp_cli_sig) +#define cp_cli_ver PREFIX(cp_cli_ver) +#define cp_clb_gen PREFIX(cp_clb_gen) +#define cp_clb_sig PREFIX(cp_clb_sig) +#define cp_clb_ver PREFIX(cp_clb_ver) +#define cp_pss_gen PREFIX(cp_pss_gen) +#define cp_pss_sig PREFIX(cp_pss_sig) +#define cp_pss_ver PREFIX(cp_pss_ver) +#define cp_psb_gen PREFIX(cp_psb_gen) +#define cp_psb_sig PREFIX(cp_psb_sig) +#define cp_psb_ver PREFIX(cp_psb_ver) +#define cp_zss_gen PREFIX(cp_zss_gen) +#define cp_zss_sig PREFIX(cp_zss_sig) +#define cp_zss_ver PREFIX(cp_zss_ver) +#define cp_vbnn_gen PREFIX(cp_vbnn_gen) +#define cp_vbnn_gen_prv PREFIX(cp_vbnn_gen_prv) +#define cp_vbnn_sig PREFIX(cp_vbnn_sig) +#define cp_vbnn_ver PREFIX(cp_vbnn_ver) +#define cp_cmlhs_init PREFIX(cp_cmlhs_init) +#define cp_cmlhs_gen PREFIX(cp_cmlhs_gen) +#define cp_cmlhs_sig PREFIX(cp_cmlhs_sig) +#define cp_cmlhs_fun PREFIX(cp_cmlhs_fun) +#define cp_cmlhs_evl PREFIX(cp_cmlhs_evl) +#define cp_cmlhs_ver PREFIX(cp_cmlhs_ver) +#define cp_mklhs_gen PREFIX(cp_mklhs_gen) +#define cp_mklhs_sig PREFIX(cp_mklhs_sig) +#define cp_mklhs_fun PREFIX(cp_mklhs_fun) +#define cp_mklhs_evl PREFIX(cp_mklhs_evl) +#define cp_mklhs_ver PREFIX(cp_mklhs_ver) +#define cp_mklhs_off PREFIX(cp_mklhs_off) +#define cp_mklhs_onv PREFIX(cp_mklhs_onv) + +#undef md_map_sh224 +#undef md_map_sh256 +#undef md_map_sh384 +#undef md_map_sh512 +#undef md_map_b2s160 +#undef md_map_b2s256 +#undef md_kdf +#undef md_mgf +#undef md_hmac +#undef md_xmd_sh224 +#undef md_xmd_sh256 +#undef md_xmd_sh384 +#undef md_xmd_sh512 + +#define md_map_sh224 PREFIX(md_map_sh224) +#define md_map_sh256 PREFIX(md_map_sh256) +#define md_map_sh384 PREFIX(md_map_sh384) +#define md_map_sh512 PREFIX(md_map_sh512) +#define md_map_b2s160 PREFIX(md_map_b2s160) +#define md_map_b2s256 PREFIX(md_map_b2s256) +#define md_kdf PREFIX(md_kdf) +#define md_mgf PREFIX(md_mgf) +#define md_hmac PREFIX(md_hmac) +#define md_xmd_sh224 PREFIX(md_xmd_sh224) +#define md_xmd_sh256 PREFIX(md_xmd_sh256) +#define md_xmd_sh384 PREFIX(md_xmd_sh384) +#define md_xmd_sh512 PREFIX(md_xmd_sh512) + +#endif /* LABEL */ + +#endif /* !RLC_LABEL_H */ diff --git a/bls/contrib/relic/include/relic_md.h b/bls/contrib/relic/include/relic_md.h new file mode 100644 index 00000000..d8d1bce4 --- /dev/null +++ b/bls/contrib/relic/include/relic_md.h @@ -0,0 +1,274 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @defgroup md Hash functions + */ + +/** + * @file + * + * Interface of the module for computing hash functions. + * + * @ingroup md + */ + +#ifndef RLC_MD_H +#define RLC_MD_H + +#include "relic_conf.h" +#include "relic_types.h" +#include "relic_label.h" + +/*============================================================================*/ +/* Constant definitions */ +/*============================================================================*/ + +enum { + /** Hash length for SHA-224 function. */ + RLC_MD_LEN_SH224 = 28, + /** Hash length for SHA-256 function. */ + RLC_MD_LEN_SH256 = 32, + /** Hash length for SHA-384 function. */ + RLC_MD_LEN_SH384 = 48, + /** Hash length for SHA-512 function. */ + RLC_MD_LEN_SH512 = 64, + /** Hash length for BLAKE2s-160 function. */ + RLC_MD_LEN_B2S160 = 20, + /** Hash length for BLAKE2s-256 function. */ + RLC_MD_LEN_B2S256 = 32 +}; + +/** + * Length in bytes of default hash function output. + */ +#if MD_MAP == SH224 +#define RLC_MD_LEN RLC_MD_LEN_SH224 +#elif MD_MAP == SH256 +#define RLC_MD_LEN RLC_MD_LEN_SH256 +#elif MD_MAP == SH384 +#define RLC_MD_LEN RLC_MD_LEN_SH384 +#elif MD_MAP == SH512 +#define RLC_MD_LEN RLC_MD_LEN_SH512 +#elif MD_MAP == B2S160 +#define RLC_MD_LEN RLC_MD_LEN_B2S160 +#elif MD_MAP == B2S256 +#define RLC_MD_LEN RLC_MD_LEN_B2S256 +#endif + +/*============================================================================*/ +/* Macro definitions */ +/*============================================================================*/ + +/** + * Maps a byte vector to a fixed-length byte vector using the chosen hash + * function. + * + * @param[out] H - the digest. + * @param[in] M - the message to hash. + * @param[in] L - the message length in bytes. + */ +#if MD_MAP == SH224 +#define md_map(H, M, L) md_map_sh224(H, M, L) +#elif MD_MAP == SH256 +#define md_map(H, M, L) md_map_sh256(H, M, L) +#elif MD_MAP == SH384 +#define md_map(H, M, L) md_map_sh384(H, M, L) +#elif MD_MAP == SH512 +#define md_map(H, M, L) md_map_sh512(H, M, L) +#elif MD_MAP == BLAKE2S_160 +#define md_map(H, M, L) md_map_b2s160(H, M, L) +#elif MD_MAP == BLAKE2S_256 +#define md_map(H, M, L) md_map_b2s256(H, M, L) +#endif + +/** + * Maps a byte vector and optional domain separation tag to an arbitrary-length + * pseudorandom output using the chosen hash function. + * + * @param[out] B - the output buffer. + * @param[in] BL - the requested size of the output. + * @param[in] I - the message to hash. + * @param[in] IL - the message length in bytes. + * @param[in] D - the domain separation tag. + * @param[in] DL - the domain separation tag length in bytes. + */ +#if MD_MAP == SH224 +#define md_xmd(B, BL, I, IL, D, DL) md_xmd_sh224(B, BL, I, IL, D, DL) +#elif MD_MAP == SH256 +#define md_xmd(B, BL, I, IL, D, DL) md_xmd_sh256(B, BL, I, IL, D, DL) +#elif MD_MAP == SH384 +#define md_xmd(B, BL, I, IL, D, DL) md_xmd_sh384(B, BL, I, IL, D, DL) +#elif MD_MAP == SH512 +#define md_xmd(B, BL, I, IL, D, DL) md_xmd_sh512(B, BL, I, IL, D, DL) +#endif + +/*============================================================================*/ +/* Function prototypes */ +/*============================================================================*/ + +/** + * Computes the SHA-224 hash function. + * + * @param[out] hash - the digest. + * @param[in] msg - the message to hash. + * @param[in] len - the message length in bytes. + */ +void md_map_sh224(uint8_t *hash, const uint8_t *msg, int len); + +/** + * Computes the SHA-256 hash function. + * + * @param[out] hash - the digest. + * @param[in] msg - the message to hash. + * @param[in] len - the message length in bytes. + */ +void md_map_sh256(uint8_t *hash, const uint8_t *msg, int len); + +/** + * Computes the SHA-384 hash function. + * + * @param[out] hash - the digest. + * @param[in] msg - the message to hash. + * @param[in] len - the message length in bytes. + */ +void md_map_sh384(uint8_t *hash, const uint8_t *msg, int len); + +/** + * Computes the SHA-512 hash function. + * + * @param[out] hash - the digest. + * @param[in] msg - the message to hash. + * @param[in] len - the message length in bytes. + */ +void md_map_sh512(uint8_t *hash, const uint8_t *msg, int len); + +/** + * Computes the BLAKE2s-160 hash function. + * + * @param[out] hash - the digest. + * @param[in] msg - the message to hash. + * @param[in] len - the message length in bytes. + */ +void md_map_b2s160(uint8_t *hash, const uint8_t *msg, int len); + +/** + * Computes the BLAKE2s-256 hash function. + * + * @param[out] hash - the digest. + * @param[in] msg - the message to hash. + * @param[in] len - the message length in bytes. + */ +void md_map_b2s256(uint8_t *hash, const uint8_t *msg, int len); + +/** + * Derives a key from shared secret material through the standardized KDF2 + * function. + * + * @param[out] key - the resulting key. + * @param[in] key_len - the intended key length in bytes. + * @param[in] in - the shared secret. + * @param[in] in_len - the length of the shared secret in bytes. + */ +void md_kdf(uint8_t *key, int key_len, const uint8_t *in, int in_len); + +/** + * Derives a mask from shared secret material through the PKCS#1 2.1 MGF1 + * function. This is the same as the standardized KDF1 key derivation function. + * + * @param[out] key - the resulting mask. + * @param[in] key_len - the intended mask length in bytes. + * @param[in] in - the shared secret. + * @param[in] in_len - the length of the shared secret in bytes. + */ +void md_mgf(uint8_t *mask, int mask_len, const uint8_t *in, int in_len); + +/** + * Computes a Message Authentication Code through HMAC. + * + * @param[out] mac - the authentication. + * @param[in] in - the date to authenticate. + * @param[in] in_len - the number of bytes to authenticate. + * @param[in] key - the cryptographic key. + * @param[in] key_len - the size of the key in bytes. + */ +void md_hmac(uint8_t *mac, const uint8_t *in, int in_len, const uint8_t *key, + int key_len); + +/** + * Map a byte vector and optional domain separation tag to an arbitrary-length + * pseudorandom output using the SHA-224 hash function. + * + * @param[out] buf - the output buffer. + * @param[in] buf_len - the requested size of the output. + * @param[in] in - the message to hash. + * @param[in] in_len - the message length in bytes. + * @param[in] dst - the domain separation tag. + * @param[in] dst_len - the domain separation tag length in bytes. + */ +void md_xmd_sh224(uint8_t *buf, int buf_len, const uint8_t *in, int in_len, + const uint8_t *dst, int dst_len); + +/** + * Map a byte vector and optional domain separation tag to an arbitrary-length + * pseudorandom output using the SHA-256 hash function. + * + * @param[out] buf - the output buffer. + * @param[in] buf_len - the requested size of the output. + * @param[in] in - the message to hash. + * @param[in] in_len - the message length in bytes. + * @param[in] dst - the domain separation tag. + * @param[in] dst_len - the domain separation tag length in bytes. + */ +void md_xmd_sh256(uint8_t *buf, int buf_len, const uint8_t *in, int in_len, + const uint8_t *dst, int dst_len); + +/** + * Map a byte vector and optional domain separation tag to an arbitrary-length + * pseudorandom output using the SHA-384 hash function. + * + * @param[out] buf - the output buffer. + * @param[in] buf_len - the requested size of the output. + * @param[in] in - the message to hash. + * @param[in] in_len - the message length in bytes. + * @param[in] dst - the domain separation tag. + * @param[in] dst_len - the domain separation tag length in bytes. + */ +void md_xmd_sh384(uint8_t *buf, int buf_len, const uint8_t *in, int in_len, + const uint8_t *dst, int dst_len); + +/** + * Map a byte vector and optional domain separation tag to an arbitrary-length + * pseudorandom output using the SHA-512 hash function. + * + * @param[out] buf - the output buffer. + * @param[in] buf_len - the requested size of the output. + * @param[in] in - the message to hash. + * @param[in] in_len - the message length in bytes. + * @param[in] dst - the domain separation tag. + * @param[in] dst_len - the domain separation tag length in bytes. + */ +void md_xmd_sh512(uint8_t *buf, int buf_len, const uint8_t *in, int in_len, + const uint8_t *dst, int dst_len); + +#endif /* !RLC_MD_H */ diff --git a/bls/contrib/relic/include/relic_pc.h b/bls/contrib/relic/include/relic_pc.h new file mode 100644 index 00000000..c673aae8 --- /dev/null +++ b/bls/contrib/relic/include/relic_pc.h @@ -0,0 +1,895 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @defgroup pc Pairing-based cryptography + */ + +/** + * @file + * + * Abstractions of pairing computation useful to protocol implementors. + * + * @ingroup pc + */ + +#ifndef RLC_PC_H +#define RLC_PC_H + +#include "relic_fbx.h" +#include "relic_ep.h" +#include "relic_eb.h" +#include "relic_pp.h" +#include "relic_bn.h" +#include "relic_util.h" +#include "relic_conf.h" +#include "relic_types.h" + +/*============================================================================*/ +/* Constant definitions */ +/*============================================================================*/ + +/** + * Prefix for function mappings. + */ +/** @{ */ +#if FP_PRIME < 1536 +#define G1_LOWER ep_ +#define G1_UPPER EP +#define G2_LOWER ep2_ +#define G2_UPPER EP +#define GT_LOWER fp12_ +#define PC_LOWER pp_ +#else +#define G1_LOWER ep_ +#define G1_UPPER EP +#define G2_LOWER ep_ +#define G2_UPPER EP +#define GT_LOWER fp2_ +#define PC_LOWER pp_ +#endif +/** @} */ + +/** + * Represents the size in bytes of the order of G_1 and G_2. + */ +#define RLC_PC_BYTES RLC_FP_BYTES + +/** + * Represents a G_1 precomputed table. + */ +#define RLC_G1_TABLE RLC_CAT(RLC_CAT(RLC_, G1_UPPER), _TABLE) + +/** + * Represents a G_2 precomputed table. + */ +#define RLC_G2_TABLE RLC_CAT(RLC_CAT(RLC_, G2_UPPER), _TABLE) + +/*============================================================================*/ +/* Type definitions */ +/*============================================================================*/ + +/** + * Represents a G_1 element. + */ +typedef RLC_CAT(G1_LOWER, t) g1_t; + +/** + * Represents a G_1 element with automatic allocation. + */ +typedef RLC_CAT(G1_LOWER, st) g1_st; + +/** + * Represents a G_2 element. + */ +typedef RLC_CAT(G2_LOWER, t) g2_t; + +/** + * Represents a G_2 element with automatic allocation. + */ +typedef RLC_CAT(G2_LOWER, st) g2_st; + +/** + * Represents a G_T element. + */ +typedef RLC_CAT(GT_LOWER, t) gt_t; + +/*============================================================================*/ +/* Macro definitions */ +/*============================================================================*/ + +/** + * Initializes a G_1 element with a null value. + * + * @param[out] A - the element to initialize. + */ +#define g1_null(A) RLC_CAT(G1_LOWER, null)(A) + +/** + * Initializes a G_2 element with a null value. + * + * @param[out] A - the element to initialize. + */ +#define g2_null(A) RLC_CAT(G2_LOWER, null)(A) + +/** + * Initializes a G_T element with a null value. + * + * @param[out] A - the element to initialize. + */ +#define gt_null(A) RLC_CAT(GT_LOWER, null)(A) + +/** + * Calls a function to allocate a G_1 element. + * + * @param[out] A - the new element. + * @throw ERR_NO_MEMORY - if there is no available memory. + */ +#define g1_new(A) RLC_CAT(G1_LOWER, new)(A) + +/** + * Calls a function to allocate a G_2 element. + * + * @param[out] A - the new element. + * @throw ERR_NO_MEMORY - if there is no available memory. + */ +#define g2_new(A) RLC_CAT(G2_LOWER, new)(A) + +/** + * Calls a function to allocate a G_T element. + * + * @param[out] A - the new element. + * @throw ERR_NO_MEMORY - if there is no available memory. + */ +#define gt_new(A) RLC_CAT(GT_LOWER, new)(A) + +/** + * Calls a function to clean and free a G_1 element. + * + * @param[out] A - the element to clean and free. + */ +#define g1_free(A) RLC_CAT(G1_LOWER, free)(A) + +/** + * Calls a function to clean and free a G_2 element. + * + * @param[out] A - the element to clean and free. + */ +#define g2_free(A) RLC_CAT(G2_LOWER, free)(A) + +/** + * Calls a function to clean and free a G_T element. + * + * @param[out] A - the element to clean and free. + */ +#define gt_free(A) RLC_CAT(GT_LOWER, free)(A) + +/** + * Returns the generator of the group G_1. + * + * @param[out] G - the returned generator. + */ +#define g1_get_gen(G) RLC_CAT(G1_LOWER, curve_get_gen)(G) + +/** + * Returns the generator of the group G_2. + * + * @param[out] G - the returned generator. + */ +#define g2_get_gen(G) RLC_CAT(G2_LOWER, curve_get_gen)(G) + +/** + * Returns the order of the group G_1. + * + * @param[out] N 0 the returned order. + */ +#define g1_get_ord(N) RLC_CAT(G1_LOWER, curve_get_ord)(N) + +/** + * Returns the order of the group G_2. + * + * @param[out] N 0 the returned order. + */ +#define g2_get_ord(N) RLC_CAT(G2_LOWER, curve_get_ord)(N) + +/** + * Returns the order of the group G_T. + * + * @param[out] N 0 the returned order. + */ +#define gt_get_ord(N) RLC_CAT(G1_LOWER, curve_get_ord)(N) + +/** + * Configures some set of curve parameters for the current security level. + */ +#define pc_param_set_any() ep_param_set_any_pairf() + +/** + * Returns the type of the configured pairing. + * + * @{ + */ +#if FP_PRIME < 1536 +#define pc_map_is_type1() (0) +#define pc_map_is_type3() (1) +#else +#define pc_map_is_type1() (1) +#define pc_map_is_type3() (0) +#endif +/** + * @} + */ + +/** + * Prints the current configured binary elliptic curve. + */ +#define pc_param_print() RLC_CAT(G1_LOWER, param_print)() + +/** + * Returns the current security level. + */ +#define pc_param_level() RLC_CAT(G1_LOWER, param_level)() + +/** + * Tests if a G_1 element is the unity. + * + * @param[in] P - the element to test. + * @return 1 if the element it the unity, 0 otherwise. + */ +#define g1_is_infty(P) RLC_CAT(G1_LOWER, is_infty)(P) + +/** + * Tests if a G_2 element is the unity. + * + * @param[in] P - the element to test. + * @return 1 if the element it the unity, 0 otherwise. + */ +#define g2_is_infty(P) RLC_CAT(G2_LOWER, is_infty)(P) + +/** + * Tests if a G_T element is the unity. + * + * @param[in] A - the element to test. + * @return 1 if the element it the unity, 0 otherwise. + */ +#define gt_is_unity(A) (RLC_CAT(GT_LOWER, cmp_dig)(A, 1) == RLC_EQ) + +/** + * Assigns a G_1 element to the unity. + * + * @param[out] P - the element to assign. + */ +#define g1_set_infty(P) RLC_CAT(G1_LOWER, set_infty)(P) + +/** + * Assigns a G_2 element to the unity. + * + * @param[out] P - the element to assign. + */ +#define g2_set_infty(P) RLC_CAT(G2_LOWER, set_infty)(P) + +/** + * Assigns a G_T element to zero. + * + * @param[out] A - the element to assign. + */ +#define gt_zero(A) RLC_CAT(GT_LOWER, zero)(A) + +/** + * Assigns a G_T element to the unity. + * + * @param[out] A - the element to assign. + */ +#define gt_set_unity(A) RLC_CAT(GT_LOWER, set_dig)(A, 1) + +/** + * Copies the second argument to the first argument. + * + * @param[out] R - the result. + * @param[in] P - the element to copy. + */ +#define g1_copy(R, P) RLC_CAT(G1_LOWER, copy)(R, P) + +/** + * Copies the second argument to the first argument. + * + * @param[out] R - the result. + * @param[in] P - the element to copy. + */ +#define g2_copy(R, P) RLC_CAT(G2_LOWER, copy)(R, P) + +/** + * Copies the second argument to the first argument. + * + * @param[out] C - the result. + * @param[in] A - the element to copy. + */ +#define gt_copy(C, A) RLC_CAT(GT_LOWER, copy)(C, A) + +/** + * Compares two elements from G_1. + * + * @param[in] P - the first element. + * @param[in] Q - the second element. + * @return RLC_EQ if P == Q and RLC_NE if P != Q. + */ +#define g1_cmp(P, Q) RLC_CAT(G1_LOWER, cmp)(P, Q) + +/** + * Compares two elements from G_2. + * + * @param[in] P - the first element. + * @param[in] Q - the second element. + * @return RLC_EQ if P == Q and RLC_NE if P != Q. + */ +#define g2_cmp(P, Q) RLC_CAT(G2_LOWER, cmp)(P, Q) + +/** + * Compares two elements from G_T. + * + * @param[in] A - the first element. + * @param[in] B - the second element. + * @return RLC_EQ if A == B and RLC_NE if P != Q. + */ +#define gt_cmp(A, B) RLC_CAT(GT_LOWER, cmp)(A, B) + +/** + * Compares a G_T element with a digit. + * + * @param[in] A - the G_T element. + * @param[in] D - the digit. + * @return RLC_EQ if A == D and RLC_NE if A != D. + */ +#define gt_cmp_dig(A, D) RLC_CAT(GT_LOWER, cmp_dig)(A, D) + +/** + * Assigns a random value to a G_1 element. + * + * @param[out] P - the element to assign. + */ +#define g1_rand(P) RLC_CAT(G1_LOWER, rand)(P) + +/** + * Assigns a random value to a G_2 element. + * + * @param[out] P - the element to assign. + */ +#define g2_rand(P) RLC_CAT(G2_LOWER, rand)(P) + +/** + * Prints a G_1 element. + * + * @param[in] P - the element to print. + */ +#define g1_print(P) RLC_CAT(G1_LOWER, print)(P) + +/** + * Prints a G_2 element. + * + * @param[in] P - the element to print. + */ +#define g2_print(P) RLC_CAT(G2_LOWER, print)(P) + +/** + * Prints a G_T element. + * + * @param[in] A - the element to print. + */ +#define gt_print(A) RLC_CAT(GT_LOWER, print)(A) + +/** + * Returns the number of bytes necessary to store a G_1 element. + * + * @param[in] P - the element of G_1. + * @param[in] C - the flag to indicate point compression. + */ +#define g1_size_bin(P, C) RLC_CAT(G1_LOWER, size_bin)(P, C) + +/** + * Returns the number of bytes necessary to store a G_2 element. + * + * @param[in] P - the element of G_2. + * @param[in] C - the flag to indicate point compression. + */ +#define g2_size_bin(P, C) RLC_CAT(G2_LOWER, size_bin)(P, C) + +/** + * Returns the number of bytes necessary to store a G_T element. + * + * @param[in] A - the element of G_T. + * @param[in] C - the flag to indicate compression. + */ +#define gt_size_bin(A, C) RLC_CAT(GT_LOWER, size_bin)(A, C) + +/** + * Reads a G_1 element from a byte vector in big-endian format. + * + * @param[out] P - the result. + * @param[in] B - the byte vector. + * @param[in] L - the buffer capacity. + * @throw ERR_NO_BUFFER - if the buffer capacity is not sufficient. + */ +#define g1_read_bin(P, B, L) RLC_CAT(G1_LOWER, read_bin)(P, B, L) + +/** + * Reads a G_2 element from a byte vector in big-endian format. + * + * @param[out] P - the result. + * @param[in] B - the byte vector. + * @param[in] L - the buffer capacity. + * @throw ERR_NO_BUFFER - if the buffer capacity is not sufficient. + */ +#define g2_read_bin(P, B, L) RLC_CAT(G2_LOWER, read_bin)(P, B, L) + +/** + * Reads a G_T element from a byte vector in big-endian format. + * + * @param[out] A - the result. + * @param[in] B - the byte vector. + * @param[in] L - the buffer capacity. + * @throw ERR_NO_BUFFER - if the buffer capacity is not sufficient. + */ +#define gt_read_bin(A, B, L) RLC_CAT(GT_LOWER, read_bin)(A, B, L) + +/** + * Writes an optionally compressed G_1 element to a byte vector in big-endian + * format. + * + * @param[out] B - the byte vector. + * @param[in] L - the buffer capacity. + * @param[in] P - the G_1 element to write. + * @param[in] C - the flag to indicate point compression. + * @throw ERR_NO_BUFFER - if the buffer capacity is not enough. + */ +#define g1_write_bin(B, L, P, C) RLC_CAT(G1_LOWER, write_bin)(B, L, P, C) + +/** + * Writes an optionally compressed G_2 element to a byte vector in big-endian + * format. + * + * @param[out] B - the byte vector. + * @param[in] L - the buffer capacity. + * @param[in] P - the G_2 element to write. + * @param[in] C - the flag to indicate point compression. + * @throw ERR_NO_BUFFER - if the buffer capacity is not enough. + */ +#define g2_write_bin(B, L, P, C) RLC_CAT(G2_LOWER, write_bin)(B, L, P, C) + +/** + * Writes an optionally compresseds G_T element to a byte vector in big-endian + * format. + * + * @param[out] B - the byte vector. + * @param[in] L - the buffer capacity. + * @param[in] A - the G_T element to write. + * @param[in] C - the flag to indicate point compression. + * @throw ERR_NO_BUFFER - if the buffer capacity is not sufficient. + */ +#define gt_write_bin(B, L, A, C) RLC_CAT(GT_LOWER, write_bin)(B, L, A, C) + +/** + * Negates a element from G_1. Computes R = -P. + * + * @param[out] R - the result. + * @param[in] P - the element to negate. + */ +#define g1_neg(R, P) RLC_CAT(G1_LOWER, neg)(R, P) + +/** + * Negates a element from G_2. Computes R = -P. + * + * @param[out] R - the result. + * @param[in] P - the element to negate. + */ +#define g2_neg(R, P) RLC_CAT(G2_LOWER, neg)(R, P) + +/** + * Inverts a element from G_T. Computes C = 1/A. + * + * @param[out] C - the result. + * @param[in] A - the element to invert. + */ +#define gt_inv(C, A) RLC_CAT(GT_LOWER, inv_cyc)(C, A) + +/** + * Adds two elliptic elements from G_1. Computes R = P + Q. + * + * @param[out] R - the result. + * @param[in] P - the first element to add. + * @param[in] Q - the second element to add. + */ +#define g1_add(R, P, Q) RLC_CAT(G1_LOWER, add)(R, P, Q) + +/** + * Adds two elliptic elements from G_2. Computes R = P + Q. + * + * @param[out] R - the result. + * @param[in] P - the first element to add. + * @param[in] Q - the second element to add. + */ +#define g2_add(R, P, Q) RLC_CAT(G2_LOWER, add)(R, P, Q) + +/** + * Multiplies two elliptic elements from G_T. Computes C = A * B. + * + * @param[out] C - the result. + * @param[in] A - the first element to multiply. + * @param[in] B - the second element to multiply. + */ +#define gt_mul(C, A, B) RLC_CAT(GT_LOWER, mul)(C, A, B) + +/** + * Subtracts a G_1 element from another. Computes R = P - Q. + * + * @param[out] R - the result. + * @param[in] P - the first element. + * @param[in] Q - the second element. + */ +#define g1_sub(R, P, Q) RLC_CAT(G1_LOWER, sub)(R, P, Q) + +/** + * Subtracts a G_2 element from another. Computes R = P - Q. + * + * @param[out] R - the result. + * @param[in] P - the first element. + * @param[in] Q - the second element. + */ +#define g2_sub(R, P, Q) RLC_CAT(G2_LOWER, sub)(R, P, Q) + +/** + * Doubles a G_1 element. Computes R = 2P. + * + * @param[out] R - the result. + * @param[in] P - the element to double. + */ +#define g1_dbl(R, P) RLC_CAT(G1_LOWER, dbl)(R, P) + +/** + * Doubles a G_2 element. Computes R = 2P. + * + * @param[out] R - the result. + * @param[in] P - the element to double. + */ +#define g2_dbl(R, P) RLC_CAT(G2_LOWER, dbl)(R, P) + +/** + * Squares a G_T element. Computes C = A^2. + * + * @param[out] C - the result. + * @param[in] A - the element to square. + */ +#define gt_sqr(C, A) RLC_CAT(GT_LOWER, sqr)(C, A) + +/** + * Normalizes an element of G_1. + * + * @param[out] R - the result. + * @param[in] P - the element to normalize. + */ +#define g1_norm(R, P) RLC_CAT(G1_LOWER, norm)(R, P) + +/** + * Normalizes a vector of G_1 elements. + * + * @param[out] R - the result. + * @param[in] P - the elements to normalize. + * @param[in] N - the number of elements to normalize. + */ +#define g1_norm_sim(R, P, N) RLC_CAT(G1_LOWER, norm_sim)(R, P, N) + +/** + * Normalizes an element of G_2. + * + * @param[out] R - the result. + * @param[in] P - the element to normalize. + */ +#define g2_norm(R, P) RLC_CAT(G2_LOWER, norm)(R, P) + +/** + * Normalizes a vector of G_2 elements. + * + * @param[out] R - the result. + * @param[in] P - the elements to normalize. + * @param[in] N - the number of elements to normalize. + */ +#define g2_norm_sim(R, P, N) RLC_CAT(G2_LOWER, norm_sim)(R, P, N) + +/** + * Multiplies an element from G_1 by a secret scalar. Computes R = kP. + * + * @param[out] R - the result. + * @param[in] P - the element to multiply. + * @param[in] K - the secret scalar. + */ +#define g1_mul_key(R, P, K) RLC_CAT(G1_LOWER, mul_lwreg)(R, P, K) + +/** + * Multiplies an element from G_1 by a small integer. Computes R = kP. + * + * @param[out] R - the result. + * @param[in] P - the element to multiply. + * @param[in] K - the small integer. + */ +#define g1_mul_dig(R, P, K) RLC_CAT(G1_LOWER, mul_dig)(R, P, K) + +/** + * Multiplies an element from G_2 by a small integer. Computes R = kP. + * + * @param[out] R - the result. + * @param[in] P - the element to multiply. + * @param[in] K - the small integer. + */ +#define g2_mul_dig(R, P, K) RLC_CAT(G2_LOWER, mul_dig)(R, P, K) + +/** + * Exponentiates an element from G_T by a small integer. Computes c = a^b. + * + * @param[out] R - the result. + * @param[in] P - the element to multiply. + * @param[in] K - the small integer. + */ +#define gt_exp_dig(C, A, B) RLC_CAT(GT_LOWER, exp_dig)(C, A, B) + +/** + * Multiplies the generator of G_1 by an integer. + * + * @param[out] R - the result. + * @param[in] K - the integer. + */ +#define g1_mul_gen(R, K) RLC_CAT(G1_LOWER, mul_gen)(R, K) + +/** + * Multiplies the generator of G_2 by an integer. + * + * @param[out] R - the result. + * @param[in] K - the integer. + */ +#define g2_mul_gen(R, K) RLC_CAT(G2_LOWER, mul_gen)(R, K) + +/** + * Builds a precomputation table for multiplying an element from G_1. + * + * @param[out] T - the precomputation table. + * @param[in] P - the element to multiply. + */ +#define g1_mul_pre(T, P) RLC_CAT(G1_LOWER, mul_pre)(T, P) + +/** + * Builds a precomputation table for multiplying an element from G_2. + * + * @param[out] T - the precomputation table. + * @param[in] P - the element to multiply. + */ +#define g2_mul_pre(T, P) RLC_CAT(G2_LOWER, mul_pre)(T, P) + +/** + * Multiplies an element from G_1 using a precomputation table. + * Computes R = kP. + * + * @param[out] R - the result. + * @param[in] T - the precomputation table. + * @param[in] K - the integer. + */ +#define g1_mul_fix(R, T, K) RLC_CAT(G1_LOWER, mul_fix)(R, T, K) + +/** + * Multiplies an element from G_2 using a precomputation table. + * Computes R = kP. + * + * @param[out] R - the result. + * @param[in] T - the precomputation table. + * @param[in] K - the integer. + */ +#define g2_mul_fix(R, T, K) RLC_CAT(G2_LOWER, mul_fix)(R, T, K) + +/** + * Multiplies simultaneously two elements from G_1. Computes R = kP + lQ. + * + * @param[out] R - the result. + * @param[out] P - the first G_1 element to multiply. + * @param[out] K - the first integer scalar. + * @param[out] L - the second G_1 element to multiply. + * @param[out] Q - the second integer scalar. + */ +#define g1_mul_sim(R, P, K, Q, L) RLC_CAT(G1_LOWER, mul_sim)(R, P, K, Q, L) + +/** + * Multiplies elements from G_1 by small scalars. Computes R = \sum k_iP_i. + * + * @param[out] R - the result. + * @param[in] P - the elements to multiply. + * @param[in] K - the small scalars. + * @param[in] L - the number of points to multiply. + */ +#define g1_mul_sim_dig(R, P, K, L) RLC_CAT(G1_LOWER, mul_sim_dig)(R, P, K, L) + +/** + * Multiplies simultaneously two elements from G_2. Computes R = kP + lQ. + * + * @param[out] R - the result. + * @param[out] P - the first G_2 element to multiply. + * @param[out] K - the first integer scalar. + * @param[out] L - the second G_2 element to multiply. + * @param[out] Q - the second integer scalar. + */ +#define g2_mul_sim(R, P, K, Q, L) RLC_CAT(G2_LOWER, mul_sim)(R, P, K, Q, L) + +/** + * Multiplies elements from G_2 by small scalars. Computes R = \sum k_iP_i. + * + * @param[out] R - the result. + * @param[in] P - the elements to multiply. + * @param[in] K - the small scalars. + * @param[in] L - the number of points to multiply. + */ +#define g2_mul_sim_dig(R, P, K, L) RLC_CAT(G2_LOWER, mul_sim_dig)(R, P, K, L) + +/** + * Multiplies simultaneously two elements from G_1, where one of the is the + * generator. Computes R = kG + lQ. + * + * @param[out] R - the result. + * @param[out] K - the first integer scalar. + * @param[out] L - the second G_1 element to multiply. + * @param[out] Q - the second integer scalar. + */ +#define g1_mul_sim_gen(R, K, Q, L) RLC_CAT(G1_LOWER, mul_sim_gen)(R, K, Q, L) + +/** + * Multiplies simultaneously two elements from G_1, where one of the is the + * generator. Computes R = kG + lQ. + * + * @param[out] R - the result. + * @param[out] K - the first integer scalar. + * @param[out] L - the second G_1 element to multiply. + * @param[out] Q - the second integer scalar. + */ +#define g2_mul_sim_gen(R, K, Q, L) RLC_CAT(G2_LOWER, mul_sim_gen)(R, K, Q, L) + +/** + * Maps a byte array to an element in G_1. + * + * @param[out] P - the result. + * @param[in] M - the byte array to map. + * @param[in] L - the array length in bytes. + */ +#define g1_map(P, M, L); RLC_CAT(G1_LOWER, map)(P, M, L) + +/** + * Maps a byte array to an element in G_2. + * + * @param[out] P - the result. + * @param[in] M - the byte array to map. + * @param[in] L - the array length in bytes. + * @param[in] H - whether to hash internally. + */ +#define g2_map(P, M, L, H); RLC_CAT(G2_LOWER, map)(P, M, L, H) + +/** + * Computes the bilinear pairing of a G_1 element and a G_2 element. Computes + * R = e(P, Q). + * + * @param[out] R - the result. + * @param[in] P - the first element. + * @param[in] Q - the second element. + */ +#if FP_PRIME < 1536 +#define pc_map(R, P, Q); RLC_CAT(PC_LOWER, map_k12)(R, P, Q) +#else +#define pc_map(R, P, Q); RLC_CAT(PC_LOWER, map_k2)(R, P, Q) +#endif + +/** + * Computes the multi-pairing of G_1 elements and G_2 elements. Computes + * R = \prod e(P_i, Q_i). + * + * @param[out] R - the result. + * @param[in] P - the first pairing arguments. + * @param[in] Q - the second pairing arguments. + * @param[in] M - the number of pairing arguments. + */ +#if FP_PRIME < 1536 +#define pc_map_sim(R, P, Q, M); RLC_CAT(PC_LOWER, map_sim_k12)(R, P, Q, M) +#else +#define pc_map_sim(R, P, Q, M); RLC_CAT(PC_LOWER, map_sim_k2)(R, P, Q, M) +#endif + +/** + * Computes the final exponentiation of the pairing. + * + * @param[out] C - the result. + * @param[in] A - the field element to exponentiate. + */ +#if FP_PRIME < 1536 +#define pc_exp(C, A); RLC_CAT(PC_LOWER, exp_k12)(C, A) +#else +#define pc_exp(C, A); RLC_CAT(PC_LOWER, exp_k2)(C, A) +#endif + +/*============================================================================*/ +/* Function prototypes */ +/*============================================================================*/ + +/** + * Assigns a random value to an element from G_T. + * + * @param[out] a - the element to assign. + */ +void gt_rand(gt_t a); + +/** + * Multiplies an element from G_1 by an integer. Computes R = kP. + * + * @param[out] r - the result. + * @param[in] p - the element to multiply. + * @param[in] k - the integer. + */ +void g1_mul(g1_t r, g1_t p, bn_t k); + +/** + * Multiplies an element from G_2 by an integer. Computes R = kP. + * + * @param[out] r - the result. + * @param[in] p - the element to multiply. + * @param[in] k - the integer. + */ +void g2_mul(g2_t r, g2_t p, bn_t k); + +/** + * Exponentiates an element from G_T by an integer. Computes c = a^b. + * + * @param[out] c - the result. + * @param[in] a - the element to exponentiate. + * @param[in] b - the integer exponent. + */ +void gt_exp(gt_t c, gt_t a, bn_t b); + + /** + * Returns the generator for the group G_T. + * + * @param[out] g - the returned generator. + */ +void gt_get_gen(gt_t g); + +/** + * Checks if an element from G_1 is valid (has the right order). + * + * @param[in] a - the element to check. + */ +int g1_is_valid(g1_t a); + +/** + * Checks if an element form G_2 is valid (has the right order). + * + * @param[in] a - the element to check. + */ +int g2_is_valid(g2_t a); + +/** + * Checks if an element form G_T is valid (has the right order). + * + * @param[in] a - the element to check. + */ +int gt_is_valid(gt_t a); + +#endif /* !RLC_PC_H */ diff --git a/bls/contrib/relic/include/relic_pp.h b/bls/contrib/relic/include/relic_pp.h new file mode 100644 index 00000000..15502c14 --- /dev/null +++ b/bls/contrib/relic/include/relic_pp.h @@ -0,0 +1,911 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @defgroup pp Bilinear pairings over prime elliptic curves. + */ + +/** + * @file + * + * Interface of the module for computing bilinear pairings over prime elliptic + * curves. + * + * @ingroup pp + */ + +#ifndef RLC_PP_H +#define RLC_PP_H + +#include "relic_fpx.h" +#include "relic_epx.h" +#include "relic_types.h" + +/*============================================================================*/ +/* Macro definitions */ +/*============================================================================*/ + +/** + * Adds two points and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 2. + * + * @param[out] L - the result of the evaluation. + * @param[in, out] R - the resulting point and first point to add. + * @param[in] P - the second point to add. + * @param[in] Q - the affine point to evaluate the line function. + */ +#if EP_ADD == BASIC +#define pp_add_k2(L, R, P, Q) pp_add_k2_basic(L, R, P, Q) +#elif EP_ADD == PROJC +#define pp_add_k2(L, R, P, Q) pp_add_k2_projc(L, R, P, Q) +#endif + +/** + * Adds two points and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 2 using projective + * coordinates. + * + * @param[out] L - the result of the evaluation. + * @param[in, out] R - the resulting point and first point to add. + * @param[in] P - the second point to add. + * @param[in] Q - the affine point to evaluate the line function. + */ +#if PP_EXT == BASIC +#define pp_add_k2_projc(L, R, P, Q) pp_add_k2_projc_basic(L, R, P, Q) +#elif PP_EXT == LAZYR +#define pp_add_k2_projc(L, R, P, Q) pp_add_k2_projc_lazyr(L, R, P, Q) +#endif + +/** + * Adds two points and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 8. + * + * @param[out] L - the result of the evaluation. + * @param[in, out] R - the resulting point and first point to add. + * @param[in] Q - the second point to add. + * @param[in] P - the affine point to evaluate the line function. + */ +#if EP_ADD == BASIC +#define pp_add_k8(L, R, Q, P) pp_add_k8_basic(L, R, Q, P) +#elif EP_ADD == PROJC +#define pp_add_k8(L, R, Q, P) pp_add_k8_projc(L, R, Q, P) +#endif + +/** + * Adds two points and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 8 using projective + * coordinates. + * + * @param[out] L - the result of the evaluation. + * @param[in, out] R - the resulting point and first point to add. + * @param[in] Q - the second point to add. + * @param[in] P - the affine point to evaluate the line function. + */ +#if PP_EXT == BASIC +#define pp_add_k8_projc(L, R, Q, P) pp_add_k8_projc_basic(L, R, Q, P) +#elif PP_EXT == LAZYR +#define pp_add_k8_projc(L, R, Q, P) pp_add_k8_projc_lazyr(L, R, Q, P) +#endif + +/** + * Adds two points and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 12. + * + * @param[out] L - the result of the evaluation. + * @param[in, out] R - the resulting point and first point to add. + * @param[in] Q - the second point to add. + * @param[in] P - the affine point to evaluate the line function. + */ +#if EP_ADD == BASIC +#define pp_add_k12(L, R, Q, P) pp_add_k12_basic(L, R, Q, P) +#elif EP_ADD == PROJC +#define pp_add_k12(L, R, Q, P) pp_add_k12_projc(L, R, Q, P) +#endif + +/** + * Adds two points and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 12 using projective + * coordinates. + * + * @param[out] L - the result of the evaluation. + * @param[in, out] R - the resulting point and first point to add. + * @param[in] Q - the second point to add. + * @param[in] P - the affine point to evaluate the line function. + */ +#if PP_EXT == BASIC +#define pp_add_k12_projc(L, R, Q, P) pp_add_k12_projc_basic(L, R, Q, P) +#elif PP_EXT == LAZYR +#define pp_add_k12_projc(L, R, Q, P) pp_add_k12_projc_lazyr(L, R, Q, P) +#endif + +/** + * Adds two points and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 48. + * + * @param[out] L - the result of the evaluation. + * @param[in, out] R - the resulting point and first point to add. + * @param[in] Q - the second point to add. + * @param[in] P - the affine point to evaluate the line function. + */ +#if EP_ADD == BASIC +#define pp_add_k48(L, RX, RY, RZ, QX, QY, P) pp_add_k48_basic(L, RX, RY, QX, QY, P) +#elif EP_ADD == PROJC +#define pp_add_k48(L, RX, RY, RZ, QX, QY, P) pp_add_k48_projc(L, RX, RY, RZ, QX, QY, P) +#endif + +/** + * Adds two points and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 54. + * + * @param[out] L - the result of the evaluation. + * @param[in, out] R - the resulting point and first point to add. + * @param[in] Q - the second point to add. + * @param[in] P - the affine point to evaluate the line function. + */ +#if EP_ADD == BASIC +#define pp_add_k54(L, RX, RY, RZ, QX, QY, P) pp_add_k54_basic(L, RX, RY, QX, QY, P) +#elif EP_ADD == PROJC +#define pp_add_k54(L, RX, RY, RZ, QX, QY, P) pp_add_k54_projc(L, RX, RY, RZ, QX, QY, P) +#endif + +/** + * Doubles a point and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 2. + * + * @param[out] L - the result of the evaluation. + * @param[out] R - the resulting point. + * @param[in] P - the point to double. + * @param[in] Q - the affine point to evaluate the line function. + */ +#if EP_ADD == BASIC +#define pp_dbl_k2(L, R, P, Q) pp_dbl_k2_basic(L, R, P, Q) +#elif EP_ADD == PROJC +#define pp_dbl_k2(L, R, P, Q) pp_dbl_k2_projc(L, R, P, Q) +#endif + +/** + * Doubles a point and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 8. + * + * @param[out] L - the result of the evaluation. + * @param[out] R - the resulting point. + * @param[in] Q - the point to double. + * @param[in] P - the affine point to evaluate the line function. + */ +#if EP_ADD == BASIC +#define pp_dbl_k8(L, R, Q, P) pp_dbl_k8_basic(L, R, Q, P) +#elif EP_ADD == PROJC +#define pp_dbl_k8(L, R, Q, P) pp_dbl_k8_projc(L, R, Q, P) +#endif + +/** + * Doubles a point and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 12. + * + * @param[out] L - the result of the evaluation. + * @param[out] R - the resulting point. + * @param[in] Q - the point to double. + * @param[in] P - the affine point to evaluate the line function. + */ +#if EP_ADD == BASIC +#define pp_dbl_k12(L, R, Q, P) pp_dbl_k12_basic(L, R, Q, P) +#elif EP_ADD == PROJC +#define pp_dbl_k12(L, R, Q, P) pp_dbl_k12_projc(L, R, Q, P) +#endif + +/** + * Doubles a point and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 12 using projective + * coordinates. + * + * @param[out] L - the result of the evaluation. + * @param[in, out] R - the resulting point. + * @param[in] Q - the point to double. + * @param[in] P - the affine point to evaluate the line function. + */ +#if PP_EXT == BASIC +#define pp_dbl_k8_projc(L, R, Q, P) pp_dbl_k8_projc_basic(L, R, Q, P) +#elif PP_EXT == LAZYR +#define pp_dbl_k8_projc(L, R, Q, P) pp_dbl_k8_projc_lazyr(L, R, Q, P) +#endif + +/** + * Doubles a point and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 2 using projective + * coordinates. + * + * @param[out] L - the result of the evaluation. + * @param[in, out] R - the resulting point. + * @param[in] Q - the point to double. + * @param[in] P - the affine point to evaluate the line function. + */ +#if PP_EXT == BASIC +#define pp_dbl_k2_projc(L, R, P, Q) pp_dbl_k2_projc_basic(L, R, P, Q) +#elif PP_EXT == LAZYR +#define pp_dbl_k2_projc(L, R, P, Q) pp_dbl_k2_projc_lazyr(L, R, P, Q) +#endif + +/** + * Doubles a point and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 12 using projective + * coordinates. + * + * @param[out] L - the result of the evaluation. + * @param[in, out] R - the resulting point. + * @param[in] Q - the point to double. + * @param[in] P - the affine point to evaluate the line function. + */ +#if PP_EXT == BASIC +#define pp_dbl_k12_projc(L, R, Q, P) pp_dbl_k12_projc_basic(L, R, Q, P) +#elif PP_EXT == LAZYR +#define pp_dbl_k12_projc(L, R, Q, P) pp_dbl_k12_projc_lazyr(L, R, Q, P) +#endif + +/** + * Doubles a point and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 48. + * + * @param[out] L - the result of the evaluation. + * @param[out] R - the resulting point. + * @param[in] Q - the point to double. + * @param[in] P - the affine point to evaluate the line function. + */ +#if EP_ADD == BASIC +#define pp_dbl_k48(L, RX, RY, RZ, P) pp_dbl_k48_basic(L, RX, RY, P) +#elif EP_ADD == PROJC +#define pp_dbl_k48(L, RX, RY, RZ, P) pp_dbl_k48_projc(L, RX, RY, RZ, P) +#endif + +/** + * Doubles a point and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 54. + * + * @param[out] L - the result of the evaluation. + * @param[out] R - the resulting point. + * @param[in] Q - the point to double. + * @param[in] P - the affine point to evaluate the line function. + */ +#if EP_ADD == BASIC +#define pp_dbl_k54(L, RX, RY, RZ, P) pp_dbl_k54_basic(L, RX, RY, P) +#elif EP_ADD == PROJC +#define pp_dbl_k54(L, RX, RY, RZ, P) pp_dbl_k54_projc(L, RX, RY, RZ, P) +#endif + +/** + * Computes a pairing of two prime elliptic curve points defined on an elliptic + * curves of embedding degree 2. Computes e(P, Q). + * + * @param[out] R - the result. + * @param[in] P - the first elliptic curve point. + * @param[in] Q - the second elliptic curve point. + */ +#if PP_MAP == TATEP +#define pp_map_k2(R, P, Q) pp_map_tatep_k2(R, P, Q) +#elif PP_MAP == WEILP +#define pp_map_k2(R, P, Q) pp_map_weilp_k2(R, P, Q) +#elif PP_MAP == OATEP +#define pp_map_k2(R, P, Q) pp_map_tatep_k2(R, P, Q) +#endif + +/** + * Computes a pairing of two prime elliptic curve points defined on an elliptic + * curve of embedding degree 12. Computes e(P, Q). + * + * @param[out] R - the result. + * @param[in] P - the first elliptic curve point. + * @param[in] Q - the second elliptic curve point. + */ +#if PP_MAP == TATEP +#define pp_map_k12(R, P, Q) pp_map_tatep_k12(R, P, Q) +#elif PP_MAP == WEILP +#define pp_map_k12(R, P, Q) pp_map_weilp_k12(R, P, Q) +#elif PP_MAP == OATEP +#define pp_map_k12(R, P, Q) pp_map_oatep_k12(R, P, Q) +#endif + +/** + * Computes a multi-pairing of elliptic curve points defined on an elliptic + * curve of embedding degree 2. Computes \prod e(P_i, Q_i). + * + * @param[out] R - the result. + * @param[in] P - the first pairing arguments. + * @param[in] Q - the second pairing arguments. + * @param[in] M - the number of pairings to evaluate. + */ +#if PP_MAP == WEILP +#define pp_map_sim_k2(R, P, Q, M) pp_map_sim_weilp_k2(R, P, Q, M) +#elif PP_MAP == TATEP || PP_MAP == OATEP +#define pp_map_sim_k2(R, P, Q, M) pp_map_sim_tatep_k2(R, P, Q, M) +#endif + + +/** + * Computes a multi-pairing of elliptic curve points defined on an elliptic + * curve of embedding degree 12. Computes \prod e(P_i, Q_i). + * + * @param[out] R - the result. + * @param[in] P - the first pairing arguments. + * @param[in] Q - the second pairing arguments. + * @param[in] M - the number of pairings to evaluate. + */ +#if PP_MAP == TATEP +#define pp_map_sim_k12(R, P, Q, M) pp_map_sim_tatep_k12(R, P, Q, M) +#elif PP_MAP == WEILP +#define pp_map_sim_k12(R, P, Q, M) pp_map_sim_weilp_k12(R, P, Q, M) +#elif PP_MAP == OATEP +#define pp_map_sim_k12(R, P, Q, M) pp_map_sim_oatep_k12(R, P, Q, M) +#endif + +/*============================================================================*/ +/* Function prototypes */ +/*============================================================================*/ + +/** + * Initializes the pairing over prime fields. + */ +void pp_map_init(void); + +/** + * Finalizes the pairing over prime fields. + */ +void pp_map_clean(void); + +/** + * Adds two points and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 2 using affine coordinates. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point and first point to add. + * @param[in] p - the second point to add. + * @param[in] q - the affine point to evaluate the line function. + */ +void pp_add_k2_basic(fp2_t l, ep_t r, ep_t p, ep_t q); + +/** + * Adds two points and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 12 using projective + * coordinates. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point and first point to add. + * @param[in] p - the second point to add. + * @param[in] q - the affine point to evaluate the line function. + */ +void pp_add_k2_projc_basic(fp2_t l, ep_t r, ep_t p, ep_t q); + +/** + * Adds two points and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 12 using projective + * coordinates and lazy reduction. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point and first point to add. + * @param[in] p - the second point to add. + * @param[in] q - the affine point to evaluate the line function. + */ +void pp_add_k2_projc_lazyr(fp2_t l, ep_t r, ep_t p, ep_t q); + +/** + * Adds two points and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 8 using affine coordinates. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point and first point to add. + * @param[in] q - the second point to add. + * @param[in] p - the affine point to evaluate the line function. + */ +void pp_add_k8_basic(fp8_t l, ep2_t r, ep2_t q, ep_t p); + +/** + * Adds two points and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 8 using projective + * coordinates. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point and first point to add. + * @param[in] q - the second point to add. + * @param[in] p - the affine point to evaluate the line function. + */ +void pp_add_k8_projc_basic(fp8_t l, ep2_t r, ep2_t q, ep_t p); + +/** + * Adds two points and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 8 using projective + * coordinates and lazy reduction. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point and first point to add. + * @param[in] q - the second point to add. + * @param[in] p - the affine point to evaluate the line function. + */ +void pp_add_k8_projc_lazyr(fp8_t l, ep2_t r, ep2_t q, ep_t p); + +/** + * Adds two points and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 12 using affine coordinates. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point and first point to add. + * @param[in] q - the second point to add. + * @param[in] p - the affine point to evaluate the line function. + */ +void pp_add_k12_basic(fp12_t l, ep2_t r, ep2_t q, ep_t p); + +/** + * Adds two points and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 12 using projective + * coordinates. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point and first point to add. + * @param[in] q - the second point to add. + * @param[in] p - the affine point to evaluate the line function. + */ +void pp_add_k12_projc_basic(fp12_t l, ep2_t r, ep2_t q, ep_t p); + +/** + * Adds two points and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 12 using projective + * coordinates and lazy reduction. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point and first point to add. + * @param[in] q - the second point to add. + * @param[in] p - the affine point to evaluate the line function. + */ +void pp_add_k12_projc_lazyr(fp12_t l, ep2_t r, ep2_t q, ep_t p); + +/** + * Adds two points and evaluates the corresponding line function at another + * point on an elliptic curve twist with embedding degree 12 using projective + * coordinates. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point and first point to add. + * @param[in] p - the second point to add. + * @param[in] q - the affine point to evaluate the line function. + */ +void pp_add_lit_k12(fp12_t l, ep_t r, ep_t p, ep2_t q); + +/** + * Adds two points and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 48 using affine coordinates. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point and first point to add. + * @param[in] q - the second point to add. + * @param[in] p - the affine point to evaluate the line function. + */ +void pp_add_k48_basic(fp48_t l, fp8_t rx, fp8_t ry, fp8_t qx, fp8_t qy, ep_t p); + +/** + * Adds two points and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 48 using projective + * coordinates. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point and first point to add. + * @param[in] q - the second point to add. + * @param[in] p - the affine point to evaluate the line function. + */ +void pp_add_k48_projc(fp48_t l, fp8_t rx, fp8_t ry, fp8_t rz, fp8_t qx, fp8_t qy, ep_t p); + +/** + * Adds two points and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 54 using affine coordinates. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point and first point to add. + * @param[in] q - the second point to add. + * @param[in] p - the affine point to evaluate the line function. + */ +void pp_add_k54_basic(fp54_t l, fp9_t rx, fp9_t ry, fp9_t qx, fp9_t qy, ep_t p); + +/** + * Adds two points and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 54 using projective + * coordinates. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point and first point to add. + * @param[in] q - the second point to add. + * @param[in] p - the affine point to evaluate the line function. + */ +void pp_add_k54_projc(fp54_t l, fp9_t rx, fp9_t ry, fp9_t rz, fp9_t qx, fp9_t qy, ep_t p); + +/** + * Doubles a point and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 2 using affine + * coordinates. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point. + * @param[in] p - the point to double. + * @param[in] q - the affine point to evaluate the line function. + */ +void pp_dbl_k2_basic(fp2_t l, ep_t r, ep_t p, ep_t q); + +/** + * Doubles a point and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 12 using projective + * coordinates. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point. + * @param[in] p - the point to double. + * @param[in] q - the affine point to evaluate the line function. + */ +void pp_dbl_k2_projc_basic(fp2_t l, ep_t r, ep_t p, ep_t q); + +/** + * Doubles a point and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 12 using projective + * coordinates and lazy reduction. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point. + * @param[in] p - the point to double. + * @param[in] q - the affine point to evaluate the line function. + */ +void pp_dbl_k2_projc_lazyr(fp2_t l, ep_t r, ep_t p, ep_t q); + +/** + * Doubles a point and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 8 using affine + * coordinates. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point. + * @param[in] q - the point to double. + * @param[in] p - the affine point to evaluate the line function. + */ +void pp_dbl_k8_basic(fp8_t l, ep2_t r, ep2_t q, ep_t p); + +/** + * Doubles a point and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 8 using projective + * coordinates. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point. + * @param[in] q - the point to double. + * @param[in] p - the affine point to evaluate the line function. + */ +void pp_dbl_k8_projc_basic(fp8_t l, ep2_t r, ep2_t q, ep_t p); + +/** + * Doubles a point and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 8 using projective + * coordinates and lazy reduction. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point. + * @param[in] q - the point to double. + * @param[in] p - the affine point to evaluate the line function. + */ +void pp_dbl_k8_projc_lazyr(fp8_t l, ep2_t r, ep2_t q, ep_t p); + +/** + * Doubles a point and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 12 using affine + * coordinates. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point. + * @param[in] q - the point to double. + * @param[in] p - the affine point to evaluate the line function. + */ +void pp_dbl_k12_basic(fp12_t l, ep2_t r, ep2_t q, ep_t p); + +/** + * Doubles a point and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 12 using projective + * coordinates. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point. + * @param[in] q - the point to double. + * @param[in] p - the affine point to evaluate the line function. + */ +void pp_dbl_k12_projc_basic(fp12_t l, ep2_t r, ep2_t q, ep_t p); + +/** + * Doubles a point and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 12 using projective + * coordinates and lazy reduction. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point. + * @param[in] q - the point to double. + * @param[in] p - the affine point to evaluate the line function. + */ +void pp_dbl_k12_projc_lazyr(fp12_t l, ep2_t r, ep2_t q, ep_t p); + +/** + * Doubles a point and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 48 using affine + * coordinates. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point. + * @param[in] q - the point to double. + * @param[in] p - the affine point to evaluate the line function. + */ +void pp_dbl_k48_basic(fp48_t l, fp8_t rx, fp8_t ry, ep_t p); + +/** + * Doubles a point and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 48 using projective + * coordinates. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point. + * @param[in] q - the point to double. + * @param[in] p - the affine point to evaluate the line function. + */ +void pp_dbl_k48_projc(fp48_t l, fp8_t rx, fp8_t ry, fp8_t rz, ep_t p); + +/** + * Doubles a point and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 54 using affine + * coordinates. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point. + * @param[in] q - the point to double. + * @param[in] p - the affine point to evaluate the line function. + */ +void pp_dbl_k54_basic(fp54_t l, fp9_t rx, fp9_t ry, ep_t p); + +/** + * Doubles a point and evaluates the corresponding line function at another + * point on an elliptic curve with embedding degree 54 using projective + * coordinates. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point. + * @param[in] q - the point to double. + * @param[in] p - the affine point to evaluate the line function. + */ +void pp_dbl_k54_projc(fp54_t l, fp9_t rx, fp9_t ry, fp9_t rz, ep_t p); + +/** + * Doubles a point and evaluates the corresponding line function at another + * point on an elliptic curve twist with embedding degree 12 using projective + * coordinates. + * + * @param[out] l - the result of the evaluation. + * @param[in, out] r - the resulting point. + * @param[in] p - the point to double. + * @param[in] q - the affine point to evaluate the line function. + */ +void pp_dbl_lit_k12(fp12_t l, ep_t r, ep_t p, ep2_t q); + +/** + * Computes the final exponentiation for a pairing defined over curves of + * embedding degree 2. Computes c = a^(p^2 - 1)/r. + * + * @param[out] c - the result. + * @param[in] a - the extension field element to exponentiate. + */ +void pp_exp_k2(fp2_t c, fp2_t a); + +/** + * Computes the final exponentiation for a pairing defined over curves of + * embedding degree 8. Computes c = a^(p^8 - 1)/r. + * + * @param[out] c - the result. + * @param[in] a - the extension field element to exponentiate. + */ +void pp_exp_k8(fp8_t c, fp8_t a); + +/** + * Computes the final exponentiation for a pairing defined over curves of + * embedding degree 12. Computes c = a^(p^12 - 1)/r. + * + * @param[out] c - the result. + * @param[in] a - the extension field element to exponentiate. + */ +void pp_exp_k12(fp12_t c, fp12_t a); + +/** + * Computes the final exponentiation for a pairing defined over curves of + * embedding degree 48. Computes c = a^(p^48 - 1)/r. + * + * @param[out] c - the result. + * @param[in] a - the extension field element to exponentiate. + */ +void pp_exp_k48(fp48_t c, fp48_t a); + +/** + * Computes the final exponentiation for a pairing defined over curves of + * embedding degree 54. Computes c = a^(p^54 - 1)/r. + * + * @param[out] c - the result. + * @param[in] a - the extension field element to exponentiate. + */ +void pp_exp_k54(fp54_t c, fp54_t a); + +/** + * Normalizes the accumulator point used inside pairing computation defined + * over curves of embedding degree 2. + * + * @param[out] r - the resulting point. + * @param[in] p - the point to normalize. + */ +void pp_norm_k2(ep_t c, ep_t a); + +/** + * Normalizes the accumulator point used inside pairing computation defined + * over curves of embedding degree 8. + * + * @param[out] r - the resulting point. + * @param[in] p - the point to normalize. + */ +void pp_norm_k8(ep2_t c, ep2_t a); + +/** + * Normalizes the accumulator point used inside pairing computation defined + * over curves of embedding degree 12. + * + * @param[out] r - the resulting point. + * @param[in] p - the point to normalize. + */ +void pp_norm_k12(ep2_t c, ep2_t a); + +/** + * Computes the Tate pairing of two points in a parameterized elliptic curve + * with embedding degree 12. + * + * @param[out] r - the result. + * @param[in] q - the first elliptic curve point. + * @param[in] p - the second elliptic curve point. + */ +void pp_map_tatep_k2(fp2_t r, ep_t p, ep_t q); + +/** + * Computes the Tate multi-pairing of in a parameterized elliptic curve with + * embedding degree 2. + * + * @param[out] r - the result. + * @param[in] q - the first pairing arguments. + * @param[in] p - the second pairing arguments. + * @param[in] m - the number of pairings to evaluate. + */ +void pp_map_sim_tatep_k2(fp2_t r, ep_t *p, ep_t *q, int m); + +/** + * Computes the Weil pairing of two points in a parameterized elliptic curve + * with embedding degree 2. + * + * @param[out] r - the result. + * @param[in] q - the first elliptic curve point. + * @param[in] p - the second elliptic curve point. + */ +void pp_map_weilp_k2(fp2_t r, ep_t p, ep_t q); + +/** + * Computes the optimal ate pairing of two points in a parameterized elliptic + * curve with embedding degree 8. + * + * @param[out] r - the result. + * @param[in] q - the first elliptic curve point. + * @param[in] p - the second elliptic curve point. + */ +void pp_map_oatep_k8(fp8_t r, ep_t p, ep2_t q); + +/** + * Computes the Weil multi-pairing of in a parameterized elliptic curve with + * embedding degree 2. + * + * @param[out] r - the result. + * @param[in] q - the first pairing arguments. + * @param[in] p - the second pairing arguments. + * @param[in] m - the number of pairings to evaluate. + */ +void pp_map_sim_weilp_k2(fp2_t r, ep_t *p, ep_t *q, int m); + +/** + * Computes the Tate pairing of two points in a parameterized elliptic curve + * with embedding degree 12. + * + * @param[out] r - the result. + * @param[in] q - the first elliptic curve point. + * @param[in] p - the second elliptic curve point. + */ +void pp_map_tatep_k12(fp12_t r, ep_t p, ep2_t q); + +/** + * Computes the Tate multi-pairing of in a parameterized elliptic curve with + * embedding degree 12. + * + * @param[out] r - the result. + * @param[in] q - the first pairing arguments. + * @param[in] p - the second pairing arguments. + * @param[in] m - the number of pairings to evaluate. + */ +void pp_map_sim_tatep_k12(fp12_t r, ep_t *p, ep2_t *q, int m); + +/** + * Computes the Weil pairing of two points in a parameterized elliptic curve + * with embedding degree 12. + * + * @param[out] r - the result. + * @param[in] q - the first elliptic curve point. + * @param[in] p - the second elliptic curve point. + */ +void pp_map_weilp_k12(fp12_t r, ep_t p, ep2_t q); + +/** + * Computes the Weil multi-pairing of in a parameterized elliptic curve with + * embedding degree 12. + * + * @param[out] r - the result. + * @param[in] q - the first pairing arguments. + * @param[in] p - the second pairing arguments. + * @param[in] m - the number of pairings to evaluate. + */ +void pp_map_sim_weilp_k12(fp12_t r, ep_t *p, ep2_t *q, int m); + +/** + * Computes the optimal ate pairing of two points in a parameterized elliptic + * curve with embedding degree 12. + * + * @param[out] r - the result. + * @param[in] q - the first elliptic curve point. + * @param[in] p - the second elliptic curve point. + */ +void pp_map_oatep_k12(fp12_t r, ep_t p, ep2_t q); + +/** + * Computes the optimal ate multi-pairing of in a parameterized elliptic + * curve with embedding degree 12. + * + * @param[out] r - the result. + * @param[in] q - the first pairing arguments. + * @param[in] p - the second pairing arguments. + * @param[in] m - the number of pairings to evaluate. + */ +void pp_map_sim_oatep_k12(fp12_t r, ep_t *p, ep2_t *q, int m); + +/** + * Computes the Optimal Ate pairing of two points in a parameterized elliptic + * curve with embedding degree 48. + * + * @param[out] r - the result. + * @param[in] q - the first elliptic curve point. + * @param[in] p - the second elliptic curve point. + */ +void pp_map_k48(fp48_t r, ep_t p, fp8_t qx, fp8_t qy); + +/** + * Computes the Optimal Ate pairing of two points in a parameterized elliptic + * curve with embedding degree 54. + * + * @param[out] r - the result. + * @param[in] q - the first elliptic curve point. + * @param[in] p - the second elliptic curve point. + */ +void pp_map_k54(fp54_t r, ep_t p, fp9_t qx, fp9_t qy); + +#endif /* !RLC_PP_H */ diff --git a/bls/contrib/relic/include/relic_rand.h b/bls/contrib/relic/include/relic_rand.h new file mode 100644 index 00000000..9f828af5 --- /dev/null +++ b/bls/contrib/relic/include/relic_rand.h @@ -0,0 +1,118 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @defgroup rand Pseudo-random number generators. + */ + +/** + * @file + * + * Interface of the module for pseudo-random number generation. + * + * @ingroup rand + */ + +#ifndef RLC_RAND_H +#define RLC_RAND_H + +#include "relic_rand.h" + +/*============================================================================*/ +/* Constant definitions */ +/*============================================================================*/ + +/** + * Size of the PRNG internal state in bytes. + */ +#if RAND == HASHD + +#if MD_MAP == SH224 || MD_MAP == SH256 || MD_MAP == BLAKE2S_160 || MD_MAP == BLAKE2S_256 +#define RAND_SIZE (1 + 2*440/8) +#elif MD_MAP == SH384 || MD_MAP == SH512 +#define RAND_SIZE (1 + 2*888/8) +#endif + +#elif RAND == UDEV +#define RAND_SIZE (sizeof(int)) +#elif RAND == CALL +#define RAND_SIZE (sizeof(void (*)(uint8_t *, int))) +#elif RAND == RDRND +#define RAND_SIZE 0 +#endif + +/** + * Minimum size of the PRNG seed. + */ +#define SEED_SIZE 64 + +/*============================================================================*/ +/* Function prototypes */ +/*============================================================================*/ + +/** + * Initializes the pseudo-random number generator. + */ +void rand_init(void); + +/** + * Finishes the pseudo-random number generator. + */ +void rand_clean(void); + +#if RAND != CALL + +/** + * Sets the initial state of the pseudo-random number generator. + * + * @param[in] buf - the buffer that represents the initial state. + * @param[in] size - the number of bytes. + * @throw ERR_NO_VALID - if the entropy length is too small or too large. + */ +void rand_seed(uint8_t *buf, int size); + +#else + +/** + * Sets the initial state of the pseudo-random number generator as a function + * pointer. + * + * @param[in] callback - the callback to call. + * @param[in] arg - the argument for the callback. + */ +void rand_seed(void (*callback)(uint8_t *, int, void *), void *arg); + +#endif + +/** + * Gathers pseudo-random bytes from the pseudo-random number generator. + * + * @param[out] buf - the buffer to write. + * @param[in] size - the number of bytes to gather. + * @throw ERR_NO_VALID - if the required length is too large. + * @throw ERR_NO_READ - it the pseudo-random number generator cannot + * generate the specified number of bytes. + */ +void rand_bytes(uint8_t *buf, int size); + +#endif /* !RLC_RAND_H */ diff --git a/bls/contrib/relic/include/relic_test.h b/bls/contrib/relic/include/relic_test.h new file mode 100644 index 00000000..9039dbc1 --- /dev/null +++ b/bls/contrib/relic/include/relic_test.h @@ -0,0 +1,104 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @defgroup tests Automated tests + */ + +/** + * @file + * + * Interface of useful routines for testing. + * + * @ingroup test + */ + +#ifndef RLC_TEST_H +#define RLC_TEST_H + +#include + +#include "relic_conf.h" +#include "relic_label.h" +#include "relic_util.h" + +/*============================================================================*/ +/* Macro definitions */ +/*============================================================================*/ + +/** + * Runs a new benchmark once. + * + * @param[in] P - the property description. + */ +#define TEST_ONCE(P) \ + util_print("Testing if " P "...%*c", (64 - strlen(P)), ' '); \ + +/** + * Tests a sequence of commands to see if they respect some property. + * + * @param[in] P - the property description. + */ +#define TEST_BEGIN(P) \ + util_print("Testing if " P "...%*c", (64 - strlen(P)), ' '); \ + for (int i = 0; i < TESTS; i++) \ + +/** + * Asserts a condition. + * + * If the condition is not satisfied, a unconditional jump is made to the passed + * label. + * + * @param[in] C - the condition to assert. + * @param[in] LABEL - the label to jump if the condition is no satisfied. + */ +#define TEST_ASSERT(C, LABEL) \ + if (!(C)) { \ + test_fail(); \ + util_print("(at "); \ + util_print(__FILE__); \ + util_print(":%d)\n", __LINE__); \ + ERROR(LABEL); \ + } \ + +/** + * Finalizes a test printing the test result. + */ +#define TEST_END \ + test_pass() \ + +/*============================================================================*/ +/* Function prototypes */ +/*============================================================================*/ + +/** + * Prints a string indicating that the test failed. + */ +void test_fail(void); + +/** + * Prints a string indicating that the test passed. + */ +void test_pass(void); + +#endif /* !RLC_TEST_H */ diff --git a/bls/contrib/relic/include/relic_types.h b/bls/contrib/relic/include/relic_types.h new file mode 100644 index 00000000..acc7125f --- /dev/null +++ b/bls/contrib/relic/include/relic_types.h @@ -0,0 +1,166 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @file + * + * Elementary types. + * + * @ingroup relic + */ + +#ifndef RLC_TYPES_H +#define RLC_TYPES_H + +#include + +#include "relic_conf.h" + +#if defined GMP && ARITH == GMP +#include +#endif + +/*============================================================================*/ +/* Constant definitions */ +/*============================================================================*/ + +/** + * Size in bits of a digit. + */ +#define RLC_DIG (WSIZE) + +/** + * Logarithm of the digit size in bits in base two. + */ +#if RLC_DIG == 8 +#define RLC_DIG_LOG 3 +#elif RLC_DIG == 16 +#define RLC_DIG_LOG 4 +#elif RLC_DIG == 32 +#define RLC_DIG_LOG 5 +#elif RLC_DIG == 64 +#define RLC_DIG_LOG 6 +#endif + +/*============================================================================*/ +/* Type definitions */ +/*============================================================================*/ + +/** + * Represents a digit from a multiple precision integer. + * + * Each digit is represented as an unsigned long to use the biggest native + * type that potentially supports native instructions. + */ +#if ARITH == GMP +typedef mp_limb_t dig_t; +#elif WSIZE == 8 +typedef uint8_t dig_t; +#elif WSIZE == 16 +typedef uint16_t dig_t; +#elif WSIZE == 32 +typedef uint32_t dig_t; +#elif WSIZE == 64 +typedef uint64_t dig_t; +#endif + +/** + * Represents a signed digit. + */ +#if WSIZE == 8 +typedef int8_t dis_t; +#elif WSIZE == 16 +typedef int16_t dis_t; +#elif WSIZE == 32 +typedef int32_t dis_t; +#elif WSIZE == 64 +typedef int64_t dis_t; +#endif + +/** + * Represents a double-precision integer from a multiple precision integer. + * + * This is useful to store a result from a multiplication of two digits. + */ +#if WSIZE == 8 +typedef uint16_t dbl_t; +#elif WSIZE == 16 +typedef uint32_t dbl_t; +#elif WSIZE == 32 +typedef uint64_t dbl_t; +#elif WSIZE == 64 +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) +typedef __uint128_t dbl_t; +#elif ARITH == EASY +#error "Easy backend in 64-bit mode supported only in GCC compiler." +#else +#endif +#endif + +/* + * Represents the unsigned integer with maximum precision. + */ +typedef unsigned long long ull_t; + +/*============================================================================*/ +/* Macro definitions */ +/*============================================================================*/ + +/** + * Specification for aligned variables. + */ +#if ALIGN > 1 +#define rlc_align __attribute__ ((aligned (ALIGN))) +#else +#define rlc_align /* empty*/ +#endif + +/** + * Size of padding to be added so that digit vectors are aligned. + */ +#if ALIGN > 1 +#define RLC_PAD(A) ((A) % ALIGN == 0 ? 0 : ALIGN - ((A) % ALIGN)) +#else +#define RLC_PAD(A) (0) +#endif + +/** + * Align digit vector pointer to specified byte-boundary. + * + * @param[in,out] A - the pointer to align. + */ +#if ALIGN > 1 +#if ARCH == AVR || ARCH == MSP || ARCH == X86 || ARCH == ARM +#define RLC_ALIGN(A) \ + ((unsigned int)(A) + RLC_PAD((unsigned int)(A))); \ + +#elif ARCH == X64 +#define RLC_ALIGN(A) \ + ((unsigned long)(A) + RLC_PAD((unsigned long)(A))); \ + +#endif +#else +#define RLC_ALIGN(A) (A) +#endif + +#endif /* !RLC_TYPES_H */ diff --git a/bls/contrib/relic/include/relic_util.h b/bls/contrib/relic/include/relic_util.h new file mode 100644 index 00000000..f90f1533 --- /dev/null +++ b/bls/contrib/relic/include/relic_util.h @@ -0,0 +1,248 @@ +/* + * RELIC is an Efficient LIbrary for Cryptography + * Copyright (C) 2007-2019 RELIC Authors + * + * This file is part of RELIC. RELIC is legal property of its developers, + * whose names are not listed here. Please refer to the COPYRIGHT file + * for contact information. + * + * RELIC is free software; you can redistribute it and/or modify it under the + * terms of the version 2.1 (or later) of the GNU Lesser General Public License + * as published by the Free Software Foundation; or version 2.0 of the Apache + * License as published by the Apache Software Foundation. See the LICENSE files + * for more details. + * + * RELIC is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the LICENSE files for more details. + * + * You should have received a copy of the GNU Lesser General Public or the + * Apache License along with RELIC. If not, see + * or . + */ + +/** + * @defgroup util Misc utilities + */ + +/** + * @file + * + * Interface of misc utilitles. + * + * @ingroup util + */ + +#ifndef RLC_UTIL_H +#define RLC_UTIL_H + +#include "relic_arch.h" +#include "relic_types.h" +#include "relic_label.h" + +/*============================================================================*/ +/* Macro definitions */ +/*============================================================================*/ + +/** + * Returns the minimum between two numbers. + * + * @param[in] A - the first number. + * @param[in] B - the second number. + */ +#define RLC_MIN(A, B) ((A) < (B) ? (A) : (B)) + +/** + * Returns the maximum between two numbers. + * + * @param[in] A - the first number. + * @param[in] B - the second number. + */ +#define RLC_MAX(A, B) ((A) > (B) ? (A) : (B)) + +/** + * Splits a bit count in a digit count and an updated bit count. + * + * @param[out] B - the resulting bit count. + * @param[out] D - the resulting digit count. + * @param[out] V - the bit count. + */ +#define RLC_RIP(B, D, V) \ + D = (V) >> (RLC_DIG_LOG); B = (V) - ((D) * (1 << RLC_DIG_LOG)); + +/** + * Computes the ceiling function of an integer division. + * + * @param[in] A - the dividend. + * @param[in] B - the divisor. + */ +#define RLC_CEIL(A, B) (((A) - 1) / (B) + 1) + +/** + * Returns a bit mask to isolate the lowest part of a digit. + * + * @param[in] B - the number of bits to isolate. + */ +#define RLC_MASK(B) \ + ((-(dig_t)((B) >= WSIZE)) | (((dig_t)1 << ((B) % WSIZE)) - 1)) + +/** + * Returns a bit mask to isolate the lowest half of a digit. + */ +#define RLC_LMASK (RLC_MASK(RLC_DIG >> 1)) + +/** + * Returns a bit mask to isolate the highest half of a digit. + */ +#define RLC_HMASK (RLC_LMASK << (RLC_DIG >> 1)) + +/** + * Bit mask used to return an entire digit. + */ +#define RLC_DMASK (RLC_HMASK | RLC_LMASK) + +/** + * Returns the lowest half of a digit. + * + * @param[in] D - the digit. + */ +#define RLC_LOW(D) (D & RLC_LMASK) + +/** + * Returns the highest half of a digit. + * + * @param[in] D - the digit. + */ +#define RLC_HIGH(D) (D >> (RLC_DIG >> 1)) + +/** + * Selects between two values based on the value of a given flag. + * + * @param[in] A - the first argument. + * @param[in] B - the second argument. + * @param[in] C - the selection flag. + */ +#define RLC_SEL(A, B, C) ((-(C) & ((A) ^ (B))) ^ (A)) + +/** + * Swaps two values. + * + * @param[in] A - the first argument. + * @param[in] B - the second argument. + */ +#define RLC_SWAP(A, B) ((A) ^= (B), (B) ^= (A), (A) ^= (B)) + +/** + * Returns the given character in upper case. + * + * @param[in] C - the character. + */ +#define RLC_UPP(C) ((C) - 0x20 * (((C) >= 'a') && ((C) <= 'z'))) + +/** + * Indirection to help some compilers expand symbols. + */ +#define RLC_ECHO(A) A + +/** + * Concatenates two tokens. + */ +/** @{ */ +#define RLC_CAT(A, B) _RLC_CAT(A, B) +#define _RLC_CAT(A, B) A ## B +/** @} */ + +/** + * Selects a basic or advanced version of a function by checking if an + * additional argument was passed. + */ +/** @{ */ +#define RLC_OPT(...) _OPT(__VA_ARGS__, _imp, _basic, _error) +#define _OPT(...) RLC_ECHO(__OPT(__VA_ARGS__)) +#define __OPT(_1, _2, N, ...) N +/** @} */ + +/** + * Selects a real or dummy printing function depending on library flags. + * + * @param[in] F - the format string. + */ +#ifndef QUIET +#define util_print(F, ...) util_printf(RLC_STR(F), ##__VA_ARGS__) +#else +#define util_print(F, ...) /* empty */ +#endif + +/** + * Prints a standard label. + * + * @param[in] L - the label of the banner. + * @param[in] I - if the banner is inside an hierarchy. + */ +#define util_banner(L, I) \ + if (!I) { \ + util_print("\n-- " L "\n"); \ + } else { \ + util_print("\n** " L "\n\n"); \ + } \ + +/*============================================================================*/ +/* Function prototypes */ +/*============================================================================*/ + +/** + * Toggle endianess of a digit. + */ +uint32_t util_conv_endian(uint32_t i); + +/** + * Convert a digit to big-endian. + */ +uint32_t util_conv_big(uint32_t i); + +/** + * Convert a digit to little-endian. + */ +uint32_t util_conv_little(uint32_t i); + +/** + * Converts a small digit to a character. + */ +char util_conv_char(dig_t i); + +/** + * Returns the highest bit set on a digit. + * + * @param[in] a - the digit. + * @return the position of the highest bit set. + */ +int util_bits_dig(dig_t a); + +/** + * Compares two buffers in constant time. + * + * @param[in] a - the first buffer. + * @param[in] b - the second buffer. + * @param[in] n - the length in bytes of the buffers. + * @return RLC_EQ if they are equal and RLC_NE otherwise. + */ +int util_cmp_const(const void *a, const void *b, int n); + +/** + * Formats and prints data following a printf-like syntax. + * + * @param[in] format - the format. + * @param[in] ... - the list of arguments matching the format. + */ +void util_printf(const char *format, ...); + +/** + * Prints a digit. + * + * @param[in] a - the digit to print. + * @param[in] pad - the flag to indicate if the digit must be padded + * with zeroes. + */ +void util_print_dig(dig_t a, int pad); + +#endif /* !RLC_UTIL_H */ diff --git a/bls/src/CMakeLists.txt b/bls/src/CMakeLists.txt new file mode 100644 index 00000000..01d499f7 --- /dev/null +++ b/bls/src/CMakeLists.txt @@ -0,0 +1,76 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 3.1.0 FATAL_ERROR) +set (CMAKE_CXX_STANDARD 11) + +file(GLOB HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp) +source_group("SrcHeaders" FILES ${HEADERS}) + +include_directories( + ${INCLUDE_DIRECTORIES} + ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/relic/include + ${CMAKE_BINARY_DIR}/contrib/relic/include + ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/catch + ) + +set(C_LIB ${CMAKE_BINARY_DIR}/libbls.a) + +add_library(bls ${CMAKE_CURRENT_SOURCE_DIR}/chaincode.cpp) + +add_library(blstmp ${HEADERS} + ${CMAKE_CURRENT_SOURCE_DIR}/extendedpublickey.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/extendedprivatekey.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/chaincode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/signature.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/publickey.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/privatekey.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/bls.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/aggregationinfo.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/threshold.cpp +) + +set(OPREFIX object_) +find_library(GMP_NAME NAMES libgmp.a gmp) +find_library(SODIUM_NAME NAMES libsodium.a sodium) + +set(LIBRARIES_TO_COMBINE + COMMAND mkdir ${OPREFIX}$ || true && cd ${OPREFIX}$ && ${CMAKE_AR} -x $ + COMMAND mkdir ${OPREFIX}$ || true && cd ${OPREFIX}$ && ${CMAKE_AR} -x $ +) + +if (GMP_FOUND) + list(APPEND LIBRARIES_TO_COMBINE COMMAND mkdir ${OPREFIX}gmp || true && cd ${OPREFIX}gmp && ${CMAKE_AR} -x ${GMP_NAME}) +endif() +if (SODIUM_FOUND) + list(APPEND LIBRARIES_TO_COMBINE COMMAND mkdir ${OPREFIX}sodium || true && cd ${OPREFIX}sodium && ${CMAKE_AR} -x ${SODIUM_NAME}) +endif() + +add_custom_target(combined_custom + ${LIBRARIES_TO_COMBINE} + COMMAND ${CMAKE_AR} -rs ${C_LIB} ${OPREFIX}*/*${CMAKE_C_OUTPUT_EXTENSION} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + DEPENDS blstmp relic_s + ) + +add_library(combined STATIC IMPORTED GLOBAL) +add_dependencies(combined combined_custom) + +target_link_libraries(bls combined) + +set_target_properties(combined + PROPERTIES + IMPORTED_LOCATION ${C_LIB} + ) + +file(GLOB includes "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp") +install(FILES ${includes} DESTINATION include/chiabls) +install(FILES ${C_LIB} DESTINATION lib) + +add_executable(runtest test.cpp) +add_executable(runbench test-bench.cpp) + +if (SODIUM_FOUND) + target_link_libraries(runtest blstmp relic_s sodium) + target_link_libraries(runbench blstmp relic_s sodium) +else() + target_link_libraries(runtest blstmp relic_s) + target_link_libraries(runbench blstmp relic_s) +endif() diff --git a/bls/src/aggregationinfo.cpp b/bls/src/aggregationinfo.cpp new file mode 100644 index 00000000..74bf5e4b --- /dev/null +++ b/bls/src/aggregationinfo.cpp @@ -0,0 +1,410 @@ +// Copyright 2018 Chia Network Inc + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include "aggregationinfo.hpp" +#include "bls.hpp" +namespace bls { + +// Creates a new object, copying the messageHash and pk +AggregationInfo AggregationInfo::FromMsgHash(const PublicKey &pk, + const uint8_t *messageHash) { + uint8_t* mapKey = new uint8_t[BLS::MESSAGE_HASH_LEN + + PublicKey::PUBLIC_KEY_SIZE]; + + std::memcpy(mapKey, messageHash, BLS::MESSAGE_HASH_LEN); + pk.Serialize(mapKey + BLS::MESSAGE_HASH_LEN); + AggregationInfo::AggregationTree tree; + bn_t *one = new bn_t[1]; + bn_new(*one); + bn_zero(*one); + bn_set_dig(*one, 1); + tree.insert(std::make_pair(mapKey, one)); + + std::vector hashes = {mapKey}; + std::vector pks = {pk}; + + return AggregationInfo(tree, hashes, pks); +} + +AggregationInfo AggregationInfo::FromMsg(const PublicKey &pk, + const uint8_t *message, + size_t len) { + uint8_t hash[BLS::MESSAGE_HASH_LEN]; + Util::Hash256(hash, message, len); + return FromMsgHash(pk, hash); +} + +AggregationInfo AggregationInfo::FromVectors( + std::vector const &pubKeys, + std::vector const &messageHashes, + std::vector const &exponents) { + if (pubKeys.size() != messageHashes.size() || messageHashes.size() != + exponents.size()) { + throw std::length_error("Invalid input, all std::vectors must have the same length"); + } + AggregationInfo::AggregationTree tree; + for (size_t i = 0; i < pubKeys.size(); i++) { + uint8_t * mapKey = new uint8_t[BLS::MESSAGE_HASH_LEN + + PublicKey::PUBLIC_KEY_SIZE]; + std::memcpy(mapKey, messageHashes[i], BLS::MESSAGE_HASH_LEN); + pubKeys[i].Serialize(mapKey + BLS::MESSAGE_HASH_LEN); + bn_t *mapValue = new bn_t[1]; + bn_new(*mapValue) + bn_copy(*mapValue, *exponents[i]); + tree.insert(std::make_pair(mapKey, mapValue)); + } + std::vector sortedPubKeys; + std::vector sortedMessageHashes; + SortIntoVectors(sortedMessageHashes, sortedPubKeys, tree); + return AggregationInfo(tree, sortedMessageHashes, sortedPubKeys); +} + +// Merges multiple AggregationInfo objects together. +AggregationInfo AggregationInfo::MergeInfos(std::vector + const &infos) { + // Find messages that are in multiple infos + std::set messages; + std::set collidingMessages; + for (const AggregationInfo &info : infos) { + std::set messagesLocal; + for (auto &mapEntry : info.tree) { + auto lookupEntry = messages.find(mapEntry.first); + auto lookupEntryLocal = messagesLocal.find(mapEntry.first); + if (lookupEntryLocal == messagesLocal.end() && + lookupEntry != messages.end()) { + collidingMessages.insert(mapEntry.first); + } + messages.insert(mapEntry.first); + messagesLocal.insert(mapEntry.first); + } + } + if (collidingMessages.empty()) { + // If there are no colliding messages, combine without exponentiation + return SimpleMergeInfos(infos); + } else { + // Otherwise, figure out with infos collide + std::vector collidingInfos; + std::vector nonCollidingInfos; + for (const AggregationInfo &info : infos) { + bool infoCollides = false; + for (auto &mapEntry : info.tree) { + auto lookupEntry = collidingMessages.find(mapEntry.first); + if (lookupEntry != collidingMessages.end()) { + infoCollides = true; + collidingInfos.push_back(info); + break; + } + } + if (!infoCollides) { + nonCollidingInfos.push_back(info); + } + } + // Combine the infos that collide securely (with exponentiation) + AggregationInfo combined = SecureMergeInfos(collidingInfos); + nonCollidingInfos.push_back(combined); + + // Do a simple combination of the rest (no exponentiation) + return SimpleMergeInfos(nonCollidingInfos); + } +} + +AggregationInfo::AggregationInfo(const AggregationInfo& info) { + InsertIntoTree(tree, info); + SortIntoVectors(sortedMessageHashes, sortedPubKeys, tree); +} + +void AggregationInfo::RemoveEntries(std::vector const &messages, + std::vector const &pubKeys) { + if (messages.size() != pubKeys.size()) { + throw std::length_error("Invalid entries"); + } + // Erase the keys from the tree + for (size_t i = 0; i < messages.size(); i++) { + uint8_t entry[BLS::MESSAGE_HASH_LEN + PublicKey::PUBLIC_KEY_SIZE]; + std::memcpy(entry, messages[i], BLS::MESSAGE_HASH_LEN); + pubKeys[i].Serialize(entry + BLS::MESSAGE_HASH_LEN); + auto kv = tree.find(entry); + const uint8_t* first = kv->first; + const bn_t* second = kv->second; + delete[] second; + tree.erase(entry); + delete[] first; + } + // Remove all elements from vectors, and regenerate them + sortedMessageHashes.clear(); + sortedPubKeys.clear(); + SortIntoVectors(sortedMessageHashes, sortedPubKeys, tree); +} + +void AggregationInfo::GetExponent(bn_t *result, const uint8_t* messageHash, + const PublicKey &pubKey) const { + uint8_t mapKey[BLS::MESSAGE_HASH_LEN + + PublicKey::PUBLIC_KEY_SIZE]; + std::memcpy(mapKey, messageHash, BLS::MESSAGE_HASH_LEN); + pubKey.Serialize(mapKey + BLS::MESSAGE_HASH_LEN); + bn_copy(*result, *tree.at(mapKey)); +} + +std::vector AggregationInfo::GetPubKeys() const { + return sortedPubKeys; +} + +std::vector AggregationInfo::GetMessageHashes() const { + return sortedMessageHashes; +} + +bool AggregationInfo::Empty() const { + return tree.empty(); +} + +// Compares two aggregation infos by the following process: +// (A.msgHash || A.pk || A.exponent) < (B.msgHash || B.pk || B.exponent) +// for each element in their sorted trees. +bool operator<(AggregationInfo const&a, AggregationInfo const&b) { + if (a.Empty() && b.Empty()) { + return false; + } + bool lessThan = false; + for (size_t i=0; i < a.sortedMessageHashes.size() + || i < b.sortedMessageHashes.size(); i++) { + // If we run out of elements, return + if (a.sortedMessageHashes.size() == i) { + lessThan = true; + break; + } else if (b.sortedMessageHashes.size() == i) { + lessThan = false; + break; + } + // Otherwise, generate the msgHash || pk element, and compare + uint8_t bufferA[BLS::MESSAGE_HASH_LEN + PublicKey::PUBLIC_KEY_SIZE]; + uint8_t bufferB[BLS::MESSAGE_HASH_LEN + PublicKey::PUBLIC_KEY_SIZE]; + std::memcpy(bufferA, a.sortedMessageHashes[i], BLS::MESSAGE_HASH_LEN); + std::memcpy(bufferB, b.sortedMessageHashes[i], BLS::MESSAGE_HASH_LEN); + a.sortedPubKeys[i].Serialize(bufferA + BLS::MESSAGE_HASH_LEN); + b.sortedPubKeys[i].Serialize(bufferB + BLS::MESSAGE_HASH_LEN); + if (std::memcmp(bufferA, bufferB, BLS::MESSAGE_HASH_LEN + + PublicKey::PUBLIC_KEY_SIZE) < 0) { + lessThan = true; + break; + } else if (std::memcmp(bufferA, bufferB, BLS::MESSAGE_HASH_LEN + + PublicKey::PUBLIC_KEY_SIZE) > 0) { + lessThan = false; + break; + } + // If they are equal, compare the exponents + auto aExp = a.tree.find(bufferA); + auto bExp = b.tree.find(bufferB); + int cmpRes = bn_cmp(*aExp->second, *bExp->second); + if (cmpRes == RLC_LT) { + lessThan = true; + break; + } else if (cmpRes == RLC_GT) { + lessThan = false; + break; + } + } + // If all comparisons are equal, false is returned. + return lessThan; +} + +bool operator==(AggregationInfo const&a, AggregationInfo const&b) { + return !(a < b) && !(b < a); +} + +bool operator!=(AggregationInfo const&a, AggregationInfo const&b) { + return (a < b) || (b < a); +} + +std::ostream &operator<<(std::ostream &os, AggregationInfo const &a) { + for (auto &kv : a.tree) { + os << Util::HexStr(kv.first, 80) << ".." << ":" << std::endl; + uint8_t str[RLC_BN_SIZE * 3 + 1]; + bn_write_bin(str, sizeof(str), *kv.second); + os << Util::HexStr(str + RLC_BN_SIZE * 3 + 1 - 5, 5) + << std::endl; + } + return os; +} + +AggregationInfo& AggregationInfo::operator=(const AggregationInfo &rhs) { + Clear(); + InsertIntoTree(tree, rhs); + SortIntoVectors(sortedMessageHashes, sortedPubKeys, tree); + return *this; +} + +void AggregationInfo::InsertIntoTree(AggregationInfo::AggregationTree &tree, + const AggregationInfo& info) { + for (auto &mapEntry : info.tree) { + uint8_t* messageCopy = new uint8_t[BLS::MESSAGE_HASH_LEN + + PublicKey::PUBLIC_KEY_SIZE]; + std::memcpy(messageCopy, mapEntry.first, BLS::MESSAGE_HASH_LEN + + PublicKey::PUBLIC_KEY_SIZE); + bn_t * exponent = new bn_t[1]; + bn_new(*exponent); + bn_copy(*exponent, *mapEntry.second); + bn_t ord; + g1_get_ord(ord); + bn_mod(*exponent, *exponent, ord); + tree.insert(std::make_pair(messageCopy, exponent)); + } +} + +// This method is used to keep an alternate copy of the tree +// keys (hashes and pks) in sorted order, for easy access. +// Note: these are sorted in mh + pk order. +void AggregationInfo::SortIntoVectors(std::vector &ms, + std::vector &pks, + const AggregationInfo::AggregationTree &tree) { + for (auto &kv : tree) { + ms.push_back(kv.first); + } + sort(begin(ms), end(ms), + Util::BytesCompare80()); + for (auto &m : ms) { + pks.push_back(PublicKey::FromBytes(m + BLS::MESSAGE_HASH_LEN)); + } +} + +// Simple merging, no exponentiation is performed +AggregationInfo AggregationInfo::SimpleMergeInfos( + std::vector const &infos) { + std::set pubKeysDedup; + + AggregationTree newTree; + for (const AggregationInfo &info : infos) { + InsertIntoTree(newTree, info); + } + std::vector pks; + std::vector messageHashes; + SortIntoVectors(messageHashes, pks, newTree); + + return AggregationInfo(newTree, messageHashes, pks); +} + +AggregationInfo AggregationInfo::SecureMergeInfos( + std::vector const &collidingInfosArg) { + // Sort colliding Infos + std::vector sortedCollidingInfos(collidingInfosArg.size()); + size_t pkCount = 0; + for (size_t i = 0; i < sortedCollidingInfos.size(); i++) { + sortedCollidingInfos[i] = i; + pkCount += collidingInfosArg[i].tree.size(); + } + // Groups are sorted by message then pk then exponent + // Each info object (and all of it's exponents) will be + // exponentiated by one of the Ts + std::sort(sortedCollidingInfos.begin(), sortedCollidingInfos.end(), [&collidingInfosArg](size_t a, size_t b) { + return collidingInfosArg[a] < collidingInfosArg[b]; + }); + + std::vector msgAndPks; + std::vector serPks; + std::vector sortedKeys; + msgAndPks.reserve(pkCount); + serPks.reserve(pkCount); + sortedKeys.reserve(pkCount); + for (size_t i = 0; i < sortedCollidingInfos.size(); i++) { + for (auto &mapEntry : collidingInfosArg[sortedCollidingInfos[i]].tree) { + uint8_t *serPk = new uint8_t[PublicKey::PUBLIC_KEY_SIZE]; + memcpy(serPk, mapEntry.first + BLS::MESSAGE_HASH_LEN, PublicKey::PUBLIC_KEY_SIZE); + + msgAndPks.emplace_back(mapEntry.first); + serPks.emplace_back(serPk); + sortedKeys.emplace_back(sortedKeys.size()); + } + } + // Pks are sorted by message then pk + std::sort(sortedKeys.begin(), sortedKeys.end(), [&msgAndPks](size_t a, size_t b) { + return memcmp(msgAndPks[a], msgAndPks[b], BLS::MESSAGE_HASH_LEN + PublicKey::PUBLIC_KEY_SIZE) < 0; + }); + + // Calculate Ts + // Each T is multiplied with an exponent in one of the collidingInfos + bn_t* computedTs = new bn_t[sortedCollidingInfos.size()]; + for (size_t i = 0; i < sortedCollidingInfos.size(); i++) { + bn_new(computedTs[i]); + } + BLS::HashPubKeys(computedTs, sortedCollidingInfos.size(), serPks, sortedKeys); + + bn_t ord; + g1_get_ord(ord); + + // Merge the trees, multiplying by the Ts, and then adding + // to total + AggregationTree newTree; + for (size_t i = 0; i < sortedCollidingInfos.size(); i++) { + const AggregationInfo info = collidingInfosArg[sortedCollidingInfos[i]]; + for (auto &mapEntry : info.tree) { + auto newMapEntry = newTree.find(mapEntry.first); + if (newMapEntry == newTree.end()) { + // This message & pk has not been included yet + uint8_t* mapKeyCopy = new uint8_t[BLS::MESSAGE_HASH_LEN + + PublicKey::PUBLIC_KEY_SIZE]; + std::memcpy(mapKeyCopy, mapEntry.first, BLS::MESSAGE_HASH_LEN + + PublicKey::PUBLIC_KEY_SIZE); + + bn_t * exponent = new bn_t[1]; + bn_new(*exponent); + bn_copy(*exponent, *mapEntry.second); + bn_mul(*exponent, *exponent, computedTs[i]); + bn_mod(*exponent, *exponent, ord); + newTree.insert(std::make_pair(mapKeyCopy, exponent)); + } else { + // This message & pk is already included. Multiply. + bn_t tmp; + bn_new(tmp); + bn_copy(tmp, *mapEntry.second); + bn_mul(tmp, tmp, computedTs[i]); + bn_add(*newMapEntry->second, *newMapEntry->second, tmp); + bn_mod(*newMapEntry->second, *newMapEntry->second, ord); + } + } + } + delete[] computedTs; + std::vector pks; + std::vector messageHashes; + SortIntoVectors(messageHashes, pks, newTree); + + for (auto p : serPks) { + delete[] p; + } + + return AggregationInfo(newTree, messageHashes, pks); +} + +// Frees all memory +void AggregationInfo::Clear() { + sortedMessageHashes.clear(); + sortedPubKeys.clear(); + if (!(tree.empty())) { + for (auto &mapEntry : tree) { + delete[] mapEntry.first; + delete[] mapEntry.second; + } + tree.clear(); + } +} + +AggregationInfo::AggregationInfo() {} + +AggregationInfo::~AggregationInfo() { + Clear(); +} +} // end namespace bls diff --git a/bls/src/aggregationinfo.hpp b/bls/src/aggregationinfo.hpp new file mode 100644 index 00000000..1eb6ff74 --- /dev/null +++ b/bls/src/aggregationinfo.hpp @@ -0,0 +1,109 @@ +// Copyright 2018 Chia Network Inc + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SRC_AGGREGATIONINFO_HPP_ +#define SRC_AGGREGATIONINFO_HPP_ + +#include +#include +#include "publickey.hpp" +#include "util.hpp" +namespace bls { +/** + * Represents information about how aggregation was performed, + * or how a signature was generated (pks, messageHashes, etc). + * The AggregationTree is a map from messageHash, pk -> exponent. + * The exponent is the number that the public key needs to be + * raised to, and the messageHash is the message that was signed, + * and it's signature raised to that exponent. The flat + * representation allows for simple and efficient lookup of a + * given public key when verifying an aggregate signature. + * + * Invariant: always maintains sortedMessageHashes and sortedPubKeys + * for efficiency. This data is equivalent to the keys in tree. + */ +class AggregationInfo { + public: + // Creates a base aggregation info object. + static AggregationInfo FromMsgHash(const PublicKey &pk, + const uint8_t* messageHash); + + static AggregationInfo FromMsg(const PublicKey &pk, + const uint8_t* message, + size_t len); + + static AggregationInfo FromVectors( + std::vector const &pubKeys, + std::vector const &messageHashes, + std::vector const &exponents); + + // Merge two AggregationInfo objects into one. + static AggregationInfo MergeInfos(std::vector + const &infos); + + // Copy constructor, deep copies data. + AggregationInfo(const AggregationInfo& info); + + // Removes the messages and pubkeys from the tree + void RemoveEntries(std::vector const &messages, + std::vector const &pubKeys); + + // Public accessors + void GetExponent(bn_t *result, const uint8_t* messageHash, + const PublicKey &pubkey) const; + std::vector GetPubKeys() const; + std::vector GetMessageHashes() const; + bool Empty() const; + + // Overloaded operators. + friend bool operator<(AggregationInfo const &a, AggregationInfo const &b); + friend bool operator==(AggregationInfo const &a, AggregationInfo const &b); + friend bool operator!=(AggregationInfo const &a, AggregationInfo const &b); + friend std::ostream &operator<<(std::ostream &os, AggregationInfo const &a); + AggregationInfo& operator=(const AggregationInfo& rhs); + + AggregationInfo(); + ~AggregationInfo(); + + private: + // This is the data structure that maps messages (32) and + // public keys (48) to exponents (bn_t*). + typedef std::map AggregationTree; + + explicit AggregationInfo(const AggregationTree& tr, + std::vector ms, + std::vector pks) + : tree(tr), + sortedMessageHashes(ms), + sortedPubKeys(pks) {} + + static void InsertIntoTree(AggregationTree &tree, + const AggregationInfo& info); + static void SortIntoVectors(std::vector &ms, + std::vector &pks, + const AggregationTree &tree); + static AggregationInfo SimpleMergeInfos( + std::vector const &infos); + static AggregationInfo SecureMergeInfos( + std::vector const &infos); + void Clear(); + + AggregationTree tree; + std::vector sortedMessageHashes; + std::vector sortedPubKeys; +}; +} // end namespace bls + +#endif // SRC_AGGREGATIONINFO_HPP_ diff --git a/bls/src/bls.cpp b/bls/src/bls.cpp new file mode 100644 index 00000000..6e8d5e05 --- /dev/null +++ b/bls/src/bls.cpp @@ -0,0 +1,135 @@ +// Copyright 2018 Chia Network Inc + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include "bls.hpp" +namespace bls { + +const char BLS::GROUP_ORDER[] = + "73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001"; + +bool BLSInitResult = BLS::Init(); + +Util::SecureAllocCallback Util::secureAllocCallback; +Util::SecureFreeCallback Util::secureFreeCallback; + +static void relic_core_initializer(void* ptr) { + core_init(); + if (err_get_code() != RLC_OK) { + std::cout << "core_init() failed"; + // this will most likely crash the application...but there isn't much we can do + throw std::string("core_init() failed"); + } + + const int r = ep_param_set_any_pairf(); + if (r != RLC_OK) { + std::cout << "ep_param_set_any_pairf() failed"; + // this will most likely crash the application...but there isn't much we can do + throw std::string("ep_param_set_any_pairf() failed"); + } +} + +bool BLS::Init() { + if (ALLOC != AUTO) { + std::cout << "Must have ALLOC == AUTO"; + throw std::string("Must have ALLOC == AUTO"); + } +#if BLSALLOC_SODIUM + if (sodium_init() < 0) { + std::cout << "libsodium init failed"; + throw std::string("libsodium init failed"); + } + SetSecureAllocator(libsodium::sodium_malloc, libsodium::sodium_free); +#else + SetSecureAllocator(malloc, free); +#endif + + core_set_thread_initializer(relic_core_initializer, nullptr); + + return true; +} + +void BLS::SetSecureAllocator(Util::SecureAllocCallback allocCb, Util::SecureFreeCallback freeCb) { + Util::secureAllocCallback = allocCb; + Util::secureFreeCallback = freeCb; +} + +void BLS::HashPubKeys(bn_t* output, size_t numOutputs, + std::vector const &serPubKeys, + std::vector const& sortedIndices) { + bn_t order; + + bn_new(order); + g2_get_ord(order); + + uint8_t *pkBuffer = new uint8_t[serPubKeys.size() * PublicKey::PUBLIC_KEY_SIZE]; + + for (size_t i = 0; i < serPubKeys.size(); i++) { + memcpy(pkBuffer + i * PublicKey::PUBLIC_KEY_SIZE, serPubKeys[sortedIndices[i]], PublicKey::PUBLIC_KEY_SIZE); + } + + uint8_t pkHash[32]; + Util::Hash256(pkHash, pkBuffer, serPubKeys.size() * PublicKey::PUBLIC_KEY_SIZE); + for (size_t i = 0; i < numOutputs; i++) { + uint8_t hash[32]; + uint8_t buffer[4 + 32]; + memset(buffer, 0, 4); + // Set first 4 bytes to index, to generate different ts + Util::IntToFourBytes(buffer, i); + // Set next 32 bytes as the hash of all the public keys + std::memcpy(buffer + 4, pkHash, 32); + Util::Hash256(hash, buffer, 4 + 32); + + bn_read_bin(output[i], hash, 32); + bn_mod_basic(output[i], output[i], order); + } + + delete[] pkBuffer; + + CheckRelicErrors(); +} + +PublicKey BLS::DHKeyExchange(const PrivateKey& privKey, const PublicKey& pubKey) { + if (!privKey.keydata) { + throw std::string("keydata not initialized"); + } + PublicKey ret = pubKey.Exp(*privKey.keydata); + CheckRelicErrors(); + return ret; +} + +void BLS::CheckRelicErrors() { + if (!core_get()) { + throw std::string("Library not initialized properly. Call BLS::Init()"); + } + if (core_get()->code != RLC_OK) { + core_get()->code = RLC_OK; + throw std::string("Relic library error"); + } +} + +void BLS::CheckRelicErrorsInvalidArgument() { + if (!core_get()) { + throw std::string("Library not initialized properly. Call BLS::Init()"); + } + if (core_get()->code != RLC_OK) { + core_get()->code = RLC_OK; + throw std::invalid_argument("Relic library error"); + } +} +} // end namespace bls diff --git a/bls/src/bls.hpp b/bls/src/bls.hpp new file mode 100644 index 00000000..5f64a166 --- /dev/null +++ b/bls/src/bls.hpp @@ -0,0 +1,70 @@ +// Copyright 2018 Chia Network Inc + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SRC_BLS_HPP_ +#define SRC_BLS_HPP_ + +#include +#include +#include +#include + +#include "relic_conf.h" + +#if defined GMP && ARITH == GMP +#include +#endif + +#include "publickey.hpp" +#include "privatekey.hpp" +#include "signature.hpp" +#include "extendedprivatekey.hpp" +#include "aggregationinfo.hpp" +#include "threshold.hpp" + +#include "relic.h" +#include "relic_test.h" + +namespace bls { + +/* + * Principal class for verification and signature aggregation. + * Include this file to use the library. + */ +class BLS { + public: + // Order of g1, g2, and gt. Private keys are in {0, GROUP_ORDER}. + static const char GROUP_ORDER[]; + static const size_t MESSAGE_HASH_LEN = 32; + + // Initializes the BLS library (called automatically) + static bool Init(); + + static void SetSecureAllocator(Util::SecureAllocCallback allocCb, Util::SecureFreeCallback freeCb); + + // Used for secure aggregation + static void HashPubKeys( + bn_t* output, + size_t numOutputs, + std::vector const &serPubKeys, + std::vector const &sortedIndices); + + static PublicKey DHKeyExchange(const PrivateKey& privKey, const PublicKey& pubKey); + + static void CheckRelicErrors(); + static void CheckRelicErrorsInvalidArgument(); +}; +} // end namespace bls + +#endif // SRC_BLS_HPP_ diff --git a/bls/src/chaincode.cpp b/bls/src/chaincode.cpp new file mode 100644 index 00000000..791e6b7d --- /dev/null +++ b/bls/src/chaincode.cpp @@ -0,0 +1,57 @@ +// Copyright 2018 Chia Network Inc + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "chaincode.hpp" +#include "bls.hpp" +namespace bls { + +ChainCode ChainCode::FromBytes(const uint8_t* bytes) { + ChainCode c = ChainCode(); + bn_new(c.chainCode); + bn_read_bin(c.chainCode, bytes, ChainCode::CHAIN_CODE_SIZE); + return c; +} + +ChainCode::ChainCode(const ChainCode &cc) { + uint8_t bytes[ChainCode::CHAIN_CODE_SIZE]; + cc.Serialize(bytes); + bn_new(chainCode); + bn_read_bin(chainCode, bytes, ChainCode::CHAIN_CODE_SIZE); +} + +// Comparator implementation. +bool operator==(ChainCode const &a, ChainCode const &b) { + return bn_cmp(a.chainCode, b.chainCode) == RLC_EQ; +} + +bool operator!=(ChainCode const &a, ChainCode const &b) { + return !(a == b); +} + +std::ostream &operator<<(std::ostream &os, ChainCode const &s) { + uint8_t buffer[ChainCode::CHAIN_CODE_SIZE]; + s.Serialize(buffer); + return os << Util::HexStr(buffer, ChainCode::CHAIN_CODE_SIZE); +} + +void ChainCode::Serialize(uint8_t *buffer) const { + bn_write_bin(buffer, ChainCode::CHAIN_CODE_SIZE, chainCode); +} + +std::vector ChainCode::Serialize() const { + std::vector data(CHAIN_CODE_SIZE); + Serialize(data.data()); + return data; +} +} // end namespace bls diff --git a/bls/src/chaincode.hpp b/bls/src/chaincode.hpp new file mode 100644 index 00000000..9b19cd18 --- /dev/null +++ b/bls/src/chaincode.hpp @@ -0,0 +1,58 @@ +// Copyright 2018 Chia Network Inc + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SRC_CHAINCODE_HPP_ +#define SRC_CHAINCODE_HPP_ + +#include +#include + +#include "relic_conf.h" + +#if defined GMP && ARITH == GMP +#include +#endif + + +#include "relic.h" +#include "relic_test.h" + +#include "util.hpp" +namespace bls { +class ChainCode { + public: + static const size_t CHAIN_CODE_SIZE = 32; + + static ChainCode FromBytes(const uint8_t* bytes); + + ChainCode(const ChainCode &cc); + + // Comparator implementation. + friend bool operator==(ChainCode const &a, ChainCode const &b); + friend bool operator!=(ChainCode const &a, ChainCode const &b); + friend std::ostream &operator<<(std::ostream &os, ChainCode const &s); + + void Serialize(uint8_t *buffer) const; + std::vector Serialize() const; + + private: + // Prevent direct construction, use static constructor + ChainCode() {} + + bn_t chainCode; +}; +} // end namespace bls + +#endif // SRC_CHAINCODE_HPP_ + diff --git a/bls/src/extendedprivatekey.cpp b/bls/src/extendedprivatekey.cpp new file mode 100644 index 00000000..352ffb16 --- /dev/null +++ b/bls/src/extendedprivatekey.cpp @@ -0,0 +1,203 @@ +// Copyright 2018 Chia Network Inc + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include "extendedprivatekey.hpp" +#include "util.hpp" +#include "bls.hpp" +namespace bls { + +ExtendedPrivateKey ExtendedPrivateKey::FromSeed(const uint8_t* seed, + size_t seedLen) { + // "BLS HD seed" in ascii + const uint8_t prefix[] = {66, 76, 83, 32, 72, 68, 32, 115, 101, 101, 100}; + + uint8_t* hashInput = Util::SecAlloc(seedLen + 1); + std::memcpy(hashInput, seed, seedLen); + + // 32 bytes for secret key, and 32 bytes for chaincode + uint8_t* ILeft = Util::SecAlloc( + PrivateKey::PRIVATE_KEY_SIZE); + uint8_t IRight[ChainCode::CHAIN_CODE_SIZE]; + + // Hash the seed into 64 bytes, half will be sk, half will be cc + hashInput[seedLen] = 0; + md_hmac(ILeft, hashInput, seedLen + 1, prefix, sizeof(prefix)); + + hashInput[seedLen] = 1; + md_hmac(IRight, hashInput, seedLen + 1, prefix, sizeof(prefix)); + + // Make sure private key is less than the curve order + bn_t* skBn = Util::SecAlloc(1); + bn_t order; + bn_new(order); + g1_get_ord(order); + + bn_new(*skBn); + bn_read_bin(*skBn, ILeft, PrivateKey::PRIVATE_KEY_SIZE); + bn_mod_basic(*skBn, *skBn, order); + bn_write_bin(ILeft, PrivateKey::PRIVATE_KEY_SIZE, *skBn); + + ExtendedPrivateKey esk(ExtendedPublicKey::VERSION, 0, 0, 0, + ChainCode::FromBytes(IRight), + PrivateKey::FromBytes(ILeft)); + + Util::SecFree(skBn); + Util::SecFree(ILeft); + Util::SecFree(hashInput); + return esk; +} + +ExtendedPrivateKey ExtendedPrivateKey::FromBytes(const uint8_t* serialized) { + uint32_t version = Util::FourBytesToInt(serialized); + uint32_t depth = serialized[4]; + uint32_t parentFingerprint = Util::FourBytesToInt(serialized + 5); + uint32_t childNumber = Util::FourBytesToInt(serialized + 9); + const uint8_t* ccPointer = serialized + 13; + const uint8_t* skPointer = ccPointer + ChainCode::CHAIN_CODE_SIZE; + + ExtendedPrivateKey esk(version, depth, parentFingerprint, childNumber, + ChainCode::FromBytes(ccPointer), + PrivateKey::FromBytes(skPointer)); + return esk; +} + +ExtendedPrivateKey ExtendedPrivateKey::PrivateChild(uint32_t i) const { + if (depth >= 255) { + throw std::logic_error("Cannot go further than 255 levels"); + } + // Hardened keys have i >= 2^31. Non-hardened have i < 2^31 + uint32_t cmp = (1 << 31); + bool hardened = i >= cmp; + + uint8_t* ILeft = Util::SecAlloc( + PrivateKey::PRIVATE_KEY_SIZE); + uint8_t IRight[ChainCode::CHAIN_CODE_SIZE]; + + // Chain code is used as hmac key + uint8_t hmacKey[ChainCode::CHAIN_CODE_SIZE]; + chainCode.Serialize(hmacKey); + + size_t inputLen = hardened ? PrivateKey::PRIVATE_KEY_SIZE + 4 + 1 + : PublicKey::PUBLIC_KEY_SIZE + 4 + 1; + // Hmac input includes sk or pk, int i, and byte with 0 or 1 + uint8_t* hmacInput = Util::SecAlloc(inputLen); + + // Fill the input with the required data + if (hardened) { + sk.Serialize(hmacInput); + Util::IntToFourBytes(hmacInput + PrivateKey::PRIVATE_KEY_SIZE, i); + } else { + sk.GetPublicKey().Serialize(hmacInput); + Util::IntToFourBytes(hmacInput + PublicKey::PUBLIC_KEY_SIZE, i); + } + hmacInput[inputLen - 1] = 0; + + md_hmac(ILeft, hmacInput, inputLen, + hmacKey, ChainCode::CHAIN_CODE_SIZE); + + // Change 1 byte to generate a different sequence for chaincode + hmacInput[inputLen - 1] = 1; + + md_hmac(IRight, hmacInput, inputLen, + hmacKey, ChainCode::CHAIN_CODE_SIZE); + + PrivateKey newSk = PrivateKey::FromBytes(ILeft, true); + newSk = PrivateKey::AggregateInsecure({sk, newSk}); + + ExtendedPrivateKey esk(version, depth + 1, + sk.GetPublicKey().GetFingerprint(), i, + ChainCode::FromBytes(IRight), + newSk); + + Util::SecFree(ILeft); + Util::SecFree(hmacInput); + + return esk; +} + +uint32_t ExtendedPrivateKey::GetVersion() const { + return version; +} + +uint8_t ExtendedPrivateKey::GetDepth() const { + return depth; +} + +uint32_t ExtendedPrivateKey::GetParentFingerprint() const { + return parentFingerprint; +} + +uint32_t ExtendedPrivateKey::GetChildNumber() const { + return childNumber; +} + +ExtendedPublicKey ExtendedPrivateKey::PublicChild(uint32_t i) const { + return PrivateChild(i).GetExtendedPublicKey(); +} + +PrivateKey ExtendedPrivateKey::GetPrivateKey() const { + return sk; +} + +PublicKey ExtendedPrivateKey::GetPublicKey() const { + return sk.GetPublicKey(); +} + +ChainCode ExtendedPrivateKey::GetChainCode() const { + return chainCode; +} + +ExtendedPublicKey ExtendedPrivateKey::GetExtendedPublicKey() const { + uint8_t buffer[ExtendedPublicKey::EXTENDED_PUBLIC_KEY_SIZE]; + Util::IntToFourBytes(buffer, version); + buffer[4] = depth; + Util::IntToFourBytes(buffer + 5, parentFingerprint); + Util::IntToFourBytes(buffer + 9, childNumber); + + chainCode.Serialize(buffer + 13); + sk.GetPublicKey().Serialize(buffer + 13 + ChainCode::CHAIN_CODE_SIZE); + + return ExtendedPublicKey::FromBytes(buffer); +} + +// Comparator implementation. +bool operator==(ExtendedPrivateKey const &a, ExtendedPrivateKey const &b) { + return (a.GetPrivateKey() == b.GetPrivateKey() && + a.GetChainCode() == b.GetChainCode()); +} + +bool operator!=(ExtendedPrivateKey const&a, ExtendedPrivateKey const&b) { + return !(a == b); +} + +void ExtendedPrivateKey::Serialize(uint8_t *buffer) const { + Util::IntToFourBytes(buffer, version); + buffer[4] = depth; + Util::IntToFourBytes(buffer + 5, parentFingerprint); + Util::IntToFourBytes(buffer + 9, childNumber); + chainCode.Serialize(buffer + 13); + sk.Serialize(buffer + 13 + ChainCode::CHAIN_CODE_SIZE); +} + +std::vector ExtendedPrivateKey::Serialize() const { + std::vector data(EXTENDED_PRIVATE_KEY_SIZE); + Serialize(data.data()); + return data; +} + +// Destructors in PrivateKey and ChainCode handle cleaning of memory +ExtendedPrivateKey::~ExtendedPrivateKey() {} +} // end namespace bls diff --git a/bls/src/extendedprivatekey.hpp b/bls/src/extendedprivatekey.hpp new file mode 100644 index 00000000..52093df3 --- /dev/null +++ b/bls/src/extendedprivatekey.hpp @@ -0,0 +1,109 @@ +// Copyright 2018 Chia Network Inc + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SRC_EXTENDEDPRIVATEKEY_HPP_ +#define SRC_EXTENDEDPRIVATEKEY_HPP_ + +#include "relic_conf.h" + +#include + +#if defined GMP && ARITH == GMP +#include +#endif + +#include "privatekey.hpp" +#include "publickey.hpp" +#include "chaincode.hpp" +#include "extendedpublickey.hpp" + + +#include "relic.h" +#include "relic_test.h" + +namespace bls { +/* +Defines a BIP-32 style node, which is composed of a private key and a +chain code. This follows the spec from BIP-0032, with a few changes: + * The master secret key is generated mod n from the master seed, + since not all 32 byte sequences are valid BLS private keys + * Instead of SHA512(input), do SHA256(input || 00000000) || + SHA256(input || 00000001) + * Mod n for the output of key derivation. + * ID of a key is SHA256(pk) instead of HASH160(pk) + * Serialization of extended public key is 93 bytes +*/ +class ExtendedPrivateKey { + public: + // version(4) depth(1) parent fingerprint(4) child#(4) cc(32) sk(32) + static const uint32_t EXTENDED_PRIVATE_KEY_SIZE = 77; + + // Generates a master private key and chain code from a seed + static ExtendedPrivateKey FromSeed( + const uint8_t* seed, size_t seedLen); + + // Parse private key and chain code from bytes + static ExtendedPrivateKey FromBytes(const uint8_t* serialized); + + // Derive a child extEnded private key, hardened if i >= 2^31 + ExtendedPrivateKey PrivateChild(uint32_t i) const; + + // Derive a child extended public key, hardened if i >= 2^31 + ExtendedPublicKey PublicChild(uint32_t i) const; + + uint32_t GetVersion() const; + uint8_t GetDepth() const; + uint32_t GetParentFingerprint() const; + uint32_t GetChildNumber() const; + + ChainCode GetChainCode() const; + PrivateKey GetPrivateKey() const; + + PublicKey GetPublicKey() const; + ExtendedPublicKey GetExtendedPublicKey() const; + + // Compare to different private key + friend bool operator==(const ExtendedPrivateKey& a, + const ExtendedPrivateKey& b); + friend bool operator!=(const ExtendedPrivateKey& a, + const ExtendedPrivateKey& b); + + void Serialize(uint8_t* buffer) const; + std::vector Serialize() const; + + ~ExtendedPrivateKey(); + + private: + // Private constructor, force use of static methods + explicit ExtendedPrivateKey(const uint32_t v, const uint8_t d, + const uint32_t pfp, const uint32_t cn, + const ChainCode code, const PrivateKey key) + : version(v), + depth(d), + parentFingerprint(pfp), + childNumber(cn), + chainCode(code), + sk(key) {} + + const uint32_t version; + const uint8_t depth; + const uint32_t parentFingerprint; + const uint32_t childNumber; + + const ChainCode chainCode; + const PrivateKey sk; +}; +} // end namespace bls + +#endif // SRC_EXTENDEDPRIVATEKEY_HPP_ diff --git a/bls/src/extendedpublickey.cpp b/bls/src/extendedpublickey.cpp new file mode 100644 index 00000000..d6c93f52 --- /dev/null +++ b/bls/src/extendedpublickey.cpp @@ -0,0 +1,136 @@ +// Copyright 2018 Chia Network Inc + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include "extendedpublickey.hpp" +#include "extendedprivatekey.hpp" +#include "util.hpp" +#include "bls.hpp" +namespace bls { + +ExtendedPublicKey ExtendedPublicKey::FromBytes( + const uint8_t* serialized) { + uint32_t version = Util::FourBytesToInt(serialized); + uint32_t depth = serialized[4]; + uint32_t parentFingerprint = Util::FourBytesToInt(serialized + 5); + uint32_t childNumber = Util::FourBytesToInt(serialized + 9); + const uint8_t* ccPointer = serialized + 13; + const uint8_t* pkPointer = ccPointer + ChainCode::CHAIN_CODE_SIZE; + + ExtendedPublicKey epk(version, depth, parentFingerprint, childNumber, + ChainCode::FromBytes(ccPointer), + PublicKey::FromBytes(pkPointer)); + return epk; +} + +ExtendedPublicKey ExtendedPublicKey::PublicChild(uint32_t i) const { + // Hardened children have i >= 2^31. Non-hardened have i < 2^31 + uint32_t cmp = (1 << 31); + if (i >= cmp) { + throw std::invalid_argument("Cannot derive hardened children from public key"); + } + if (depth >= 255) { + throw std::logic_error("Cannot go further than 255 levels"); + } + uint8_t ILeft[PrivateKey::PRIVATE_KEY_SIZE]; + uint8_t IRight[ChainCode::CHAIN_CODE_SIZE]; + + // Chain code is used as hmac key + uint8_t hmacKey[ChainCode::CHAIN_CODE_SIZE]; + chainCode.Serialize(hmacKey); + + // Public key serialization, i serialization, and one 0 or 1 byte + size_t inputLen = PublicKey::PUBLIC_KEY_SIZE + 4 + 1; + + // Hmac input includes sk or pk, int i, and byte with 0 or 1 + uint8_t hmacInput[PublicKey::PUBLIC_KEY_SIZE + 4 + 1]; + + // Fill the input with the required data + pk.Serialize(hmacInput); + hmacInput[inputLen - 1] = 0; + Util::IntToFourBytes(hmacInput + PublicKey::PUBLIC_KEY_SIZE, i); + + md_hmac(ILeft, hmacInput, inputLen, + hmacKey, ChainCode::CHAIN_CODE_SIZE); + + // Change 1 byte to generate a different sequence for chaincode + hmacInput[inputLen - 1] = 1; + + md_hmac(IRight, hmacInput, inputLen, + hmacKey, ChainCode::CHAIN_CODE_SIZE); + + PrivateKey leftSk = PrivateKey::FromBytes(ILeft, true); + PublicKey newPk = PublicKey::AggregateInsecure({pk, leftSk.GetPublicKey()}); + + ExtendedPublicKey epk(version, depth + 1, + GetPublicKey().GetFingerprint(), i, + ChainCode::FromBytes(IRight), + newPk); + + return epk; +} + +uint32_t ExtendedPublicKey::GetVersion() const { + return version; +} + +uint8_t ExtendedPublicKey::GetDepth() const { + return depth; +} + +uint32_t ExtendedPublicKey::GetParentFingerprint() const { + return parentFingerprint; +} + +uint32_t ExtendedPublicKey::GetChildNumber() const { + return childNumber; +} + +ChainCode ExtendedPublicKey::GetChainCode() const { + return chainCode; +} + +PublicKey ExtendedPublicKey::GetPublicKey() const { + return pk; +} + +// Comparator implementation. +bool operator==(ExtendedPublicKey const &a, ExtendedPublicKey const &b) { + return (a.GetPublicKey() == b.GetPublicKey() && + a.GetChainCode() == b.GetChainCode()); +} + +bool operator!=(ExtendedPublicKey const&a, ExtendedPublicKey const&b) { + return !(a == b); +} + +std::ostream &operator<<(std::ostream &os, ExtendedPublicKey const &a) { + return os << a.GetPublicKey() << a.GetChainCode(); +} + +void ExtendedPublicKey::Serialize(uint8_t *buffer) const { + Util::IntToFourBytes(buffer, version); + buffer[4] = depth; + Util::IntToFourBytes(buffer + 5, parentFingerprint); + Util::IntToFourBytes(buffer + 9, childNumber); + chainCode.Serialize(buffer + 13); + pk.Serialize(buffer + 13 + ChainCode::CHAIN_CODE_SIZE); +} + +std::vector ExtendedPublicKey::Serialize() const { + std::vector data(EXTENDED_PUBLIC_KEY_SIZE); + Serialize(data.data()); + return data; +} +} // end namespace bls diff --git a/bls/src/extendedpublickey.hpp b/bls/src/extendedpublickey.hpp new file mode 100644 index 00000000..c69a2430 --- /dev/null +++ b/bls/src/extendedpublickey.hpp @@ -0,0 +1,100 @@ +// Copyright 2018 Chia Network Inc + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SRC_EXTENDEDPUBLICKEY_HPP_ +#define SRC_EXTENDEDPUBLICKEY_HPP_ + +#include "relic_conf.h" + +#include + +#if defined GMP && ARITH == GMP +#include +#endif + +#include "publickey.hpp" +#include "chaincode.hpp" + + +#include "relic.h" +#include "relic_test.h" + +namespace bls { + +/* +Defines a BIP-32 style node, which is composed of a private key and a +chain code. This follows the spec from BIP-0032, with a few changes: + * The master secret key is generated mod n from the master seed, + since not all 32 byte sequences are valid BLS private keys + * Instead of SHA512(input), do SHA256(input || 00000000) || + SHA256(input || 00000001) + * Mod n for the output of key derivation. + * ID of a key is SHA256(pk) instead of HASH160(pk) + * Serialization of extended public key is 93 bytes +*/ +class ExtendedPublicKey { + public: + static const uint32_t VERSION = 1; + + // version(4) depth(1) parent fingerprint(4) child#(4) cc(32) pk(48) + static const uint32_t EXTENDED_PUBLIC_KEY_SIZE = 93; + + // Parse public key and chain code from bytes + static ExtendedPublicKey FromBytes(const uint8_t* serialized); + + // Derive a child extended public key, cannot be hardened + ExtendedPublicKey PublicChild(uint32_t i) const; + + uint32_t GetVersion() const; + uint8_t GetDepth() const; + uint32_t GetParentFingerprint() const; + uint32_t GetChildNumber() const; + + ChainCode GetChainCode() const; + PublicKey GetPublicKey() const; + + // Comparator implementation. + friend bool operator==(ExtendedPublicKey const &a, + ExtendedPublicKey const &b); + friend bool operator!=(ExtendedPublicKey const &a, + ExtendedPublicKey const &b); + friend std::ostream &operator<<(std::ostream &os, + ExtendedPublicKey const &s); + + void Serialize(uint8_t *buffer) const; + std::vector Serialize() const; + + private: + // private constructor, force use of static methods + explicit ExtendedPublicKey(const uint32_t v, const uint8_t d, + const uint32_t pfp, const uint32_t cn, + const ChainCode code, const PublicKey key) + : version(v), + depth(d), + parentFingerprint(pfp), + childNumber(cn), + chainCode(code), + pk(key) {} + + const uint32_t version; + const uint8_t depth; + const uint32_t parentFingerprint; + const uint32_t childNumber; + + const ChainCode chainCode; + const PublicKey pk; +}; +} // end namespace bls + +#endif // SRC_EXTENDEDPUBLICKEY_HPP_ diff --git a/bls/src/privatekey.cpp b/bls/src/privatekey.cpp new file mode 100644 index 00000000..d9ce43d4 --- /dev/null +++ b/bls/src/privatekey.cpp @@ -0,0 +1,261 @@ +// Copyright 2018 Chia Network Inc + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include "bls.hpp" +#include "util.hpp" +#include "privatekey.hpp" + +namespace bls { +PrivateKey PrivateKey::FromSeed(const uint8_t* seed, size_t seedLen) { + // "BLS private key seed" in ascii + const uint8_t hmacKey[] = {66, 76, 83, 32, 112, 114, 105, 118, 97, 116, 101, + 32, 107, 101, 121, 32, 115, 101, 101, 100}; + + uint8_t* hash = Util::SecAlloc( + PrivateKey::PRIVATE_KEY_SIZE); + + // Hash the seed into sk + md_hmac(hash, seed, seedLen, hmacKey, sizeof(hmacKey)); + + bn_t order; + bn_new(order); + g1_get_ord(order); + bn_free(order); + + // Make sure private key is less than the curve order + bn_t* skBn = Util::SecAlloc(1); + bn_new(*skBn); + bn_read_bin(*skBn, hash, PrivateKey::PRIVATE_KEY_SIZE); + bn_mod_basic(*skBn, *skBn, order); + + PrivateKey k; + k.AllocateKeyData(); + bn_copy(*k.keydata, *skBn); + + Util::SecFree(skBn); + Util::SecFree(hash); + + return k; +} + +// Construct a private key from a bytearray. +PrivateKey PrivateKey::FromBytes(const uint8_t* bytes, bool modOrder) { + PrivateKey k; + k.AllocateKeyData(); + bn_read_bin(*k.keydata, bytes, PrivateKey::PRIVATE_KEY_SIZE); + bn_t ord; + bn_new(ord); + g1_get_ord(ord); + if (modOrder) { + bn_mod_basic(*k.keydata, *k.keydata, ord); + } else { + if (bn_cmp(*k.keydata, ord) > 0) { + throw std::invalid_argument("Key data too large, must be smaller than group order"); + } + } + return k; +} + +PrivateKey PrivateKey::FromBN(bn_t sk) { + PrivateKey k; + k.AllocateKeyData(); + bn_copy(*k.keydata, sk); + return k; +} + +// Construct a private key from another private key. +PrivateKey::PrivateKey(const PrivateKey &privateKey) { + AllocateKeyData(); + bn_copy(*keydata, *privateKey.keydata); +} + +PrivateKey::PrivateKey(PrivateKey&& k) { + std::swap(keydata, k.keydata); +} + +PrivateKey::~PrivateKey() { + Util::SecFree(keydata); +} + +PublicKey PrivateKey::GetPublicKey() const { + g1_t *q = Util::SecAlloc(1); + g1_mul_gen(*q, *keydata); + + const PublicKey ret = PublicKey::FromG1(q); + Util::SecFree(*q); + return ret; +} + +PrivateKey PrivateKey::AggregateInsecure(std::vector const& privateKeys) { + if (privateKeys.empty()) { + throw std::length_error("Number of private keys must be at least 1"); + } + + bn_t order; + bn_new(order); + g1_get_ord(order); + + PrivateKey ret(privateKeys[0]); + for (size_t i = 1; i < privateKeys.size(); i++) { + bn_add(*ret.keydata, *ret.keydata, *privateKeys[i].keydata); + bn_mod_basic(*ret.keydata, *ret.keydata, order); + } + return ret; +} + +PrivateKey PrivateKey::Aggregate(std::vector const& privateKeys, + std::vector const& pubKeys) { + if (pubKeys.size() != privateKeys.size()) { + throw std::length_error("Number of public keys must equal number of private keys"); + } + if (privateKeys.empty()) { + throw std::length_error("Number of keys must be at least 1"); + } + + std::vector serPubKeys(pubKeys.size()); + for (size_t i = 0; i < pubKeys.size(); i++) { + serPubKeys[i] = new uint8_t[PublicKey::PUBLIC_KEY_SIZE]; + pubKeys[i].Serialize(serPubKeys[i]); + } + + // Sort the public keys and private keys by public key + std::vector keysSorted(privateKeys.size()); + for (size_t i = 0; i < privateKeys.size(); i++) { + keysSorted[i] = i; + } + + std::sort(keysSorted.begin(), keysSorted.end(), [&serPubKeys](size_t a, size_t b) { + return memcmp(serPubKeys[a], serPubKeys[b], PublicKey::PUBLIC_KEY_SIZE) < 0; + }); + + + bn_t *computedTs = new bn_t[keysSorted.size()]; + for (size_t i = 0; i < keysSorted.size(); i++) { + bn_new(computedTs[i]); + } + BLS::HashPubKeys(computedTs, keysSorted.size(), serPubKeys, keysSorted); + + // Raise all keys to power of the corresponding t's and aggregate the results into aggKey + std::vector expKeys; + expKeys.reserve(keysSorted.size()); + for (size_t i = 0; i < keysSorted.size(); i++) { + auto& k = privateKeys[keysSorted[i]]; + expKeys.emplace_back(k.Mul(computedTs[i])); + } + PrivateKey aggKey = PrivateKey::AggregateInsecure(expKeys); + + for (auto p : serPubKeys) { + delete[] p; + } + delete[] computedTs; + + BLS::CheckRelicErrors(); + return aggKey; +} + +PrivateKey PrivateKey::Mul(const bn_t n) const { + bn_t order; + bn_new(order); + g2_get_ord(order); + + PrivateKey ret; + ret.AllocateKeyData(); + bn_mul_comba(*ret.keydata, *keydata, n); + bn_mod_basic(*ret.keydata, *ret.keydata, order); + return ret; +} + +bool operator==(const PrivateKey& a, const PrivateKey& b) { + return bn_cmp(*a.keydata, *b.keydata) == RLC_EQ; +} + +bool operator!=(const PrivateKey& a, const PrivateKey& b) { + return !(a == b); +} + +PrivateKey& PrivateKey::operator=(const PrivateKey &rhs) { + Util::SecFree(keydata); + AllocateKeyData(); + bn_copy(*keydata, *rhs.keydata); + return *this; +} + +void PrivateKey::Serialize(uint8_t* buffer) const { + bn_write_bin(buffer, PrivateKey::PRIVATE_KEY_SIZE, *keydata); +} + +std::vector PrivateKey::Serialize() const { + std::vector data(PRIVATE_KEY_SIZE); + Serialize(data.data()); + return data; +} + +InsecureSignature PrivateKey::SignInsecure(const uint8_t *msg, size_t len) const { + uint8_t messageHash[BLS::MESSAGE_HASH_LEN]; + Util::Hash256(messageHash, msg, len); + return SignInsecurePrehashed(messageHash); +} + +InsecureSignature PrivateKey::SignInsecurePrehashed(const uint8_t *messageHash) const { + g2_t sig, point; + + g2_map(point, messageHash, BLS::MESSAGE_HASH_LEN, 0); + g2_mul(sig, point, *keydata); + + return InsecureSignature::FromG2(&sig); +} + +Signature PrivateKey::Sign(const uint8_t *msg, size_t len) const { + uint8_t messageHash[BLS::MESSAGE_HASH_LEN]; + Util::Hash256(messageHash, msg, len); + return SignPrehashed(messageHash); +} + +Signature PrivateKey::SignPrehashed(const uint8_t *messageHash) const { + InsecureSignature insecureSig = SignInsecurePrehashed(messageHash); + Signature ret = Signature::FromInsecureSig(insecureSig); + + ret.SetAggregationInfo(AggregationInfo::FromMsgHash(GetPublicKey(), + messageHash)); + + return ret; +} + +PrependSignature PrivateKey::SignPrepend(const uint8_t *msg, size_t len) const { + uint8_t messageHash[BLS::MESSAGE_HASH_LEN]; + Util::Hash256(messageHash, msg, len); + return SignPrependPrehashed(messageHash); +} + +PrependSignature PrivateKey::SignPrependPrehashed(const uint8_t *messageHash) const { + uint8_t finalMessage[PublicKey::PUBLIC_KEY_SIZE + BLS::MESSAGE_HASH_LEN]; + GetPublicKey().Serialize(finalMessage); + memcpy(finalMessage + PublicKey::PUBLIC_KEY_SIZE, messageHash, BLS::MESSAGE_HASH_LEN); + + uint8_t finalMessageHash[BLS::MESSAGE_HASH_LEN]; + Util::Hash256(finalMessageHash, finalMessage, PublicKey::PUBLIC_KEY_SIZE + BLS::MESSAGE_HASH_LEN); + + return PrependSignature::FromInsecureSig(SignInsecurePrehashed(finalMessageHash)); +} + +void PrivateKey::AllocateKeyData() { + keydata = Util::SecAlloc(1); + bn_new(*keydata); // Freed in destructor + bn_zero(*keydata); +} +} // end namespace bls diff --git a/bls/src/privatekey.hpp b/bls/src/privatekey.hpp new file mode 100644 index 00000000..1ba62576 --- /dev/null +++ b/bls/src/privatekey.hpp @@ -0,0 +1,103 @@ +// Copyright 2018 Chia Network Inc + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SRC_BLSPRIVATEKEY_HPP_ +#define SRC_BLSPRIVATEKEY_HPP_ + +#include "relic_conf.h" + +#if defined GMP && ARITH == GMP +#include +#endif + +#include "publickey.hpp" +#include "signature.hpp" +namespace bls { +class PrivateKey { +friend class BLS; +friend class Threshold; + public: + // Private keys are represented as 32 byte field elements. Note that + // not all 32 byte integers are valid keys, the private key must be + // less than the group order (which is in bls.hpp). + static const size_t PRIVATE_KEY_SIZE = 32; + + // Generates a private key from a seed, similar to HD key generation + // (hashes the seed), and reduces it mod the group order. + static PrivateKey FromSeed( + const uint8_t* seed, size_t seedLen); + + // Construct a private key from a bytearray. + static PrivateKey FromBytes(const uint8_t* bytes, bool modOrder = false); + + // Construct a private key from a native bn element. + static PrivateKey FromBN(bn_t sk); + + // Construct a private key from another private key. Allocates memory in + // secure heap, and copies keydata. + PrivateKey(const PrivateKey& k); + PrivateKey(PrivateKey&& k); + + ~PrivateKey(); + + PublicKey GetPublicKey() const; + + // Insecurely aggregate multiple private keys into one + static PrivateKey AggregateInsecure(std::vector const& privateKeys); + + // Securely aggregate multiple private keys into one by exponentiating the keys with the pubKey hashes first + static PrivateKey Aggregate(std::vector const& privateKeys, + std::vector const& pubKeys); + + // Compare to different private key + friend bool operator==(const PrivateKey& a, const PrivateKey& b); + friend bool operator!=(const PrivateKey& a, const PrivateKey& b); + PrivateKey& operator=(const PrivateKey& rhs); + + // Serialize the key into bytes + void Serialize(uint8_t* buffer) const; + std::vector Serialize() const; + + // Sign a message without setting aggreagation info. + InsecureSignature SignInsecure(const uint8_t *msg, size_t len) const; + InsecureSignature SignInsecurePrehashed(const uint8_t *hash) const; + + // The secure Signing variants, which also set and return appropriate aggregation info. + Signature Sign(const uint8_t *msg, size_t len) const; + Signature SignPrehashed(const uint8_t *hash) const; + + // Helper methods to prepend the public key to the message, allowing secure + // aggregation by proof of posession of public key. These must be verified using + // VerifyPrepend. These signatures are identical to Insecure signatures, but are generated + // and verified by prepending the pulic keys: Sign(H(pk + H(m))). + PrependSignature SignPrepend(const uint8_t *msg, size_t len) const; + PrependSignature SignPrependPrehashed(const uint8_t *msg) const; + + private: + // Don't allow public construction, force static methods + PrivateKey() {} + + // Multiply private key with n + PrivateKey Mul(const bn_t n) const; + + // Allocate memory for private key + void AllocateKeyData(); + + private: + // The actual byte data + bn_t *keydata{nullptr}; +}; +} // end namespace bls + +#endif // SRC_BLSPRIVATEKEY_HPP_ diff --git a/bls/src/publickey.cpp b/bls/src/publickey.cpp new file mode 100644 index 00000000..742c699f --- /dev/null +++ b/bls/src/publickey.cpp @@ -0,0 +1,158 @@ +// Copyright 2018 Chia Network Inc + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include "publickey.hpp" +#include "util.hpp" +#include "bls.hpp" + +namespace bls { +PublicKey PublicKey::FromBytes(const uint8_t * key) { + PublicKey pk = PublicKey(); + uint8_t uncompressed[PUBLIC_KEY_SIZE + 1]; + std::memcpy(uncompressed + 1, key, PUBLIC_KEY_SIZE); + if (key[0] & 0x80) { + uncompressed[0] = 0x03; // Insert extra byte for Y=1 + uncompressed[1] &= 0x7f; // Remove initial Y bit + } else { + uncompressed[0] = 0x02; // Insert extra byte for Y=0 + } + g1_read_bin(pk.q, uncompressed, PUBLIC_KEY_SIZE + 1); + BLS::CheckRelicErrorsInvalidArgument(); + return pk; +} + +PublicKey PublicKey::FromG1(const g1_t* pubKey) { + PublicKey pk = PublicKey(); + g1_copy(pk.q, *pubKey); + return pk; +} + +PublicKey::PublicKey() { + g1_set_infty(q); +} + +PublicKey::PublicKey(const PublicKey &pubKey) { + g1_copy(q, pubKey.q); +} + +PublicKey PublicKey::AggregateInsecure(std::vector const& pubKeys) { + if (pubKeys.empty()) { + throw std::length_error("Number of public keys must be at least 1"); + } + + PublicKey ret = pubKeys[0]; + for (size_t i = 1; i < pubKeys.size(); i++) { + g1_add(ret.q, ret.q, pubKeys[i].q); + } + return ret; +} + +PublicKey PublicKey::Aggregate(std::vector const& pubKeys) { + if (pubKeys.size() < 1) { + throw std::length_error("Number of public keys must be at least 1"); + } + + std::vector serPubKeys(pubKeys.size()); + for (size_t i = 0; i < pubKeys.size(); i++) { + serPubKeys[i] = new uint8_t[PublicKey::PUBLIC_KEY_SIZE]; + pubKeys[i].Serialize(serPubKeys[i]); + } + + // Sort the public keys by public key + std::vector pubKeysSorted(pubKeys.size()); + for (size_t i = 0; i < pubKeysSorted.size(); i++) { + pubKeysSorted[i] = i; + } + + std::sort(pubKeysSorted.begin(), pubKeysSorted.end(), [&serPubKeys](size_t a, size_t b) { + return memcmp(serPubKeys[a], serPubKeys[b], PublicKey::PUBLIC_KEY_SIZE) < 0; + }); + + bn_t *computedTs = new bn_t[pubKeysSorted.size()]; + for (size_t i = 0; i < pubKeysSorted.size(); i++) { + bn_new(computedTs[i]); + } + BLS::HashPubKeys(computedTs, pubKeysSorted.size(), serPubKeys, pubKeysSorted); + + // Raise all keys to power of the corresponding t's and aggregate the results into aggKey + std::vector expKeys; + expKeys.reserve(pubKeysSorted.size()); + for (size_t i = 0; i < pubKeysSorted.size(); i++) { + const PublicKey& pk = pubKeys[pubKeysSorted[i]]; + expKeys.emplace_back(pk.Exp(computedTs[i])); + } + PublicKey aggKey = PublicKey::AggregateInsecure(expKeys); + + for (auto p : serPubKeys) { + delete[] p; + } + delete[] computedTs; + + BLS::CheckRelicErrors(); + return aggKey; +} + +PublicKey PublicKey::Exp(bn_t const n) const { + PublicKey ret; + g1_mul(ret.q, const_cast(q), const_cast(n)); + return ret; +} + +void PublicKey::Serialize(uint8_t *buffer) const { + CompressPoint(buffer, &q); +} + +std::vector PublicKey::Serialize() const { + std::vector data(PUBLIC_KEY_SIZE); + Serialize(data.data()); + return data; +} + +// Comparator implementation. +bool operator==(PublicKey const &a, PublicKey const &b) { + return g1_cmp(a.q, b.q) == RLC_EQ; +} + +bool operator!=(PublicKey const&a, PublicKey const&b) { + return !(a == b); +} + +std::ostream &operator<<(std::ostream &os, PublicKey const &pk) { + uint8_t data[PublicKey::PUBLIC_KEY_SIZE]; + pk.Serialize(data); + return os << Util::HexStr(data, PublicKey::PUBLIC_KEY_SIZE); +} + +uint32_t PublicKey::GetFingerprint() const { + uint8_t buffer[PublicKey::PUBLIC_KEY_SIZE]; + uint8_t hash[32]; + Serialize(buffer); + Util::Hash256(hash, buffer, PublicKey::PUBLIC_KEY_SIZE); + return Util::FourBytesToInt(hash); +} + +void PublicKey::CompressPoint(uint8_t* result, const g1_t* point) { + uint8_t buffer[PublicKey::PUBLIC_KEY_SIZE + 1]; + g1_write_bin(buffer, PublicKey::PUBLIC_KEY_SIZE + 1, *point, 1); + + if (buffer[0] == 0x03) { + buffer[1] |= 0x80; + } + std::memcpy(result, buffer + 1, PUBLIC_KEY_SIZE); +} +} // end namespace bls diff --git a/bls/src/publickey.hpp b/bls/src/publickey.hpp new file mode 100644 index 00000000..938d57c5 --- /dev/null +++ b/bls/src/publickey.hpp @@ -0,0 +1,80 @@ +// Copyright 2018 Chia Network Inc + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SRC_BLSPUBLICKEY_HPP_ +#define SRC_BLSPUBLICKEY_HPP_ + +#include +#include + +#include "relic_conf.h" + +#if defined GMP && ARITH == GMP +#include +#endif + +#include "util.hpp" +namespace bls { +/** An encapsulated public key. */ +class PublicKey { + friend class InsecureSignature; + friend class Signature; + friend class ExtendedPublicKey; + friend class Threshold; + friend class BLS; + public: + static const size_t PUBLIC_KEY_SIZE = 48; + + // Construct a public key from a byte vector. + static PublicKey FromBytes(const uint8_t* key); + + // Construct a public key from a native g1 element. + static PublicKey FromG1(const g1_t* key); + + // Construct a public key from another public key. + PublicKey(const PublicKey &pubKey); + + // Insecurely aggregate multiple public keys into one + static PublicKey AggregateInsecure(std::vector const& pubKeys); + + // Securely aggregate multiple public keys into one by exponentiating the keys with the pubKey hashes first + static PublicKey Aggregate(std::vector const& pubKeys); + + // Comparator implementation. + friend bool operator==(PublicKey const &a, PublicKey const &b); + friend bool operator!=(PublicKey const &a, PublicKey const &b); + friend std::ostream &operator<<(std::ostream &os, PublicKey const &s); + + void Serialize(uint8_t *buffer) const; + std::vector Serialize() const; + + // Returns the first 4 bytes of the serialized pk + uint32_t GetFingerprint() const; + + private: + // Don't allow public construction, force static methods + PublicKey(); + + // Exponentiate public key with n + PublicKey Exp(const bn_t n) const; + + static void CompressPoint(uint8_t* result, const g1_t* point); + + private: + // Public key group element + g1_t q; +}; + +} // end namespace bls +#endif // SRC_BLSPUBLICKEY_HPP_ diff --git a/bls/src/signature.cpp b/bls/src/signature.cpp new file mode 100644 index 00000000..abff50b4 --- /dev/null +++ b/bls/src/signature.cpp @@ -0,0 +1,773 @@ +// Copyright 2018 Chia Network Inc + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include "signature.hpp" +#include "bls.hpp" + +using std::string; +namespace bls { +InsecureSignature InsecureSignature::FromBytes(const uint8_t *data) { + InsecureSignature sigObj = InsecureSignature(); + uint8_t uncompressed[SIGNATURE_SIZE + 1]; + std::memcpy(uncompressed + 1, data, SIGNATURE_SIZE); + if (data[0] & 0x80) { + uncompressed[0] = 0x03; // Insert extra byte for Y=1 + uncompressed[1] &= 0x7f; // Remove initial Y bit + } else { + uncompressed[0] = 0x02; // Insert extra byte for Y=0 + } + g2_read_bin(sigObj.sig, uncompressed, SIGNATURE_SIZE + 1); + BLS::CheckRelicErrorsInvalidArgument(); + return sigObj; +} + +InsecureSignature InsecureSignature::FromG2(const g2_t* element) { + InsecureSignature sigObj = InsecureSignature(); + g2_copy(sigObj.sig, *(g2_t*)element); + return sigObj; +} + +InsecureSignature::InsecureSignature() { + g2_set_infty(sig); +} + +InsecureSignature::InsecureSignature(const InsecureSignature &signature) { + g2_copy(sig, *(g2_t*)&signature.sig); +} + +bool InsecureSignature::Verify(const std::vector& hashes, + const std::vector& pubKeys) const { + if (hashes.size() != pubKeys.size() || hashes.empty()) { + throw std::invalid_argument("hashes and pubKeys vectors must be of same size and non-empty"); + } + + g1_t *pubKeysNative = new g1_t[hashes.size() + 1]; + g2_t *mappedHashes = new g2_t[hashes.size() + 1]; + + g2_copy(mappedHashes[0], *(g2_t *) &sig); + g1_get_gen(pubKeysNative[0]); + bn_t ordMinus1; + bn_new(ordMinus1); + g1_get_ord(ordMinus1); + bn_sub_dig(ordMinus1, ordMinus1, 1); + g1_mul(pubKeysNative[0], pubKeysNative[0], ordMinus1); + + for (size_t i = 0; i < hashes.size(); i++) { g2_map(mappedHashes[i + 1], hashes[i], BLS::MESSAGE_HASH_LEN, 0); + g1_copy(pubKeysNative[i + 1], pubKeys[i].q); + } + + bool result = VerifyNative(pubKeysNative, mappedHashes, hashes.size() + 1); + + delete[] pubKeysNative; + delete[] mappedHashes; + + return result; +} + +bool InsecureSignature::VerifyNative( + g1_t* pubKeys, + g2_t* mappedHashes, + size_t len) { + gt_t target, candidate; + + // Target = 1 + fp12_zero(target); + fp_set_dig(target[0][0][0], 1); + + // prod e(pubkey[i], hash[i]) * e(-1 * g1, aggSig) + // Performs pubKeys.size() pairings + pc_map_sim(candidate, pubKeys, mappedHashes, len); + + // 1 =? prod e(pubkey[i], hash[i]) * e(g1, aggSig) + if (gt_cmp(target, candidate) != RLC_EQ || + core_get()->code != RLC_OK) { + core_get()->code = RLC_OK; + return false; + } + BLS::CheckRelicErrors(); + return true; +} + +InsecureSignature InsecureSignature::Aggregate(const std::vector& sigs) { + if (sigs.empty()) { + throw std::length_error("sigs must not be empty"); + } + InsecureSignature result = sigs[0]; + for (size_t i = 1; i < sigs.size(); i++) { + g2_add(result.sig, result.sig, *(g2_t*)&sigs[i].sig); + } + return result; +} + +InsecureSignature InsecureSignature::DivideBy(const std::vector& sigs) const { + if (sigs.empty()) { + return *this; + } + + InsecureSignature tmpAgg = Aggregate(sigs); + InsecureSignature result(*this); + g2_sub(result.sig, result.sig, tmpAgg.sig); + return result; +} + +InsecureSignature InsecureSignature::Exp(const bn_t n) const { + InsecureSignature result(*this); + g2_mul(result.sig, result.sig, const_cast(n)); + return result; +} + +void InsecureSignature::Serialize(uint8_t* buffer) const { + CompressPoint(buffer, &sig); +} + +std::vector InsecureSignature::Serialize() const { + std::vector data(SIGNATURE_SIZE); + Serialize(data.data()); + return data; +} + +bool operator==(InsecureSignature const &a, InsecureSignature const &b) { + return g2_cmp(*(g2_t*)&a.sig, *(g2_t*)b.sig) == RLC_EQ; +} + +bool operator!=(InsecureSignature const &a, InsecureSignature const &b) { + return !(a == b); +} + +std::ostream &operator<<(std::ostream &os, InsecureSignature const &s) { + uint8_t data[InsecureSignature::SIGNATURE_SIZE]; + s.Serialize(data); + return os << Util::HexStr(data, InsecureSignature::SIGNATURE_SIZE); +} + +InsecureSignature& InsecureSignature::operator=(const InsecureSignature &rhs) { + g2_copy(sig, *(g2_t*)&rhs.sig); + return *this; +} + +void InsecureSignature::CompressPoint(uint8_t* result, const g2_t* point) { + uint8_t buffer[InsecureSignature::SIGNATURE_SIZE + 1]; + g2_write_bin(buffer, InsecureSignature::SIGNATURE_SIZE + 1, *(g2_t*)point, 1); + + if (buffer[0] == 0x03) { + buffer[1] |= 0x80; + } + std::memcpy(result, buffer + 1, SIGNATURE_SIZE); +} + +/// Signature + +Signature Signature::FromBytes(const uint8_t* data) { + if ((data[0] & 0x40) > 0) { + throw std::invalid_argument("Invalid signature. Second bit is set, so it's a PrependSignature."); + } + Signature result; + result.sig = InsecureSignature::FromBytes(data); + return result; +} + +Signature Signature::FromBytes(const uint8_t *data, const AggregationInfo &info) { + if ((data[0] & 0x40) > 0) { + throw std::invalid_argument("Invalid signature. Second bit is set, so it's a PrependSignature."); + } + + Signature ret = FromBytes(data); + ret.SetAggregationInfo(info); + return ret; +} + +Signature Signature::FromG2(const g2_t* element) { + Signature result; + result.sig = InsecureSignature::FromG2(element); + return result; +} + +Signature Signature::FromG2(const g2_t* element, const AggregationInfo& info) { + Signature ret = FromG2(element); + ret.SetAggregationInfo(info); + return ret; +} + +Signature Signature::FromInsecureSig(const InsecureSignature& sig) { + return FromG2(&sig.sig); +} + +Signature Signature::FromInsecureSig(const InsecureSignature& sig, const AggregationInfo& info) { + return FromG2(&sig.sig, info); +} + +Signature::Signature(const Signature &_signature) + : sig(_signature.sig), + aggregationInfo(_signature.aggregationInfo) { +} + +const AggregationInfo* Signature::GetAggregationInfo() const { + return &aggregationInfo; +} + +void Signature::SetAggregationInfo( + const AggregationInfo &newAggregationInfo) { + aggregationInfo = newAggregationInfo; +} + +void Signature::Serialize(uint8_t* buffer) const { + sig.Serialize(buffer); +} + +std::vector Signature::Serialize() const { + return sig.Serialize(); +} + +InsecureSignature Signature::GetInsecureSig() const { + return sig; +} + +bool operator==(Signature const &a, Signature const &b) { + return a.sig == b.sig; +} + +bool operator!=(Signature const &a, Signature const &b) { + return !(a == b); +} + +std::ostream &operator<<(std::ostream &os, Signature const &s) { + uint8_t data[InsecureSignature::SIGNATURE_SIZE]; + s.Serialize(data); + return os << Util::HexStr(data, InsecureSignature::SIGNATURE_SIZE); +} + +/* + * This implementation of verify has several steps. First, it + * reorganizes the pubkeys and messages into groups, where + * each group corresponds to a message. Then, it checks if the + * siganture has info on how it was aggregated. If so, we + * exponentiate each pk based on the exponent in the AggregationInfo. + * If not, we find public keys that share messages with others, + * and aggregate all of these securely (with exponents.). + * Finally, since each public key now corresponds to a unique + * message (since we grouped them), we can verify using the + * distinct verification procedure. + */ +bool Signature::Verify() const { + if (GetAggregationInfo()->Empty()) { + return false; + } + + std::vector pubKeys = GetAggregationInfo() + ->GetPubKeys(); + std::vector messageHashes = GetAggregationInfo() + ->GetMessageHashes(); + if (pubKeys.size() != messageHashes.size()) { + return false; + } + + // Group all of the messages that are idential, with the + // pubkeys and signatures, the std::maps's key is the message hash + std::map, + Util::BytesCompare32> hashToPubKeys; + + for (size_t i = 0; i < messageHashes.size(); i++) { + auto pubKeyIter = hashToPubKeys.find(messageHashes[i]); + if (pubKeyIter != hashToPubKeys.end()) { + // Already one identical message, so push to vector + pubKeyIter->second.push_back(pubKeys[i]); + } else { + // First time seeing this message, so create a vector + std::vector newPubKey = {pubKeys[i]}; + hashToPubKeys.insert(make_pair(messageHashes[i], newPubKey)); + } + } + + // Aggregate pubkeys of identical messages + std::vector finalPubKeys; + std::vector finalMessageHashes; + std::vector collidingKeys; + + for (const auto &kv : hashToPubKeys) { + PublicKey prod; + std::map> dedupMap; + for (size_t i = 0; i < kv.second.size(); i++) { + const PublicKey& pk = kv.second[i]; + uint8_t *k = new uint8_t[PublicKey::PUBLIC_KEY_SIZE]; + pk.Serialize(k); + dedupMap.emplace(k, i); + } + + for (const auto &kv2 : dedupMap) { + const PublicKey& pk = kv.second[kv2.second]; + + bn_t exponent; + bn_new(exponent); + try { + GetAggregationInfo()->GetExponent(&exponent, kv.first, pk); + } catch (std::out_of_range) { + for (auto &p : dedupMap) { + delete[] p.first; + } + return false; + } + prod = PublicKey::AggregateInsecure({prod, pk.Exp(exponent)}); + } + finalPubKeys.push_back(prod); + finalMessageHashes.push_back(kv.first); + + for (auto &p : dedupMap) { + delete[] p.first; + } + } + + // Now we have all distinct messages, so we can verify + return sig.Verify(finalMessageHashes, finalPubKeys); +} + +Signature Signature::Aggregate( + std::vector const &sigs) { + std::vector > pubKeys; + std::vector > messageHashes; + + // Extracts the public keys and messages from the aggregation info + for (const Signature &sig : sigs) { + const AggregationInfo &info = *sig.GetAggregationInfo(); + if (info.Empty()) { + throw std::invalid_argument("Signature must include aggregation info."); + } + std::vector infoPubKeys = info.GetPubKeys(); + std::vector infoMessageHashes = info.GetMessageHashes(); + if (infoPubKeys.size() < 1 || infoMessageHashes.size() < 1) { + throw std::length_error("AggregationInfo must have items"); + } + pubKeys.push_back(infoPubKeys); + std::vector currMessageHashes; + for (const uint8_t* infoMessageHash : infoMessageHashes) { + uint8_t* messageHash = new uint8_t[BLS::MESSAGE_HASH_LEN]; + std::memcpy(messageHash, infoMessageHash, BLS::MESSAGE_HASH_LEN); + currMessageHashes.push_back(messageHash); + } + messageHashes.push_back(currMessageHashes); + } + + if (sigs.size() != pubKeys.size() + || pubKeys.size() != messageHashes.size()) { + throw std::length_error("Lengths of vectors must match."); + } + for (size_t i = 0; i < messageHashes.size(); i++) { + if (pubKeys[i].size() != messageHashes[i].size()) { + throw std::length_error("Lengths of vectors must match."); + } + } + Signature ret = AggregateSigsInternal(sigs, pubKeys, messageHashes); + for (std::vector group : messageHashes) { + for (const uint8_t* messageHash : group) { + delete[] messageHash; + } + } + return ret; +} + +Signature Signature::AggregateSigsSecure( + std::vector const &sigs, + std::vector const &pubKeys, + std::vector const &messageHashes) { + if (sigs.size() != pubKeys.size() || sigs.size() != messageHashes.size() + || sigs.size() < 1) { + throw std::invalid_argument("Must have atleast one signature, key, and message"); + } + + // Sort the public keys and signature by message + public key + std::vector serPubKeys(pubKeys.size()); + std::vector sortKeys(pubKeys.size()); + std::vector keysSorted(pubKeys.size()); + for (size_t i = 0; i < pubKeys.size(); i++) { + serPubKeys[i] = new uint8_t[PublicKey::PUBLIC_KEY_SIZE]; + pubKeys[i].Serialize(serPubKeys[i]); + + uint8_t *sortKey = new uint8_t[BLS::MESSAGE_HASH_LEN + PublicKey::PUBLIC_KEY_SIZE]; + memcpy(sortKey, messageHashes[i], BLS::MESSAGE_HASH_LEN); + memcpy(sortKey + BLS::MESSAGE_HASH_LEN, serPubKeys[i], PublicKey::PUBLIC_KEY_SIZE); + + sortKeys[i] = sortKey; + keysSorted[i] = i; + } + + std::sort(keysSorted.begin(), keysSorted.end(), [&sortKeys](size_t a, size_t b) { + return memcmp(sortKeys[a], sortKeys[b], BLS::MESSAGE_HASH_LEN + PublicKey::PUBLIC_KEY_SIZE) < 0; + }); + + bn_t* computedTs = new bn_t[keysSorted.size()]; + for (size_t i = 0; i < keysSorted.size(); i++) { + bn_new(computedTs[i]); + } + BLS::HashPubKeys(computedTs, keysSorted.size(), serPubKeys, keysSorted); + + // Raise all signatures to power of the corresponding t's and aggregate the results into aggSig + std::vector expSigs; + expSigs.reserve(keysSorted.size()); + for (size_t i = 0; i < keysSorted.size(); i++) { + auto& s = sigs[keysSorted[i]].sig; + expSigs.emplace_back(s.Exp(computedTs[i])); + } + InsecureSignature aggSig = InsecureSignature::Aggregate(expSigs); + + delete[] computedTs; + for (auto p : serPubKeys) { + delete[] p; + } + for (auto p : sortKeys) { + delete[] p; + } + + Signature ret = Signature::FromInsecureSig(aggSig); + BLS::CheckRelicErrors(); + return ret; +} + +Signature Signature::AggregateSigsInternal( + std::vector const &sigs, + std::vector > const &pubKeys, + std::vector > const &messageHashes) { + if (sigs.size() != pubKeys.size() + || pubKeys.size() != messageHashes.size()) { + throw std::length_error("Lengths of std::vectors must match."); + } + for (size_t i = 0; i < messageHashes.size(); i++) { + if (pubKeys[i].size() != messageHashes[i].size()) { + throw std::length_error("Lengths of std::vectors must match."); + } + } + + // Find colliding vectors, save colliding messages + std::set messagesSet; + std::set collidingMessagesSet; + for (auto &msgVector : messageHashes) { + std::set messagesSetLocal; + for (auto &msg : msgVector) { + auto lookupEntry = messagesSet.find(msg); + auto lookupEntryLocal = messagesSetLocal.find(msg); + if (lookupEntryLocal == messagesSetLocal.end() && + lookupEntry != messagesSet.end()) { + collidingMessagesSet.insert(msg); + } + messagesSet.insert(msg); + messagesSetLocal.insert(msg); + } + } + if (collidingMessagesSet.empty()) { + // There are no colliding messages between the groups, so we + // will just aggregate them all simply. Note that we assume + // that every group is a valid aggregate signature. If an invalid + // or insecure signature is given, and invalid signature will + // be created. We don't verify for performance reasons. + Signature ret = AggregateSigsSimple(sigs); + std::vector infos; + for (const Signature &sig : sigs) { + infos.push_back(*sig.GetAggregationInfo()); + } + ret.SetAggregationInfo(AggregationInfo::MergeInfos(infos)); + return ret; + } + + // There are groups that share messages, therefore we need + // to use a secure form of aggregation. First we find which + // groups collide, and securely aggregate these. Then, we + // use simple aggregation at the end. + std::vector collidingSigs; + std::vector nonCollidingSigs; + std::vector > collidingMessageHashes; + std::vector > collidingPks; + + for (size_t i = 0; i < sigs.size(); i++) { + bool groupCollides = false; + for (const uint8_t* msg : messageHashes[i]) { + auto lookupEntry = collidingMessagesSet.find(msg); + if (lookupEntry != collidingMessagesSet.end()) { + groupCollides = true; + collidingSigs.push_back(sigs[i]); + collidingMessageHashes.push_back(messageHashes[i]); + collidingPks.push_back(pubKeys[i]); + break; + } + } + if (!groupCollides) { + nonCollidingSigs.push_back(sigs[i]); + } + } + + // Sort signatures by aggInfo + std::vector sigsSorted(collidingSigs.size()); + for (size_t i = 0; i < sigsSorted.size(); i++) { + sigsSorted[i] = i; + } + std::sort(sigsSorted.begin(), sigsSorted.end(), [&collidingSigs](size_t a, size_t b) { + return *collidingSigs[a].GetAggregationInfo() < *collidingSigs[b].GetAggregationInfo(); + }); + + std::vector serPubKeys; + std::vector sortKeys; + std::vector sortKeysSorted; + size_t sortKeysCount = 0; + for (size_t i = 0; i < collidingPks.size(); i++) { + sortKeysCount += collidingPks[i].size(); + } + sortKeys.reserve(sortKeysCount); + sortKeysSorted.reserve(sortKeysCount); + for (size_t i = 0; i < collidingPks.size(); i++) { + for (size_t j = 0; j < collidingPks[i].size(); j++) { + uint8_t *serPk = new uint8_t[PublicKey::PUBLIC_KEY_SIZE]; + uint8_t *sortKey = new uint8_t[BLS::MESSAGE_HASH_LEN + PublicKey::PUBLIC_KEY_SIZE]; + collidingPks[i][j].Serialize(serPk); + std::memcpy(sortKey, collidingMessageHashes[i][j], BLS::MESSAGE_HASH_LEN); + std::memcpy(sortKey + BLS::MESSAGE_HASH_LEN, serPk, PublicKey::PUBLIC_KEY_SIZE); + serPubKeys.emplace_back(serPk); + sortKeysSorted.emplace_back(sortKeys.size()); + sortKeys.emplace_back(sortKey); + } + } + // Sort everything according to message || pubkey + std::sort(sortKeysSorted.begin(), sortKeysSorted.end(), [&sortKeys](size_t a, size_t b) { + return memcmp(sortKeys[a], sortKeys[b], BLS::MESSAGE_HASH_LEN + PublicKey::PUBLIC_KEY_SIZE) < 0; + }); + + std::vector pubKeysSorted; + for (size_t i = 0; i < sortKeysSorted.size(); i++) { + const uint8_t *sortKey = sortKeys[sortKeysSorted[i]]; + pubKeysSorted.push_back(PublicKey::FromBytes(sortKey + + BLS::MESSAGE_HASH_LEN)); + } + bn_t* computedTs = new bn_t[sigsSorted.size()]; + for (size_t i = 0; i < sigsSorted.size(); i++) { + bn_new(computedTs[i]); + } + BLS::HashPubKeys(computedTs, sigsSorted.size(), serPubKeys, sortKeysSorted); + + // Raise all signatures to power of the corresponding t's and aggregate the results into aggSig + // Also accumulates aggregation info for each signature + std::vector infos; + std::vector expSigs; + infos.reserve(sigsSorted.size()); + expSigs.reserve(sigsSorted.size()); + for (size_t i = 0; i < sigsSorted.size(); i++) { + auto& s = collidingSigs[sigsSorted[i]]; + expSigs.emplace_back(s.sig.Exp(computedTs[i])); + infos.emplace_back(*s.GetAggregationInfo()); + } + + // Also collect all non-colliding signatures for aggregation + // These don't need exponentiation + for (const Signature &nonColliding : nonCollidingSigs) { + expSigs.emplace_back(nonColliding.sig); + infos.emplace_back(*nonColliding.GetAggregationInfo()); + } + + InsecureSignature aggSig = InsecureSignature::Aggregate(expSigs); + Signature ret = Signature::FromInsecureSig(aggSig); + + // Merge the aggregation infos, which will be combined in an + // identical way as above. + ret.SetAggregationInfo(AggregationInfo::MergeInfos(infos)); + + delete[] computedTs; + + for (auto p : serPubKeys) { + delete[] p; + } + for (auto p : sortKeys) { + delete[] p; + } + + return ret; +} + +Signature Signature::AggregateSigsSimple(std::vector const &sigs) { + if (sigs.size() < 1) { + throw std::length_error("Must have atleast one signatures and key"); + } + if (sigs.size() == 1) { + return sigs[0]; + } + + // Multiplies the signatures together (relic uses additive group operation) + std::vector sigs2; + sigs2.reserve(sigs.size()); + for (const Signature &sig : sigs) { + sigs2.emplace_back(sig.sig); + } + InsecureSignature aggSig = InsecureSignature::Aggregate(sigs2); + Signature ret = Signature::FromInsecureSig(aggSig); + BLS::CheckRelicErrors(); + return ret; +} + +Signature Signature::DivideBy(std::vector const &divisorSigs) const { + bn_t ord; + g2_get_ord(ord); + + std::vector messageHashesToRemove; + std::vector pubKeysToRemove; + + std::vector expSigs; + expSigs.reserve(divisorSigs.size()); + for (const Signature &divisorSig : divisorSigs) { + std::vector pks = divisorSig.GetAggregationInfo() + ->GetPubKeys(); + std::vector messageHashes = divisorSig.GetAggregationInfo() + ->GetMessageHashes(); + if (pks.size() != messageHashes.size()) { + throw std::length_error("Invalid aggregation info."); + } + bn_t quotient; + for (size_t i = 0; i < pks.size(); i++) { + bn_t divisor; + bn_new(divisor); + divisorSig.GetAggregationInfo()->GetExponent(&divisor, + messageHashes[i], + pks[i]); + bn_t dividend; + bn_new(dividend); + try { + aggregationInfo.GetExponent(÷nd, messageHashes[i], + pks[i]); + } catch (std::out_of_range e) { + throw std::logic_error("Signature is not a subset."); + } + + if (i == 0) { + bn_t inverted; + fp_inv_exgcd_bn(inverted, divisor, ord); + bn_mul(quotient, dividend, inverted); + bn_mod(quotient, quotient, ord); + } else { + bn_t leftHandSide; + bn_mul(leftHandSide, quotient, divisor); + bn_mod(leftHandSide, leftHandSide, ord); + + if (bn_cmp(leftHandSide, dividend) != RLC_EQ) { + throw std::logic_error("Cannot divide by aggregate signature," + "msg/pk pairs are not unique"); + } + } + messageHashesToRemove.push_back(messageHashes[i]); + pubKeysToRemove.push_back(pks[i]); + } + expSigs.emplace_back(divisorSig.sig.Exp(quotient)); + } + + InsecureSignature prod = sig.DivideBy(expSigs); + Signature result = Signature::FromInsecureSig(prod, aggregationInfo); + result.aggregationInfo.RemoveEntries(messageHashesToRemove, pubKeysToRemove); + + return result; +} + +// Prepend Signature + +PrependSignature PrependSignature::FromBytes(const uint8_t *data) { + PrependSignature result; + if ((data[0] & 0x40) == 0) { + throw std::invalid_argument("Invalid prepend signature. Second bit must be set to two"); + } + uint8_t new_data[PrependSignature::SIGNATURE_SIZE]; + memcpy(new_data, data, SIGNATURE_SIZE); + new_data[0] ^= 0x40; + result.sig = InsecureSignature::FromBytes(new_data); + return result; +} + +PrependSignature PrependSignature::FromG2(const g2_t* element) { + PrependSignature ret; + ret.sig = InsecureSignature::FromG2(element); + return ret; +} + +PrependSignature PrependSignature::FromInsecureSig(const InsecureSignature& sig) { + return FromG2(&sig.sig); +} + +PrependSignature::PrependSignature(const PrependSignature &_signature) + : sig(_signature.sig) {} + + +bool PrependSignature::Verify(const std::vector& hashes, + const std::vector& pubKeys) const { + if (pubKeys.size() != hashes.size()) { + return false; + } + + std::vector newHashes; + for (uint32_t i = 0; i < hashes.size(); i++) { + uint8_t newMessage[PublicKey::PUBLIC_KEY_SIZE + BLS::MESSAGE_HASH_LEN]; + pubKeys[i].Serialize(newMessage); + memcpy(newMessage + PublicKey::PUBLIC_KEY_SIZE, hashes[i], BLS::MESSAGE_HASH_LEN); + uint8_t* newHash = new uint8_t[BLS::MESSAGE_HASH_LEN]; + Util::Hash256(newHash, newMessage, PublicKey::PUBLIC_KEY_SIZE + BLS::MESSAGE_HASH_LEN); + newHashes.push_back(newHash); + } + + bool res = sig.Verify(newHashes, pubKeys); + for (uint32_t i = 0; i < newHashes.size(); i++) { + delete[] newHashes[i]; + } + return res; +} + +PrependSignature PrependSignature::Aggregate(std::vector const &sigs) { + std::vector insecureSignatures; + for (PrependSignature sig : sigs) { + insecureSignatures.push_back(sig.GetInsecureSig()); + } + return PrependSignature::FromInsecureSig(InsecureSignature::Aggregate(insecureSignatures)); +} + +PrependSignature PrependSignature::DivideBy(std::vector const &divisorSigs) const { + std::vector insecureSignatures; + for (PrependSignature sig : divisorSigs) { + insecureSignatures.push_back(sig.GetInsecureSig()); + } + return PrependSignature::FromInsecureSig(sig.DivideBy(insecureSignatures)); +} + +void PrependSignature::Serialize(uint8_t* buffer) const { + sig.Serialize(buffer); + buffer[0] |= 0x40; +} + +std::vector PrependSignature::Serialize() const { + std::vector ret = sig.Serialize(); + ret[0] |= 0x40; + return ret; +} + +InsecureSignature PrependSignature::GetInsecureSig() const { + return sig; +} + +bool operator==(PrependSignature const &a, PrependSignature const &b) { + return a.sig == b.sig; +} + +bool operator!=(PrependSignature const &a, PrependSignature const &b) { + return !(a == b); +} + +std::ostream &operator<<(std::ostream &os, PrependSignature const &s) { + uint8_t data[InsecureSignature::SIGNATURE_SIZE]; + s.Serialize(data); + return os << Util::HexStr(data, InsecureSignature::SIGNATURE_SIZE); +} + +} // end namespace bls diff --git a/bls/src/signature.hpp b/bls/src/signature.hpp new file mode 100644 index 00000000..79cb698f --- /dev/null +++ b/bls/src/signature.hpp @@ -0,0 +1,242 @@ +// Copyright 2018 Chia Network Inc + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SRC_BLSSIGNATURE_HPP_ +#define SRC_BLSSIGNATURE_HPP_ + +#include +#include + +#include "relic_conf.h" + +#if defined GMP && ARITH == GMP +#include +#endif + +#include "util.hpp" +#include "aggregationinfo.hpp" +namespace bls { +/** + * An insecure BLS signature. + * A Signature is a group element of g2 + * Aggregation of these signatures is not secure on it's own, use Signature or PrependSignature instead. + * For more documentation of the rogue public key attack, and the insecurity of this class, + * see https://crypto.stanford.edu/~dabo/pubs/papers/BLSmultisig.html. + */ +class InsecureSignature { + friend class Signature; + friend class PrependSignature; + friend class Threshold; + public: + static const size_t SIGNATURE_SIZE = 96; + + // Initializes from serialized byte array. + static InsecureSignature FromBytes(const uint8_t *data); + + // Initializes from native relic g2 element. + static InsecureSignature FromG2(const g2_t* element); + + // Copy constructor. Deep copies contents. + InsecureSignature(const InsecureSignature &signature); + + // This verification method is insecure in regard to the rogue public key attack + bool Verify(const std::vector& hashes, const std::vector& pubKeys) const; + + // Insecurely aggregates signatures + static InsecureSignature Aggregate(const std::vector& sigs); + + // Insecurely divides signatures + InsecureSignature DivideBy(const std::vector& sigs) const; + + // Serializes ONLY the 96 byte public key. It does not serialize + // the aggregation info. + void Serialize(uint8_t* buffer) const; + std::vector Serialize() const; + + friend bool operator==(InsecureSignature const &a, InsecureSignature const &b); + friend bool operator!=(InsecureSignature const &a, InsecureSignature const &b); + friend std::ostream &operator<<(std::ostream &os, InsecureSignature const &s); + InsecureSignature& operator=(const InsecureSignature& rhs); + + private: + // Prevent public construction, force static method + InsecureSignature(); + + // Exponentiate signature with n + InsecureSignature Exp(const bn_t n) const; + + static void CompressPoint(uint8_t* result, const g2_t* point); + + // Performs multipairing and checks that everything matches. This is an + // internal method, only called from Verify. It should not be used + // anywhere else. + static bool VerifyNative( + g1_t* pubKeys, + g2_t* mappedHashes, + size_t len); + + private: + // Signature group element + g2_t sig; +}; + +/** + * An encapsulated signature. + * A Signature is composed of two things: + * 1. 96 byte group element of g2 + * 2. AggregationInfo object, which describes how the signature was + * generated, and how it should be verified. + */ +class Signature { + public: + static const size_t SIGNATURE_SIZE = InsecureSignature::SIGNATURE_SIZE; + + // Initializes from serialized byte array. + static Signature FromBytes(const uint8_t *data); + + // Initializes from bytes with AggregationInfo. + static Signature FromBytes(const uint8_t *data, const AggregationInfo &info); + + // Initializes from native relic g2 element. + static Signature FromG2(const g2_t* element); + + // Initializes from native relic g2 element with AggregationInfo. + static Signature FromG2(const g2_t* element, const AggregationInfo &info); + + // Initializes from insecure signature/ + static Signature FromInsecureSig(const InsecureSignature& sig); + + // Initializes from insecure signature with AggregationInfo/ + static Signature FromInsecureSig(const InsecureSignature& sig, const AggregationInfo &info); + + // Copy constructor. Deep copies contents. + Signature(const Signature &signature); + + // Verifies a single or aggregate signature. + // Performs two pairing operations, sig must contain information on + // how aggregation was performed (AggregationInfo). The Aggregation + // Info contains all the public keys and messages required. + bool Verify() const; + + // Securely aggregates many signatures on messages, some of + // which may be identical. The returned signature contains + // information on how the aggregation was done (AggragationInfo). + static Signature Aggregate(std::vector const &sigs); + + // Divides the aggregate signature (this) by a list of signatures. + // These divisors can be single or aggregate signatures, but all + // msg/pk pairs in these signatures must be distinct and unique. + Signature DivideBy(std::vector const &divisorSigs) const; + + // Gets the aggregation info on this signature. + const AggregationInfo* GetAggregationInfo() const; + + // Sets the aggregation information on this signature, which + // describes how this signature was generated, and how it should + // be verified. + void SetAggregationInfo(const AggregationInfo &newAggregationInfo); + + // Serializes ONLY the 96 byte public key. It does not serialize + // the aggregation info. + void Serialize(uint8_t* buffer) const; + std::vector Serialize() const; + + InsecureSignature GetInsecureSig() const; + + friend bool operator==(Signature const &a, Signature const &b); + friend bool operator!=(Signature const &a, Signature const &b); + friend std::ostream &operator<<(std::ostream &os, Signature const &s); + + private: + // Prevent public construction, force static method + Signature() {} + + // Aggregates many signatures using the secure aggregation method. + // Performs ~ n * 256 g2 operations. + static Signature AggregateSigsSecure( + std::vector const &sigs, + std::vector const &pubKeys, + std::vector const &messageHashes); + + // Internal methods + static Signature AggregateSigsInternal( + std::vector const &sigs, + std::vector > const &pubKeys, + std::vector > const &messageHashes); + + // Efficiently aggregates many signatures using the simple aggregation + // method. Performs only n g2 operations. + static Signature AggregateSigsSimple( + std::vector const &sigs); + + private: + // internal signature + InsecureSignature sig; + + // Optional info about how this was aggregated + AggregationInfo aggregationInfo; +}; + +/** + * An encapsulated signature. + * A Prepend Signature is generated using PrivateKey::SignPrepend. It a secure against rogue + * public key attacks, since it signs the signer's public key. + */ +class PrependSignature { + public: + static const size_t SIGNATURE_SIZE = InsecureSignature::SIGNATURE_SIZE; + + // Initializes from serialized byte array. + static PrependSignature FromBytes(const uint8_t *data); + + // Initializes from native relic g2 element. + static PrependSignature FromG2(const g2_t* element); + + // Initializes from insecure signature. + static PrependSignature FromInsecureSig(const InsecureSignature& sig); + + // Copy constructor. Deep copies contents. + PrependSignature(const PrependSignature &signature); + + // Verifies a single or aggregate signature. + bool Verify(const std::vector& hashes, const std::vector& pubKeys) const; + + static PrependSignature Aggregate(std::vector const &sigs); + + // Divides the aggregate signature (this) by a list of signatures. + // These divisors can be single or aggregate signatures, but all + // msg/pk pairs in these signatures must be distinct and unique. + PrependSignature DivideBy(std::vector const &divisorSigs) const; + + void Serialize(uint8_t* buffer) const; + std::vector Serialize() const; + + InsecureSignature GetInsecureSig() const; + + friend bool operator==(PrependSignature const &a, PrependSignature const &b); + friend bool operator!=(PrependSignature const &a, PrependSignature const &b); + friend std::ostream &operator<<(std::ostream &os, PrependSignature const &s); + + private: + // Prevent public construction, force static method + PrependSignature() {} + + private: + // internal signature + InsecureSignature sig; +}; + +} // end namespace bls + +#endif // SRC_BLSSIGNATURE_HPP_ diff --git a/bls/src/test-bench.cpp b/bls/src/test-bench.cpp new file mode 100644 index 00000000..10d2bb17 --- /dev/null +++ b/bls/src/test-bench.cpp @@ -0,0 +1,199 @@ +// Copyright 2018 Chia Network Inc + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include "bls.hpp" +#include "test-utils.hpp" +#include "relic.h" + +using std::string; +using std::vector; +using std::cout; +using std::endl; + +using namespace bls; + +void benchSigs() { + string testName = "Sigining"; + double numIters = 1000; + uint8_t seed[32]; + getRandomSeed(seed); + PrivateKey sk = PrivateKey::FromSeed(seed, 32); + PublicKey pk = sk.GetPublicKey(); + uint8_t message1[48]; + pk.Serialize(message1); + + auto start = startStopwatch(); + + for (size_t i = 0; i < numIters; i++) { + sk.Sign(message1, sizeof(message1)); + } + endStopwatch(testName, start, numIters); +} + +void benchVerification() { + string testName = "Verification"; + double numIters = 1000; + uint8_t seed[32]; + getRandomSeed(seed); + PrivateKey sk = PrivateKey::FromSeed(seed, 32); + + std::vector sigs; + + for (size_t i = 0; i < numIters; i++) { + uint8_t message[4]; + Util::IntToFourBytes(message, i); + sigs.push_back(sk.Sign(message, 4)); + } + + auto start = startStopwatch(); + for (size_t i = 0; i < numIters; i++) { + uint8_t message[4]; + Util::IntToFourBytes(message, i); + bool ok = sigs[i].Verify(); + ASSERT(ok); + } + endStopwatch(testName, start, numIters); +} + +void benchAggregateSigsSecure() { + uint8_t message1[7] = {100, 2, 254, 88, 90, 45, 23}; + double numIters = 1000; + + std::vector sks; + std::vector pks; + std::vector sigs; + + for (int i = 0; i < numIters; i++) { + uint8_t seed[32]; + getRandomSeed(seed); + + PrivateKey sk = PrivateKey::FromSeed(seed, 32); + const PublicKey pk = sk.GetPublicKey(); + sks.push_back(sk); + pks.push_back(pk); + sigs.push_back(sk.Sign(message1, sizeof(message1))); + } + + auto start = startStopwatch(); + Signature aggSig = Signature::Aggregate(sigs); + endStopwatch("Generate aggregate signature, same message", + start, numIters); + + auto start2 = startStopwatch(); + const PublicKey aggPubKey = PublicKey::Aggregate(pks); + endStopwatch("Generate aggregate pk, same message", start2, numIters); + + auto start3 = startStopwatch(); + aggSig.SetAggregationInfo(AggregationInfo::FromMsg( + aggPubKey, message1, sizeof(message1))); + ASSERT(aggSig.Verify()); + endStopwatch("Verify agg signature, same message", start3, numIters); +} + +void benchBatchVerification() { + string testName = "Batch verification"; + double numIters = 1000; + + std::vector sigs; + std::vector cache; + for (size_t i = 0; i < numIters; i++) { + uint8_t seed[32]; + getRandomSeed(seed); + + PrivateKey sk = PrivateKey::FromSeed(seed, 32); + uint8_t *message = new uint8_t[32]; + getRandomSeed(message); + sigs.push_back(sk.Sign(message, 1 + (i % 5))); + // Small message, so some messages are the same + if (message[0] < 225) { // Simulate having ~90% cached transactions + sigs.back().Verify(); + cache.push_back(sigs.back()); + } + } + + Signature aggregate = Signature::Aggregate(sigs); + + auto start = startStopwatch(); + ASSERT(aggregate.Verify()); + endStopwatch(testName, start, numIters); + + + start = startStopwatch(); + const Signature aggSmall = aggregate.DivideBy(cache); + ASSERT(aggSmall.Verify()); + endStopwatch(testName + " with cached verifications", start, numIters); +} + +void benchAggregateSigsSimple() { + double numIters = 1000; + std::vector sks; + std::vector sigs; + + for (int i = 0; i < numIters; i++) { + uint8_t* message = new uint8_t[48]; + uint8_t seed[32]; + getRandomSeed(seed); + + PrivateKey sk = PrivateKey::FromSeed(seed, 32); + const PublicKey pk = sk.GetPublicKey(); + pk.Serialize(message); + sks.push_back(sk); + sigs.push_back(sk.Sign(message, sizeof(message))); + } + + auto start = startStopwatch(); + Signature aggSig = Signature::Aggregate(sigs); + endStopwatch("Generate aggregate signature, distinct messages", + start, numIters); + + auto start2 = startStopwatch(); + ASSERT(aggSig.Verify()); + endStopwatch("Verify aggregate signature, distinct messages", + start2, numIters); +} + +void benchDegenerateTree() { + double numIters = 30; + uint8_t message1[7] = {100, 2, 254, 88, 90, 45, 23}; + uint8_t seed[32]; + getRandomSeed(seed); + PrivateKey sk1 = PrivateKey::FromSeed(seed, 32); + Signature aggSig = sk1.Sign(message1, sizeof(message1)); + + auto start = startStopwatch(); + for (size_t i = 0; i < numIters; i++) { + getRandomSeed(seed); + PrivateKey sk = PrivateKey::FromSeed(seed, 32); + Signature sig = sk.Sign(message1, sizeof(message1)); + std::vector sigs = {aggSig, sig}; + aggSig = Signature::Aggregate(sigs); + } + endStopwatch("Generate degenerate aggSig tree", + start, numIters); + + start = startStopwatch(); + ASSERT(aggSig.Verify()); + endStopwatch("Verify degenerate aggSig tree", + start, numIters); +} + +int main(int argc, char* argv[]) { + benchSigs(); + benchVerification(); + benchBatchVerification(); + benchAggregateSigsSecure(); + benchAggregateSigsSimple(); + benchDegenerateTree(); +} diff --git a/bls/src/test-utils.hpp b/bls/src/test-utils.hpp new file mode 100644 index 00000000..1fa7bee3 --- /dev/null +++ b/bls/src/test-utils.hpp @@ -0,0 +1,50 @@ +// Copyright 2018 Chia Network Inc + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include "bls.hpp" + +using std::string; +using std::vector; +using std::cout; +using std::endl; + +#define STR(x) #x +#define ASSERT(x) if (!(x)) { printf("BLS assertion failed: (%s), function %s, file %s, line %d.\n", STR(x), __PRETTY_FUNCTION__, __FILE__, __LINE__); abort(); } + +std::chrono::time_point startStopwatch() { + return std::chrono::steady_clock::now(); +} + +void endStopwatch(string testName, + std::chrono::time_point start, + double numIters) { + auto end = std::chrono::steady_clock::now(); + auto now_ms = std::chrono::duration_cast( + end - start); + + cout << endl << testName << endl; + cout << "Total: " << numIters << " runs in " << now_ms.count() + << " ms" << endl; + cout << "Avg: " << now_ms.count() / numIters + << " ms" << endl; +} + +void getRandomSeed(uint8_t* seed) { + bn_t r; + bn_new(r); + bn_rand(r, RLC_POS, 256); + bn_write_bin(seed, 32, r); +} diff --git a/bls/src/test.cpp b/bls/src/test.cpp new file mode 100644 index 00000000..20a8fdba --- /dev/null +++ b/bls/src/test.cpp @@ -0,0 +1,1659 @@ + +// Copyright 2018 Chia Network Inc + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#define CATCH_CONFIG_RUNNER +#include "catch.hpp" +#include "bls.hpp" +#include "test-utils.hpp" +#include "relic.h" +#include "relic_test.h" + +#include +using std::string; +using std::vector; +using std::cout; +using std::endl; + +using namespace bls; + +TEST_CASE("Test vectors") { + SECTION("Test vectors 1") { + uint8_t seed1[5] = {1, 2, 3, 4, 5}; + uint8_t seed2[6] = {1, 2, 3, 4, 5, 6}; + uint8_t message1[3] = {7, 8, 9}; + + PrivateKey sk1 = PrivateKey::FromSeed(seed1, sizeof(seed1)); + PublicKey pk1 = sk1.GetPublicKey(); + Signature sig1 = sk1.Sign(message1, sizeof(message1)); + + PrivateKey sk2 = PrivateKey::FromSeed(seed2, sizeof(seed2)); + PublicKey pk2 = sk2.GetPublicKey(); + Signature sig2 = sk2.Sign(message1, sizeof(message1)); + + uint8_t buf[Signature::SIGNATURE_SIZE]; + uint8_t buf2[PrivateKey::PRIVATE_KEY_SIZE]; + + REQUIRE(pk1.GetFingerprint() == 0x26d53247); + REQUIRE(pk2.GetFingerprint() == 0x289bb56e); + + + sig1.Serialize(buf); + sk1.Serialize(buf2); + + REQUIRE(Util::HexStr(buf, Signature::SIGNATURE_SIZE) + == "93eb2e1cb5efcfb31f2c08b235e8203a67265bc6a13d9f0ab77727293b74a357ff0459ac210dc851fcb8a60cb7d393a419915cfcf83908ddbeac32039aaa3e8fea82efcb3ba4f740f20c76df5e97109b57370ae32d9b70d256a98942e5806065"); + REQUIRE(Util::HexStr(buf2, PrivateKey::PRIVATE_KEY_SIZE) + == "022fb42c08c12de3a6af053880199806532e79515f94e83461612101f9412f9e"); + + sig2.Serialize(buf); + REQUIRE(Util::HexStr(buf, Signature::SIGNATURE_SIZE) + == "975b5daa64b915be19b5ac6d47bc1c2fc832d2fb8ca3e95c4805d8216f95cf2bdbb36cc23645f52040e381550727db420b523b57d494959e0e8c0c6060c46cf173872897f14d43b2ac2aec52fc7b46c02c5699ff7a10beba24d3ced4e89c821e"); + + vector sigs = {sig1, sig2}; + Signature aggSig1 = Signature::Aggregate(sigs); + + aggSig1.Serialize(buf); + REQUIRE(Util::HexStr(buf, Signature::SIGNATURE_SIZE) + == "0a638495c1403b25be391ed44c0ab013390026b5892c796a85ede46310ff7d0e0671f86ebe0e8f56bee80f28eb6d999c0a418c5fc52debac8fc338784cd32b76338d629dc2b4045a5833a357809795ef55ee3e9bee532edfc1d9c443bf5bc658"); + REQUIRE(aggSig1.Verify()); + + uint8_t message2[3] = {1, 2, 3}; + uint8_t message3[4] = {1, 2, 3, 4}; + uint8_t message4[2] = {1, 2}; + Signature sig3 = sk1.Sign(message2, sizeof(message2)); + Signature sig4 = sk1.Sign(message3, sizeof(message3)); + Signature sig5 = sk2.Sign(message4, sizeof(message4)); + vector sigs2 = {sig3, sig4, sig5}; + Signature aggSig2 = Signature::Aggregate(sigs2); + REQUIRE(aggSig2.Verify()); + aggSig2.Serialize(buf); + REQUIRE(Util::HexStr(buf, Signature::SIGNATURE_SIZE) + == "8b11daf73cd05f2fe27809b74a7b4c65b1bb79cc1066bdf839d96b97e073c1a635d2ec048e0801b4a208118fdbbb63a516bab8755cc8d850862eeaa099540cd83621ff9db97b4ada857ef54c50715486217bd2ecb4517e05ab49380c041e159b"); + } + + SECTION("Test vector 2") { + uint8_t message1[4] = {1, 2, 3, 40}; + uint8_t message2[4] = {5, 6, 70, 201}; + uint8_t message3[5] = {9, 10, 11, 12, 13}; + uint8_t message4[6] = {15, 63, 244, 92, 0, 1}; + + uint8_t seed1[5] = {1, 2, 3, 4, 5}; + uint8_t seed2[6] = {1, 2, 3, 4, 5, 6}; + + PrivateKey sk1 = PrivateKey::FromSeed(seed1, sizeof(seed1)); + PrivateKey sk2 = PrivateKey::FromSeed(seed2, sizeof(seed2)); + + PublicKey pk1 = sk1.GetPublicKey(); + PublicKey pk2 = sk2.GetPublicKey(); + + Signature sig1 = sk1.Sign(message1, sizeof(message1)); + Signature sig2 = sk2.Sign(message2, sizeof(message2)); + Signature sig3 = sk2.Sign(message1, sizeof(message1)); + Signature sig4 = sk1.Sign(message3, sizeof(message3)); + Signature sig5 = sk1.Sign(message1, sizeof(message1)); + Signature sig6 = sk1.Sign(message4, sizeof(message4)); + + std::vector const sigsL = {sig1, sig2}; + const Signature aggSigL = Signature::Aggregate(sigsL); + + std::vector const sigsR = {sig3, sig4, sig5}; + const Signature aggSigR = Signature::Aggregate(sigsR); + + std::vector sigs = {aggSigL, aggSigR, sig6}; + + Signature aggSig = Signature::Aggregate(sigs); + + REQUIRE(aggSig.Verify()); + + uint8_t buf[Signature::SIGNATURE_SIZE]; + aggSig.Serialize(buf); + REQUIRE(Util::HexStr(buf, Signature::SIGNATURE_SIZE) + == "07969958fbf82e65bd13ba0749990764cac81cf10d923af9fdd2723f1e3910c3fdb874a67f9d511bb7e4920f8c01232b12e2fb5e64a7c2d177a475dab5c3729ca1f580301ccdef809c57a8846890265d195b694fa414a2a3aa55c32837fddd80"); + vector signatures_to_divide = {sig2, sig5, sig6}; + Signature quotient = aggSig.DivideBy(signatures_to_divide); + aggSig.DivideBy(signatures_to_divide); + + quotient.Serialize(buf); + REQUIRE(Util::HexStr(buf, Signature::SIGNATURE_SIZE) + == "8ebc8a73a2291e689ce51769ff87e517be6089fd0627b2ce3cd2f0ee1ce134b39c4da40928954175014e9bbe623d845d0bdba8bfd2a85af9507ddf145579480132b676f027381314d983a63842fcc7bf5c8c088461e3ebb04dcf86b431d6238f"); + + REQUIRE(quotient.Verify()); + REQUIRE(quotient.DivideBy(vector()) == quotient); + signatures_to_divide = {sig6}; + REQUIRE_THROWS(quotient.DivideBy(signatures_to_divide)); + + // Should not throw + signatures_to_divide = {sig1}; + aggSig.DivideBy(signatures_to_divide); + + // Should throw due to not unique + signatures_to_divide = {aggSigL}; + REQUIRE_THROWS(aggSig.DivideBy(signatures_to_divide)); + + Signature sig7 = sk2.Sign(message3, sizeof(message3)); + Signature sig8 = sk2.Sign(message4, sizeof(message4)); + + // Divide by aggregate + std::vector sigsR2 = {sig7, sig8}; + Signature aggSigR2 = Signature::Aggregate(sigsR2); + std::vector sigsFinal2 = {aggSig, aggSigR2}; + Signature aggSig2 = Signature::Aggregate(sigsFinal2); + std::vector divisorFinal2 = {aggSigR2}; + Signature quotient2 = aggSig2.DivideBy(divisorFinal2); + + REQUIRE(quotient2.Verify()); + quotient2.Serialize(buf); + REQUIRE(Util::HexStr(buf, Signature::SIGNATURE_SIZE) + == "06af6930bd06838f2e4b00b62911fb290245cce503ccf5bfc2901459897731dd08fc4c56dbde75a11677ccfbfa61ab8b14735fddc66a02b7aeebb54ab9a41488f89f641d83d4515c4dd20dfcf28cbbccb1472c327f0780be3a90c005c58a47d3"); + } + + SECTION("Test vector 3") { + uint8_t seed[] = {1, 50, 6, 244, 24, 199, 1, 25}; + ExtendedPrivateKey esk = ExtendedPrivateKey::FromSeed( + seed, sizeof(seed)); + REQUIRE(esk.GetPublicKey().GetFingerprint() == 0xa4700b27); + uint8_t chainCode[32]; + esk.GetChainCode().Serialize(chainCode); + REQUIRE(Util::HexStr(chainCode, 32) == "d8b12555b4cc5578951e4a7c80031e22019cc0dce168b3ed88115311b8feb1e3"); + + ExtendedPrivateKey esk77 = esk.PrivateChild(77 + (1 << 31)); + esk77.GetChainCode().Serialize(chainCode); + REQUIRE(Util::HexStr(chainCode, 32) == "f2c8e4269bb3e54f8179a5c6976d92ca14c3260dd729981e9d15f53049fd698b"); + REQUIRE(esk77.GetPrivateKey().GetPublicKey().GetFingerprint() == 0xa8063dcf); + + REQUIRE(esk.PrivateChild(3) + .PrivateChild(17) + .GetPublicKey() + .GetFingerprint() == 0xff26a31f); + REQUIRE(esk.GetExtendedPublicKey() + .PublicChild(3) + .PublicChild(17) + .GetPublicKey() + .GetFingerprint() == 0xff26a31f); + } + + SECTION("Test vector 4") { + uint8_t seed1[5] = {1, 2, 3, 4, 5}; + uint8_t seed2[6] = {1, 2, 3, 4, 5, 6}; + uint8_t message1[3] = {7, 8, 9}; + uint8_t message2[3] = {10, 11, 12}; + + PrivateKey sk1 = PrivateKey::FromSeed(seed1, sizeof(seed1)); + PublicKey pk1 = sk1.GetPublicKey(); + + PrivateKey sk2 = PrivateKey::FromSeed(seed2, sizeof(seed2)); + PublicKey pk2 = sk2.GetPublicKey(); + + PrependSignature sig9 = sk1.SignPrepend(message1, sizeof(message1)); + PrependSignature sig10 = sk2.SignPrepend(message2, sizeof(message2)); + + uint8_t buf[Signature::SIGNATURE_SIZE]; + sig9.Serialize(buf); + REQUIRE(Util::HexStr(buf, Signature::SIGNATURE_SIZE) + == "d2135ad358405d9f2d4e68dc253d64b6049a821797817cffa5aa804086a8fb7b135175bb7183750e3aa19513db1552180f0b0ffd513c322f1c0c30a0a9c179f6e275e0109d4db7fa3e09694190947b17d890f3d58fe0b1866ec4d4f5a59b16ed"); + sig10.Serialize(buf); + REQUIRE(Util::HexStr(buf, Signature::SIGNATURE_SIZE) + == "cc58c982f9ee5817d4fbf22d529cfc6792b0fdcf2d2a8001686755868e10eb32b40e464e7fbfe30175a962f1972026f2087f0495ba6e293ac3cf271762cd6979b9413adc0ba7df153cf1f3faab6b893404c2e6d63351e48cd54e06e449965f08"); + + uint8_t messageHash1[BLS::MESSAGE_HASH_LEN]; + uint8_t messageHash2[BLS::MESSAGE_HASH_LEN]; + Util::Hash256(messageHash1, message1, sizeof(message1)); + Util::Hash256(messageHash2, message2, sizeof(message2)); + vector messageHashes1 = {messageHash1}; + vector messageHashes2 = {messageHash2}; + vector messageHashes = {messageHash1, messageHash1, messageHash2}; + vector pks = {pk1, pk1, pk2}; + + vector sigs = {sig9, sig9, sig10}; + PrependSignature agg = PrependSignature::Aggregate(sigs); + + agg.Serialize(buf); + REQUIRE(Util::HexStr(buf, Signature::SIGNATURE_SIZE) + == "c37077684e735e62e3f1fd17772a236b4115d4b581387733d3b97cab08b90918c7e91c23380c93e54be345544026f93505d41e6000392b82ab3c8af1b2e3954b0ef3f62c52fc89f99e646ff546881120396c449856428e672178e5e0e14ec894"); + + REQUIRE(agg.Verify(messageHashes, pks)); + } +} + +TEST_CASE("Key generation") { + SECTION("Should generate a keypair from a seed") { + uint8_t seed[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + + + PrivateKey sk = PrivateKey::FromSeed(seed, sizeof(seed)); + PublicKey pk = sk.GetPublicKey(); + REQUIRE(core_get()->code == RLC_OK); + REQUIRE(pk.GetFingerprint() == 0xddad59bb); + } +} + +TEST_CASE("Error handling") { + SECTION("Should throw on a bad private key") { + uint8_t seed[32]; + getRandomSeed(seed); + PrivateKey sk1 = PrivateKey::FromSeed(seed, 32); + uint8_t* skData = Util::SecAlloc( + Signature::SIGNATURE_SIZE); + sk1.Serialize(skData); + skData[0] = 255; + REQUIRE_THROWS(PrivateKey::FromBytes(skData)); + + Util::SecFree(skData); + } + + SECTION("Should throw on a bad public key") { + uint8_t buf[PublicKey::PUBLIC_KEY_SIZE] = {0}; + std::set invalid = {1, 2, 3, 4}; + + for (int i = 0; i < 10; i++) { + buf[0] = (uint8_t)i; + try { + PublicKey::FromBytes(buf); + REQUIRE(invalid.count(i) == 0); + } catch (std::invalid_argument& s) { + REQUIRE(invalid.count(i) != 0); + } + } + } + + SECTION("Should throw on a bad signature") { + uint8_t buf[Signature::SIGNATURE_SIZE] = {0}; + std::set invalid = {0, 1, 2, 3, 5, 6, 7, 8}; + + for (int i = 0; i < 10; i++) { + buf[0] = (uint8_t)i; + try { + Signature::FromBytes(buf); + REQUIRE(invalid.count(i) == 0); + } catch (std::invalid_argument& s) { + REQUIRE(invalid.count(i) != 0); + } + } + } + + SECTION("Error handling should be thread safe") { + core_get()->code = 10; + REQUIRE(core_get()->code == 10); + + ctx_t* ctx1 = core_get(); + bool ctxError = false; + + // spawn a thread and make sure it uses a different context + std::thread([&]() { + if (ctx1 == core_get()) { + ctxError = true; + } + if (core_get()->code != RLC_OK) { + ctxError = true; + } + // this should not modify the code of the main thread + core_get()->code = 1; + }).join(); + + REQUIRE(!ctxError); + + // other thread should not modify code + REQUIRE(core_get()->code == 10); + + // reset so that future test cases don't fail + core_get()->code = RLC_OK; + } +} + +TEST_CASE("Util tests") { + SECTION("Should convert an int to four bytes") { + uint32_t x = 1024; + uint8_t expected[4] = {0x00, 0x00, 0x04, 0x00}; + uint8_t result[4]; + Util::IntToFourBytes(result, x); + REQUIRE(result[0] == expected[0]); + REQUIRE(result[1] == expected[1]); + REQUIRE(result[2] == expected[2]); + REQUIRE(result[3] == expected[3]); + uint32_t again = Util::FourBytesToInt(result); + REQUIRE(again == x); + } + + SECTION("Should calculate public key fingerprints") { + uint8_t seed[] = {1, 50, 6, 244, 24, 199, 1, 25}; + ExtendedPrivateKey esk = ExtendedPrivateKey::FromSeed( + seed, sizeof(seed)); + uint32_t fingerprint = esk.GetPublicKey().GetFingerprint(); + REQUIRE(fingerprint == 0xa4700b27); + } +} + +TEST_CASE("Signatures") { + SECTION("Should sign and verify") { + uint8_t message1[7] = {1, 65, 254, 88, 90, 45, 22}; + + uint8_t seed[6] = {28, 20, 102, 229, 1, 157}; + PrivateKey sk1 = PrivateKey::FromSeed(seed, sizeof(seed)); + PublicKey pk1 = sk1.GetPublicKey(); + Signature sig1 = sk1.Sign(message1, sizeof(message1)); + + sig1.SetAggregationInfo( + AggregationInfo::FromMsg(pk1, message1, sizeof(message1))); + REQUIRE(sig1.Verify()); + + uint8_t hash[32]; + Util::Hash256(hash, message1, 7); + Signature sig2 = sk1.SignPrehashed(hash); + sig2.SetAggregationInfo( + AggregationInfo::FromMsg(pk1, message1, sizeof(message1))); + REQUIRE(sig1 == sig2); + REQUIRE(sig2.Verify()); + + // Hashing to g1 + uint8_t mapMsg[0] = {}; + g1_t result; + uint8_t buf[49]; + ep_map(result, mapMsg, 0); + g1_write_bin(buf, 49, result, 1); + REQUIRE(Util::HexStr(buf + 1, 48) == "12fc5ad5a2fbe9d4b6eb0bc16d530e5f263b6d59cbaf26c3f2831962924aa588ab84d46cc80d3a433ce064adb307f256"); + } + + SECTION("Should use copy constructor") { + uint8_t message1[7] = {1, 65, 254, 88, 90, 45, 22}; + + uint8_t seed[32]; + getRandomSeed(seed); + PrivateKey sk1 = PrivateKey::FromSeed(seed, 32); + PublicKey pk1 = sk1.GetPublicKey(); + PrivateKey sk2 = PrivateKey(sk1); + + uint8_t skBytes[PrivateKey::PRIVATE_KEY_SIZE]; + sk2.Serialize(skBytes); + PrivateKey sk4 = PrivateKey::FromBytes(skBytes); + + PublicKey pk2 = PublicKey(pk1); + Signature sig1 = sk4.Sign(message1, sizeof(message1)); + Signature sig2 = Signature(sig1); + + REQUIRE(sig2.Verify()); + } + + SECTION("Should use operators") { + uint8_t message1[7] = {1, 65, 254, 88, 90, 45, 22}; + uint8_t seed[32]; + getRandomSeed(seed); + uint8_t seed3[32]; + getRandomSeed(seed3); + + PrivateKey sk1 = PrivateKey::FromSeed(seed, 32); + PrivateKey sk2 = PrivateKey(sk1); + PrivateKey sk3 = PrivateKey::FromSeed(seed3, 32); + PublicKey pk1 = sk1.GetPublicKey(); + PublicKey pk2 = sk2.GetPublicKey(); + PublicKey pk3 = PublicKey(pk2); + PublicKey pk4 = sk3.GetPublicKey(); + Signature sig1 = sk1.Sign(message1, sizeof(message1)); + Signature sig2 = sk1.Sign(message1, sizeof(message1)); + Signature sig3 = sk2.Sign(message1, sizeof(message1)); + Signature sig4 = sk3.Sign(message1, sizeof(message1)); + + REQUIRE(sk1 == sk2); + REQUIRE(sk1 != sk3); + REQUIRE(pk1 == pk2); + REQUIRE(pk2 == pk3); + REQUIRE(pk1 != pk4); + REQUIRE(sig1 == sig2); + REQUIRE(sig2 == sig3); + REQUIRE(sig3 != sig4); + + REQUIRE(pk1.Serialize() == pk2.Serialize()); + REQUIRE(sig1.Serialize() == sig2.Serialize()); + } + + SECTION("Should serialize and deserialize") { + uint8_t message1[7] = {1, 65, 254, 88, 90, 45, 22}; + + uint8_t seed[32]; + getRandomSeed(seed); + PrivateKey sk1 = PrivateKey::FromSeed(seed, 32); + PublicKey pk1 = sk1.GetPublicKey(); + + uint8_t* skData = Util::SecAlloc( + Signature::SIGNATURE_SIZE); + sk1.Serialize(skData); + PrivateKey sk2 = PrivateKey::FromBytes(skData); + REQUIRE(sk1 == sk2); + + uint8_t pkData[PublicKey::PUBLIC_KEY_SIZE]; + pk1.Serialize(pkData); + + PublicKey pk2 = PublicKey::FromBytes(pkData); + REQUIRE(pk1 == pk2); + + Signature sig1 = sk1.Sign(message1, sizeof(message1)); + + uint8_t sigData[Signature::SIGNATURE_SIZE]; + sig1.Serialize(sigData); + + Signature sig2 = Signature::FromBytes(sigData); + REQUIRE(sig1 == sig2); + sig2.SetAggregationInfo(AggregationInfo::FromMsg( + pk2, message1, sizeof(message1))); + + REQUIRE(sig2.Verify()); + Util::SecFree(skData); + + InsecureSignature sig3 = InsecureSignature::FromBytes(sigData); + REQUIRE(Signature::FromInsecureSig(sig3) == sig2); + } + + SECTION("Should not validate a bad sig") { + uint8_t message1[7] = {100, 2, 254, 88, 90, 45, 22}; + uint8_t seed[32]; + getRandomSeed(seed); + uint8_t seed2[32]; + getRandomSeed(seed2); + PrivateKey sk1 = PrivateKey::FromSeed(seed, 32); + PrivateKey sk2 = PrivateKey::FromSeed(seed2, 32); + + PublicKey pk1 = sk1.GetPublicKey(); + PublicKey pk2 = sk2.GetPublicKey(); + + Signature sig2 = sk2.Sign(message1, sizeof(message1)); + sig2.SetAggregationInfo(AggregationInfo::FromMsg( + pk1, message1, sizeof(message1))); + + REQUIRE(sig2.Verify() == false); + } + + SECTION("Should insecurely aggregate and verify aggregate same message") { + uint8_t message[7] = {100, 2, 254, 88, 90, 45, 23}; + uint8_t hash[BLS::MESSAGE_HASH_LEN]; + + uint8_t seed[32]; + getRandomSeed(seed); + uint8_t seed2[32]; + getRandomSeed(seed2); + + Util::Hash256(hash, message, sizeof(message)); + + PrivateKey sk1 = PrivateKey::FromSeed(seed, 32); + PrivateKey sk2 = PrivateKey::FromSeed(seed2, 32); + + InsecureSignature sig1 = sk1.SignInsecure(message, sizeof(message)); + InsecureSignature sig2 = sk2.SignInsecure(message, sizeof(message)); + REQUIRE(sig1 != sig2); + REQUIRE(sig1.Verify({hash}, {sk1.GetPublicKey()})); + REQUIRE(sig2.Verify({hash}, {sk2.GetPublicKey()})); + + std::vector const sigs = {sig1, sig2}; + std::vector const pks = {sk1.GetPublicKey(), sk2.GetPublicKey()}; + InsecureSignature aggSig = InsecureSignature::Aggregate(sigs); + PublicKey aggPk = PublicKey::AggregateInsecure(pks); + REQUIRE(aggSig.Verify({hash}, {aggPk})); + } + + SECTION("Should insecurely aggregate and verify aggregate diff messages") { + uint8_t message1[7] = {100, 2, 254, 88, 90, 45, 23}; + uint8_t message2[8] = {100, 2, 254, 88, 90, 45, 24, 1}; + + uint8_t seed[32]; + getRandomSeed(seed); + uint8_t seed2[32]; + getRandomSeed(seed2); + + PrivateKey sk1 = PrivateKey::FromSeed(seed, 32); + PrivateKey sk2 = PrivateKey::FromSeed(seed2, 32); + + uint8_t hash1[BLS::MESSAGE_HASH_LEN]; + uint8_t hash2[BLS::MESSAGE_HASH_LEN]; + Util::Hash256(hash1, message1, sizeof(message1)); + Util::Hash256(hash2, message2, sizeof(message2)); + + InsecureSignature sig1 = sk1.SignInsecurePrehashed(hash1); + InsecureSignature sig2 = sk2.SignInsecurePrehashed(hash2); + REQUIRE(sig1 != sig2); + REQUIRE(sig1.Verify({hash1}, {sk1.GetPublicKey()})); + REQUIRE(sig2.Verify({hash2}, {sk2.GetPublicKey()})); + + std::vector const sigs = {sig1, sig2}; + std::vector const pks = {sk1.GetPublicKey(), sk2.GetPublicKey()}; + InsecureSignature aggSig = InsecureSignature::Aggregate(sigs); + + // same message verification should fail + PublicKey aggPk = PublicKey::AggregateInsecure(pks); + REQUIRE(!aggSig.Verify({hash1}, {aggPk})); + REQUIRE(!aggSig.Verify({hash2}, {aggPk})); + + // diff message verification should succeed + std::vector hashes = {hash1, hash2}; + REQUIRE(aggSig.Verify(hashes, pks)); + } + + SECTION("Should securely aggregate and verify aggregate") { + uint8_t message1[7] = {100, 2, 254, 88, 90, 45, 23}; + uint8_t message2[7] = {192, 29, 2, 0, 0, 45, 23}; + + uint8_t seed[32]; + getRandomSeed(seed); + uint8_t seed2[32]; + getRandomSeed(seed2); + + PrivateKey sk1 = PrivateKey::FromSeed(seed, 32); + PrivateKey sk2 = PrivateKey::FromSeed(seed2, 32); + + PublicKey pk1 = sk1.GetPublicKey(); + PublicKey pk2 = sk2.GetPublicKey(); + + Signature sig1 = sk1.Sign(message1, sizeof(message1)); + Signature sig2 = sk2.Sign(message2, sizeof(message2)); + + std::vector const sigs = {sig1, sig2}; + Signature aggSig = Signature::Aggregate(sigs); + + Signature sig3 = sk1.Sign(message1, sizeof(message1)); + Signature sig4 = sk2.Sign(message2, sizeof(message2)); + + std::vector const sigs2 = {sig3, sig4}; + Signature aggSig2 = Signature::Aggregate(sigs2); + REQUIRE(sig1 == sig3); + REQUIRE(sig2 == sig4); + REQUIRE(aggSig == aggSig2); + REQUIRE(sig1 != sig2); + + REQUIRE(aggSig.Verify()); + } + + SECTION("Should securely aggregate many signatures, diff message") { + std::vector sks; + std::vector sigs; + + for (int i = 0; i < 80; i++) { + uint8_t* message = new uint8_t[8]; + message[0] = 0; + message[1] = 100; + message[2] = 2; + message[3] = 59; + message[4] = 255; + message[5] = 92; + message[6] = 5; + message[7] = i; + uint8_t seed[32]; + getRandomSeed(seed); + const PrivateKey sk = PrivateKey::FromSeed(seed, 32); + const PublicKey pk = sk.GetPublicKey(); + sks.push_back(sk); + sigs.push_back(sk.Sign(message, sizeof(message))); + delete[] message; + } + + Signature aggSig = Signature::Aggregate(sigs); + + REQUIRE(aggSig.Verify()); + } + + SECTION("Should insecurely aggregate many signatures, diff message") { + std::vector sks; + std::vector pks; + std::vector sigs; + std::vector hashes; + + for (int i = 0; i < 80; i++) { + uint8_t* message = new uint8_t[8]; + uint8_t* hash = new uint8_t[BLS::MESSAGE_HASH_LEN]; + message[0] = 0; + message[1] = 100; + message[2] = 2; + message[3] = 59; + message[4] = 255; + message[5] = 92; + message[6] = 5; + message[7] = i; + Util::Hash256(hash, message, 8); + hashes.push_back(hash); + uint8_t seed[32]; + getRandomSeed(seed); + const PrivateKey sk = PrivateKey::FromSeed(seed, 32); + const PublicKey pk = sk.GetPublicKey(); + sks.push_back(sk); + pks.push_back(pk); + sigs.push_back(sk.SignInsecurePrehashed(hash)); + delete[] message; + } + + InsecureSignature aggSig = InsecureSignature::Aggregate(sigs); + + REQUIRE(aggSig.Verify(hashes, pks)); + std::swap(pks[0], pks[1]); + REQUIRE(!aggSig.Verify(hashes, pks)); + std::swap(hashes[0], hashes[1]); + REQUIRE(aggSig.Verify(hashes, pks)); + + for (auto& p : hashes) { + delete[] p; + } + } + + SECTION("Should securely aggregate same message") { + uint8_t message1[7] = {100, 2, 254, 88, 90, 45, 23}; + uint8_t seed[32]; + getRandomSeed(seed); + uint8_t seed2[32]; + getRandomSeed(seed2); + uint8_t seed3[32]; + getRandomSeed(seed3); + + PrivateKey sk1 = PrivateKey::FromSeed(seed, 32); + PublicKey pk1 = sk1.GetPublicKey(); + + PrivateKey sk2 = PrivateKey::FromSeed(seed2, 32); + PublicKey pk2 = sk2.GetPublicKey(); + + PrivateKey sk3 = PrivateKey::FromSeed(seed3, 32); + PublicKey pk3 = sk3.GetPublicKey(); + + Signature sig1 = sk1.Sign(message1, sizeof(message1)); + Signature sig2 = sk2.Sign(message1, sizeof(message1)); + Signature sig3 = sk3.Sign(message1, sizeof(message1)); + + std::vector const sigs = {sig1, sig2, sig3}; + std::vector const pubKeys = {pk1, pk2, pk3}; + Signature aggSig = Signature::Aggregate(sigs); + + const PublicKey aggPubKey = PublicKey::Aggregate(pubKeys); + aggSig.SetAggregationInfo(AggregationInfo::FromMsg( + aggPubKey, message1, sizeof(message1))); + REQUIRE(aggSig.Verify()); + } + + SECTION("Should securely divide signatures") { + uint8_t message1[7] = {100, 2, 254, 88, 90, 45, 23}; + uint8_t seed[32]; + getRandomSeed(seed); + uint8_t seed2[32]; + getRandomSeed(seed2); + uint8_t seed3[32]; + getRandomSeed(seed3); + + PrivateKey sk1 = PrivateKey::FromSeed(seed, 32); + PublicKey pk1 = sk1.GetPublicKey(); + + PrivateKey sk2 = PrivateKey::FromSeed(seed2, 32); + PublicKey pk2 = sk2.GetPublicKey(); + + PrivateKey sk3 = PrivateKey::FromSeed(seed3, 32); + PublicKey pk3 = sk3.GetPublicKey(); + + Signature sig1 = sk1.Sign(message1, sizeof(message1)); + Signature sig2 = sk2.Sign(message1, sizeof(message1)); + Signature sig3 = sk3.Sign(message1, sizeof(message1)); + + std::vector sigs = {sig1, sig2, sig3}; + Signature aggSig = Signature::Aggregate(sigs); + + REQUIRE(sig2.Verify()); + REQUIRE(sig3.Verify()); + std::vector divisorSigs = {sig2, sig3}; + + REQUIRE(aggSig.Verify()); + + REQUIRE(aggSig.GetAggregationInfo()->GetPubKeys().size() == 3); + const Signature aggSig2 = aggSig.DivideBy(divisorSigs); + REQUIRE(aggSig.GetAggregationInfo()->GetPubKeys().size() == 3); + REQUIRE(aggSig2.GetAggregationInfo()->GetPubKeys().size() == 1); + + REQUIRE(aggSig.Verify()); + REQUIRE(aggSig2.Verify()); + } + + SECTION("Should securely divide aggregate signatures") { + uint8_t message1[7] = {100, 2, 254, 88, 90, 45, 23}; + uint8_t message2[7] = {92, 20, 5, 89, 91, 15, 105}; + uint8_t message3[7] = {200, 10, 10, 159, 4, 15, 24}; + uint8_t seed[32]; + getRandomSeed(seed); + uint8_t seed2[32]; + getRandomSeed(seed2); + uint8_t seed3[32]; + getRandomSeed(seed3); + uint8_t seed4[32]; + getRandomSeed(seed4); + + PrivateKey sk1 = PrivateKey::FromSeed(seed, 32); + PublicKey pk1 = sk1.GetPublicKey(); + + PrivateKey sk2 = PrivateKey::FromSeed(seed2, 32); + PublicKey pk2 = sk2.GetPublicKey(); + + PrivateKey sk3 = PrivateKey::FromSeed(seed3, 32); + PublicKey pk3 = sk3.GetPublicKey(); + + PrivateKey sk4 = PrivateKey::FromSeed(seed4, 32); + PublicKey pk4 = sk4.GetPublicKey(); + + Signature sig1 = sk1.Sign(message1, sizeof(message1)); + Signature sig2 = sk2.Sign(message1, sizeof(message1)); + Signature sig3 = sk3.Sign(message1, sizeof(message1)); + Signature sig4 = sk4.Sign(message2, sizeof(message2)); + Signature sig5 = sk4.Sign(message1, sizeof(message1)); + Signature sig6 = sk2.Sign(message3, sizeof(message3)); + + std::vector sigsL = {sig1, sig2}; + std::vector sigsC = {sig3, sig4}; + std::vector sigsR = {sig5, sig6}; + Signature aggSigL = Signature::Aggregate(sigsL); + Signature aggSigC = Signature::Aggregate(sigsC); + Signature aggSigR = Signature::Aggregate(sigsR); + + std::vector sigsL2 = {aggSigL, aggSigC}; + Signature aggSigL2 = Signature::Aggregate(sigsL2); + + std::vector sigsFinal = {aggSigL2, aggSigR}; + Signature aggSigFinal = Signature::Aggregate(sigsFinal); + + REQUIRE(aggSigFinal.Verify()); + REQUIRE(aggSigFinal.GetAggregationInfo()->GetPubKeys().size() == 6); + std::vector divisorSigs = {aggSigL, sig6}; + aggSigFinal = aggSigFinal.DivideBy(divisorSigs); + REQUIRE(aggSigFinal.GetAggregationInfo()->GetPubKeys().size() == 3); + REQUIRE(aggSigFinal.Verify()); + + // Throws when the m/pk pair is not unique within the aggregate (sig1 + // is in both aggSigL2 and sig1. + std::vector sigsFinal2 = {aggSigL2, aggSigR, sig1}; + Signature aggSigFinal2 = Signature::Aggregate(sigsFinal2); + std::vector divisorSigs2 = {aggSigL}; + std::vector divisorSigs3 = {sig6}; + aggSigFinal2 = aggSigFinal2.DivideBy(divisorSigs3); + REQUIRE_THROWS(aggSigFinal2.DivideBy(divisorSigs)); + } + + SECTION("Should insecurely aggregate many sigs, same message") { + uint8_t message1[7] = {100, 2, 254, 88, 90, 45, 23}; + uint8_t hash1[BLS::MESSAGE_HASH_LEN]; + + std::vector sks; + std::vector pks; + std::vector sigs; + + Util::Hash256(hash1, message1, sizeof(message1)); + + for (int i = 0; i < 70; i++) { + uint8_t seed[32]; + getRandomSeed(seed); + PrivateKey sk = PrivateKey::FromSeed(seed, 32); + const PublicKey pk = sk.GetPublicKey(); + sks.push_back(sk); + pks.push_back(pk); + sigs.push_back(sk.SignInsecure(message1, sizeof(message1))); + } + + InsecureSignature aggSig = InsecureSignature::Aggregate(sigs); + const PublicKey aggPubKey = PublicKey::AggregateInsecure(pks); + REQUIRE(aggSig.Verify({hash1}, {aggPubKey})); + } + + SECTION("Should securely aggregate many sigs, same message") { + uint8_t message1[7] = {100, 2, 254, 88, 90, 45, 23}; + + std::vector sks; + std::vector pks; + std::vector sigs; + + for (int i = 0; i < 70; i++) { + uint8_t seed[32]; + getRandomSeed(seed); + PrivateKey sk = PrivateKey::FromSeed(seed, 32); + const PublicKey pk = sk.GetPublicKey(); + sks.push_back(sk); + pks.push_back(pk); + sigs.push_back(sk.Sign(message1, sizeof(message1))); + } + + Signature aggSig = Signature::Aggregate(sigs); + const PublicKey aggPubKey = PublicKey::Aggregate(pks); + aggSig.SetAggregationInfo(AggregationInfo::FromMsg( + aggPubKey, message1, sizeof(message1))); + REQUIRE(aggSig.Verify()); + } + + SECTION("Should have at least one sig, with AggregationInfo") { + uint8_t message1[7] = {100, 2, 254, 88, 90, 45, 23}; + uint8_t seed[32]; + getRandomSeed(seed); + PrivateKey sk1 = PrivateKey::FromSeed(seed, 32); + PublicKey pk1 = sk1.GetPublicKey(); + + Signature sig1 = sk1.Sign(message1, sizeof(message1)); + + std::vector const sigs = {}; + REQUIRE_THROWS(Signature::Aggregate(sigs)); + + sig1.SetAggregationInfo(AggregationInfo()); + std::vector const sigs2 = {sig1}; + REQUIRE_THROWS(Signature::Aggregate(sigs2)); + } + + SECTION("Should perform batch verification") { + uint8_t message1[7] = {100, 2, 254, 88, 90, 45, 23}; + uint8_t message2[8] = {10, 28, 254, 88, 90, 45, 29, 38}; + uint8_t message3[9] = {10, 28, 254, 88, 90, 45, 29, 38, 177}; + uint8_t seed[32]; + getRandomSeed(seed); + uint8_t seed2[32]; + getRandomSeed(seed2); + uint8_t seed3[32]; + getRandomSeed(seed3); + uint8_t seed4[32]; + getRandomSeed(seed4); + + PrivateKey sk1 = PrivateKey::FromSeed(seed, 32); + PublicKey pk1 = sk1.GetPublicKey(); + + PrivateKey sk2 = PrivateKey::FromSeed(seed2, 32); + PublicKey pk2 = sk2.GetPublicKey(); + + PrivateKey sk3 = PrivateKey::FromSeed(seed3, 32); + PublicKey pk3 = sk3.GetPublicKey(); + + PrivateKey sk4 = PrivateKey::FromSeed(seed4, 32); + PublicKey pk4 = sk4.GetPublicKey(); + + + Signature sig1 = sk1.Sign(message1, sizeof(message1)); + Signature sig2 = sk2.Sign(message1, sizeof(message1)); + Signature sig3 = sk3.Sign(message2, sizeof(message2)); + Signature sig4 = sk4.Sign(message3, sizeof(message3)); + Signature sig5 = sk3.Sign(message1, sizeof(message1)); + Signature sig6 = sk2.Sign(message1, sizeof(message1)); + Signature sig7 = sk4.Sign(message2, sizeof(message2)); + + std::vector const sigs = + {sig1, sig2, sig3, sig4, sig5, sig6, sig7}; + std::vector const pubKeys = + {pk1, pk2, pk3, pk4, pk3, pk2, pk4}; + std::vector const messages = + {message1, message1, message2, message3, message1, + message1, message2}; + std::vector const messageLens = + {sizeof(message1), sizeof(message1), sizeof(message2), + sizeof(message3), sizeof(message1), sizeof(message1), + sizeof(message2)}; + + // Verifier generates a batch signature for efficiency + Signature aggSig = Signature::Aggregate(sigs); + REQUIRE(aggSig.Verify()); + } + + SECTION("Should perform batch verification with cache optimization") { + uint8_t message1[7] = {100, 2, 254, 88, 90, 45, 23}; + uint8_t message2[8] = {10, 28, 254, 88, 90, 45, 29, 38}; + uint8_t message3[9] = {10, 28, 254, 88, 90, 45, 29, 38, 177}; + uint8_t seed[32]; + getRandomSeed(seed); + uint8_t seed2[32]; + getRandomSeed(seed2); + uint8_t seed3[32]; + getRandomSeed(seed3); + uint8_t seed4[32]; + getRandomSeed(seed4); + + PrivateKey sk1 = PrivateKey::FromSeed(seed, 32); + PublicKey pk1 = sk1.GetPublicKey(); + + PrivateKey sk2 = PrivateKey::FromSeed(seed2, 32); + PublicKey pk2 = sk2.GetPublicKey(); + + PrivateKey sk3 = PrivateKey::FromSeed(seed3, 32); + PublicKey pk3 = sk3.GetPublicKey(); + + PrivateKey sk4 = PrivateKey::FromSeed(seed4, 32); + PublicKey pk4 = sk4.GetPublicKey(); + + + Signature sig1 = sk1.Sign(message1, sizeof(message1)); + Signature sig2 = sk2.Sign(message1, sizeof(message1)); + Signature sig3 = sk3.Sign(message2, sizeof(message2)); + Signature sig4 = sk4.Sign(message3, sizeof(message3)); + Signature sig5 = sk3.Sign(message1, sizeof(message1)); + Signature sig6 = sk2.Sign(message1, sizeof(message1)); + Signature sig7 = sk4.Sign(message2, sizeof(message2)); + + std::vector const sigs = + {sig1, sig2, sig3, sig4, sig5, sig6, sig7}; + + REQUIRE(sig1.Verify()); + REQUIRE(sig3.Verify()); + REQUIRE(sig4.Verify()); + REQUIRE(sig7.Verify()); + std::vector cache = {sig1, sig3, sig4, sig7}; + + // Verifier generates a batch signature for efficiency + Signature aggSig = Signature::Aggregate(sigs); + + const Signature aggSig2 = aggSig.DivideBy(cache); + REQUIRE(aggSig.Verify()); + REQUIRE(aggSig2.Verify()); + } + + SECTION("Should aggregate same message with agg sk") { + uint8_t message1[7] = {100, 2, 254, 88, 90, 45, 23}; + uint8_t seed[32]; + getRandomSeed(seed); + uint8_t seed2[32]; + getRandomSeed(seed2); + + PrivateKey sk1 = PrivateKey::FromSeed(seed, 32); + PublicKey pk1 = sk1.GetPublicKey(); + + PrivateKey sk2 = PrivateKey::FromSeed(seed2, 32); + PublicKey pk2 = sk2.GetPublicKey(); + + std::vector const privateKeys = {sk1, sk2}; + std::vector const pubKeys = {pk1, pk2}; + const PrivateKey aggSk = PrivateKey::Aggregate( + privateKeys, pubKeys); + + Signature sig1 = sk1.Sign(message1, sizeof(message1)); + Signature sig2 = sk2.Sign(message1, sizeof(message1)); + + Signature aggSig2 = aggSk.Sign(message1, sizeof(message1)); + + std::vector const sigs = {sig1, sig2}; + std::vector const messages = {message1, message1}; + std::vector const messageLens = {sizeof(message1), sizeof(message1)}; + Signature aggSig = Signature::Aggregate(sigs); + ASSERT(aggSig == aggSig2); + + const PublicKey aggPubKey = PublicKey::Aggregate(pubKeys); + REQUIRE(aggSig.Verify()); + REQUIRE(aggSig2.Verify()); + } +} + +TEST_CASE("HD keys") { + SECTION("Should create an extended private key from seed") { + uint8_t seed[] = {1, 50, 6, 244, 24, 199, 1, 25}; + ExtendedPrivateKey esk = ExtendedPrivateKey::FromSeed( + seed, sizeof(seed)); + + ExtendedPrivateKey esk77 = esk.PrivateChild(77 + (1 << 31)); + ExtendedPrivateKey esk77copy = esk.PrivateChild(77 + (1 << 31)); + + REQUIRE(esk77 == esk77copy); + + ExtendedPrivateKey esk77nh = esk.PrivateChild(77); + + auto eskLong = esk.PrivateChild((1 << 31) + 5) + .PrivateChild(0) + .PrivateChild(0) + .PrivateChild((1 << 31) + 56) + .PrivateChild(70) + .PrivateChild(4); + uint8_t chainCode[32]; + eskLong.GetChainCode().Serialize(chainCode); + } + + + SECTION("Should match derivation through private and public keys") { + uint8_t seed[] = {1, 50, 6, 244, 24, 199, 1, 25}; + ExtendedPrivateKey esk = ExtendedPrivateKey::FromSeed( + seed, sizeof(seed)); + ExtendedPublicKey epk = esk.GetExtendedPublicKey(); + + PublicKey pk1 = esk.PrivateChild(238757).GetPublicKey(); + PublicKey pk2 = epk.PublicChild(238757).GetPublicKey(); + + REQUIRE(pk1 == pk2); + + PrivateKey sk3 = esk.PrivateChild(0) + .PrivateChild(3) + .PrivateChild(8) + .PrivateChild(1) + .GetPrivateKey(); + + PublicKey pk4 = epk.PublicChild(0) + .PublicChild(3) + .PublicChild(8) + .PublicChild(1) + .GetPublicKey(); + REQUIRE(sk3.GetPublicKey() == pk4); + + Signature sig = sk3.Sign(seed, sizeof(seed)); + + REQUIRE(sig.Verify()); + } + + SECTION("Should prevent hardened pk derivation") { + uint8_t seed[] = {1, 50, 6, 244, 24, 199, 1, 25}; + ExtendedPrivateKey esk = ExtendedPrivateKey::FromSeed( + seed, sizeof(seed)); + ExtendedPublicKey epk = esk.GetExtendedPublicKey(); + + ExtendedPrivateKey sk = esk.PrivateChild((1 << 31) + 3); + REQUIRE_THROWS(epk.PublicChild((1 << 31) + 3)); + } + + SECTION("Should derive public child from parent") { + uint8_t seed[] = {1, 50, 6, 244, 24, 199, 1, 0, 0, 0}; + ExtendedPrivateKey esk = ExtendedPrivateKey::FromSeed( + seed, sizeof(seed)); + ExtendedPublicKey epk = esk.GetExtendedPublicKey(); + + ExtendedPublicKey pk1 = esk.PublicChild(13); + ExtendedPublicKey pk2 = epk.PublicChild(13); + + REQUIRE(pk1 == pk2); + } + + SECTION("Should cout structures") { + uint8_t seed[] = {1, 50, 6, 244, 24, 199, 1, 0, 0, 0}; + ExtendedPrivateKey esk = ExtendedPrivateKey::FromSeed( + seed, sizeof(seed)); + ExtendedPublicKey epk = esk.GetExtendedPublicKey(); + + cout << epk << endl; + cout << epk.GetPublicKey() << endl; + cout << epk.GetChainCode() << endl; + + Signature sig1 = esk.GetPrivateKey() + .Sign(seed, sizeof(seed)); + cout << sig1 << endl; + } + + SECTION("Should serialize extended keys") { + uint8_t seed[] = {1, 50, 6, 244, 25, 199, 1, 25}; + ExtendedPrivateKey esk = ExtendedPrivateKey::FromSeed( + seed, sizeof(seed)); + ExtendedPublicKey epk = esk.GetExtendedPublicKey(); + + PublicKey pk1 = esk.PrivateChild(238757).GetPublicKey(); + PublicKey pk2 = epk.PublicChild(238757).GetPublicKey(); + + REQUIRE(pk1 == pk2); + + ExtendedPrivateKey sk3 = esk.PrivateChild(0) + .PrivateChild(3) + .PrivateChild(8) + .PrivateChild(1); + + ExtendedPublicKey pk4 = epk.PublicChild(0) + .PublicChild(3) + .PublicChild(8) + .PublicChild(1); + uint8_t buffer1[ExtendedPrivateKey::EXTENDED_PRIVATE_KEY_SIZE]; + uint8_t buffer2[ExtendedPublicKey::EXTENDED_PUBLIC_KEY_SIZE]; + uint8_t buffer3[ExtendedPublicKey::EXTENDED_PUBLIC_KEY_SIZE]; + + sk3.Serialize(buffer1); + sk3.GetExtendedPublicKey().Serialize(buffer2); + pk4.Serialize(buffer3); + REQUIRE(std::memcmp(buffer2, buffer3, + ExtendedPublicKey::EXTENDED_PUBLIC_KEY_SIZE) == 0); + } +} + +TEST_CASE("AggregationInfo") { + SECTION("Should create object") { + uint8_t message1[7] = {1, 65, 254, 88, 90, 45, 22}; + uint8_t message2[8] = {1, 65, 254, 88, 90, 45, 22, 12}; + uint8_t message3[8] = {2, 65, 254, 88, 90, 45, 22, 12}; + uint8_t message4[8] = {3, 65, 254, 88, 90, 45, 22, 12}; + uint8_t message5[8] = {4, 65, 254, 88, 90, 45, 22, 12}; + uint8_t message6[8] = {5, 65, 254, 88, 90, 45, 22, 12}; + uint8_t messageHash1[32]; + uint8_t messageHash2[32]; + uint8_t messageHash3[32]; + uint8_t messageHash4[32]; + uint8_t messageHash5[32]; + uint8_t messageHash6[32]; + Util::Hash256(messageHash1, message1, 7); + Util::Hash256(messageHash2, message2, 8); + Util::Hash256(messageHash3, message3, 8); + Util::Hash256(messageHash4, message4, 8); + Util::Hash256(messageHash5, message5, 8); + Util::Hash256(messageHash6, message6, 8); + + uint8_t seed[32]; + getRandomSeed(seed); + PrivateKey sk1 = PrivateKey::FromSeed(seed, 32); + getRandomSeed(seed); + PrivateKey sk2 = PrivateKey::FromSeed(seed, 32); + getRandomSeed(seed); + PrivateKey sk3 = PrivateKey::FromSeed(seed, 32); + getRandomSeed(seed); + PrivateKey sk4 = PrivateKey::FromSeed(seed, 32); + getRandomSeed(seed); + PrivateKey sk5 = PrivateKey::FromSeed(seed, 32); + getRandomSeed(seed); + PrivateKey sk6 = PrivateKey::FromSeed(seed, 32); + + PublicKey pk1 = sk1.GetPublicKey(); + PublicKey pk2 = sk2.GetPublicKey(); + PublicKey pk3 = sk3.GetPublicKey(); + PublicKey pk4 = sk4.GetPublicKey(); + PublicKey pk5 = sk5.GetPublicKey(); + PublicKey pk6 = sk6.GetPublicKey(); + + AggregationInfo a1 = AggregationInfo::FromMsgHash(pk1, messageHash1); + AggregationInfo a2 = AggregationInfo::FromMsgHash(pk2, messageHash2); + std::vector infosA = {a1, a2}; + std::vector infosAcopy = {a2, a1}; + + AggregationInfo a3 = AggregationInfo::FromMsgHash(pk3, messageHash1); + AggregationInfo a4 = AggregationInfo::FromMsgHash(pk4, messageHash1); + std::vector infosB = {a3, a4}; + std::vector infosBcopy = {a4, a3}; + std::vector infosC = {a1, a2, a3, a4}; + + AggregationInfo a5 = AggregationInfo::MergeInfos(infosA); + AggregationInfo a5b = AggregationInfo::MergeInfos(infosAcopy); + AggregationInfo a6 = AggregationInfo::MergeInfos(infosB); + AggregationInfo a6b = AggregationInfo::MergeInfos(infosBcopy); + std::vector infosD = {a5, a6}; + + AggregationInfo a7 = AggregationInfo::MergeInfos(infosC); + AggregationInfo a8 = AggregationInfo::MergeInfos(infosD); + + REQUIRE(a5 == a5b); + REQUIRE(a5 != a6); + REQUIRE(a6 == a6b); + + std::vector infosE = {a1, a3, a4}; + AggregationInfo a9 = AggregationInfo::MergeInfos(infosE); + std::vector infosF = {a2, a9}; + AggregationInfo a10 = AggregationInfo::MergeInfos(infosF); + + REQUIRE(a10 == a7); + + AggregationInfo a11 = AggregationInfo::FromMsgHash(pk1, messageHash1); + AggregationInfo a12 = AggregationInfo::FromMsgHash(pk2, messageHash2); + AggregationInfo a13 = AggregationInfo::FromMsgHash(pk3, messageHash3); + AggregationInfo a14 = AggregationInfo::FromMsgHash(pk4, messageHash4); + AggregationInfo a15 = AggregationInfo::FromMsgHash(pk5, messageHash5); + AggregationInfo a16 = AggregationInfo::FromMsgHash(pk6, messageHash6); + AggregationInfo a17 = AggregationInfo::FromMsgHash(pk6, messageHash5); + AggregationInfo a18 = AggregationInfo::FromMsgHash(pk5, messageHash6); + + // Tree L + std::vector L1 = {a15, a17}; + std::vector L2 = {a11, a13}; + std::vector L3 = {a18, a14}; + + AggregationInfo a19 = AggregationInfo::MergeInfos(L1); + AggregationInfo a20 = AggregationInfo::MergeInfos(L2); + AggregationInfo a21 = AggregationInfo::MergeInfos(L3); + + std::vector L4 = {a21, a16}; + std::vector L5 = {a19, a20}; + AggregationInfo a22 = AggregationInfo::MergeInfos(L4); + AggregationInfo a23 = AggregationInfo::MergeInfos(L5); + + std::vector L6 = {a22, a12}; + AggregationInfo a24 = AggregationInfo::MergeInfos(L6); + std::vector L7 = {a23, a24}; + AggregationInfo LFinal = AggregationInfo::MergeInfos(L7); + + // Tree R + std::vector R1 = {a17, a12, a11, a15}; + std::vector R2 = {a14, a18}; + + AggregationInfo a25 = AggregationInfo::MergeInfos(R1); + AggregationInfo a26 = AggregationInfo::MergeInfos(R2); + + std::vector R3 = {a26, a16}; + + AggregationInfo a27 = AggregationInfo::MergeInfos(R3); + + std::vector R4 = {a27, a13}; + AggregationInfo a28 = AggregationInfo::MergeInfos(R4); + std::vector R5 = {a25, a28}; + + AggregationInfo RFinal = AggregationInfo::MergeInfos(R5); + + REQUIRE(LFinal == RFinal); + } + + SECTION("Should aggregate with multiple levels.") { + uint8_t message1[7] = {100, 2, 254, 88, 90, 45, 23}; + uint8_t message2[8] = {192, 29, 2, 0, 0, 45, 23, 192}; + uint8_t message3[7] = {52, 29, 2, 0, 0, 45, 102}; + uint8_t message4[7] = {99, 29, 2, 0, 0, 45, 222}; + + uint8_t seed[32]; + getRandomSeed(seed); + uint8_t seed2[32]; + getRandomSeed(seed2); + + PrivateKey sk1 = PrivateKey::FromSeed(seed, 32); + PrivateKey sk2 = PrivateKey::FromSeed(seed2, 32); + + PublicKey pk1 = sk1.GetPublicKey(); + PublicKey pk2 = sk2.GetPublicKey(); + + Signature sig1 = sk1.Sign(message1, sizeof(message1)); + Signature sig2 = sk2.Sign(message2, sizeof(message2)); + Signature sig3 = sk2.Sign(message1, sizeof(message1)); + Signature sig4 = sk1.Sign(message3, sizeof(message3)); + Signature sig5 = sk1.Sign(message4, sizeof(message4)); + Signature sig6 = sk1.Sign(message1, sizeof(message1)); + + std::vector const sigsL = {sig1, sig2}; + std::vector const pksL = {pk1, pk2}; + const Signature aggSigL = Signature::Aggregate(sigsL); + + std::vector const sigsR = {sig3, sig4, sig6}; + const Signature aggSigR = Signature::Aggregate(sigsR); + + std::vector pk1Vec = {pk1}; + + std::vector sigs = {aggSigL, aggSigR, sig5}; + + const Signature aggSig = Signature::Aggregate(sigs); + + REQUIRE(aggSig.Verify()); + } + + SECTION("Should aggregate with multiple levels, degenerate") { + uint8_t message1[7] = {100, 2, 254, 88, 90, 45, 23}; + uint8_t seed[32]; + getRandomSeed(seed); + PrivateKey sk1 = PrivateKey::FromSeed(seed, 32); + PublicKey pk1 = sk1.GetPublicKey(); + Signature aggSig = sk1.Sign(message1, sizeof(message1)); + + for (size_t i = 0; i < 10; i++) { + getRandomSeed(seed); + PrivateKey sk = PrivateKey::FromSeed(seed, 32); + PublicKey pk = sk.GetPublicKey(); + Signature sig = sk.Sign(message1, sizeof(message1)); + std::vector sigs = {aggSig, sig}; + aggSig = Signature::Aggregate(sigs); + } + REQUIRE(aggSig.Verify()); + uint8_t sigSerialized[Signature::SIGNATURE_SIZE]; + aggSig.Serialize(sigSerialized); + + const Signature aggSig2 = Signature::FromBytes(sigSerialized); + REQUIRE(aggSig2.Verify() == false); + } + + SECTION("Should aggregate with multiple levels, different messages") { + uint8_t message1[7] = {100, 2, 254, 88, 90, 45, 23}; + uint8_t message2[7] = {192, 29, 2, 0, 0, 45, 23}; + uint8_t message3[7] = {52, 29, 2, 0, 0, 45, 102}; + uint8_t message4[7] = {99, 29, 2, 0, 0, 45, 222}; + + uint8_t seed[32]; + getRandomSeed(seed); + uint8_t seed2[32]; + getRandomSeed(seed2); + + PrivateKey sk1 = PrivateKey::FromSeed(seed, 32); + PrivateKey sk2 = PrivateKey::FromSeed(seed2, 32); + + PublicKey pk1 = sk1.GetPublicKey(); + PublicKey pk2 = sk2.GetPublicKey(); + + Signature sig1 = sk1.Sign(message1, sizeof(message1)); + Signature sig2 = sk2.Sign(message2, sizeof(message2)); + Signature sig3 = sk2.Sign(message3, sizeof(message4)); + Signature sig4 = sk1.Sign(message4, sizeof(message4)); + + std::vector const sigsL = {sig1, sig2}; + std::vector const pksL = {pk1, pk2}; + std::vector const messagesL = {message1, message2}; + std::vector const messageLensL = {sizeof(message1), + sizeof(message2)}; + const Signature aggSigL = Signature::Aggregate(sigsL); + + std::vector const sigsR = {sig3, sig4}; + std::vector const pksR = {pk2, pk1}; + std::vector const messagesR = {message3, message4}; + std::vector const messageLensR = {sizeof(message3), + sizeof(message4)}; + const Signature aggSigR = Signature::Aggregate(sigsR); + + std::vector sigs = {aggSigL, aggSigR}; + std::vector > pks = {pksL, pksR}; + std::vector > messages = {messagesL, messagesR}; + std::vector > messageLens = {messageLensL, messageLensR}; + + const Signature aggSig = Signature::Aggregate(sigs); + + std::vector allPks = {pk1, pk2, pk2, pk1}; + std::vector allMessages = {message1, message2, + message3, message4}; + std::vector allMessageLens = {sizeof(message1), sizeof(message2), + sizeof(message3), sizeof(message4)}; + + REQUIRE(aggSig.Verify()); + } + + SECTION("Should sign and verify using prepend method") { + uint8_t message1[7] = {100, 2, 254, 88, 90, 45, 23}; + uint8_t seed[32]; + getRandomSeed(seed); + PrivateKey sk1 = PrivateKey::FromSeed(seed, 32); + PublicKey pk1 = sk1.GetPublicKey(); + std::cout << "PK: " << pk1 << std::endl; + + uint8_t messageHash[BLS::MESSAGE_HASH_LEN]; + Util::Hash256(messageHash, message1, 7); + vector messageHashes = {messageHash}; + vector pks = {pk1}; + + const PrependSignature sig1 = sk1.SignPrepend(message1, 7); + REQUIRE(sig1.Verify(messageHashes, pks)); + + uint8_t sigData[PrependSignature::SIGNATURE_SIZE]; + uint8_t sigData2[PrependSignature::SIGNATURE_SIZE]; + sig1.Serialize(sigData); + sig1.GetInsecureSig().Serialize(sigData2); + REQUIRE(memcmp(sigData, sigData2, PrependSignature::SIGNATURE_SIZE) != 0); + + PrependSignature sig2 = PrependSignature::FromBytes(sigData); + REQUIRE(sig1 == sig2); + + REQUIRE(sig2.Verify(messageHashes, pks)); + } + + SECTION("Should aggregate using prepend method") { + uint8_t message1[7] = {100, 2, 254, 88, 90, 45, 23}; + uint8_t message2[7] = {192, 29, 2, 0, 0, 45, 23}; + + uint8_t seed[32]; + getRandomSeed(seed); + uint8_t seed2[32]; + getRandomSeed(seed2); + uint8_t seed3[32]; + getRandomSeed(seed3); + + PrivateKey sk1 = PrivateKey::FromSeed(seed, 32); + PrivateKey sk2 = PrivateKey::FromSeed(seed2, 32); + PrivateKey sk3 = PrivateKey::FromSeed(seed3, 32); + + PublicKey pk1 = sk1.GetPublicKey(); + PublicKey pk2 = sk2.GetPublicKey(); + PublicKey pk3 = sk3.GetPublicKey(); + + PrependSignature sig1 = sk1.SignPrepend(message1, 7); + PrependSignature sig2 = sk2.SignPrepend(message1, 7); + PrependSignature sig3 = sk3.SignPrepend(message2, 7); + + uint8_t messageHash1[BLS::MESSAGE_HASH_LEN]; + uint8_t messageHash2[BLS::MESSAGE_HASH_LEN]; + Util::Hash256(messageHash1, message1, 7); + Util::Hash256(messageHash2, message2, 7); + vector messageHashes1 = {messageHash1}; + vector messageHashes2 = {messageHash2}; + vector messageHashes = {messageHash1, messageHash1, messageHash2}; + vector pks1 = {pk1}; + vector pks2 = {pk2}; + vector pks3 = {pk3}; + vector pks = {pk1, pk2, pk3}; + + REQUIRE(sig1.Verify(messageHashes1, pks1)); + REQUIRE(sig2.Verify(messageHashes1, pks2)); + REQUIRE(sig3.Verify(messageHashes2, pks3)); + + vector sigs = {sig1, sig2, sig3}; + + PrependSignature agg = PrependSignature::Aggregate(sigs); + REQUIRE(agg.Verify(messageHashes, pks)); + + vector pksWrong = {pk1, pk2, pk2}; + REQUIRE(agg.Verify(messageHashes, pksWrong) == false); + } + + SECTION("README") { + // Example seed, used to generate private key. Always use + // a secure RNG with sufficient entropy to generate a seed. + uint8_t seed[] = {0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, + 19, 18, 12, 89, 6, 220, 18, 102, 58, 209, + 82, 12, 62, 89, 110, 182, 9, 44, 20, 254, 22}; + + PrivateKey sk = PrivateKey::FromSeed(seed, sizeof(seed)); + PublicKey pk = sk.GetPublicKey(); + + uint8_t msg[] = {100, 2, 254, 88, 90, 45, 23}; + + Signature sig = sk.Sign(msg, sizeof(msg)); + + uint8_t skBytes[PrivateKey::PRIVATE_KEY_SIZE]; // 32 byte array + uint8_t pkBytes[PublicKey::PUBLIC_KEY_SIZE]; // 48 byte array + uint8_t sigBytes[Signature::SIGNATURE_SIZE]; // 96 byte array + + sk.Serialize(skBytes); // 32 bytes + pk.Serialize(pkBytes); // 48 bytes + sig.Serialize(sigBytes); // 96 bytes + // Takes array of 32 bytes + sk = PrivateKey::FromBytes(skBytes); + + // Takes array of 48 bytes + pk = PublicKey::FromBytes(pkBytes); + + // Takes array of 96 bytes + sig = Signature::FromBytes(sigBytes); + // Add information required for verification, to sig object + sig.SetAggregationInfo(AggregationInfo::FromMsg(pk, msg, sizeof(msg))); + + bool ok = sig.Verify(); + // Generate some more private keys + seed[0] = 1; + PrivateKey sk1 = PrivateKey::FromSeed(seed, sizeof(seed)); + seed[0] = 2; + PrivateKey sk2 = PrivateKey::FromSeed(seed, sizeof(seed)); + + // Generate first sig + PublicKey pk1 = sk1.GetPublicKey(); + Signature sig1 = sk1.Sign(msg, sizeof(msg)); + + // Generate second sig + PublicKey pk2 = sk2.GetPublicKey(); + Signature sig2 = sk2.Sign(msg, sizeof(msg)); + + // Aggregate signatures together + std::vector sigs = {sig1, sig2}; + Signature aggSig = Signature::Aggregate(sigs); + + // For same message, public keys can be aggregated into one. + // The signature can be verified the same as a single signature, + // using this public key. + std::vector pubKeys = {pk1, pk2}; + PublicKey aggPubKey = PublicKey::Aggregate(pubKeys); + // Generate one more key + seed[0] = 3; + PrivateKey sk3 = PrivateKey::FromSeed(seed, sizeof(seed)); + PublicKey pk3 = sk3.GetPublicKey(); + uint8_t msg2[] = {100, 2, 254, 88, 90, 45, 23}; + + // Generate the signatures, assuming we have 3 private keys + sig1 = sk1.Sign(msg, sizeof(msg)); + sig2 = sk2.Sign(msg, sizeof(msg)); + Signature sig3 = sk3.Sign(msg2, sizeof(msg2)); + + // They can be noninteractively combined by anyone + // Aggregation below can also be done by the verifier, to + // make batch verification more efficient + std::vector sigsL = {sig1, sig2}; + Signature aggSigL = Signature::Aggregate(sigsL); + + // Arbitrary trees of aggregates + std::vector sigsFinal = {aggSigL, sig3}; + Signature aggSigFinal = Signature::Aggregate(sigsFinal); + + // Serialize the final signature + aggSigFinal.Serialize(sigBytes); + // Deserialize aggregate signature + aggSigFinal = Signature::FromBytes(sigBytes); + + // Create aggregation information (or deserialize it) + AggregationInfo a1 = AggregationInfo::FromMsg(pk1, msg, sizeof(msg)); + AggregationInfo a2 = AggregationInfo::FromMsg(pk2, msg, sizeof(msg)); + AggregationInfo a3 = AggregationInfo::FromMsg(pk3, msg2, sizeof(msg2)); + std::vector infos = {a1, a2}; + AggregationInfo a1a2 = AggregationInfo::MergeInfos(infos); + std::vector infos2 = {a1a2, a3}; + AggregationInfo aFinal = AggregationInfo::MergeInfos(infos2); + + // Verify final signature using the aggregation info + aggSigFinal.SetAggregationInfo(aFinal); + ok = aggSigFinal.Verify(); + + // If you previously verified a signature, you can also divide + // the aggregate signature by the signature you already verified. + ok = aggSigL.Verify(); + std::vector cache = {aggSigL}; + aggSigFinal = aggSigFinal.DivideBy(cache); + + // Final verification is now more efficient + ok = aggSigFinal.Verify(); + + std::vector privateKeysList = {sk1, sk2}; + std::vector pubKeysList = {pk1, pk2}; + + // Create an aggregate private key, that can generate + // aggregate signatures + const PrivateKey aggSk = PrivateKey::Aggregate( + privateKeysList, pubKeysList); + + Signature aggSig3 = aggSk.Sign(msg, sizeof(msg)); + + PrependSignature prepend1 = sk1.SignPrepend(msg, sizeof(msg)); + PrependSignature prepend2 = sk2.SignPrepend(msg, sizeof(msg)); + std::vector prependPubKeys = {pk1, pk2}; + uint8_t messageHash[BLS::MESSAGE_HASH_LEN]; + Util::Hash256(messageHash, msg, sizeof(msg)); + std::vector hashes = {messageHash, messageHash}; + std::vector prependSigs = {prepend1, prepend2}; + PrependSignature prependAgg = PrependSignature::Aggregate(prependSigs); + prependAgg.Verify(hashes, prependPubKeys); + } +} + +TEST_CASE("Threshold") { + SECTION("Threshold tests") { + // To initialize a T of N threshold key under a + // Joint-Feldman scheme: + size_t T = 2; + size_t N = 3; + + // 1. Each player calls Threshold::Create. + // They send everyone commitment to the polynomial, + // and send secret share fragments frags[j-1] to + // the j-th player (All players have index >= 1). + + // PublicKey commits[N][T] + // PrivateKey frags[N][N] + std::vector> commits; + std::vector> frags; + for (size_t i = 0; i < N; ++i) { + commits.emplace_back(std::vector()); + frags.emplace_back(std::vector()); + for (size_t j = 0; j < N; ++j) { + if (j < T) { + g1_t g; + commits[i].emplace_back(PublicKey::FromG1(&g)); + } + bn_t b; + bn_new(b); + frags[i].emplace_back(PrivateKey::FromBN(b)); + } + } + + PrivateKey sk1 = Threshold::Create(commits[0], frags[0], T, N); + PrivateKey sk2 = Threshold::Create(commits[1], frags[1], T, N); + PrivateKey sk3 = Threshold::Create(commits[2], frags[2], T, N); + + // 2. Each player calls Threshold::VerifySecretFragment + // on all secret fragments they receive. If any verify + // false, they complain to abort the scheme. (Note that + // repeatedly aborting, or 'speaking' last, can bias the + // master public key.) + + for (int target = 1; target <= N; ++target) { + for (int source = 1; source <= N; ++source) { + REQUIRE(Threshold::VerifySecretFragment( + target, frags[source-1][target-1], commits[source-1], T)); + } + } + + // 3. Each player computes the shared, master public key: + // masterPubkey = PublicKey::AggregateInsecure(...) + // They also create their secret share from all secret + // fragments received (now verified): + // secretShare = PrivateKey::AggregateInsecure(...) + + PublicKey masterPubkey = PublicKey::AggregateInsecure({ + commits[0][0], commits[1][0], commits[2][0] + }); + + // recvdFrags[j][i] = frags[i][j] + std::vector> recvdFrags = {{}}; + for (int i = 0; i < N; ++i) { + recvdFrags.emplace_back(std::vector()); + for (int j = 0; j < N; ++j) { + recvdFrags[i].emplace_back(frags[j][i]); + } + } + + PrivateKey secretShare1 = PrivateKey::AggregateInsecure(recvdFrags[0]); + PrivateKey secretShare2 = PrivateKey::AggregateInsecure(recvdFrags[1]); + PrivateKey secretShare3 = PrivateKey::AggregateInsecure(recvdFrags[2]); + + // 4a. Player P creates a pre-multiplied signature share wrt T players: + // sigShare = Threshold::SignWithCoefficient(...) + // These signature shares can be combined to sign the msg: + // signature = InsecureSignature::Aggregate(...) + // The advantage of this approach is that forming the final signature + // no longer requires information about the players. + + uint8_t msg[] = {100, 2, 254, 88, 90, 45, 23}; + uint8_t hash[32]; + Util::Hash256(hash, msg, sizeof(msg)); + + size_t players[] = {1, 3}; + // For example, players 1 and 3 sign. + // As we have verified the coefficients through the commitments given, + // using InsecureSignature is okay. + InsecureSignature sigShareC1 = Threshold::SignWithCoefficient( + secretShare1, msg, (size_t) sizeof(msg), (size_t) 1, players, T); + InsecureSignature sigShareC3 = Threshold::SignWithCoefficient( + secretShare3, msg, (size_t) sizeof(msg), (size_t) 3, players, T); + + InsecureSignature signature = InsecureSignature::Aggregate({ + sigShareC1, sigShareC3}); + + REQUIRE(signature.Verify({hash}, {masterPubkey})); + + // 4b. Alternatively, players may sign the message blindly, creating + // a unit signature share: sigShare = secretShare.SignInsecure(...) + // These signatures may be combined with lagrange coefficients to + // sign the message: signature = Threshold::AggregateUnitSigs(...) + // The advantage to this approach is that each player does not need + // to know the final list of signatories. + + // For example, players 1 and 3 sign. + InsecureSignature sigShareU1 = secretShare1.SignInsecure( + msg, (size_t) sizeof(msg)); + InsecureSignature sigShareU3 = secretShare3.SignInsecure( + msg, (size_t) sizeof(msg)); + InsecureSignature signature2 = Threshold::AggregateUnitSigs( + {sigShareU1, sigShareU3}, msg, (size_t) sizeof(msg), players, T); + + REQUIRE(signature2.Verify({hash}, {masterPubkey})); + } +} + +int main(int argc, char* argv[]) { + int result = Catch::Session().run(argc, argv); + return result; +} diff --git a/bls/src/threshold.cpp b/bls/src/threshold.cpp new file mode 100644 index 00000000..f7291149 --- /dev/null +++ b/bls/src/threshold.cpp @@ -0,0 +1,227 @@ +// Copyright 2018 Chia Network Inc + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include "signature.hpp" +#include "bls.hpp" + +using std::string; +namespace bls { + +PrivateKey Threshold::Create(std::vector &commitment, + std::vector &secretFragments, size_t T, size_t N) { + if (T < 1 || T > N) { + throw std::string("Threshold parameter T must be between 1 and N"); + } + PrivateKey k; + k.AllocateKeyData(); + bn_t ord; + bn_new(ord); + g1_get_ord(ord); + + // poly = [random(1, ord-1), ...] + // commitment = [g1 * poly[i], ...] + g1_t g; + bn_t *poly = new bn_t[T]; + for (int i = 0; i < T; ++i) { + bn_new(poly[i]); + bn_rand_mod(poly[i], ord); + g1_mul_gen(g, poly[i]); + commitment[i] = PublicKey::FromG1(&g); + } + + bn_t frag, w, e; + bn_new(frag); + bn_new(w); + bn_new(e); + for (int x = 1; x <= N; ++x) { + bn_zero(frag); + // frag = sum_i (poly[i] * (x ** i % ord)) + for (int i = 0; i < T; ++i) { + bn_set_dig(w, (dig_t) x); + bn_set_dig(e, (dig_t) i); + bn_mxp(w, w, e, ord); + bn_mul(w, w, poly[i]); + bn_mod(w, w, ord); + bn_add(frag, frag, w); + bn_mod(frag, frag, ord); + } + secretFragments[x-1] = PrivateKey::FromBN(frag); + } + + bn_copy(*k.keydata, poly[0]); + + delete[] poly; + + return k; +} + +InsecureSignature Threshold::SignWithCoefficient(PrivateKey sk, const uint8_t *msg, + size_t len, size_t player, size_t *players, size_t T) { + if (player == 0) { + throw std::string("player must be a positive integer"); + } + int index = std::distance(players, + std::find(players, players + T, player)); + + uint8_t messageHash[BLS::MESSAGE_HASH_LEN]; + Util::Hash256(messageHash, msg, len); + + g2_t sig; + g2_map(sig, messageHash, BLS::MESSAGE_HASH_LEN, 0); + + bn_t *coeffs = new bn_t[T]; + try { + Threshold::LagrangeCoeffsAtZero(coeffs, players, T); + } catch (const std::exception& e) { + delete[] coeffs; + throw e; + } + + g2_mul(sig, sig, coeffs[index]); + g2_mul(sig, sig, *sk.keydata); + + delete[] coeffs; + + return InsecureSignature::FromG2(&sig); +} + +InsecureSignature Threshold::AggregateUnitSigs( + std::vector sigs, const uint8_t *msg, size_t len, + size_t *players, size_t T) { + uint8_t messageHash[BLS::MESSAGE_HASH_LEN]; + Util::Hash256(messageHash, msg, len); + + bn_t *coeffs = new bn_t[T]; + Threshold::LagrangeCoeffsAtZero(coeffs, players, T); + + std::vector powers; + for (size_t i = 0; i < T; ++i) { + powers.emplace_back(sigs[i].Exp(coeffs[i])); + } + + InsecureSignature ret = InsecureSignature::Aggregate(powers); + delete[] coeffs; + return ret; +} + +void Threshold::LagrangeCoeffsAtZero(bn_t *res, size_t *players, size_t T) { + if (T <= 0) { + throw std::invalid_argument("T must be a positive integer"); + } + // n: the order of the curve + bn_t denominator, n, u, weight, x; + bn_new(denominator); + bn_new(n); + bn_new(weight); + bn_new(x); + g1_get_ord(n); + + bn_zero(denominator); + for (int j = 0; j < T; ++j) { + if (players[j] <= 0) { + throw std::invalid_argument("Player index must be positive"); + } + // weight = (prod (X[j] - X[i])) ** -1 + bn_set_dig(weight, (dig_t) 1); + for (int i = 0; i < T; ++i) if (i != j) { + if (players[j] > players[i]) { + bn_set_dig(x, (dig_t)(players[j] - players[i])); + } else if (players[i] > players[j]){ + bn_set_dig(x, (dig_t)(players[i] - players[j])); + bn_sub(x, n, x); + } else { + throw std::invalid_argument("Must not have duplicate player indices"); + } + bn_mul(weight, weight, x); + bn_mod(weight, weight, n); + } + // weight = weight ** -1 + // x = (-players[j]) ** -1 + if (bn_is_zero(weight)) { + throw std::invalid_argument("Player indices can't be equiv. mod group order"); + } + fp_inv_exgcd_bn(weight, weight, n); + bn_set_dig(x, (dig_t) players[j]); + bn_sub(x, n, x); + fp_inv_exgcd_bn(x, x, n); + + bn_mul(weight, weight, x); + bn_mod(weight, weight, n); + bn_copy(res[j], weight); + + bn_add(denominator, denominator, weight); + } + + fp_inv_exgcd_bn(denominator, denominator, n); + for (int j = 0; j < T; ++j) { + bn_mul(res[j], res[j], denominator); + bn_mod(res[j], res[j], n); + } +} + +void Threshold::InterpolateAtZero(bn_t res, size_t *X, bn_t *Y, size_t T) { + if (T <= 0) { + throw std::invalid_argument("T must be a positive integer"); + } + + bn_zero(res); + bn_t n; + bn_new(n); + g1_get_ord(n); + + bn_t *coeffs = new bn_t[T]; + LagrangeCoeffsAtZero(coeffs, X, T); + for (int i = 0; i < T; ++i) { + // res += coeffs[i] * Y[i] + bn_mul(coeffs[i], coeffs[i], Y[i]); + bn_mod(coeffs[i], coeffs[i], n); + bn_add(res, res, coeffs[i]); + bn_mod(res, res, n); + } +} + +bool Threshold::VerifySecretFragment(size_t player, PrivateKey secretFragment, std::vector const& commitment, size_t T) { + if (T <= 0) { + throw std::invalid_argument("T must be a positive integer"); + } else if (player <= 0) { + throw std::invalid_argument("Player index must be positive"); + } + + g1_t rhs, t; + bn_t x, n, e; + bn_new(x); + bn_new(n); + bn_new(e); + g1_get_ord(n); + + // rhs = sum commitment[i] ** (player ** i) + std::vector expKeys; + expKeys.reserve(T); + for (size_t i = 0; i < T; i++) { + bn_set_dig(x, (dig_t) player); + bn_set_dig(e, (dig_t) i); + bn_mxp(x, x, e, n); + expKeys.emplace_back(commitment[i].Exp(x)); + } + + return (secretFragment.GetPublicKey() == + PublicKey::AggregateInsecure(expKeys)); +} + +} // end namespace bls diff --git a/bls/src/threshold.hpp b/bls/src/threshold.hpp new file mode 100644 index 00000000..3d39689a --- /dev/null +++ b/bls/src/threshold.hpp @@ -0,0 +1,118 @@ +// Copyright 2018 Chia Network Inc + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SRC_BLSTHRESHOLD_HPP_ +#define SRC_BLSTHRESHOLD_HPP_ + +#include +#include + +#include "relic_conf.h" + +#if defined GMP && ARITH == GMP +#include +#endif + +#include "util.hpp" + +namespace bls { +/** + * Utility functions for threshold signatures. + */ +class Threshold { +public: + /** + * Construct a PrivateKey with associated data suitable for a + * threshold signature scheme. + * + * @param[out] commitment - commitments g1 * [x^i]P to the polynomial. + * @param[out] secretFragments - P(j) for j = 1..N + * @param[in] T - the threshold parameter, deg(P) + 1 + * @param[in] N - the number of players. + * @return PrivateKey representing P(0). + */ + static PrivateKey Create(std::vector &commitment, + std::vector &secretFragments, + size_t T, size_t N); + + /** + * Sign a message with lagrange coefficients. The T signatures signed + * this way (with the same parameters players and T) can be multiplied + * together to create a final signature for that message. + * + * @param[in] sk - secret key to sign with + * @param[in] msg - message to sign + * @param[in] len - length of message + * @param[in] player - index (>= 1) of player + * @param[in] players - list of players + * @param[in] T - number of players and threshold parameter + * @return the partial signature. + */ + static InsecureSignature SignWithCoefficient(PrivateKey sk, const uint8_t *msg, + size_t len, size_t player, size_t *players, size_t T); + + /** + * Aggregate signatures (that have not been multiplied by lagrange + * coefficients) into a final signature for the master private key. + * + * @param[in] sigs - list of sigs + * @param[in] msg - message to sign + * @param[in] len - length of message + * @param[in] players - list of players + * @param[in] T - number of players and threshold parameter + * @return the final signature. + */ + static InsecureSignature AggregateUnitSigs( + std::vector sigs, const uint8_t *msg, size_t len, + size_t *players, size_t T); + + /** + * Returns lagrange coefficients of a polynomial evaluated at zero. + * If we have T points (players[i], P(players[i])), it interpolates + * to a degree T-1 polynomial P. The returned coefficients are + * such that P(0) = sum_i res[i] * P(players[i]). + * + * @param[out] res - the lagrange coefficients. + * @param[in] players - the indices of each player. + * @param[in] T - the number of points. + */ + static void LagrangeCoeffsAtZero(bn_t *res, size_t *players, size_t T); + + /** + * The points (X[i], Y[i]) for i = 0...T-1 interpolate into P, + * a degree T-1 polynomial. Returns P(0). + * + * @param[out] res - the value P(0). + * @param[in] X - the X coordinates, + * @param[in] Y - the Y coordinates. + * @param[in] T - the number of points. + */ + static void InterpolateAtZero(bn_t res, size_t *X, bn_t *Y, size_t T); + + /** + * Return true iff the secretFragment from the given player + * matches their given commitment to a polynomial. + * + * @param[in] player - the index of the player giving the fragment. + * @param[in] secretFragment - the fragment, a number in [1, n) + * @param[in] commitment - the player's claim commitment[i] = g1 * [x^i]P + * @param[in] T - the threshold parameter and number of points. + * @return true if the fragment is verified, else false. + */ + static bool VerifySecretFragment(size_t player, PrivateKey secretFragment, + std::vector const& commitment, size_t T); +}; +} // end namespace bls + +#endif // SRC_BLSTHRESHOLD_HPP_ diff --git a/bls/src/util.hpp b/bls/src/util.hpp new file mode 100644 index 00000000..1f03816d --- /dev/null +++ b/bls/src/util.hpp @@ -0,0 +1,112 @@ +// Copyright 2018 Chia Network Inc + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SRC_BLSUTIL_HPP_ +#define SRC_BLSUTIL_HPP_ + +#include +#include +#include +#include +#include + +#include "relic_conf.h" + +#if defined GMP && ARITH == GMP +#include +#endif + +#include "relic.h" +#include "relic_test.h" + +namespace bls { + +class BLS; + +class Util { + public: + typedef void *(*SecureAllocCallback)(size_t); + typedef void (*SecureFreeCallback)(void*); + public: + static void Hash256(uint8_t* output, const uint8_t* message, + size_t messageLen) { + md_map_sh256(output, message, messageLen); + } + + template + struct BytesCompare { + bool operator() (const uint8_t* lhs, const uint8_t* rhs) const { + for (size_t i = 0; i < S; i++) { + if (lhs[i] < rhs[i]) return true; + if (lhs[i] > rhs[i]) return false; + } + return false; + } + }; + typedef struct BytesCompare<32> BytesCompare32; + typedef struct BytesCompare<80> BytesCompare80; + + static std::string HexStr(const uint8_t* data, size_t len) { + std::stringstream s; + s << std::hex; + for (int i=0; i < len; ++i) + s << std::setw(2) << std::setfill('0') << static_cast(data[i]); + return s.str(); + } + + /* + * Securely allocates a portion of memory, using libsodium. This prevents + * paging to disk, and zeroes out the memory when it's freed. + */ + template + static T* SecAlloc(size_t numTs) { + return static_cast(secureAllocCallback(sizeof(T) * numTs)); + } + + /* + * Frees memory allocated using SecAlloc. + */ + static void SecFree(void* ptr) { + secureFreeCallback(ptr); + } + + /* + * Converts a 32 bit int to bytes. + */ + static void IntToFourBytes(uint8_t* result, + const uint32_t input) { + for (size_t i = 0; i < 4; i++) { + result[3 - i] = (input >> (i * 8)); + } + } + + /* + * Converts a byte array to a 32 bit int. + */ + static uint32_t FourBytesToInt(const uint8_t* bytes) { + uint32_t sum = 0; + for (size_t i = 0; i < 4; i++) { + uint32_t addend = bytes[i] << (8 * (3 - i)); + sum += addend; + } + return sum; + } + + private: + friend class BLS; + static SecureAllocCallback secureAllocCallback; + static SecureFreeCallback secureFreeCallback; +}; +} // end namespace bls +#endif // SRC_BLSUTIL_HPP_ diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index e0e3e2ac..77fe77c3 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -18,8 +18,15 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +INCLUDE_DIRECTORIES(bls/src) +LINK_DIRECTORIES(bls/build/src) + +LINK_DIRECTORIES(bls/build/contrib/relic/lib) +INCLUDE_DIRECTORIES(bls/build/contrib/relic/include) +INCLUDE_DIRECTORIES(bls/contrib/relic/include) + add_executable(hotstuff-app hotstuff_app.cpp) -target_link_libraries(hotstuff-app hotstuff_static) +target_link_libraries(hotstuff-app hotstuff_static blstmp relic_s) add_executable(hotstuff-client hotstuff_client.cpp) -target_link_libraries(hotstuff-client hotstuff_static) +target_link_libraries(hotstuff-client hotstuff_static blstmp relic_s) diff --git a/examples/hotstuff_app.cpp b/examples/hotstuff_app.cpp index 63c29f38..f093ca55 100644 --- a/examples/hotstuff_app.cpp +++ b/examples/hotstuff_app.cpp @@ -63,7 +63,7 @@ using hotstuff::MsgRespCmd; using hotstuff::get_hash; using hotstuff::promise_t; -using HotStuff = hotstuff::HotStuffSecp256k1; +using HotStuff = hotstuff::HotStuffTH; class HotStuffApp: public HotStuff { double stat_period; diff --git a/hotstuff-sec0.conf b/hotstuff-sec0.conf index bbfd3f26..5148c495 100644 --- a/hotstuff-sec0.conf +++ b/hotstuff-sec0.conf @@ -1,4 +1,4 @@ -privkey = 445fa01dbbb9d0510ab6d6f630c94ab43ba21ad91f31d47da92f7b679ba2f582 +privkey = 0bd129220239d6a0b23cb2e942152260ea8dba1deff40c3bae840d747fcd137c tls-privkey = 308204a10201000282010100c5a358cee61ca7592dbe62cd28225426dc3fc65b33432043efb5e8fcfaf334720b2000d10c422172e6f94f82746928a6d51193342a1555684eedb141321170cb02cc7b189f5506cc30cb5c26d9b84123328ed6df61fc1a6582b046def7a662bb15d84e29ffa279f1d853c25ca79fbe3fab0200f8c85566a5eedb98df4a958e8512a647258e55a7a56c1ca8b05607b38b01b6a2669af9a70efa59141f6079341c6044f615687be756d4830ea359139ea35e23f34ce226215a1a2fb8271cc60a037841e44c460e149a71d3e2fa907a48677ad18af2e7348343932f5f29ac5241cd20ce64e6798ada684164cd1109c3a969662d9aaf9897fedc5a4e256eb92bf7bd02011102820100516160cdaa0bcc7003c6dd6388ff139787de0661c9d0589471c35fefb2a060e3aa3a5ab06e75954d6e2a6c088a496b1784e91e7ee426e6eeb7169448058eb5f93d6341bed83211db9b9f07d3c30fa259c9861c3ddd0d7447ea84d1e356ea28a7635911205a33d7dc0dc822dadb9c2129466a3ca2acd7def9080011c55af249bd98e3f84a5475a43cc0369cf7fa5e4ecdd1c09ac0b0a41bd19d8af70cad8f1b6aec66a22179e5dbf9c446c645e9daa9080b455fca64365d8e02a686fbd707198302db43cd37629033574561c025d89d29c393746ce12fa01bbe60feb3fab292928ead3f8f6def6b9a7dffcd2139f6e8d1f79844d216b28dfae29dc6ba8c11063102818100f770f6dea12236dd39cb46ba96c171f3cfa92c961a12bfb62108e82e0bac280554a9ad4b99c4faee9287467573eaf6cfcba360753668c40ab1b015fbbb95f6a2d3c2402966971fa54540befdc39b58962f7d0cfaa96ff268df02efab32238544ed75fd6586bd93e38934c9d59b037f3cd7f727b38c854e1061de1f68bf43a26d02818100cc7963002015bd593af15276f185cb5a34a76bb36633c85bc86c6640419612a5a8eb2cc1a6ad43e51c2b545f88a7e8c0096a6110b85de7d1f458eca33267f9fde6b4489e346304787d33c8e1033e96b502a53ea6ad2c55299cae973719587d24468f164930f58a56aac2c7eabd68870a1056f06b8bcec5b3d2156c8a1375d89102818048c6df326ba0a6b9897805be68933fa20fe676868023a1cc27d57176f45fcf8918e69c61879449cdb2a041e64f451b6a4af3d1136a5b0c7b9dac42b3736857994d57400c2d3b81c7327c7468c10f9286867012e04ff3bfc47dd3afe70ebf273263f586c381fb85d982b52c4de24c52996cb21abc56818f6e3ae6fa2ddde6b74d028180180e47e1e5a83464d9c209b3a3f19f740631d06f756f80fbbd39ede97120b6e6501baae99b2371663f8ca083b5b966ad2e48c02015b0b1dc77198540604877c3848dae30bade78ff1dc9db65c4257b245aaa075ee732645f3f9c11ca3f37964080c58a26ba773d739b9e71df6193d3a6d4beef1bb618537e912fb26a98e0b01102818100950d7d5ec366f8bca918011359590c6e7d6fe4d3e8922d68468c3e24277f27621db17cb41d0dcddf1f77e289e49dc92101d8544e84281ec7732fbfd4e9194924a2adac4e22ef79c2ad61428f1fa03e6affa3b0de07f857de87a2e758953122b0d693cf49e54ede4eba44dcdc2c5cbd6751af5117fd107fc0e4ffb18f8774d79e tls-cert = 308202e4308201cc020101300d06092a864886f70d01010505003039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f7374301e170d3139303730323036353535365a170d3139303730323036353535365a3039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f737430820120300d06092a864886f70d01010105000382010d00308201080282010100c5a358cee61ca7592dbe62cd28225426dc3fc65b33432043efb5e8fcfaf334720b2000d10c422172e6f94f82746928a6d51193342a1555684eedb141321170cb02cc7b189f5506cc30cb5c26d9b84123328ed6df61fc1a6582b046def7a662bb15d84e29ffa279f1d853c25ca79fbe3fab0200f8c85566a5eedb98df4a958e8512a647258e55a7a56c1ca8b05607b38b01b6a2669af9a70efa59141f6079341c6044f615687be756d4830ea359139ea35e23f34ce226215a1a2fb8271cc60a037841e44c460e149a71d3e2fa907a48677ad18af2e7348343932f5f29ac5241cd20ce64e6798ada684164cd1109c3a969662d9aaf9897fedc5a4e256eb92bf7bd020111300d06092a864886f70d0101050500038201010009fc34f2835e4c14de1e03202c0f0884acb51e7568b286a9b3a374e8b69f304600a2787303cd382e52923db352cf91587ea7a33da5116c886c67775b5f96357971dddb568948fbb12987523a8be0e2e537284f8ee591af17c6d58410e41d32fc634f99289089915fb4273feaaca45d3442820155f5014fbd5d19fef7954729e4439218cad6a83b9dcd21834aaec379a276f163599cdac6b9513d0c07310852bb4104a58141a158d302908c23761899a4c68c3bf81115f302d41f42ff38150c0b7dc798fd7319abec6bd9365e00bf0a0998c3b97fe4834f0688e95d1eea4df4031274c781c6661cab085d629cb924c5c65b865ae98aa2349875fafe62b7eacbc5 idx = 0 diff --git a/hotstuff-sec1.conf b/hotstuff-sec1.conf index 54c9b5f6..cafc547e 100644 --- a/hotstuff-sec1.conf +++ b/hotstuff-sec1.conf @@ -1,4 +1,4 @@ -privkey = 71f2f7aa5fb0f6d8fcdebe6c6c249aa7de068eb5d617dffa0dcfbc2f1dd73177 +privkey = 6140f1ddab14281130b6e713dc0066c0b384dc1131d6a743bbf0774050359b32 tls-privkey = 308204a20201000282010100abfe4a55f831720dd46e2bca05e767aef9838d2069f893f3213bf5a31f5be249c2b356476e01d3fc221581bf4ffa93a6ec41898fbed6119b7981065d07fe476fa12b7da4a22f37d4cfc8a667ff163c05d17762f789df64995a1e80c50ed0d1f7ab8e733fb543d962818ce3ba7b38bf4fe0ca39926b6e99e3fa32eff48f503cf7f66824573e9fb34cb9c4e952f0f584d30c5b7312172facb0439ed5af6d0c6f7382db15315dce8f2fe1704f11bd76e5e3fbffd6f44b240036492187a13e23c0cc8769a52f5bbc90400867093d031483b84fe5c40a7ce66d7dab7a474689de080cc2b6670359f08d5bff53cfa92bf49fc306cccfe0b6fed8c6e4edef86d81638610201110282010100a1e045f68f3d98857ca3ecfa5fe8da0e180357a609626d2110386eb7a50b2f547b032406fe1fd692f2e710b40f09f460de5bccc3866f1fa1634c423970ef524af20ad09af2ff439b1dea060786ab83c93d9d8a5263a5136327a43cf5b3975c34653ac6d28c7c17e43db1c746199ed22d0fcd635ca159094f09995a4f95f12a513ebec6fe1af47c260090fcf8908e04192bb8b9a9c75608d221110d183a80380193b076354b2cb396500c94c8ca33e45559eeadefe217ef04898a2350390fadcf3e4ccb4d1783c619168c9fe7e29701f15476e980408975050d0a8e5df4e4ea35dc6fe3e3f71964952cf600c45d88688b5e92cf5144d869448290e7cefc8f793102818100d5c267d9f5b82ce47e3b7e3fa80fa599b73406b21d240c863bfc4c20d858c729d96e89adc0e51aa6248112fb351bcf5102dada449b5226842d9e7482e65391b8e89a8a0982a1f1b0e75922d416e45f28a06842d4ef00d9c7c8fa43d47487e79121e69d25f5dbbdf49ea85dc7035cb7a92fa79cad5666a2bd4bcd29be9ec31fff02818100cdfb090f4c43c27fdaef5e4b2f4efade96b3271b964036cac4806ba4d68b6cc7fc810deafd09f5ba07e1de013183f3f8499763e0cf986bbd49604d991b2f86676c9d8323f01e9c1479187c828b6fb27f45bf291d4953876084a4cc2e4122e7a26698e7bb2d89d488e0e611118536f905c2a936ed07724630ce66cf7c4cfaa79f0281810096e39499daa01fb0591aefb476a1a21226f78c417dfb542284b2179eb6d5414ab79952204bed03c0923cfe56f84fdda2989a7bf431672a3f2f42ac98a29557cdd15e0715c59f7d6dd07b27a4c4dd7058e9b301ffb7c45d7df7473ef05241d0a2ae84ab29dab93acaca58baaa98f6274a3fc19bc5a66690fe1763a4ff06a7da59028180792a41908736eae1cc145595a35ba2a10d5a533d6771112bfb1e5d7005bb6d2a584bea11c205dbd6d775cde29598e9dd58772bb16b0e5d7e6765d34b00eec78821c610e7f6a8980c0aff584cca7df08719f7fa113a31227502bb4aee0832a65f87a53d04b16022aadea57373b7c5fbe545547aa98be8ddfe9787c5582d48265d02818006385a17426489bc3393300bfec08c440cbfd894d991b1c1e1b672f17809ff150703496fde8df3bfa9d67553f0d6d4bb1bf73706454470479fc4aec0250b0613bd028cc111f61edfeb6ad40e6801fc22afcb67788a7a514c5b3f04a3986dbf063f4277bcf5182763242781f8ba6b2cb3a8cb909332f9b1966601675297a601cf tls-cert = 308202e4308201cc020101300d06092a864886f70d01010505003039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f7374301e170d3139303730323036353535365a170d3139303730323036353535365a3039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f737430820120300d06092a864886f70d01010105000382010d00308201080282010100abfe4a55f831720dd46e2bca05e767aef9838d2069f893f3213bf5a31f5be249c2b356476e01d3fc221581bf4ffa93a6ec41898fbed6119b7981065d07fe476fa12b7da4a22f37d4cfc8a667ff163c05d17762f789df64995a1e80c50ed0d1f7ab8e733fb543d962818ce3ba7b38bf4fe0ca39926b6e99e3fa32eff48f503cf7f66824573e9fb34cb9c4e952f0f584d30c5b7312172facb0439ed5af6d0c6f7382db15315dce8f2fe1704f11bd76e5e3fbffd6f44b240036492187a13e23c0cc8769a52f5bbc90400867093d031483b84fe5c40a7ce66d7dab7a474689de080cc2b6670359f08d5bff53cfa92bf49fc306cccfe0b6fed8c6e4edef86d8163861020111300d06092a864886f70d0101050500038201010069f87140cc279dfc03b89cd6de3833aa7bb824f522b46943d8ea32c0bf24b2a7d7b77da04a359fe4fa840770552794836dc6cdbf80396ab87edfe5df187915cb94ef4b142b8b20c438b54608059fca91f5792a39bfaea547c6a56fac3ae165ce89d29e7af5f914304da4aabe02961f5dab7dc94124837539958015d89a22eedfd42981819004d1af6342498aa43f58cf84c391e0427835407089d0e95b5fdfe350974cb507dffeca15e55851e03b68ce4ac640ca898ea6a75a7f5469f677f74a14d05ce4bbd44e8a2a70366edb94f6e8706246dd904847e37abe3116320dc1688a4788a8600bf7ae05932541be665efb5b564c3c964504555f09175494517469 idx = 1 diff --git a/hotstuff-sec2.conf b/hotstuff-sec2.conf index 12a361a0..17bc812f 100644 --- a/hotstuff-sec2.conf +++ b/hotstuff-sec2.conf @@ -1,4 +1,4 @@ -privkey = f09707974bd60c68734e45172928eb600710675fc45822b6db5a8c75eec0f5a1 +privkey = 65b19963364811f65bf8731f93d2ceb045b931f989b7d2c36fed0f5813e1f62e tls-privkey = 308204a20201000282010100c1460bf8018ceec075d67405e96e056e2e3acf9c7c2d7d28ee6edfe9ee8fbeef0e978ac874ceff3ee770dafde1d019d9920b2ff334a3ac115bcf95e2bdc0b70faf46b8f13c46335c4815c72d75b488de46b96f8582446e886c6b7fdfb479bc40a0da03b7c4e414fde9ab44b1957e39c5e5c167ba88a233854f29404a1f35aa29994bcd7a62b57fc2000850c37569a8a1bfa75e6e06c54c40633e0fee1672c1f97689aabee650285a41fd6df24f20cd94733aeccdae68debba30a3588b71625f9ec7669d3f4c51317192f5acdee9b968d1a6db4a98a9c0eeef63a969c2ecaba95a9ddfd5841d996977696e41a541393ba40ae44b71c00129a25b30f6c44e89d8d0201110282010071b0bbbf0ff88c713641e9e55c2299c8576de38939fca3f9f5aaa1d4e6aee8c8db683384f96ab4431ebadb2bee3e2d52ce60ef07886047194510b285608f7abdeea2126fc91a3c5466a3661abdb57dafed5e055d97ec04c8b83f3c293cfc509e7cbc7aa855b357a46b55afeffd958b6559f94c135f6e78a8c52752fe6cb627db36195ca7e30537e3a1a2cfd2dfe23c2f6c9c91a45119e8b6c128dce763157d4f21350c7293f4cc7c96201e3b63484e22b6308c2d9351e1c5b833bcc301c68f9111c10c9e79ee6f590ce7cff86e1c8e6bf970d8d0e2d0bc32a6c06997e3cdcad17657cfa6d0300966fd1c0a4ad5e9817ab4d41b5ff0010ce93c08eae7ad053ef102818100e8b87e8ca3a329afedda121b2f005533749b067a3f9b38f43252f760ed18a9cdea42bd14a3b0ac599dc6c00fb873303713e030507fda557ab3de70864de60cba13dde108eedfe57df0a5fcbe3062b0cfce80aab3739e7f83b5534215c01830234bd439afdd02fd0755da8eb9c56466c762fb3c8cec5fa4229c8e94092db7b24102818100d49b649d2389770f18ffdd5b6368b9ea78cef9f60a17a148b558d43700e8c3250706588113e5b9f9a50014173ab2b2225cd50162e750230a693a37507fc4f1fc6d9d268a69cfd6b4f8ff494fcfd526d28a46cc92fbcde915256d076a9ea17e74ae747c4002eb56610c0caa47bca2373bdd7da66d7e050bb7d64885a60aa8004d02818100b1f67ee404a9f2b3b5e2fec97e4b8c72a4768c7b9a0d49abae0335a47912dc340d7e545b13c3569ee21074c0ba39f7b1a5c98e5bad105f7bf2f5651b68befaac698b8df7c5ba46150351c14625002cdb2571737a2b3cf8196c8af64cde309d482aed95867bd51bd86ed44f0687e35da787ed4c6bc3d0aab10e4ee9acaa7d6a31028181008991b992dac25c18d3f0da866d7fffd3f3d13853e869a4987557985fd3696f36139ab1bceec1d2b097f0fdf0e9beebbbe1b700e5a4bb61f7ad8005ac8ee8d8d08329734a80b3a90bb02cb6f7685cbec477973913d01bd30daece13db93d1e8699e0f23387a5c0ab7440831f22ec350ea80423e83154e8f1c99b674989d7bc3f5028180267c5167cd1f8dce4b15611b8ea0220e6be74efbf55e3bf4a775b1edf0e49b377c12f49fbf683f24e1850c455b8b7a96d0c7eff9f47661ec75004a2a435dd741e7d7bb6423fa576053a0677b2a0b714e7fadcc37c03dc9da053069477c1ce0afac316c1c63ffb510d30e11adc0865e94177f3545c0594860c10baa51bc074e4c tls-cert = 308202e4308201cc020101300d06092a864886f70d01010505003039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f7374301e170d3139303730323036353535365a170d3139303730323036353535365a3039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f737430820120300d06092a864886f70d01010105000382010d00308201080282010100c1460bf8018ceec075d67405e96e056e2e3acf9c7c2d7d28ee6edfe9ee8fbeef0e978ac874ceff3ee770dafde1d019d9920b2ff334a3ac115bcf95e2bdc0b70faf46b8f13c46335c4815c72d75b488de46b96f8582446e886c6b7fdfb479bc40a0da03b7c4e414fde9ab44b1957e39c5e5c167ba88a233854f29404a1f35aa29994bcd7a62b57fc2000850c37569a8a1bfa75e6e06c54c40633e0fee1672c1f97689aabee650285a41fd6df24f20cd94733aeccdae68debba30a3588b71625f9ec7669d3f4c51317192f5acdee9b968d1a6db4a98a9c0eeef63a969c2ecaba95a9ddfd5841d996977696e41a541393ba40ae44b71c00129a25b30f6c44e89d8d020111300d06092a864886f70d01010505000382010100706c7eb29939c38cfcbab592c62a3572e05dcaa4d54e24cce74a244972e74ac8ed6e0b3eb1add0d4de6007d392ac75a7fb9836a9a1d937d0b2c3f01a6b1994ac317328527c763eae26a6ca647752badcd09e73364ac7828d375b4966e510de1cdbd01a5be047e45533f5a3d81df00ffe9d13fe5d54e18584691abb3a9a3d423d348d7714382317547338a8e83d14f404348db41c10a05e57221eda1e220b265ae4237e59ab2db1facbe8cc8d2198ca5fe2ad074bb8c7c4dd675cbe3d60b9e29f6b12ab4c587c6576e1ce2d2512be035e4692100c6c3e47d4d84dbbc865804af1bd0240fb804ef99c7038191dae2fab73a1a1ffa09f536a0fbf49fa1a3234b62a idx = 2 diff --git a/hotstuff-sec3.conf b/hotstuff-sec3.conf index 9c36b9ba..8d8c43d7 100644 --- a/hotstuff-sec3.conf +++ b/hotstuff-sec3.conf @@ -1,4 +1,4 @@ -privkey = 3d0cdf598a2514649a5dedf626467716d04e22d2b6a83dc0f5ca810701f728f3 +privkey = 19231fb2a3d594503401570c698c5a2fa12abbd6f7978ebaca79d5bbcad22470 tls-privkey = 308204a20201000282010100de01b461213afa37d4aa68bdc7e1a6de12307440f1de6588e5362450694cbb4ba63b1f992a7dc88b999c7dec9088d17253ac278c33018ea8caa1f96c7d90bcb5a6a3f8568825bafa9a696699a4eaf0c6fcdd8ed7bc91a688ead564fb882a1c25c7f72bbe44eb44fda1d11d6ca090503e36de532f2fededff03da30f8f95f11b6472e9588fd6be69cad285915c68edaa7754c6524017bf08c3c336f04d0246d8e967a4de2824a3ac7486aaf9160540c63f75d36ecba9261ff6b859a7684b023ecfbc5408dc7c59942c76464040770c6097833dd770a7dffc6ed6a8716b1f683379843969f937d859d8f69a21362eda9dabd64dd6fb7131ee46b2654d3aa8dc9df02011102820100414bcba418d51c6ac61400b049d8f4d7e73b6d7c835f8746618865089770ebcaf4a7fa3c1b8e68290f0fe8cd1b7388e563e756ecfff16631a5027689521b82cc03d5dfa0faddebb31e5b3c4b4e9f73fe4a5f48215594400a26f3780dbea2f93849df4919d808f62c7ae326c598a2ea6ca6b9dc3b0e18cd873d5e4aa394a37dad88a49b91b7446343d03d4ea067b72c62ba622d68f7fb97c031a7f9259401318905e092b0aec27e643fb3efd9bf392050941d43fe06a87630412bf765a4800f57561a9fc339ff92a9b33e748efe5c6ddafe4069e99cf039794b4641ab4f199703860b4f8ee3669a04ad664379012650e68debe0ccc4c41a39e6bf8a3de15003f902818100f56482abd14db0f327311b376dc4cfac86cc3379036b6672713d296a0665797de7b115350d77a27193de1f5abd9e2b44eff6c5a323b1209c4aac68c86e3488abab89139a7cbb98a4f0c1e930c2bc276bbcf0efd47cf4dc6614b9c16c332a5f7ef339d5c746780884a66e087236ec784361fda7e72c21528c0427d7abbc9751f502818100e79a68542368e4295b8d3289c4f4da780e6597461952b9592221901b05bae53ece00df87ef7084340f28c71f188d400d0fcfbd504d0ae2bf101082214d9500b1f8480dc1ec3ea7900ece21b9e3e0c2b5279b1f21de585ff7a58eb330d841ef13107ce58c14a8a4a29b6cb438f4e551baac120603878a3ff9f00cda5589800403028181009ec890c9876e818e46892fba74340de81afc99c6c5fa333afdfa66176d8cf44268bde08bbd6b873a6ebce71c98cfc1a513bdcb2d53547e833f60800938401c32d867c163f65b44a6f6231e6ad85ba1097a418c20149e707e49a55f09c6c1109d70347b44b5207dfb7abfab1cba208a0d7ba4215958ca4478b7651314c552daad02818100cc5b10c2b5d5058de75e77e2f914484bd077c1b652944930878706ae6e77bb376a793db42d9f83b576c9a0a2f78bb0fc775cf255e9a0317b68870968adddd36fdb12667dee91a2e88588b458ba028daee6b60c692d99459e46c934b2a0b2a5c58704ca8aa8d109bca741cc32417f0be0f22e054e68890b45f1ed391e4c25a92f02818016d4c0a1d4cc7fadb7033ae8506221a7dde9c2437fe5989175e8de47791b4ff957fb485d6d04c85b9fd1d7734950dc4d032dd3fdf9c14193b04ea179839fb4560282d106b684b5712a9b140afbe4d92ff30c745a7bdca71de9808f6d2a88340e116cc4475e908993c27a27847601ec378d4357dc5e99a147c60d7258e282453e tls-cert = 308202e4308201cc020101300d06092a864886f70d01010505003039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f7374301e170d3139303730323036353535365a170d3139303730323036353535365a3039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f737430820120300d06092a864886f70d01010105000382010d00308201080282010100de01b461213afa37d4aa68bdc7e1a6de12307440f1de6588e5362450694cbb4ba63b1f992a7dc88b999c7dec9088d17253ac278c33018ea8caa1f96c7d90bcb5a6a3f8568825bafa9a696699a4eaf0c6fcdd8ed7bc91a688ead564fb882a1c25c7f72bbe44eb44fda1d11d6ca090503e36de532f2fededff03da30f8f95f11b6472e9588fd6be69cad285915c68edaa7754c6524017bf08c3c336f04d0246d8e967a4de2824a3ac7486aaf9160540c63f75d36ecba9261ff6b859a7684b023ecfbc5408dc7c59942c76464040770c6097833dd770a7dffc6ed6a8716b1f683379843969f937d859d8f69a21362eda9dabd64dd6fb7131ee46b2654d3aa8dc9df020111300d06092a864886f70d010105050003820101007f9d4f2848059831e5ea7d727d9b09f826027c78fdc86d27ea83d32d727ac4a0484e55ed34851adcc8903a3ef39c1b0c447c28cd84cbc513cdcd607da3fa903495a70b7772e71873e3c8a734d3e8b9f82c7380604ccb8416bd92822e703a3b8839aff411f967d2bcc1cd96d158e7839a2bff6110ffd005808f7047fd57a7150c1e14ddcfd2e1a24a5878f99409b7ede1d5f4a385077b6f55f4818c854c6e64adb4789433667e672b9a615b680301a05852255cef958ff1031a489dd95327d045be0315359644ec51f2fd3cb724382ba2425da519dbf1d89098e10a1091f44c7a8e12733b7d0b1fce7c6d19adfee3cdac89f95ed1ae979093cb2793892724d7d9 idx = 3 diff --git a/hotstuff.conf b/hotstuff.conf index cadf3aef..148cb54b 100644 --- a/hotstuff.conf +++ b/hotstuff.conf @@ -1,6 +1,6 @@ block-size = 1 pace-maker = rr -replica = 127.0.0.1:10000;20000, 039f89215177475ac408d079b45acef4591fc477dd690f2467df052cf0c7baba23, 542865a568784c4e77c172b82e99cb8a1a53b7bee5f86843b04960ea4157f420 -replica = 127.0.0.1:10001;20001, 0278740a5bec75e333b3c93965b1609163b15d2e3c2fdef141d4859ec70c238e7a, c261250345ebcd676a0edeea173526608604f626b2e8bc4fd2142d3bde1d44d5 -replica = 127.0.0.1:10002;20002, 0269eb606576a315a630c2483deed35cc4bd845abae1c693f97c440c89503fa92e, 065b010aed5629edfb5289e8b22fc6cc6b33c4013bfdd128caba80c3c02d6d78 -replica = 127.0.0.1:10003;20003, 03e6911bf17e632eecdfa0dc9fc6efc9ddca60c0e3100db469a3d3d62008044a53, 6540a0fea67efcb08f53ec3a952df4c3f0e2e07c2778fd92320807717e29a651 +replica = 127.0.0.1:10000;20000, 0bc7e156bad174ab1e176b25663589b3b457aa89d1cf30dff94670d5318caf070f2fbad7d598d737933d94933ee728ca, 542865a568784c4e77c172b82e99cb8a1a53b7bee5f86843b04960ea4157f420 +replica = 127.0.0.1:10001;20001, 8a5b14563257919307d7db01da5528ae35aef89fc524ab08ae5d5f5e0b534324705dc3d868f81f1f35b7fca0a57f2d8a, c261250345ebcd676a0edeea173526608604f626b2e8bc4fd2142d3bde1d44d5 +replica = 127.0.0.1:10002;20002, 018f7f4c04024d10277ab087a5a19df65808e1f0286ac064f29d2ff49bea57a81d2dcec4c0ccd5d63fddc803393024e6, 065b010aed5629edfb5289e8b22fc6cc6b33c4013bfdd128caba80c3c02d6d78 +replica = 127.0.0.1:10003;20003, 99590c2344ba54efab5583a21def085c1b8e58172d660e87e024692765335139874114cc5779c19203eec5a1529fc1c0, 6540a0fea67efcb08f53ec3a952df4c3f0e2e07c2778fd92320807717e29a651 diff --git a/include/hotstuff/crypto.h b/include/hotstuff/crypto.h index 60e7dfc7..c5951d3c 100644 --- a/include/hotstuff/crypto.h +++ b/include/hotstuff/crypto.h @@ -23,6 +23,7 @@ #include "salticidae/crypto.h" #include "hotstuff/type.h" #include "hotstuff/task.h" +#include namespace hotstuff { @@ -141,7 +142,6 @@ class QuorumCertDummy: public QuorumCert { const uint256_t &get_obj_hash() const override { return obj_hash; } }; - class Secp256k1Context { secp256k1_context *ctx; friend class PubKeySecp256k1; @@ -180,7 +180,7 @@ class PubKeySecp256k1: public PubKey { PubKeySecp256k1(const secp256k1_context_t &ctx = secp256k1_default_sign_ctx): PubKey(), ctx(ctx) {} - + PubKeySecp256k1(const bytearray_t &raw_bytes, const secp256k1_context_t &ctx = secp256k1_default_sign_ctx): @@ -318,6 +318,8 @@ class SigSecp256k1: public Serializable { bool verify(const bytearray_t &msg, const PubKeySecp256k1 &pub_key, const secp256k1_context_t &_ctx) const { check_msg_length(msg); + std::cout << "blah1" << std::endl; + std::cout << (unsigned char *)&*msg.begin() << std::endl; return secp256k1_ecdsa_verify( _ctx->ctx, &data, (unsigned char *)&*msg.begin(), @@ -425,6 +427,317 @@ class QuorumCertSecp256k1: public QuorumCert { } }; + class PrivKeyBLS; + class PubKeyBLS: public PubKey { + static const auto _olen = bls::PublicKey::PUBLIC_KEY_SIZE; + friend class SigSecBLS; + + bls::PublicKey* data = nullptr; + + public: + PubKeyBLS() : + PubKey() {} + + PubKeyBLS(const bytearray_t &raw_bytes) : + PubKeyBLS() { + data = new bls::PublicKey(bls::PublicKey::FromBytes(&raw_bytes[0])); + } + + PubKeyBLS(const PubKeyBLS &obj) { + data = new bls::PublicKey(*(obj.data)); + } + + ~PubKeyBLS() override { + delete data; + data = nullptr; + } + + inline PubKeyBLS(const PrivKeyBLS &priv_key); + + void serialize(DataStream &s) const override { + static uint8_t output[_olen]; + data->Serialize(output); + s.put_data(output, output + _olen); + } + + void unserialize(DataStream &s) override { + static const auto _exc = std::invalid_argument("ill-formed public key"); + + try { + data = new bls::PublicKey(bls::PublicKey::FromBytes(s.get_data_inplace(_olen))); + } catch (std::ios_base::failure &) { + throw _exc; + } + } + + PubKeyBLS *clone() override { + return new PubKeyBLS(*this); + } + }; + + class PrivKeyBLS: public PrivKey { + static const auto nbytes = bls::PrivateKey::PRIVATE_KEY_SIZE;; + friend class SigSecBLS; + + public: + bls::PrivateKey* data = nullptr; + + PrivKeyBLS(): + PrivKey() {} + + PrivKeyBLS(const bytearray_t &raw_bytes): + PrivKeyBLS() + { + static const auto _exc = std::invalid_argument("ill-formed public key"); + try { + data = new bls::PrivateKey(bls::PrivateKey::FromBytes(&raw_bytes[0])); + } catch (std::ios_base::failure &) { + throw _exc; + } + } + + ~PrivKeyBLS() + { + delete data; + data = nullptr; + } + + void serialize(DataStream &s) const override { + static uint8_t output[nbytes]; + data->Serialize(output); + s.put_data(output, output + nbytes); + } + + void unserialize(DataStream &s) override { + static const auto _exc = std::invalid_argument("ill-formed public key"); + try { + const uint8_t* dat = s.get_data_inplace(bls::PrivateKey::PRIVATE_KEY_SIZE); + data = new bls::PrivateKey(bls::PrivateKey(bls::PrivateKey::FromBytes(dat))); + } catch (std::ios_base::failure &) { + throw _exc; + } + } + + void from_rand() override { + bn_t b; + bn_new(b); + data = new bls::PrivateKey(bls::PrivateKey::FromBN(b)); + } + + inline pubkey_bt get_pubkey() const override; + }; + + pubkey_bt PrivKeyBLS::get_pubkey() const { + return new PubKeyBLS(*this); + } + + PubKeyBLS::PubKeyBLS(const PrivKeyBLS &priv_key): PubKey() { + data = new bls::PublicKey(priv_key.data->GetPublicKey()); + } + + class SigSecBLS: public Serializable { + + static void check_msg_length(const bytearray_t &msg) { + if (msg.size() != 32) + throw std::invalid_argument("the message should be 32-bytes"); + } + + public: + bls::InsecureSignature* data = nullptr; + + SigSecBLS (): + Serializable(){} + SigSecBLS(const uint256_t &digest, + const PrivKeyBLS &priv_key): + Serializable() { + sign(digest, priv_key); + } + + SigSecBLS (const SigSecBLS &obj) + { + data = new bls::InsecureSignature(*(obj.data)); + } + + SigSecBLS (bls::InsecureSignature sig): + Serializable() + { + data = new bls::InsecureSignature(sig); + } + + ~SigSecBLS() override + { + delete data; + data = nullptr; + } + + void serialize(DataStream &s) const override { + static uint8_t output[bls::InsecureSignature::SIGNATURE_SIZE]; + + int i = 0; + for (auto in : data->Serialize()) + { + output[i++] = in; + } + s.put_data(output, output + bls::InsecureSignature::SIGNATURE_SIZE); + } + + void unserialize(DataStream &s) override { + static const auto _exc = std::invalid_argument("ill-formed signature"); + try { + data = new bls::InsecureSignature(bls::InsecureSignature::FromBytes(s.get_data_inplace(bls::InsecureSignature::SIGNATURE_SIZE))); + } catch (std::ios_base::failure &) { + throw _exc; + } + } + + void sign(const bytearray_t &msg, const PrivKeyBLS &priv_key) { + check_msg_length(msg); + std::cout << "sign: " << msg.data() << std::endl; + data = new bls::InsecureSignature(priv_key.data->SignInsecure(msg.data(), sizeof(&msg))); + } + + bool verify(const bytearray_t &msg, const PubKeyBLS &pub_key) const { + check_msg_length(msg); + std::cout << "blah1" << std::endl; + std::cout << (unsigned char *)&*msg.begin() << std::endl; + bool res1 = data->Verify({(unsigned char *)&*msg.begin()}, {*(pub_key.data)}); + std::cout << "blah2 " << res1 << std::endl; + return res1; + } + }; + + class SigVeriTaskBLS: public VeriTask { + uint256_t msg; + PubKeyBLS pubkey; + SigSecBLS sig; + public: + SigVeriTaskBLS(const uint256_t &msg, + const PubKeyBLS &pubkey, + const SigSecBLS &sig): + msg(msg), pubkey(pubkey), sig(sig) {} + virtual ~SigVeriTaskBLS() = default; + + bool verify() override { + return sig.verify(msg, pubkey); + } + }; + + class PartCertBLS: public SigSecBLS, public PartCert { + uint256_t obj_hash; + + public: + PartCertBLS() = default; + PartCertBLS(const PrivKeyBLS &priv_key, const uint256_t &obj_hash): + SigSecBLS(obj_hash, priv_key), + PartCert(), + obj_hash(obj_hash) {} + + PartCertBLS(const PartCertBLS &obj) : SigSecBLS(obj) { } + + bool verify(const PubKey &pub_key) override { + return SigSecBLS::verify(obj_hash, + static_cast(pub_key)); + } + + promise_t verify(const PubKey &pub_key, VeriPool &vpool) override { + return vpool.verify(new SigVeriTaskBLS(obj_hash, + static_cast(pub_key), + static_cast(*this))); + } + + const uint256_t &get_obj_hash() const override { return obj_hash; } + + PartCertBLS *clone() override { + return new PartCertBLS(*this); + } + + void serialize(DataStream &s) const override { + s << obj_hash; + this->SigSecBLS::serialize(s); + } + + void unserialize(DataStream &s) override { + s >> obj_hash; + this->SigSecBLS::unserialize(s); + } + }; + + class QuorumCertBLS: public QuorumCert { + uint256_t obj_hash; + salticidae::Bits rids; + std::unordered_map signatures; + SigSecBLS* theSig = nullptr; + + public: + QuorumCertBLS() = default; + QuorumCertBLS(const ReplicaConfig &config, const uint256_t &obj_hash); + + ~QuorumCertBLS() + { + delete theSig; + theSig = nullptr; + } + + void add_part(ReplicaID rid, const PartCert &pc) override { + if (pc.get_obj_hash() != obj_hash) + throw std::invalid_argument("PartCert does match the block hash"); + signatures.insert(std::make_pair( + rid, static_cast(pc))); + rids.set(rid); + } + + void compute() override + { + std::vector sigShareOut; + std::vector players; + + for(auto elem : signatures) { + players.push_back(elem.first); + sigShareOut.push_back(*elem.second.data); + } + std::cout << "Try combine?" << std::endl; + std::cout << players.size() << std::endl; + std::cout << sigShareOut.size() << std::endl; + uint8_t* d = obj_hash.to_bytes().data(); + + theSig = new SigSecBLS(bls::Threshold::AggregateUnitSigs(sigShareOut, d, sizeof(d), &players[0], 10)); + std::cout << "those5?" << std::endl; + } + + bool verify(const ReplicaConfig &config) override; + promise_t verify(const ReplicaConfig &config, VeriPool &vpool) override; + + const uint256_t &get_obj_hash() const override { return obj_hash; } + + QuorumCertBLS *clone() override { + return new QuorumCertBLS(*this); + } + + void serialize(DataStream &s) const override { + bool combined = (theSig != nullptr); + s << obj_hash << rids << combined; + if (combined) { + s << *theSig; + } + else { + for (size_t i = 0; i < rids.size(); i++) + if (rids.get(i)) s << signatures.at(i); + } + } + + void unserialize(DataStream &s) override { + bool combined; + s >> obj_hash >> rids >> combined; + if (combined) { + s >> *theSig; + } + else { + for (size_t i = 0; i < rids.size(); i++) + if (rids.get(i)) s >> signatures[i]; + } + } + }; + } #endif diff --git a/include/hotstuff/entity.h b/include/hotstuff/entity.h index dea980d2..19127857 100644 --- a/include/hotstuff/entity.h +++ b/include/hotstuff/entity.h @@ -63,7 +63,9 @@ class ReplicaConfig { size_t nreplicas; size_t nmajority; - ReplicaConfig(): nreplicas(0), nmajority(0) {} + PubKey* globalPub; + + ReplicaConfig(): nreplicas(0), nmajority(0), globalPub(new PubKeyBLS(hotstuff::from_hex("8cb772444852e35624d70af1140d63c84fbf5be339bc0da0feb35fcd36ba81c35ebe3150c0b3f71233b6919385d7d561"))) {} void add_replica(ReplicaID rid, const ReplicaInfo &info) { replica_map.insert(std::make_pair(rid, info)); diff --git a/include/hotstuff/hotstuff.h b/include/hotstuff/hotstuff.h index 33b673f8..40970dc9 100644 --- a/include/hotstuff/hotstuff.h +++ b/include/hotstuff/hotstuff.h @@ -309,6 +309,8 @@ class HotStuff: public HotStuffBase { using HotStuffNoSig = HotStuff<>; using HotStuffSecp256k1 = HotStuff; +using HotStuffTH = HotStuff; template FetchContext::FetchContext(FetchContext && other): diff --git a/src/consensus.cpp b/src/consensus.cpp index 9de7cc21..83cf007c 100644 --- a/src/consensus.cpp +++ b/src/consensus.cpp @@ -248,9 +248,10 @@ void HotStuffCore::on_receive_vote(const Vote &vote) { } /*** end HotStuff protocol logic ***/ void HotStuffCore::on_init(uint32_t nfaulty) { + config.nmajority = config.nreplicas - nfaulty; b0->qc = create_quorum_cert(b0->get_hash()); - b0->qc->compute(); + //b0->qc->compute(); b0->self_qc = b0->qc->clone(); b0->qc_ref = b0; hqc = std::make_pair(b0, b0->qc->clone()); diff --git a/src/crypto.cpp b/src/crypto.cpp index 7e839ef5..6eae024d 100644 --- a/src/crypto.cpp +++ b/src/crypto.cpp @@ -19,48 +19,71 @@ namespace hotstuff { -secp256k1_context_t secp256k1_default_sign_ctx = new Secp256k1Context(true); -secp256k1_context_t secp256k1_default_verify_ctx = new Secp256k1Context(false); + secp256k1_context_t secp256k1_default_sign_ctx = new Secp256k1Context(true); + secp256k1_context_t secp256k1_default_verify_ctx = new Secp256k1Context(false); -QuorumCertSecp256k1::QuorumCertSecp256k1( - const ReplicaConfig &config, const uint256_t &obj_hash): + QuorumCertSecp256k1::QuorumCertSecp256k1( + const ReplicaConfig &config, const uint256_t &obj_hash) : QuorumCert(), obj_hash(obj_hash), rids(config.nreplicas) { - rids.clear(); -} - -bool QuorumCertSecp256k1::verify(const ReplicaConfig &config) { - if (sigs.size() < config.nmajority) return false; - for (size_t i = 0; i < rids.size(); i++) - if (rids.get(i)) - { - HOTSTUFF_LOG_DEBUG("checking cert(%d), obj_hash=%s", - i, get_hex10(obj_hash).c_str()); - if (!sigs[i].verify(obj_hash, - static_cast(config.get_pubkey(i)), - secp256k1_default_verify_ctx)) - return false; - } - return true; -} + rids.clear(); + } -promise_t QuorumCertSecp256k1::verify(const ReplicaConfig &config, VeriPool &vpool) { - if (sigs.size() < config.nmajority) - return promise_t([](promise_t &pm) { pm.resolve(false); }); - std::vector vpm; - for (size_t i = 0; i < rids.size(); i++) - if (rids.get(i)) - { - HOTSTUFF_LOG_DEBUG("checking cert(%d), obj_hash=%s", - i, get_hex10(obj_hash).c_str()); - vpm.push_back(vpool.verify(new Secp256k1VeriTask(obj_hash, - static_cast(config.get_pubkey(i)), - sigs[i]))); - } - return promise::all(vpm).then([](const promise::values_t &values) { - for (const auto &v: values) - if (!promise::any_cast(v)) return false; + bool QuorumCertSecp256k1::verify(const ReplicaConfig &config) { + if (sigs.size() < config.nmajority) return false; + for (size_t i = 0; i < rids.size(); i++) + if (rids.get(i)) { + HOTSTUFF_LOG_DEBUG("checking cert(%d), obj_hash=%s", + i, get_hex10(obj_hash).c_str()); + if (!sigs[i].verify(obj_hash, + static_cast(config.get_pubkey(i)), + secp256k1_default_verify_ctx)) + return false; + } return true; - }); -} + } + + promise_t QuorumCertSecp256k1::verify(const ReplicaConfig &config, VeriPool &vpool) { + if (sigs.size() < config.nmajority) + return promise_t([](promise_t &pm) { pm.resolve(false); }); + std::vector vpm; + for (size_t i = 0; i < rids.size(); i++) + if (rids.get(i)) { + HOTSTUFF_LOG_DEBUG("checking cert(%d), obj_hash=%s", + i, get_hex10(obj_hash).c_str()); + vpm.push_back(vpool.verify(new Secp256k1VeriTask(obj_hash, + static_cast(config.get_pubkey( + i)), + sigs[i]))); + } + return promise::all(vpm).then([](const promise::values_t &values) { + for (const auto &v: values) + if (!promise::any_cast(v)) return false; + return true; + }); + } + + QuorumCertBLS::QuorumCertBLS( + const ReplicaConfig &config, const uint256_t &obj_hash) : + QuorumCert(), obj_hash(obj_hash), rids(config.nreplicas) { + rids.clear(); + } + + bool QuorumCertBLS::verify(const ReplicaConfig &config) { + if (theSig == nullptr) return false; + + return theSig->verify(obj_hash, static_cast(*config.globalPub)); + } + + promise_t QuorumCertBLS::verify(const ReplicaConfig &config, VeriPool &vpool) { + if (theSig == nullptr) + return promise_t([](promise_t &pm) { pm.resolve(false); }); + return promise_t(vpool.verify(new SigVeriTaskBLS(obj_hash, + static_cast(*config.globalPub), + *theSig))).then([](const promise::values_t &values) { + for (const auto &v: values) + if (!promise::any_cast(v)) return false; + return true; + }); + } } From 05ee5f447df74b6f42eb5265daeb3b26751e8b31 Mon Sep 17 00:00:00 2001 From: Ray Neiheiser Date: Fri, 19 Jun 2020 19:24:48 +0100 Subject: [PATCH 02/11] Fix ser/des, fix verify/sign --- hotstuff-sec0.conf | 2 +- hotstuff-sec1.conf | 2 +- hotstuff-sec2.conf | 2 +- hotstuff-sec3.conf | 2 +- hotstuff.conf | 8 ++++---- include/hotstuff/crypto.h | 19 +++++++++---------- include/hotstuff/entity.h | 2 +- 7 files changed, 18 insertions(+), 19 deletions(-) diff --git a/hotstuff-sec0.conf b/hotstuff-sec0.conf index 5148c495..0a264df3 100644 --- a/hotstuff-sec0.conf +++ b/hotstuff-sec0.conf @@ -1,4 +1,4 @@ -privkey = 0bd129220239d6a0b23cb2e942152260ea8dba1deff40c3bae840d747fcd137c +privkey = 2f055108a3e61a827298b5e1f0bc6915fc194ecfbaad33ba5516a63c8880319b tls-privkey = 308204a10201000282010100c5a358cee61ca7592dbe62cd28225426dc3fc65b33432043efb5e8fcfaf334720b2000d10c422172e6f94f82746928a6d51193342a1555684eedb141321170cb02cc7b189f5506cc30cb5c26d9b84123328ed6df61fc1a6582b046def7a662bb15d84e29ffa279f1d853c25ca79fbe3fab0200f8c85566a5eedb98df4a958e8512a647258e55a7a56c1ca8b05607b38b01b6a2669af9a70efa59141f6079341c6044f615687be756d4830ea359139ea35e23f34ce226215a1a2fb8271cc60a037841e44c460e149a71d3e2fa907a48677ad18af2e7348343932f5f29ac5241cd20ce64e6798ada684164cd1109c3a969662d9aaf9897fedc5a4e256eb92bf7bd02011102820100516160cdaa0bcc7003c6dd6388ff139787de0661c9d0589471c35fefb2a060e3aa3a5ab06e75954d6e2a6c088a496b1784e91e7ee426e6eeb7169448058eb5f93d6341bed83211db9b9f07d3c30fa259c9861c3ddd0d7447ea84d1e356ea28a7635911205a33d7dc0dc822dadb9c2129466a3ca2acd7def9080011c55af249bd98e3f84a5475a43cc0369cf7fa5e4ecdd1c09ac0b0a41bd19d8af70cad8f1b6aec66a22179e5dbf9c446c645e9daa9080b455fca64365d8e02a686fbd707198302db43cd37629033574561c025d89d29c393746ce12fa01bbe60feb3fab292928ead3f8f6def6b9a7dffcd2139f6e8d1f79844d216b28dfae29dc6ba8c11063102818100f770f6dea12236dd39cb46ba96c171f3cfa92c961a12bfb62108e82e0bac280554a9ad4b99c4faee9287467573eaf6cfcba360753668c40ab1b015fbbb95f6a2d3c2402966971fa54540befdc39b58962f7d0cfaa96ff268df02efab32238544ed75fd6586bd93e38934c9d59b037f3cd7f727b38c854e1061de1f68bf43a26d02818100cc7963002015bd593af15276f185cb5a34a76bb36633c85bc86c6640419612a5a8eb2cc1a6ad43e51c2b545f88a7e8c0096a6110b85de7d1f458eca33267f9fde6b4489e346304787d33c8e1033e96b502a53ea6ad2c55299cae973719587d24468f164930f58a56aac2c7eabd68870a1056f06b8bcec5b3d2156c8a1375d89102818048c6df326ba0a6b9897805be68933fa20fe676868023a1cc27d57176f45fcf8918e69c61879449cdb2a041e64f451b6a4af3d1136a5b0c7b9dac42b3736857994d57400c2d3b81c7327c7468c10f9286867012e04ff3bfc47dd3afe70ebf273263f586c381fb85d982b52c4de24c52996cb21abc56818f6e3ae6fa2ddde6b74d028180180e47e1e5a83464d9c209b3a3f19f740631d06f756f80fbbd39ede97120b6e6501baae99b2371663f8ca083b5b966ad2e48c02015b0b1dc77198540604877c3848dae30bade78ff1dc9db65c4257b245aaa075ee732645f3f9c11ca3f37964080c58a26ba773d739b9e71df6193d3a6d4beef1bb618537e912fb26a98e0b01102818100950d7d5ec366f8bca918011359590c6e7d6fe4d3e8922d68468c3e24277f27621db17cb41d0dcddf1f77e289e49dc92101d8544e84281ec7732fbfd4e9194924a2adac4e22ef79c2ad61428f1fa03e6affa3b0de07f857de87a2e758953122b0d693cf49e54ede4eba44dcdc2c5cbd6751af5117fd107fc0e4ffb18f8774d79e tls-cert = 308202e4308201cc020101300d06092a864886f70d01010505003039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f7374301e170d3139303730323036353535365a170d3139303730323036353535365a3039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f737430820120300d06092a864886f70d01010105000382010d00308201080282010100c5a358cee61ca7592dbe62cd28225426dc3fc65b33432043efb5e8fcfaf334720b2000d10c422172e6f94f82746928a6d51193342a1555684eedb141321170cb02cc7b189f5506cc30cb5c26d9b84123328ed6df61fc1a6582b046def7a662bb15d84e29ffa279f1d853c25ca79fbe3fab0200f8c85566a5eedb98df4a958e8512a647258e55a7a56c1ca8b05607b38b01b6a2669af9a70efa59141f6079341c6044f615687be756d4830ea359139ea35e23f34ce226215a1a2fb8271cc60a037841e44c460e149a71d3e2fa907a48677ad18af2e7348343932f5f29ac5241cd20ce64e6798ada684164cd1109c3a969662d9aaf9897fedc5a4e256eb92bf7bd020111300d06092a864886f70d0101050500038201010009fc34f2835e4c14de1e03202c0f0884acb51e7568b286a9b3a374e8b69f304600a2787303cd382e52923db352cf91587ea7a33da5116c886c67775b5f96357971dddb568948fbb12987523a8be0e2e537284f8ee591af17c6d58410e41d32fc634f99289089915fb4273feaaca45d3442820155f5014fbd5d19fef7954729e4439218cad6a83b9dcd21834aaec379a276f163599cdac6b9513d0c07310852bb4104a58141a158d302908c23761899a4c68c3bf81115f302d41f42ff38150c0b7dc798fd7319abec6bd9365e00bf0a0998c3b97fe4834f0688e95d1eea4df4031274c781c6661cab085d629cb924c5c65b865ae98aa2349875fafe62b7eacbc5 idx = 0 diff --git a/hotstuff-sec1.conf b/hotstuff-sec1.conf index cafc547e..7b506379 100644 --- a/hotstuff-sec1.conf +++ b/hotstuff-sec1.conf @@ -1,4 +1,4 @@ -privkey = 6140f1ddab14281130b6e713dc0066c0b384dc1131d6a743bbf0774050359b32 +privkey = 6a85834d2de6a711a6cb0e6151123d76d982d274f611a6ad310a018d333bdae5 tls-privkey = 308204a20201000282010100abfe4a55f831720dd46e2bca05e767aef9838d2069f893f3213bf5a31f5be249c2b356476e01d3fc221581bf4ffa93a6ec41898fbed6119b7981065d07fe476fa12b7da4a22f37d4cfc8a667ff163c05d17762f789df64995a1e80c50ed0d1f7ab8e733fb543d962818ce3ba7b38bf4fe0ca39926b6e99e3fa32eff48f503cf7f66824573e9fb34cb9c4e952f0f584d30c5b7312172facb0439ed5af6d0c6f7382db15315dce8f2fe1704f11bd76e5e3fbffd6f44b240036492187a13e23c0cc8769a52f5bbc90400867093d031483b84fe5c40a7ce66d7dab7a474689de080cc2b6670359f08d5bff53cfa92bf49fc306cccfe0b6fed8c6e4edef86d81638610201110282010100a1e045f68f3d98857ca3ecfa5fe8da0e180357a609626d2110386eb7a50b2f547b032406fe1fd692f2e710b40f09f460de5bccc3866f1fa1634c423970ef524af20ad09af2ff439b1dea060786ab83c93d9d8a5263a5136327a43cf5b3975c34653ac6d28c7c17e43db1c746199ed22d0fcd635ca159094f09995a4f95f12a513ebec6fe1af47c260090fcf8908e04192bb8b9a9c75608d221110d183a80380193b076354b2cb396500c94c8ca33e45559eeadefe217ef04898a2350390fadcf3e4ccb4d1783c619168c9fe7e29701f15476e980408975050d0a8e5df4e4ea35dc6fe3e3f71964952cf600c45d88688b5e92cf5144d869448290e7cefc8f793102818100d5c267d9f5b82ce47e3b7e3fa80fa599b73406b21d240c863bfc4c20d858c729d96e89adc0e51aa6248112fb351bcf5102dada449b5226842d9e7482e65391b8e89a8a0982a1f1b0e75922d416e45f28a06842d4ef00d9c7c8fa43d47487e79121e69d25f5dbbdf49ea85dc7035cb7a92fa79cad5666a2bd4bcd29be9ec31fff02818100cdfb090f4c43c27fdaef5e4b2f4efade96b3271b964036cac4806ba4d68b6cc7fc810deafd09f5ba07e1de013183f3f8499763e0cf986bbd49604d991b2f86676c9d8323f01e9c1479187c828b6fb27f45bf291d4953876084a4cc2e4122e7a26698e7bb2d89d488e0e611118536f905c2a936ed07724630ce66cf7c4cfaa79f0281810096e39499daa01fb0591aefb476a1a21226f78c417dfb542284b2179eb6d5414ab79952204bed03c0923cfe56f84fdda2989a7bf431672a3f2f42ac98a29557cdd15e0715c59f7d6dd07b27a4c4dd7058e9b301ffb7c45d7df7473ef05241d0a2ae84ab29dab93acaca58baaa98f6274a3fc19bc5a66690fe1763a4ff06a7da59028180792a41908736eae1cc145595a35ba2a10d5a533d6771112bfb1e5d7005bb6d2a584bea11c205dbd6d775cde29598e9dd58772bb16b0e5d7e6765d34b00eec78821c610e7f6a8980c0aff584cca7df08719f7fa113a31227502bb4aee0832a65f87a53d04b16022aadea57373b7c5fbe545547aa98be8ddfe9787c5582d48265d02818006385a17426489bc3393300bfec08c440cbfd894d991b1c1e1b672f17809ff150703496fde8df3bfa9d67553f0d6d4bb1bf73706454470479fc4aec0250b0613bd028cc111f61edfeb6ad40e6801fc22afcb67788a7a514c5b3f04a3986dbf063f4277bcf5182763242781f8ba6b2cb3a8cb909332f9b1966601675297a601cf tls-cert = 308202e4308201cc020101300d06092a864886f70d01010505003039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f7374301e170d3139303730323036353535365a170d3139303730323036353535365a3039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f737430820120300d06092a864886f70d01010105000382010d00308201080282010100abfe4a55f831720dd46e2bca05e767aef9838d2069f893f3213bf5a31f5be249c2b356476e01d3fc221581bf4ffa93a6ec41898fbed6119b7981065d07fe476fa12b7da4a22f37d4cfc8a667ff163c05d17762f789df64995a1e80c50ed0d1f7ab8e733fb543d962818ce3ba7b38bf4fe0ca39926b6e99e3fa32eff48f503cf7f66824573e9fb34cb9c4e952f0f584d30c5b7312172facb0439ed5af6d0c6f7382db15315dce8f2fe1704f11bd76e5e3fbffd6f44b240036492187a13e23c0cc8769a52f5bbc90400867093d031483b84fe5c40a7ce66d7dab7a474689de080cc2b6670359f08d5bff53cfa92bf49fc306cccfe0b6fed8c6e4edef86d8163861020111300d06092a864886f70d0101050500038201010069f87140cc279dfc03b89cd6de3833aa7bb824f522b46943d8ea32c0bf24b2a7d7b77da04a359fe4fa840770552794836dc6cdbf80396ab87edfe5df187915cb94ef4b142b8b20c438b54608059fca91f5792a39bfaea547c6a56fac3ae165ce89d29e7af5f914304da4aabe02961f5dab7dc94124837539958015d89a22eedfd42981819004d1af6342498aa43f58cf84c391e0427835407089d0e95b5fdfe350974cb507dffeca15e55851e03b68ce4ac640ca898ea6a75a7f5469f677f74a14d05ce4bbd44e8a2a70366edb94f6e8706246dd904847e37abe3116320dc1688a4788a8600bf7ae05932541be665efb5b564c3c964504555f09175494517469 idx = 1 diff --git a/hotstuff-sec2.conf b/hotstuff-sec2.conf index 17bc812f..94df021b 100644 --- a/hotstuff-sec2.conf +++ b/hotstuff-sec2.conf @@ -1,4 +1,4 @@ -privkey = 65b19963364811f65bf8731f93d2ceb045b931f989b7d2c36fed0f5813e1f62e +privkey = 1dc6ba158efa514f46e70f68e8b60a636e04b5994b93569461b754aa34cde814 tls-privkey = 308204a20201000282010100c1460bf8018ceec075d67405e96e056e2e3acf9c7c2d7d28ee6edfe9ee8fbeef0e978ac874ceff3ee770dafde1d019d9920b2ff334a3ac115bcf95e2bdc0b70faf46b8f13c46335c4815c72d75b488de46b96f8582446e886c6b7fdfb479bc40a0da03b7c4e414fde9ab44b1957e39c5e5c167ba88a233854f29404a1f35aa29994bcd7a62b57fc2000850c37569a8a1bfa75e6e06c54c40633e0fee1672c1f97689aabee650285a41fd6df24f20cd94733aeccdae68debba30a3588b71625f9ec7669d3f4c51317192f5acdee9b968d1a6db4a98a9c0eeef63a969c2ecaba95a9ddfd5841d996977696e41a541393ba40ae44b71c00129a25b30f6c44e89d8d0201110282010071b0bbbf0ff88c713641e9e55c2299c8576de38939fca3f9f5aaa1d4e6aee8c8db683384f96ab4431ebadb2bee3e2d52ce60ef07886047194510b285608f7abdeea2126fc91a3c5466a3661abdb57dafed5e055d97ec04c8b83f3c293cfc509e7cbc7aa855b357a46b55afeffd958b6559f94c135f6e78a8c52752fe6cb627db36195ca7e30537e3a1a2cfd2dfe23c2f6c9c91a45119e8b6c128dce763157d4f21350c7293f4cc7c96201e3b63484e22b6308c2d9351e1c5b833bcc301c68f9111c10c9e79ee6f590ce7cff86e1c8e6bf970d8d0e2d0bc32a6c06997e3cdcad17657cfa6d0300966fd1c0a4ad5e9817ab4d41b5ff0010ce93c08eae7ad053ef102818100e8b87e8ca3a329afedda121b2f005533749b067a3f9b38f43252f760ed18a9cdea42bd14a3b0ac599dc6c00fb873303713e030507fda557ab3de70864de60cba13dde108eedfe57df0a5fcbe3062b0cfce80aab3739e7f83b5534215c01830234bd439afdd02fd0755da8eb9c56466c762fb3c8cec5fa4229c8e94092db7b24102818100d49b649d2389770f18ffdd5b6368b9ea78cef9f60a17a148b558d43700e8c3250706588113e5b9f9a50014173ab2b2225cd50162e750230a693a37507fc4f1fc6d9d268a69cfd6b4f8ff494fcfd526d28a46cc92fbcde915256d076a9ea17e74ae747c4002eb56610c0caa47bca2373bdd7da66d7e050bb7d64885a60aa8004d02818100b1f67ee404a9f2b3b5e2fec97e4b8c72a4768c7b9a0d49abae0335a47912dc340d7e545b13c3569ee21074c0ba39f7b1a5c98e5bad105f7bf2f5651b68befaac698b8df7c5ba46150351c14625002cdb2571737a2b3cf8196c8af64cde309d482aed95867bd51bd86ed44f0687e35da787ed4c6bc3d0aab10e4ee9acaa7d6a31028181008991b992dac25c18d3f0da866d7fffd3f3d13853e869a4987557985fd3696f36139ab1bceec1d2b097f0fdf0e9beebbbe1b700e5a4bb61f7ad8005ac8ee8d8d08329734a80b3a90bb02cb6f7685cbec477973913d01bd30daece13db93d1e8699e0f23387a5c0ab7440831f22ec350ea80423e83154e8f1c99b674989d7bc3f5028180267c5167cd1f8dce4b15611b8ea0220e6be74efbf55e3bf4a775b1edf0e49b377c12f49fbf683f24e1850c455b8b7a96d0c7eff9f47661ec75004a2a435dd741e7d7bb6423fa576053a0677b2a0b714e7fadcc37c03dc9da053069477c1ce0afac316c1c63ffb510d30e11adc0865e94177f3545c0594860c10baa51bc074e4c tls-cert = 308202e4308201cc020101300d06092a864886f70d01010505003039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f7374301e170d3139303730323036353535365a170d3139303730323036353535365a3039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f737430820120300d06092a864886f70d01010105000382010d00308201080282010100c1460bf8018ceec075d67405e96e056e2e3acf9c7c2d7d28ee6edfe9ee8fbeef0e978ac874ceff3ee770dafde1d019d9920b2ff334a3ac115bcf95e2bdc0b70faf46b8f13c46335c4815c72d75b488de46b96f8582446e886c6b7fdfb479bc40a0da03b7c4e414fde9ab44b1957e39c5e5c167ba88a233854f29404a1f35aa29994bcd7a62b57fc2000850c37569a8a1bfa75e6e06c54c40633e0fee1672c1f97689aabee650285a41fd6df24f20cd94733aeccdae68debba30a3588b71625f9ec7669d3f4c51317192f5acdee9b968d1a6db4a98a9c0eeef63a969c2ecaba95a9ddfd5841d996977696e41a541393ba40ae44b71c00129a25b30f6c44e89d8d020111300d06092a864886f70d01010505000382010100706c7eb29939c38cfcbab592c62a3572e05dcaa4d54e24cce74a244972e74ac8ed6e0b3eb1add0d4de6007d392ac75a7fb9836a9a1d937d0b2c3f01a6b1994ac317328527c763eae26a6ca647752badcd09e73364ac7828d375b4966e510de1cdbd01a5be047e45533f5a3d81df00ffe9d13fe5d54e18584691abb3a9a3d423d348d7714382317547338a8e83d14f404348db41c10a05e57221eda1e220b265ae4237e59ab2db1facbe8cc8d2198ca5fe2ad074bb8c7c4dd675cbe3d60b9e29f6b12ab4c587c6576e1ce2d2512be035e4692100c6c3e47d4d84dbbc865804af1bd0240fb804ef99c7038191dae2fab73a1a1ffa09f536a0fbf49fa1a3234b62a idx = 2 diff --git a/hotstuff-sec3.conf b/hotstuff-sec3.conf index 8d8c43d7..feed5f33 100644 --- a/hotstuff-sec3.conf +++ b/hotstuff-sec3.conf @@ -1,4 +1,4 @@ -privkey = 19231fb2a3d594503401570c698c5a2fa12abbd6f7978ebaca79d5bbcad22470 +privkey = 30a444081a5c13cbb9606908caeb7fe6611a4042bb2efb6de71e9f918d36592a tls-privkey = 308204a20201000282010100de01b461213afa37d4aa68bdc7e1a6de12307440f1de6588e5362450694cbb4ba63b1f992a7dc88b999c7dec9088d17253ac278c33018ea8caa1f96c7d90bcb5a6a3f8568825bafa9a696699a4eaf0c6fcdd8ed7bc91a688ead564fb882a1c25c7f72bbe44eb44fda1d11d6ca090503e36de532f2fededff03da30f8f95f11b6472e9588fd6be69cad285915c68edaa7754c6524017bf08c3c336f04d0246d8e967a4de2824a3ac7486aaf9160540c63f75d36ecba9261ff6b859a7684b023ecfbc5408dc7c59942c76464040770c6097833dd770a7dffc6ed6a8716b1f683379843969f937d859d8f69a21362eda9dabd64dd6fb7131ee46b2654d3aa8dc9df02011102820100414bcba418d51c6ac61400b049d8f4d7e73b6d7c835f8746618865089770ebcaf4a7fa3c1b8e68290f0fe8cd1b7388e563e756ecfff16631a5027689521b82cc03d5dfa0faddebb31e5b3c4b4e9f73fe4a5f48215594400a26f3780dbea2f93849df4919d808f62c7ae326c598a2ea6ca6b9dc3b0e18cd873d5e4aa394a37dad88a49b91b7446343d03d4ea067b72c62ba622d68f7fb97c031a7f9259401318905e092b0aec27e643fb3efd9bf392050941d43fe06a87630412bf765a4800f57561a9fc339ff92a9b33e748efe5c6ddafe4069e99cf039794b4641ab4f199703860b4f8ee3669a04ad664379012650e68debe0ccc4c41a39e6bf8a3de15003f902818100f56482abd14db0f327311b376dc4cfac86cc3379036b6672713d296a0665797de7b115350d77a27193de1f5abd9e2b44eff6c5a323b1209c4aac68c86e3488abab89139a7cbb98a4f0c1e930c2bc276bbcf0efd47cf4dc6614b9c16c332a5f7ef339d5c746780884a66e087236ec784361fda7e72c21528c0427d7abbc9751f502818100e79a68542368e4295b8d3289c4f4da780e6597461952b9592221901b05bae53ece00df87ef7084340f28c71f188d400d0fcfbd504d0ae2bf101082214d9500b1f8480dc1ec3ea7900ece21b9e3e0c2b5279b1f21de585ff7a58eb330d841ef13107ce58c14a8a4a29b6cb438f4e551baac120603878a3ff9f00cda5589800403028181009ec890c9876e818e46892fba74340de81afc99c6c5fa333afdfa66176d8cf44268bde08bbd6b873a6ebce71c98cfc1a513bdcb2d53547e833f60800938401c32d867c163f65b44a6f6231e6ad85ba1097a418c20149e707e49a55f09c6c1109d70347b44b5207dfb7abfab1cba208a0d7ba4215958ca4478b7651314c552daad02818100cc5b10c2b5d5058de75e77e2f914484bd077c1b652944930878706ae6e77bb376a793db42d9f83b576c9a0a2f78bb0fc775cf255e9a0317b68870968adddd36fdb12667dee91a2e88588b458ba028daee6b60c692d99459e46c934b2a0b2a5c58704ca8aa8d109bca741cc32417f0be0f22e054e68890b45f1ed391e4c25a92f02818016d4c0a1d4cc7fadb7033ae8506221a7dde9c2437fe5989175e8de47791b4ff957fb485d6d04c85b9fd1d7734950dc4d032dd3fdf9c14193b04ea179839fb4560282d106b684b5712a9b140afbe4d92ff30c745a7bdca71de9808f6d2a88340e116cc4475e908993c27a27847601ec378d4357dc5e99a147c60d7258e282453e tls-cert = 308202e4308201cc020101300d06092a864886f70d01010505003039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f7374301e170d3139303730323036353535365a170d3139303730323036353535365a3039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f737430820120300d06092a864886f70d01010105000382010d00308201080282010100de01b461213afa37d4aa68bdc7e1a6de12307440f1de6588e5362450694cbb4ba63b1f992a7dc88b999c7dec9088d17253ac278c33018ea8caa1f96c7d90bcb5a6a3f8568825bafa9a696699a4eaf0c6fcdd8ed7bc91a688ead564fb882a1c25c7f72bbe44eb44fda1d11d6ca090503e36de532f2fededff03da30f8f95f11b6472e9588fd6be69cad285915c68edaa7754c6524017bf08c3c336f04d0246d8e967a4de2824a3ac7486aaf9160540c63f75d36ecba9261ff6b859a7684b023ecfbc5408dc7c59942c76464040770c6097833dd770a7dffc6ed6a8716b1f683379843969f937d859d8f69a21362eda9dabd64dd6fb7131ee46b2654d3aa8dc9df020111300d06092a864886f70d010105050003820101007f9d4f2848059831e5ea7d727d9b09f826027c78fdc86d27ea83d32d727ac4a0484e55ed34851adcc8903a3ef39c1b0c447c28cd84cbc513cdcd607da3fa903495a70b7772e71873e3c8a734d3e8b9f82c7380604ccb8416bd92822e703a3b8839aff411f967d2bcc1cd96d158e7839a2bff6110ffd005808f7047fd57a7150c1e14ddcfd2e1a24a5878f99409b7ede1d5f4a385077b6f55f4818c854c6e64adb4789433667e672b9a615b680301a05852255cef958ff1031a489dd95327d045be0315359644ec51f2fd3cb724382ba2425da519dbf1d89098e10a1091f44c7a8e12733b7d0b1fce7c6d19adfee3cdac89f95ed1ae979093cb2793892724d7d9 idx = 3 diff --git a/hotstuff.conf b/hotstuff.conf index 148cb54b..94d43b8a 100644 --- a/hotstuff.conf +++ b/hotstuff.conf @@ -1,6 +1,6 @@ block-size = 1 pace-maker = rr -replica = 127.0.0.1:10000;20000, 0bc7e156bad174ab1e176b25663589b3b457aa89d1cf30dff94670d5318caf070f2fbad7d598d737933d94933ee728ca, 542865a568784c4e77c172b82e99cb8a1a53b7bee5f86843b04960ea4157f420 -replica = 127.0.0.1:10001;20001, 8a5b14563257919307d7db01da5528ae35aef89fc524ab08ae5d5f5e0b534324705dc3d868f81f1f35b7fca0a57f2d8a, c261250345ebcd676a0edeea173526608604f626b2e8bc4fd2142d3bde1d44d5 -replica = 127.0.0.1:10002;20002, 018f7f4c04024d10277ab087a5a19df65808e1f0286ac064f29d2ff49bea57a81d2dcec4c0ccd5d63fddc803393024e6, 065b010aed5629edfb5289e8b22fc6cc6b33c4013bfdd128caba80c3c02d6d78 -replica = 127.0.0.1:10003;20003, 99590c2344ba54efab5583a21def085c1b8e58172d660e87e024692765335139874114cc5779c19203eec5a1529fc1c0, 6540a0fea67efcb08f53ec3a952df4c3f0e2e07c2778fd92320807717e29a651 +replica = 127.0.0.1:10000;20000, 8a0f04a4d41e7a993336d3f5cb5f32d2fa468af5ceae179b1b9f1c6e698da5c98ccc8cfcc4226f8c3eaf466941c6c8f9, 542865a568784c4e77c172b82e99cb8a1a53b7bee5f86843b04960ea4157f420 +replica = 127.0.0.1:10001;20001, 03d1052326a84450c0086f64515a71524f8f5e13cd49ca0fddf692204bde34c7e036b201668704d9ba77cb62e38cae81, c261250345ebcd676a0edeea173526608604f626b2e8bc4fd2142d3bde1d44d5 +replica = 127.0.0.1:10002;20002, 842d687d00d36f21f971858ab7cb6d5fccc6f95c016abb9f69e3598ccb4d29efa998d5243308df0a107fb0369f59cfae, 065b010aed5629edfb5289e8b22fc6cc6b33c4013bfdd128caba80c3c02d6d78 +replica = 127.0.0.1:10003;20003, 81c8addfbeae6e7fc06dbad0f4db0b438dffd62cf235c770f776b3c96c866f7a74ad0ddda5281df2c3635a77a4bf7e85, 6540a0fea67efcb08f53ec3a952df4c3f0e2e07c2778fd92320807717e29a651 diff --git a/include/hotstuff/crypto.h b/include/hotstuff/crypto.h index c5951d3c..f81bef83 100644 --- a/include/hotstuff/crypto.h +++ b/include/hotstuff/crypto.h @@ -592,17 +592,18 @@ class QuorumCertSecp256k1: public QuorumCert { void sign(const bytearray_t &msg, const PrivKeyBLS &priv_key) { check_msg_length(msg); - std::cout << "sign: " << msg.data() << std::endl; - data = new bls::InsecureSignature(priv_key.data->SignInsecure(msg.data(), sizeof(&msg))); + uint8_t* arr = (unsigned char *)&*msg.begin(); + data = new bls::InsecureSignature(priv_key.data->SignInsecure(arr, sizeof(arr))); } bool verify(const bytearray_t &msg, const PubKeyBLS &pub_key) const { check_msg_length(msg); - std::cout << "blah1" << std::endl; - std::cout << (unsigned char *)&*msg.begin() << std::endl; - bool res1 = data->Verify({(unsigned char *)&*msg.begin()}, {*(pub_key.data)}); - std::cout << "blah2 " << res1 << std::endl; - return res1; + uint8_t* arr = (unsigned char *)&*msg.begin(); + + uint8_t hash[bls::BLS::MESSAGE_HASH_LEN]; + bls::Util::Hash256(hash, arr, sizeof(arr)); + + return data->Verify({hash}, {*(pub_key.data)}); } }; @@ -630,9 +631,7 @@ class QuorumCertSecp256k1: public QuorumCert { PartCertBLS(const PrivKeyBLS &priv_key, const uint256_t &obj_hash): SigSecBLS(obj_hash, priv_key), PartCert(), - obj_hash(obj_hash) {} - - PartCertBLS(const PartCertBLS &obj) : SigSecBLS(obj) { } + obj_hash(obj_hash) { } bool verify(const PubKey &pub_key) override { return SigSecBLS::verify(obj_hash, diff --git a/include/hotstuff/entity.h b/include/hotstuff/entity.h index 19127857..b0fa723e 100644 --- a/include/hotstuff/entity.h +++ b/include/hotstuff/entity.h @@ -65,7 +65,7 @@ class ReplicaConfig { PubKey* globalPub; - ReplicaConfig(): nreplicas(0), nmajority(0), globalPub(new PubKeyBLS(hotstuff::from_hex("8cb772444852e35624d70af1140d63c84fbf5be339bc0da0feb35fcd36ba81c35ebe3150c0b3f71233b6919385d7d561"))) {} + ReplicaConfig(): nreplicas(0), nmajority(0), globalPub(new PubKeyBLS(hotstuff::from_hex("8df60c260df14181197974051be16d9a8485c6c828b1d4f241da11bc60c7d068f0ad7e0c1d269fc7aa86f2b9204e1ca1"))) {} void add_replica(ReplicaID rid, const ReplicaInfo &info) { replica_map.insert(std::make_pair(rid, info)); From a6364aee34d7bcf51a3e19b6ccb74e91e529b21e Mon Sep 17 00:00:00 2001 From: Ray Neiheiser Date: Fri, 19 Jun 2020 19:36:34 +0100 Subject: [PATCH 03/11] fix combination of signatures --- include/hotstuff/crypto.h | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/include/hotstuff/crypto.h b/include/hotstuff/crypto.h index f81bef83..62b3cc3d 100644 --- a/include/hotstuff/crypto.h +++ b/include/hotstuff/crypto.h @@ -689,18 +689,15 @@ class QuorumCertSecp256k1: public QuorumCert { { std::vector sigShareOut; std::vector players; + players.reserve(signatures.size()); for(auto elem : signatures) { - players.push_back(elem.first); + players.push_back(elem.first + 1); sigShareOut.push_back(*elem.second.data); } - std::cout << "Try combine?" << std::endl; - std::cout << players.size() << std::endl; - std::cout << sigShareOut.size() << std::endl; - uint8_t* d = obj_hash.to_bytes().data(); - - theSig = new SigSecBLS(bls::Threshold::AggregateUnitSigs(sigShareOut, d, sizeof(d), &players[0], 10)); - std::cout << "those5?" << std::endl; + + uint8_t* arr = (unsigned char *)&*obj_hash.to_bytes().begin(); + theSig = new SigSecBLS(bls::Threshold::AggregateUnitSigs(sigShareOut, arr, sizeof(arr), &players[0], 10)); } bool verify(const ReplicaConfig &config) override; From 71cc62b416d405fa79b090f3fb2e4b8a12465242 Mon Sep 17 00:00:00 2001 From: Ray Neiheiser Date: Mon, 22 Jun 2020 11:21:45 +0100 Subject: [PATCH 04/11] updates --- examples/hotstuff_app.cpp | 13 +++++++++++++ hotstuff.conf | 3 +++ include/hotstuff/consensus.h | 3 +++ include/hotstuff/crypto.h | 11 +++++------ include/hotstuff/entity.h | 2 +- include/hotstuff/hotstuff.h | 4 ++++ src/consensus.cpp | 4 ++++ src/crypto.cpp | 17 ++++++++++++----- 8 files changed, 45 insertions(+), 12 deletions(-) diff --git a/examples/hotstuff_app.cpp b/examples/hotstuff_app.cpp index f093ca55..3584400f 100644 --- a/examples/hotstuff_app.cpp +++ b/examples/hotstuff_app.cpp @@ -132,6 +132,7 @@ class HotStuffApp: public HotStuff { const ClientNetwork::Config &clinet_config); void start(const std::vector> &reps); + void set_master_pub(const std::string &master); void stop(); }; @@ -173,6 +174,7 @@ int main(int argc, char **argv) { auto opt_notls = Config::OptValFlag::create(false); auto opt_max_rep_msg = Config::OptValInt::create(4 << 20); // 4M by default auto opt_max_cli_msg = Config::OptValInt::create(65536); // 64K by default + auto opt_master_pub = Config::OptValStr::create(""); config.add_opt("block-size", opt_blk_size, Config::SET_VAL); config.add_opt("parent-limit", opt_parent_limit, Config::SET_VAL); @@ -197,6 +199,7 @@ int main(int argc, char **argv) { config.add_opt("max-rep-msg", opt_max_rep_msg, Config::SET_VAL, 'S', "the maximum replica message size"); config.add_opt("max-cli-msg", opt_max_cli_msg, Config::SET_VAL, 'S', "the maximum client message size"); config.add_opt("help", opt_help, Config::SWITCH_ON, 'h', "show this help info"); + config.add_opt("master-pub", opt_master_pub, Config::SET_VAL, 'p', "master public key for BLS"); EventContext ec; config.parse(argc, argv); @@ -283,6 +286,11 @@ int main(int argc, char **argv) { hotstuff::from_hex(std::get<1>(r)), hotstuff::from_hex(std::get<2>(r)))); } + + if (!opt_master_pub->get().empty()) { + papp->set_master_pub(opt_master_pub->get()); + } + auto shutdown = [&](int) { papp->stop(); }; salticidae::SigEvent ev_sigint(ec, shutdown); salticidae::SigEvent ev_sigterm(ec, shutdown); @@ -290,6 +298,7 @@ int main(int argc, char **argv) { ev_sigterm.add(SIGTERM); papp->start(reps); + elapsed.stop(true); return 0; } @@ -412,3 +421,7 @@ void HotStuffApp::print_stat() const { HOTSTUFF_LOG_INFO("--- end client msg. ---"); #endif } + +void HotStuffApp::set_master_pub(const std::string& masterPub) { + HotStuff::set_master_pub(hotstuff::from_hex(masterPub)); +} diff --git a/hotstuff.conf b/hotstuff.conf index 94d43b8a..ba68173f 100644 --- a/hotstuff.conf +++ b/hotstuff.conf @@ -1,6 +1,9 @@ block-size = 1 pace-maker = rr +master-pub = 8df60c260df14181197974051be16d9a8485c6c828b1d4f241da11bc60c7d068f0ad7e0c1d269fc7aa86f2b9204e1ca1 replica = 127.0.0.1:10000;20000, 8a0f04a4d41e7a993336d3f5cb5f32d2fa468af5ceae179b1b9f1c6e698da5c98ccc8cfcc4226f8c3eaf466941c6c8f9, 542865a568784c4e77c172b82e99cb8a1a53b7bee5f86843b04960ea4157f420 replica = 127.0.0.1:10001;20001, 03d1052326a84450c0086f64515a71524f8f5e13cd49ca0fddf692204bde34c7e036b201668704d9ba77cb62e38cae81, c261250345ebcd676a0edeea173526608604f626b2e8bc4fd2142d3bde1d44d5 replica = 127.0.0.1:10002;20002, 842d687d00d36f21f971858ab7cb6d5fccc6f95c016abb9f69e3598ccb4d29efa998d5243308df0a107fb0369f59cfae, 065b010aed5629edfb5289e8b22fc6cc6b33c4013bfdd128caba80c3c02d6d78 replica = 127.0.0.1:10003;20003, 81c8addfbeae6e7fc06dbad0f4db0b438dffd62cf235c770f776b3c96c866f7a74ad0ddda5281df2c3635a77a4bf7e85, 6540a0fea67efcb08f53ec3a952df4c3f0e2e07c2778fd92320807717e29a651 + + diff --git a/include/hotstuff/consensus.h b/include/hotstuff/consensus.h index e2f7cfca..11726ea6 100644 --- a/include/hotstuff/consensus.h +++ b/include/hotstuff/consensus.h @@ -82,6 +82,9 @@ class HotStuffCore { * functions. */ void on_init(uint32_t nfaulty); + /** Call to initialize the master public key.. */ + void set_master_pub(const pubkey_bt &masterPub); + /* TODO: better name for "delivery" ? */ /** Call to inform the state machine that a block is ready to be handled. * A block is only delivered if itself is fetched, the block for the diff --git a/include/hotstuff/crypto.h b/include/hotstuff/crypto.h index 62b3cc3d..d5e39140 100644 --- a/include/hotstuff/crypto.h +++ b/include/hotstuff/crypto.h @@ -318,8 +318,6 @@ class SigSecp256k1: public Serializable { bool verify(const bytearray_t &msg, const PubKeySecp256k1 &pub_key, const secp256k1_context_t &_ctx) const { check_msg_length(msg); - std::cout << "blah1" << std::endl; - std::cout << (unsigned char *)&*msg.begin() << std::endl; return secp256k1_ecdsa_verify( _ctx->ctx, &data, (unsigned char *)&*msg.begin(), @@ -666,11 +664,11 @@ class QuorumCertSecp256k1: public QuorumCert { salticidae::Bits rids; std::unordered_map signatures; SigSecBLS* theSig = nullptr; + size_t t; public: QuorumCertBLS() = default; QuorumCertBLS(const ReplicaConfig &config, const uint256_t &obj_hash); - ~QuorumCertBLS() { delete theSig; @@ -695,9 +693,9 @@ class QuorumCertSecp256k1: public QuorumCert { players.push_back(elem.first + 1); sigShareOut.push_back(*elem.second.data); } - + uint8_t* arr = (unsigned char *)&*obj_hash.to_bytes().begin(); - theSig = new SigSecBLS(bls::Threshold::AggregateUnitSigs(sigShareOut, arr, sizeof(arr), &players[0], 10)); + theSig = new SigSecBLS(bls::Threshold::AggregateUnitSigs(sigShareOut, arr, sizeof(arr), &players[0], t)); } bool verify(const ReplicaConfig &config) override; @@ -725,7 +723,8 @@ class QuorumCertSecp256k1: public QuorumCert { bool combined; s >> obj_hash >> rids >> combined; if (combined) { - s >> *theSig; + theSig = new SigSecBLS(); + theSig->unserialize(s); } else { for (size_t i = 0; i < rids.size(); i++) diff --git a/include/hotstuff/entity.h b/include/hotstuff/entity.h index b0fa723e..59217df5 100644 --- a/include/hotstuff/entity.h +++ b/include/hotstuff/entity.h @@ -65,7 +65,7 @@ class ReplicaConfig { PubKey* globalPub; - ReplicaConfig(): nreplicas(0), nmajority(0), globalPub(new PubKeyBLS(hotstuff::from_hex("8df60c260df14181197974051be16d9a8485c6c828b1d4f241da11bc60c7d068f0ad7e0c1d269fc7aa86f2b9204e1ca1"))) {} + ReplicaConfig(): nreplicas(0), nmajority(0) {} void add_replica(ReplicaID rid, const ReplicaInfo &info) { replica_map.insert(std::make_pair(rid, info)); diff --git a/include/hotstuff/hotstuff.h b/include/hotstuff/hotstuff.h index 40970dc9..825ffb54 100644 --- a/include/hotstuff/hotstuff.h +++ b/include/hotstuff/hotstuff.h @@ -304,6 +304,10 @@ class HotStuff: public HotStuffBase { )); HotStuffBase::start(std::move(reps), ec_loop); } + + void set_master_pub(const bytearray_t &data) { + HotStuffBase::set_master_pub(new PubKeyType(data)); + } }; using HotStuffNoSig = HotStuff<>; diff --git a/src/consensus.cpp b/src/consensus.cpp index 83cf007c..9be204fe 100644 --- a/src/consensus.cpp +++ b/src/consensus.cpp @@ -355,4 +355,8 @@ HotStuffCore::operator std::string () const { return s; } +void HotStuffCore::set_master_pub(const pubkey_bt &masterPub) { + config.globalPub = masterPub->clone(); +} + } diff --git a/src/crypto.cpp b/src/crypto.cpp index 6eae024d..0b484068 100644 --- a/src/crypto.cpp +++ b/src/crypto.cpp @@ -64,13 +64,14 @@ namespace hotstuff { QuorumCertBLS::QuorumCertBLS( const ReplicaConfig &config, const uint256_t &obj_hash) : - QuorumCert(), obj_hash(obj_hash), rids(config.nreplicas) { + QuorumCert(), obj_hash(obj_hash), rids(config.nreplicas), t(config.nmajority){ rids.clear(); } bool QuorumCertBLS::verify(const ReplicaConfig &config) { if (theSig == nullptr) return false; - + HOTSTUFF_LOG_DEBUG("checking cert(%d), obj_hash=%s", + i, get_hex10(obj_hash).c_str()); return theSig->verify(obj_hash, static_cast(*config.globalPub)); } @@ -78,9 +79,15 @@ namespace hotstuff { if (theSig == nullptr) return promise_t([](promise_t &pm) { pm.resolve(false); }); - return promise_t(vpool.verify(new SigVeriTaskBLS(obj_hash, - static_cast(*config.globalPub), - *theSig))).then([](const promise::values_t &values) { + std::vector vpm; + + HOTSTUFF_LOG_DEBUG("checking cert(%d), obj_hash=%s", + i, get_hex10(obj_hash).c_str()); + vpm.push_back(vpool.verify(new SigVeriTaskBLS(obj_hash, + static_cast(*config.globalPub), + *theSig))); + + return promise::all(vpm).then([](const promise::values_t &values) { for (const auto &v: values) if (!promise::any_cast(v)) return false; return true; From b16a3336c968863ec98fac5aa4a722a679e81698 Mon Sep 17 00:00:00 2001 From: Ray Neiheiser Date: Mon, 22 Jun 2020 11:40:39 +0100 Subject: [PATCH 05/11] add keygen and extra config --- CMakeLists.txt | 5 ++++ hotstuff-bls.conf | 9 +++++++ hotstuff-sec-bls0.conf | 4 +++ hotstuff-sec-bls1.conf | 4 +++ hotstuff-sec-bls2.conf | 4 +++ hotstuff-sec-bls3.conf | 4 +++ src/hotstuff_keygen_bls.cpp | 49 +++++++++++++++++++++++++++++++++++++ 7 files changed, 79 insertions(+) create mode 100644 hotstuff-bls.conf create mode 100644 hotstuff-sec-bls0.conf create mode 100644 hotstuff-sec-bls1.conf create mode 100644 hotstuff-sec-bls2.conf create mode 100644 hotstuff-sec-bls3.conf create mode 100644 src/hotstuff_keygen_bls.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c13e44dd..2c7042f6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,6 +100,11 @@ add_executable(hotstuff-keygen src/hotstuff_keygen.cpp) target_link_libraries(hotstuff-keygen hotstuff_static blstmp relic_s) +add_executable(hotstuff-keygen_bls + src/hotstuff_keygen_bls.cpp) +target_link_libraries(hotstuff-keygen_bls hotstuff_static blstmp relic_s) + + add_executable(hotstuff-tls-keygen src/hotstuff_tls_keygen.cpp) target_link_libraries(hotstuff-tls-keygen hotstuff_static blstmp relic_s) diff --git a/hotstuff-bls.conf b/hotstuff-bls.conf new file mode 100644 index 00000000..ba68173f --- /dev/null +++ b/hotstuff-bls.conf @@ -0,0 +1,9 @@ +block-size = 1 +pace-maker = rr +master-pub = 8df60c260df14181197974051be16d9a8485c6c828b1d4f241da11bc60c7d068f0ad7e0c1d269fc7aa86f2b9204e1ca1 +replica = 127.0.0.1:10000;20000, 8a0f04a4d41e7a993336d3f5cb5f32d2fa468af5ceae179b1b9f1c6e698da5c98ccc8cfcc4226f8c3eaf466941c6c8f9, 542865a568784c4e77c172b82e99cb8a1a53b7bee5f86843b04960ea4157f420 +replica = 127.0.0.1:10001;20001, 03d1052326a84450c0086f64515a71524f8f5e13cd49ca0fddf692204bde34c7e036b201668704d9ba77cb62e38cae81, c261250345ebcd676a0edeea173526608604f626b2e8bc4fd2142d3bde1d44d5 +replica = 127.0.0.1:10002;20002, 842d687d00d36f21f971858ab7cb6d5fccc6f95c016abb9f69e3598ccb4d29efa998d5243308df0a107fb0369f59cfae, 065b010aed5629edfb5289e8b22fc6cc6b33c4013bfdd128caba80c3c02d6d78 +replica = 127.0.0.1:10003;20003, 81c8addfbeae6e7fc06dbad0f4db0b438dffd62cf235c770f776b3c96c866f7a74ad0ddda5281df2c3635a77a4bf7e85, 6540a0fea67efcb08f53ec3a952df4c3f0e2e07c2778fd92320807717e29a651 + + diff --git a/hotstuff-sec-bls0.conf b/hotstuff-sec-bls0.conf new file mode 100644 index 00000000..0a264df3 --- /dev/null +++ b/hotstuff-sec-bls0.conf @@ -0,0 +1,4 @@ +privkey = 2f055108a3e61a827298b5e1f0bc6915fc194ecfbaad33ba5516a63c8880319b +tls-privkey = 308204a10201000282010100c5a358cee61ca7592dbe62cd28225426dc3fc65b33432043efb5e8fcfaf334720b2000d10c422172e6f94f82746928a6d51193342a1555684eedb141321170cb02cc7b189f5506cc30cb5c26d9b84123328ed6df61fc1a6582b046def7a662bb15d84e29ffa279f1d853c25ca79fbe3fab0200f8c85566a5eedb98df4a958e8512a647258e55a7a56c1ca8b05607b38b01b6a2669af9a70efa59141f6079341c6044f615687be756d4830ea359139ea35e23f34ce226215a1a2fb8271cc60a037841e44c460e149a71d3e2fa907a48677ad18af2e7348343932f5f29ac5241cd20ce64e6798ada684164cd1109c3a969662d9aaf9897fedc5a4e256eb92bf7bd02011102820100516160cdaa0bcc7003c6dd6388ff139787de0661c9d0589471c35fefb2a060e3aa3a5ab06e75954d6e2a6c088a496b1784e91e7ee426e6eeb7169448058eb5f93d6341bed83211db9b9f07d3c30fa259c9861c3ddd0d7447ea84d1e356ea28a7635911205a33d7dc0dc822dadb9c2129466a3ca2acd7def9080011c55af249bd98e3f84a5475a43cc0369cf7fa5e4ecdd1c09ac0b0a41bd19d8af70cad8f1b6aec66a22179e5dbf9c446c645e9daa9080b455fca64365d8e02a686fbd707198302db43cd37629033574561c025d89d29c393746ce12fa01bbe60feb3fab292928ead3f8f6def6b9a7dffcd2139f6e8d1f79844d216b28dfae29dc6ba8c11063102818100f770f6dea12236dd39cb46ba96c171f3cfa92c961a12bfb62108e82e0bac280554a9ad4b99c4faee9287467573eaf6cfcba360753668c40ab1b015fbbb95f6a2d3c2402966971fa54540befdc39b58962f7d0cfaa96ff268df02efab32238544ed75fd6586bd93e38934c9d59b037f3cd7f727b38c854e1061de1f68bf43a26d02818100cc7963002015bd593af15276f185cb5a34a76bb36633c85bc86c6640419612a5a8eb2cc1a6ad43e51c2b545f88a7e8c0096a6110b85de7d1f458eca33267f9fde6b4489e346304787d33c8e1033e96b502a53ea6ad2c55299cae973719587d24468f164930f58a56aac2c7eabd68870a1056f06b8bcec5b3d2156c8a1375d89102818048c6df326ba0a6b9897805be68933fa20fe676868023a1cc27d57176f45fcf8918e69c61879449cdb2a041e64f451b6a4af3d1136a5b0c7b9dac42b3736857994d57400c2d3b81c7327c7468c10f9286867012e04ff3bfc47dd3afe70ebf273263f586c381fb85d982b52c4de24c52996cb21abc56818f6e3ae6fa2ddde6b74d028180180e47e1e5a83464d9c209b3a3f19f740631d06f756f80fbbd39ede97120b6e6501baae99b2371663f8ca083b5b966ad2e48c02015b0b1dc77198540604877c3848dae30bade78ff1dc9db65c4257b245aaa075ee732645f3f9c11ca3f37964080c58a26ba773d739b9e71df6193d3a6d4beef1bb618537e912fb26a98e0b01102818100950d7d5ec366f8bca918011359590c6e7d6fe4d3e8922d68468c3e24277f27621db17cb41d0dcddf1f77e289e49dc92101d8544e84281ec7732fbfd4e9194924a2adac4e22ef79c2ad61428f1fa03e6affa3b0de07f857de87a2e758953122b0d693cf49e54ede4eba44dcdc2c5cbd6751af5117fd107fc0e4ffb18f8774d79e +tls-cert = 308202e4308201cc020101300d06092a864886f70d01010505003039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f7374301e170d3139303730323036353535365a170d3139303730323036353535365a3039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f737430820120300d06092a864886f70d01010105000382010d00308201080282010100c5a358cee61ca7592dbe62cd28225426dc3fc65b33432043efb5e8fcfaf334720b2000d10c422172e6f94f82746928a6d51193342a1555684eedb141321170cb02cc7b189f5506cc30cb5c26d9b84123328ed6df61fc1a6582b046def7a662bb15d84e29ffa279f1d853c25ca79fbe3fab0200f8c85566a5eedb98df4a958e8512a647258e55a7a56c1ca8b05607b38b01b6a2669af9a70efa59141f6079341c6044f615687be756d4830ea359139ea35e23f34ce226215a1a2fb8271cc60a037841e44c460e149a71d3e2fa907a48677ad18af2e7348343932f5f29ac5241cd20ce64e6798ada684164cd1109c3a969662d9aaf9897fedc5a4e256eb92bf7bd020111300d06092a864886f70d0101050500038201010009fc34f2835e4c14de1e03202c0f0884acb51e7568b286a9b3a374e8b69f304600a2787303cd382e52923db352cf91587ea7a33da5116c886c67775b5f96357971dddb568948fbb12987523a8be0e2e537284f8ee591af17c6d58410e41d32fc634f99289089915fb4273feaaca45d3442820155f5014fbd5d19fef7954729e4439218cad6a83b9dcd21834aaec379a276f163599cdac6b9513d0c07310852bb4104a58141a158d302908c23761899a4c68c3bf81115f302d41f42ff38150c0b7dc798fd7319abec6bd9365e00bf0a0998c3b97fe4834f0688e95d1eea4df4031274c781c6661cab085d629cb924c5c65b865ae98aa2349875fafe62b7eacbc5 +idx = 0 diff --git a/hotstuff-sec-bls1.conf b/hotstuff-sec-bls1.conf new file mode 100644 index 00000000..7b506379 --- /dev/null +++ b/hotstuff-sec-bls1.conf @@ -0,0 +1,4 @@ +privkey = 6a85834d2de6a711a6cb0e6151123d76d982d274f611a6ad310a018d333bdae5 +tls-privkey = 308204a20201000282010100abfe4a55f831720dd46e2bca05e767aef9838d2069f893f3213bf5a31f5be249c2b356476e01d3fc221581bf4ffa93a6ec41898fbed6119b7981065d07fe476fa12b7da4a22f37d4cfc8a667ff163c05d17762f789df64995a1e80c50ed0d1f7ab8e733fb543d962818ce3ba7b38bf4fe0ca39926b6e99e3fa32eff48f503cf7f66824573e9fb34cb9c4e952f0f584d30c5b7312172facb0439ed5af6d0c6f7382db15315dce8f2fe1704f11bd76e5e3fbffd6f44b240036492187a13e23c0cc8769a52f5bbc90400867093d031483b84fe5c40a7ce66d7dab7a474689de080cc2b6670359f08d5bff53cfa92bf49fc306cccfe0b6fed8c6e4edef86d81638610201110282010100a1e045f68f3d98857ca3ecfa5fe8da0e180357a609626d2110386eb7a50b2f547b032406fe1fd692f2e710b40f09f460de5bccc3866f1fa1634c423970ef524af20ad09af2ff439b1dea060786ab83c93d9d8a5263a5136327a43cf5b3975c34653ac6d28c7c17e43db1c746199ed22d0fcd635ca159094f09995a4f95f12a513ebec6fe1af47c260090fcf8908e04192bb8b9a9c75608d221110d183a80380193b076354b2cb396500c94c8ca33e45559eeadefe217ef04898a2350390fadcf3e4ccb4d1783c619168c9fe7e29701f15476e980408975050d0a8e5df4e4ea35dc6fe3e3f71964952cf600c45d88688b5e92cf5144d869448290e7cefc8f793102818100d5c267d9f5b82ce47e3b7e3fa80fa599b73406b21d240c863bfc4c20d858c729d96e89adc0e51aa6248112fb351bcf5102dada449b5226842d9e7482e65391b8e89a8a0982a1f1b0e75922d416e45f28a06842d4ef00d9c7c8fa43d47487e79121e69d25f5dbbdf49ea85dc7035cb7a92fa79cad5666a2bd4bcd29be9ec31fff02818100cdfb090f4c43c27fdaef5e4b2f4efade96b3271b964036cac4806ba4d68b6cc7fc810deafd09f5ba07e1de013183f3f8499763e0cf986bbd49604d991b2f86676c9d8323f01e9c1479187c828b6fb27f45bf291d4953876084a4cc2e4122e7a26698e7bb2d89d488e0e611118536f905c2a936ed07724630ce66cf7c4cfaa79f0281810096e39499daa01fb0591aefb476a1a21226f78c417dfb542284b2179eb6d5414ab79952204bed03c0923cfe56f84fdda2989a7bf431672a3f2f42ac98a29557cdd15e0715c59f7d6dd07b27a4c4dd7058e9b301ffb7c45d7df7473ef05241d0a2ae84ab29dab93acaca58baaa98f6274a3fc19bc5a66690fe1763a4ff06a7da59028180792a41908736eae1cc145595a35ba2a10d5a533d6771112bfb1e5d7005bb6d2a584bea11c205dbd6d775cde29598e9dd58772bb16b0e5d7e6765d34b00eec78821c610e7f6a8980c0aff584cca7df08719f7fa113a31227502bb4aee0832a65f87a53d04b16022aadea57373b7c5fbe545547aa98be8ddfe9787c5582d48265d02818006385a17426489bc3393300bfec08c440cbfd894d991b1c1e1b672f17809ff150703496fde8df3bfa9d67553f0d6d4bb1bf73706454470479fc4aec0250b0613bd028cc111f61edfeb6ad40e6801fc22afcb67788a7a514c5b3f04a3986dbf063f4277bcf5182763242781f8ba6b2cb3a8cb909332f9b1966601675297a601cf +tls-cert = 308202e4308201cc020101300d06092a864886f70d01010505003039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f7374301e170d3139303730323036353535365a170d3139303730323036353535365a3039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f737430820120300d06092a864886f70d01010105000382010d00308201080282010100abfe4a55f831720dd46e2bca05e767aef9838d2069f893f3213bf5a31f5be249c2b356476e01d3fc221581bf4ffa93a6ec41898fbed6119b7981065d07fe476fa12b7da4a22f37d4cfc8a667ff163c05d17762f789df64995a1e80c50ed0d1f7ab8e733fb543d962818ce3ba7b38bf4fe0ca39926b6e99e3fa32eff48f503cf7f66824573e9fb34cb9c4e952f0f584d30c5b7312172facb0439ed5af6d0c6f7382db15315dce8f2fe1704f11bd76e5e3fbffd6f44b240036492187a13e23c0cc8769a52f5bbc90400867093d031483b84fe5c40a7ce66d7dab7a474689de080cc2b6670359f08d5bff53cfa92bf49fc306cccfe0b6fed8c6e4edef86d8163861020111300d06092a864886f70d0101050500038201010069f87140cc279dfc03b89cd6de3833aa7bb824f522b46943d8ea32c0bf24b2a7d7b77da04a359fe4fa840770552794836dc6cdbf80396ab87edfe5df187915cb94ef4b142b8b20c438b54608059fca91f5792a39bfaea547c6a56fac3ae165ce89d29e7af5f914304da4aabe02961f5dab7dc94124837539958015d89a22eedfd42981819004d1af6342498aa43f58cf84c391e0427835407089d0e95b5fdfe350974cb507dffeca15e55851e03b68ce4ac640ca898ea6a75a7f5469f677f74a14d05ce4bbd44e8a2a70366edb94f6e8706246dd904847e37abe3116320dc1688a4788a8600bf7ae05932541be665efb5b564c3c964504555f09175494517469 +idx = 1 diff --git a/hotstuff-sec-bls2.conf b/hotstuff-sec-bls2.conf new file mode 100644 index 00000000..94df021b --- /dev/null +++ b/hotstuff-sec-bls2.conf @@ -0,0 +1,4 @@ +privkey = 1dc6ba158efa514f46e70f68e8b60a636e04b5994b93569461b754aa34cde814 +tls-privkey = 308204a20201000282010100c1460bf8018ceec075d67405e96e056e2e3acf9c7c2d7d28ee6edfe9ee8fbeef0e978ac874ceff3ee770dafde1d019d9920b2ff334a3ac115bcf95e2bdc0b70faf46b8f13c46335c4815c72d75b488de46b96f8582446e886c6b7fdfb479bc40a0da03b7c4e414fde9ab44b1957e39c5e5c167ba88a233854f29404a1f35aa29994bcd7a62b57fc2000850c37569a8a1bfa75e6e06c54c40633e0fee1672c1f97689aabee650285a41fd6df24f20cd94733aeccdae68debba30a3588b71625f9ec7669d3f4c51317192f5acdee9b968d1a6db4a98a9c0eeef63a969c2ecaba95a9ddfd5841d996977696e41a541393ba40ae44b71c00129a25b30f6c44e89d8d0201110282010071b0bbbf0ff88c713641e9e55c2299c8576de38939fca3f9f5aaa1d4e6aee8c8db683384f96ab4431ebadb2bee3e2d52ce60ef07886047194510b285608f7abdeea2126fc91a3c5466a3661abdb57dafed5e055d97ec04c8b83f3c293cfc509e7cbc7aa855b357a46b55afeffd958b6559f94c135f6e78a8c52752fe6cb627db36195ca7e30537e3a1a2cfd2dfe23c2f6c9c91a45119e8b6c128dce763157d4f21350c7293f4cc7c96201e3b63484e22b6308c2d9351e1c5b833bcc301c68f9111c10c9e79ee6f590ce7cff86e1c8e6bf970d8d0e2d0bc32a6c06997e3cdcad17657cfa6d0300966fd1c0a4ad5e9817ab4d41b5ff0010ce93c08eae7ad053ef102818100e8b87e8ca3a329afedda121b2f005533749b067a3f9b38f43252f760ed18a9cdea42bd14a3b0ac599dc6c00fb873303713e030507fda557ab3de70864de60cba13dde108eedfe57df0a5fcbe3062b0cfce80aab3739e7f83b5534215c01830234bd439afdd02fd0755da8eb9c56466c762fb3c8cec5fa4229c8e94092db7b24102818100d49b649d2389770f18ffdd5b6368b9ea78cef9f60a17a148b558d43700e8c3250706588113e5b9f9a50014173ab2b2225cd50162e750230a693a37507fc4f1fc6d9d268a69cfd6b4f8ff494fcfd526d28a46cc92fbcde915256d076a9ea17e74ae747c4002eb56610c0caa47bca2373bdd7da66d7e050bb7d64885a60aa8004d02818100b1f67ee404a9f2b3b5e2fec97e4b8c72a4768c7b9a0d49abae0335a47912dc340d7e545b13c3569ee21074c0ba39f7b1a5c98e5bad105f7bf2f5651b68befaac698b8df7c5ba46150351c14625002cdb2571737a2b3cf8196c8af64cde309d482aed95867bd51bd86ed44f0687e35da787ed4c6bc3d0aab10e4ee9acaa7d6a31028181008991b992dac25c18d3f0da866d7fffd3f3d13853e869a4987557985fd3696f36139ab1bceec1d2b097f0fdf0e9beebbbe1b700e5a4bb61f7ad8005ac8ee8d8d08329734a80b3a90bb02cb6f7685cbec477973913d01bd30daece13db93d1e8699e0f23387a5c0ab7440831f22ec350ea80423e83154e8f1c99b674989d7bc3f5028180267c5167cd1f8dce4b15611b8ea0220e6be74efbf55e3bf4a775b1edf0e49b377c12f49fbf683f24e1850c455b8b7a96d0c7eff9f47661ec75004a2a435dd741e7d7bb6423fa576053a0677b2a0b714e7fadcc37c03dc9da053069477c1ce0afac316c1c63ffb510d30e11adc0865e94177f3545c0594860c10baa51bc074e4c +tls-cert = 308202e4308201cc020101300d06092a864886f70d01010505003039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f7374301e170d3139303730323036353535365a170d3139303730323036353535365a3039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f737430820120300d06092a864886f70d01010105000382010d00308201080282010100c1460bf8018ceec075d67405e96e056e2e3acf9c7c2d7d28ee6edfe9ee8fbeef0e978ac874ceff3ee770dafde1d019d9920b2ff334a3ac115bcf95e2bdc0b70faf46b8f13c46335c4815c72d75b488de46b96f8582446e886c6b7fdfb479bc40a0da03b7c4e414fde9ab44b1957e39c5e5c167ba88a233854f29404a1f35aa29994bcd7a62b57fc2000850c37569a8a1bfa75e6e06c54c40633e0fee1672c1f97689aabee650285a41fd6df24f20cd94733aeccdae68debba30a3588b71625f9ec7669d3f4c51317192f5acdee9b968d1a6db4a98a9c0eeef63a969c2ecaba95a9ddfd5841d996977696e41a541393ba40ae44b71c00129a25b30f6c44e89d8d020111300d06092a864886f70d01010505000382010100706c7eb29939c38cfcbab592c62a3572e05dcaa4d54e24cce74a244972e74ac8ed6e0b3eb1add0d4de6007d392ac75a7fb9836a9a1d937d0b2c3f01a6b1994ac317328527c763eae26a6ca647752badcd09e73364ac7828d375b4966e510de1cdbd01a5be047e45533f5a3d81df00ffe9d13fe5d54e18584691abb3a9a3d423d348d7714382317547338a8e83d14f404348db41c10a05e57221eda1e220b265ae4237e59ab2db1facbe8cc8d2198ca5fe2ad074bb8c7c4dd675cbe3d60b9e29f6b12ab4c587c6576e1ce2d2512be035e4692100c6c3e47d4d84dbbc865804af1bd0240fb804ef99c7038191dae2fab73a1a1ffa09f536a0fbf49fa1a3234b62a +idx = 2 diff --git a/hotstuff-sec-bls3.conf b/hotstuff-sec-bls3.conf new file mode 100644 index 00000000..feed5f33 --- /dev/null +++ b/hotstuff-sec-bls3.conf @@ -0,0 +1,4 @@ +privkey = 30a444081a5c13cbb9606908caeb7fe6611a4042bb2efb6de71e9f918d36592a +tls-privkey = 308204a20201000282010100de01b461213afa37d4aa68bdc7e1a6de12307440f1de6588e5362450694cbb4ba63b1f992a7dc88b999c7dec9088d17253ac278c33018ea8caa1f96c7d90bcb5a6a3f8568825bafa9a696699a4eaf0c6fcdd8ed7bc91a688ead564fb882a1c25c7f72bbe44eb44fda1d11d6ca090503e36de532f2fededff03da30f8f95f11b6472e9588fd6be69cad285915c68edaa7754c6524017bf08c3c336f04d0246d8e967a4de2824a3ac7486aaf9160540c63f75d36ecba9261ff6b859a7684b023ecfbc5408dc7c59942c76464040770c6097833dd770a7dffc6ed6a8716b1f683379843969f937d859d8f69a21362eda9dabd64dd6fb7131ee46b2654d3aa8dc9df02011102820100414bcba418d51c6ac61400b049d8f4d7e73b6d7c835f8746618865089770ebcaf4a7fa3c1b8e68290f0fe8cd1b7388e563e756ecfff16631a5027689521b82cc03d5dfa0faddebb31e5b3c4b4e9f73fe4a5f48215594400a26f3780dbea2f93849df4919d808f62c7ae326c598a2ea6ca6b9dc3b0e18cd873d5e4aa394a37dad88a49b91b7446343d03d4ea067b72c62ba622d68f7fb97c031a7f9259401318905e092b0aec27e643fb3efd9bf392050941d43fe06a87630412bf765a4800f57561a9fc339ff92a9b33e748efe5c6ddafe4069e99cf039794b4641ab4f199703860b4f8ee3669a04ad664379012650e68debe0ccc4c41a39e6bf8a3de15003f902818100f56482abd14db0f327311b376dc4cfac86cc3379036b6672713d296a0665797de7b115350d77a27193de1f5abd9e2b44eff6c5a323b1209c4aac68c86e3488abab89139a7cbb98a4f0c1e930c2bc276bbcf0efd47cf4dc6614b9c16c332a5f7ef339d5c746780884a66e087236ec784361fda7e72c21528c0427d7abbc9751f502818100e79a68542368e4295b8d3289c4f4da780e6597461952b9592221901b05bae53ece00df87ef7084340f28c71f188d400d0fcfbd504d0ae2bf101082214d9500b1f8480dc1ec3ea7900ece21b9e3e0c2b5279b1f21de585ff7a58eb330d841ef13107ce58c14a8a4a29b6cb438f4e551baac120603878a3ff9f00cda5589800403028181009ec890c9876e818e46892fba74340de81afc99c6c5fa333afdfa66176d8cf44268bde08bbd6b873a6ebce71c98cfc1a513bdcb2d53547e833f60800938401c32d867c163f65b44a6f6231e6ad85ba1097a418c20149e707e49a55f09c6c1109d70347b44b5207dfb7abfab1cba208a0d7ba4215958ca4478b7651314c552daad02818100cc5b10c2b5d5058de75e77e2f914484bd077c1b652944930878706ae6e77bb376a793db42d9f83b576c9a0a2f78bb0fc775cf255e9a0317b68870968adddd36fdb12667dee91a2e88588b458ba028daee6b60c692d99459e46c934b2a0b2a5c58704ca8aa8d109bca741cc32417f0be0f22e054e68890b45f1ed391e4c25a92f02818016d4c0a1d4cc7fadb7033ae8506221a7dde9c2437fe5989175e8de47791b4ff957fb485d6d04c85b9fd1d7734950dc4d032dd3fdf9c14193b04ea179839fb4560282d106b684b5712a9b140afbe4d92ff30c745a7bdca71de9808f6d2a88340e116cc4475e908993c27a27847601ec378d4357dc5e99a147c60d7258e282453e +tls-cert = 308202e4308201cc020101300d06092a864886f70d01010505003039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f7374301e170d3139303730323036353535365a170d3139303730323036353535365a3039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f737430820120300d06092a864886f70d01010105000382010d00308201080282010100de01b461213afa37d4aa68bdc7e1a6de12307440f1de6588e5362450694cbb4ba63b1f992a7dc88b999c7dec9088d17253ac278c33018ea8caa1f96c7d90bcb5a6a3f8568825bafa9a696699a4eaf0c6fcdd8ed7bc91a688ead564fb882a1c25c7f72bbe44eb44fda1d11d6ca090503e36de532f2fededff03da30f8f95f11b6472e9588fd6be69cad285915c68edaa7754c6524017bf08c3c336f04d0246d8e967a4de2824a3ac7486aaf9160540c63f75d36ecba9261ff6b859a7684b023ecfbc5408dc7c59942c76464040770c6097833dd770a7dffc6ed6a8716b1f683379843969f937d859d8f69a21362eda9dabd64dd6fb7131ee46b2654d3aa8dc9df020111300d06092a864886f70d010105050003820101007f9d4f2848059831e5ea7d727d9b09f826027c78fdc86d27ea83d32d727ac4a0484e55ed34851adcc8903a3ef39c1b0c447c28cd84cbc513cdcd607da3fa903495a70b7772e71873e3c8a734d3e8b9f82c7380604ccb8416bd92822e703a3b8839aff411f967d2bcc1cd96d158e7839a2bff6110ffd005808f7047fd57a7150c1e14ddcfd2e1a24a5878f99409b7ede1d5f4a385077b6f55f4818c854c6e64adb4789433667e672b9a615b680301a05852255cef958ff1031a489dd95327d045be0315359644ec51f2fd3cb724382ba2425da519dbf1d89098e10a1091f44c7a8e12733b7d0b1fce7c6d19adfee3cdac89f95ed1ae979093cb2793892724d7d9 +idx = 3 diff --git a/src/hotstuff_keygen_bls.cpp b/src/hotstuff_keygen_bls.cpp new file mode 100644 index 00000000..f6ad5101 --- /dev/null +++ b/src/hotstuff_keygen_bls.cpp @@ -0,0 +1,49 @@ +/** + * Copyright 2018 VMware + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "salticidae/util.h" +#include "hotstuff/crypto.h" + +using salticidae::Config; +using hotstuff::privkey_bt; +using hotstuff::pubkey_bt; + +int main(int argc, char **argv) { + Config config("hotstuff.conf"); + privkey_bt priv_key; + auto opt_n = Config::OptValInt::create(1); + auto opt_algo = Config::OptValStr::create("secp256k1"); + config.add_opt("num", opt_n, Config::SET_VAL); + config.add_opt("algo", opt_algo, Config::SET_VAL); + config.parse(argc, argv); + auto &algo = opt_algo->get(); + if (algo == "secp256k1") + priv_key = new hotstuff::PrivKeySecp256k1(); + else + error(1, 0, "algo not supported"); + int n = opt_n->get(); + if (n < 1) + error(1, 0, "n must be >0"); + while (n--) + { + priv_key->from_rand(); + pubkey_bt pub_key = priv_key->get_pubkey(); + printf("pub:%s sec:%s\n", get_hex(*pub_key).c_str(), + get_hex(*priv_key).c_str()); + } + return 0; +} From b41cb86b76551063005a37614f1c86f153bd611b Mon Sep 17 00:00:00 2001 From: Ray Neiheiser Date: Mon, 22 Jun 2020 11:41:30 +0100 Subject: [PATCH 06/11] finish keygen --- .gitignore | 4 ++ src/hotstuff_keygen_bls.cpp | 129 ++++++++++++++++++++++++------------ 2 files changed, 91 insertions(+), 42 deletions(-) diff --git a/.gitignore b/.gitignore index 74fcf304..dfce86d5 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,7 @@ include/hotstuff/config.h core .idea/ + +hotstuff-keygen_bls + +hotstuff.cbp diff --git a/src/hotstuff_keygen_bls.cpp b/src/hotstuff_keygen_bls.cpp index f6ad5101..c60444d3 100644 --- a/src/hotstuff_keygen_bls.cpp +++ b/src/hotstuff_keygen_bls.cpp @@ -1,49 +1,94 @@ -/** - * Copyright 2018 VMware - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include + #include "salticidae/util.h" -#include "hotstuff/crypto.h" -using salticidae::Config; -using hotstuff::privkey_bt; -using hotstuff::pubkey_bt; +#include +#include +#include +#include +#include +#include +#include + +using namespace bls; +using namespace std; int main(int argc, char **argv) { - Config config("hotstuff.conf"); - privkey_bt priv_key; - auto opt_n = Config::OptValInt::create(1); - auto opt_algo = Config::OptValStr::create("secp256k1"); - config.add_opt("num", opt_n, Config::SET_VAL); - config.add_opt("algo", opt_algo, Config::SET_VAL); - config.parse(argc, argv); - auto &algo = opt_algo->get(); - if (algo == "secp256k1") - priv_key = new hotstuff::PrivKeySecp256k1(); - else - error(1, 0, "algo not supported"); - int n = opt_n->get(); - if (n < 1) - error(1, 0, "n must be >0"); - while (n--) - { - priv_key->from_rand(); - pubkey_bt pub_key = priv_key->get_pubkey(); - printf("pub:%s sec:%s\n", get_hex(*pub_key).c_str(), - get_hex(*priv_key).c_str()); + + if (argc != 3) { + throw std::invalid_argument( "Expecting N, K as parameters" ); + } + + char *endptr; + int N = atoi(argv[1]); + int K = atoi(argv[2]); + + std::vector> commits; + std::vector> frags; + for (size_t i = 0; i < N; ++i) { + commits.emplace_back(std::vector()); + frags.emplace_back(std::vector()); + for (size_t j = 0; j < N; ++j) { + if (j < K) { + g1_t g; + commits[i].emplace_back(PublicKey::FromG1(&g)); + } + bn_t b; + bn_new(b); + frags[i].emplace_back(PrivateKey::FromBN(b)); + } + } + + frags[0][0].GetPublicKey(); + + for (int i = 0; i < N; i++) { + Threshold::Create(commits[i], frags[i], K, N); + } + + std::vector keys; + keys.reserve(N); + + std::ofstream myfile; + + myfile.open (((string) "keys").append(std::to_string(N)).append(".cfg")); + + for (int i = 0; i < N; i++) { + keys.push_back(commits[i][0]); + } + + PublicKey masterPubkey = PublicKey::AggregateInsecure(keys); + + uint8_t pkBytes[bls::PublicKey::PUBLIC_KEY_SIZE]; + masterPubkey.Serialize(pkBytes); + string hexkey = bls::Util::HexStr(pkBytes, bls::PublicKey::PUBLIC_KEY_SIZE); + myfile << "master: " << hexkey << "\n\n"; + + std::vector> recvdFrags = {{}}; + for (int i = 0; i < N; ++i) { + recvdFrags.emplace_back(std::vector()); + for (int j = 0; j < N; ++j) { + recvdFrags[i].emplace_back(frags[j][i]); + } + } + + vector privs; + privs.reserve(N); + + for (int x = 0; x < N; x++) { + PrivateKey priv = PrivateKey::AggregateInsecure(recvdFrags[x]); + privs.push_back(priv); + + uint8_t pkBytes[bls::PrivateKey::PRIVATE_KEY_SIZE]; + priv.Serialize(pkBytes); + string hexkey = bls::Util::HexStr(pkBytes, bls::PrivateKey::PRIVATE_KEY_SIZE); + myfile << "priv" << x << ": " << hexkey << "\n"; } + + for (int x = 0; x < N; x++) { + uint8_t pkBytes[bls::PublicKey::PUBLIC_KEY_SIZE]; + privs[x].GetPublicKey().Serialize(pkBytes); + string hexkey = bls::Util::HexStr(pkBytes, bls::PublicKey::PUBLIC_KEY_SIZE); + myfile << "pub" << x << ": " << hexkey << "\n"; + } + return 0; } From de59f5f1af8dfcc9b4bc141a51a4d8e662065dc2 Mon Sep 17 00:00:00 2001 From: Ray Neiheiser Date: Mon, 22 Jun 2020 11:44:55 +0100 Subject: [PATCH 07/11] reset configs --- hotstuff-sec0.conf | 2 +- hotstuff-sec1.conf | 2 +- hotstuff-sec2.conf | 2 +- hotstuff-sec3.conf | 2 +- hotstuff.conf | 11 ++++------- 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/hotstuff-sec0.conf b/hotstuff-sec0.conf index 0a264df3..bbfd3f26 100644 --- a/hotstuff-sec0.conf +++ b/hotstuff-sec0.conf @@ -1,4 +1,4 @@ -privkey = 2f055108a3e61a827298b5e1f0bc6915fc194ecfbaad33ba5516a63c8880319b +privkey = 445fa01dbbb9d0510ab6d6f630c94ab43ba21ad91f31d47da92f7b679ba2f582 tls-privkey = 308204a10201000282010100c5a358cee61ca7592dbe62cd28225426dc3fc65b33432043efb5e8fcfaf334720b2000d10c422172e6f94f82746928a6d51193342a1555684eedb141321170cb02cc7b189f5506cc30cb5c26d9b84123328ed6df61fc1a6582b046def7a662bb15d84e29ffa279f1d853c25ca79fbe3fab0200f8c85566a5eedb98df4a958e8512a647258e55a7a56c1ca8b05607b38b01b6a2669af9a70efa59141f6079341c6044f615687be756d4830ea359139ea35e23f34ce226215a1a2fb8271cc60a037841e44c460e149a71d3e2fa907a48677ad18af2e7348343932f5f29ac5241cd20ce64e6798ada684164cd1109c3a969662d9aaf9897fedc5a4e256eb92bf7bd02011102820100516160cdaa0bcc7003c6dd6388ff139787de0661c9d0589471c35fefb2a060e3aa3a5ab06e75954d6e2a6c088a496b1784e91e7ee426e6eeb7169448058eb5f93d6341bed83211db9b9f07d3c30fa259c9861c3ddd0d7447ea84d1e356ea28a7635911205a33d7dc0dc822dadb9c2129466a3ca2acd7def9080011c55af249bd98e3f84a5475a43cc0369cf7fa5e4ecdd1c09ac0b0a41bd19d8af70cad8f1b6aec66a22179e5dbf9c446c645e9daa9080b455fca64365d8e02a686fbd707198302db43cd37629033574561c025d89d29c393746ce12fa01bbe60feb3fab292928ead3f8f6def6b9a7dffcd2139f6e8d1f79844d216b28dfae29dc6ba8c11063102818100f770f6dea12236dd39cb46ba96c171f3cfa92c961a12bfb62108e82e0bac280554a9ad4b99c4faee9287467573eaf6cfcba360753668c40ab1b015fbbb95f6a2d3c2402966971fa54540befdc39b58962f7d0cfaa96ff268df02efab32238544ed75fd6586bd93e38934c9d59b037f3cd7f727b38c854e1061de1f68bf43a26d02818100cc7963002015bd593af15276f185cb5a34a76bb36633c85bc86c6640419612a5a8eb2cc1a6ad43e51c2b545f88a7e8c0096a6110b85de7d1f458eca33267f9fde6b4489e346304787d33c8e1033e96b502a53ea6ad2c55299cae973719587d24468f164930f58a56aac2c7eabd68870a1056f06b8bcec5b3d2156c8a1375d89102818048c6df326ba0a6b9897805be68933fa20fe676868023a1cc27d57176f45fcf8918e69c61879449cdb2a041e64f451b6a4af3d1136a5b0c7b9dac42b3736857994d57400c2d3b81c7327c7468c10f9286867012e04ff3bfc47dd3afe70ebf273263f586c381fb85d982b52c4de24c52996cb21abc56818f6e3ae6fa2ddde6b74d028180180e47e1e5a83464d9c209b3a3f19f740631d06f756f80fbbd39ede97120b6e6501baae99b2371663f8ca083b5b966ad2e48c02015b0b1dc77198540604877c3848dae30bade78ff1dc9db65c4257b245aaa075ee732645f3f9c11ca3f37964080c58a26ba773d739b9e71df6193d3a6d4beef1bb618537e912fb26a98e0b01102818100950d7d5ec366f8bca918011359590c6e7d6fe4d3e8922d68468c3e24277f27621db17cb41d0dcddf1f77e289e49dc92101d8544e84281ec7732fbfd4e9194924a2adac4e22ef79c2ad61428f1fa03e6affa3b0de07f857de87a2e758953122b0d693cf49e54ede4eba44dcdc2c5cbd6751af5117fd107fc0e4ffb18f8774d79e tls-cert = 308202e4308201cc020101300d06092a864886f70d01010505003039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f7374301e170d3139303730323036353535365a170d3139303730323036353535365a3039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f737430820120300d06092a864886f70d01010105000382010d00308201080282010100c5a358cee61ca7592dbe62cd28225426dc3fc65b33432043efb5e8fcfaf334720b2000d10c422172e6f94f82746928a6d51193342a1555684eedb141321170cb02cc7b189f5506cc30cb5c26d9b84123328ed6df61fc1a6582b046def7a662bb15d84e29ffa279f1d853c25ca79fbe3fab0200f8c85566a5eedb98df4a958e8512a647258e55a7a56c1ca8b05607b38b01b6a2669af9a70efa59141f6079341c6044f615687be756d4830ea359139ea35e23f34ce226215a1a2fb8271cc60a037841e44c460e149a71d3e2fa907a48677ad18af2e7348343932f5f29ac5241cd20ce64e6798ada684164cd1109c3a969662d9aaf9897fedc5a4e256eb92bf7bd020111300d06092a864886f70d0101050500038201010009fc34f2835e4c14de1e03202c0f0884acb51e7568b286a9b3a374e8b69f304600a2787303cd382e52923db352cf91587ea7a33da5116c886c67775b5f96357971dddb568948fbb12987523a8be0e2e537284f8ee591af17c6d58410e41d32fc634f99289089915fb4273feaaca45d3442820155f5014fbd5d19fef7954729e4439218cad6a83b9dcd21834aaec379a276f163599cdac6b9513d0c07310852bb4104a58141a158d302908c23761899a4c68c3bf81115f302d41f42ff38150c0b7dc798fd7319abec6bd9365e00bf0a0998c3b97fe4834f0688e95d1eea4df4031274c781c6661cab085d629cb924c5c65b865ae98aa2349875fafe62b7eacbc5 idx = 0 diff --git a/hotstuff-sec1.conf b/hotstuff-sec1.conf index 7b506379..54c9b5f6 100644 --- a/hotstuff-sec1.conf +++ b/hotstuff-sec1.conf @@ -1,4 +1,4 @@ -privkey = 6a85834d2de6a711a6cb0e6151123d76d982d274f611a6ad310a018d333bdae5 +privkey = 71f2f7aa5fb0f6d8fcdebe6c6c249aa7de068eb5d617dffa0dcfbc2f1dd73177 tls-privkey = 308204a20201000282010100abfe4a55f831720dd46e2bca05e767aef9838d2069f893f3213bf5a31f5be249c2b356476e01d3fc221581bf4ffa93a6ec41898fbed6119b7981065d07fe476fa12b7da4a22f37d4cfc8a667ff163c05d17762f789df64995a1e80c50ed0d1f7ab8e733fb543d962818ce3ba7b38bf4fe0ca39926b6e99e3fa32eff48f503cf7f66824573e9fb34cb9c4e952f0f584d30c5b7312172facb0439ed5af6d0c6f7382db15315dce8f2fe1704f11bd76e5e3fbffd6f44b240036492187a13e23c0cc8769a52f5bbc90400867093d031483b84fe5c40a7ce66d7dab7a474689de080cc2b6670359f08d5bff53cfa92bf49fc306cccfe0b6fed8c6e4edef86d81638610201110282010100a1e045f68f3d98857ca3ecfa5fe8da0e180357a609626d2110386eb7a50b2f547b032406fe1fd692f2e710b40f09f460de5bccc3866f1fa1634c423970ef524af20ad09af2ff439b1dea060786ab83c93d9d8a5263a5136327a43cf5b3975c34653ac6d28c7c17e43db1c746199ed22d0fcd635ca159094f09995a4f95f12a513ebec6fe1af47c260090fcf8908e04192bb8b9a9c75608d221110d183a80380193b076354b2cb396500c94c8ca33e45559eeadefe217ef04898a2350390fadcf3e4ccb4d1783c619168c9fe7e29701f15476e980408975050d0a8e5df4e4ea35dc6fe3e3f71964952cf600c45d88688b5e92cf5144d869448290e7cefc8f793102818100d5c267d9f5b82ce47e3b7e3fa80fa599b73406b21d240c863bfc4c20d858c729d96e89adc0e51aa6248112fb351bcf5102dada449b5226842d9e7482e65391b8e89a8a0982a1f1b0e75922d416e45f28a06842d4ef00d9c7c8fa43d47487e79121e69d25f5dbbdf49ea85dc7035cb7a92fa79cad5666a2bd4bcd29be9ec31fff02818100cdfb090f4c43c27fdaef5e4b2f4efade96b3271b964036cac4806ba4d68b6cc7fc810deafd09f5ba07e1de013183f3f8499763e0cf986bbd49604d991b2f86676c9d8323f01e9c1479187c828b6fb27f45bf291d4953876084a4cc2e4122e7a26698e7bb2d89d488e0e611118536f905c2a936ed07724630ce66cf7c4cfaa79f0281810096e39499daa01fb0591aefb476a1a21226f78c417dfb542284b2179eb6d5414ab79952204bed03c0923cfe56f84fdda2989a7bf431672a3f2f42ac98a29557cdd15e0715c59f7d6dd07b27a4c4dd7058e9b301ffb7c45d7df7473ef05241d0a2ae84ab29dab93acaca58baaa98f6274a3fc19bc5a66690fe1763a4ff06a7da59028180792a41908736eae1cc145595a35ba2a10d5a533d6771112bfb1e5d7005bb6d2a584bea11c205dbd6d775cde29598e9dd58772bb16b0e5d7e6765d34b00eec78821c610e7f6a8980c0aff584cca7df08719f7fa113a31227502bb4aee0832a65f87a53d04b16022aadea57373b7c5fbe545547aa98be8ddfe9787c5582d48265d02818006385a17426489bc3393300bfec08c440cbfd894d991b1c1e1b672f17809ff150703496fde8df3bfa9d67553f0d6d4bb1bf73706454470479fc4aec0250b0613bd028cc111f61edfeb6ad40e6801fc22afcb67788a7a514c5b3f04a3986dbf063f4277bcf5182763242781f8ba6b2cb3a8cb909332f9b1966601675297a601cf tls-cert = 308202e4308201cc020101300d06092a864886f70d01010505003039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f7374301e170d3139303730323036353535365a170d3139303730323036353535365a3039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f737430820120300d06092a864886f70d01010105000382010d00308201080282010100abfe4a55f831720dd46e2bca05e767aef9838d2069f893f3213bf5a31f5be249c2b356476e01d3fc221581bf4ffa93a6ec41898fbed6119b7981065d07fe476fa12b7da4a22f37d4cfc8a667ff163c05d17762f789df64995a1e80c50ed0d1f7ab8e733fb543d962818ce3ba7b38bf4fe0ca39926b6e99e3fa32eff48f503cf7f66824573e9fb34cb9c4e952f0f584d30c5b7312172facb0439ed5af6d0c6f7382db15315dce8f2fe1704f11bd76e5e3fbffd6f44b240036492187a13e23c0cc8769a52f5bbc90400867093d031483b84fe5c40a7ce66d7dab7a474689de080cc2b6670359f08d5bff53cfa92bf49fc306cccfe0b6fed8c6e4edef86d8163861020111300d06092a864886f70d0101050500038201010069f87140cc279dfc03b89cd6de3833aa7bb824f522b46943d8ea32c0bf24b2a7d7b77da04a359fe4fa840770552794836dc6cdbf80396ab87edfe5df187915cb94ef4b142b8b20c438b54608059fca91f5792a39bfaea547c6a56fac3ae165ce89d29e7af5f914304da4aabe02961f5dab7dc94124837539958015d89a22eedfd42981819004d1af6342498aa43f58cf84c391e0427835407089d0e95b5fdfe350974cb507dffeca15e55851e03b68ce4ac640ca898ea6a75a7f5469f677f74a14d05ce4bbd44e8a2a70366edb94f6e8706246dd904847e37abe3116320dc1688a4788a8600bf7ae05932541be665efb5b564c3c964504555f09175494517469 idx = 1 diff --git a/hotstuff-sec2.conf b/hotstuff-sec2.conf index 94df021b..12a361a0 100644 --- a/hotstuff-sec2.conf +++ b/hotstuff-sec2.conf @@ -1,4 +1,4 @@ -privkey = 1dc6ba158efa514f46e70f68e8b60a636e04b5994b93569461b754aa34cde814 +privkey = f09707974bd60c68734e45172928eb600710675fc45822b6db5a8c75eec0f5a1 tls-privkey = 308204a20201000282010100c1460bf8018ceec075d67405e96e056e2e3acf9c7c2d7d28ee6edfe9ee8fbeef0e978ac874ceff3ee770dafde1d019d9920b2ff334a3ac115bcf95e2bdc0b70faf46b8f13c46335c4815c72d75b488de46b96f8582446e886c6b7fdfb479bc40a0da03b7c4e414fde9ab44b1957e39c5e5c167ba88a233854f29404a1f35aa29994bcd7a62b57fc2000850c37569a8a1bfa75e6e06c54c40633e0fee1672c1f97689aabee650285a41fd6df24f20cd94733aeccdae68debba30a3588b71625f9ec7669d3f4c51317192f5acdee9b968d1a6db4a98a9c0eeef63a969c2ecaba95a9ddfd5841d996977696e41a541393ba40ae44b71c00129a25b30f6c44e89d8d0201110282010071b0bbbf0ff88c713641e9e55c2299c8576de38939fca3f9f5aaa1d4e6aee8c8db683384f96ab4431ebadb2bee3e2d52ce60ef07886047194510b285608f7abdeea2126fc91a3c5466a3661abdb57dafed5e055d97ec04c8b83f3c293cfc509e7cbc7aa855b357a46b55afeffd958b6559f94c135f6e78a8c52752fe6cb627db36195ca7e30537e3a1a2cfd2dfe23c2f6c9c91a45119e8b6c128dce763157d4f21350c7293f4cc7c96201e3b63484e22b6308c2d9351e1c5b833bcc301c68f9111c10c9e79ee6f590ce7cff86e1c8e6bf970d8d0e2d0bc32a6c06997e3cdcad17657cfa6d0300966fd1c0a4ad5e9817ab4d41b5ff0010ce93c08eae7ad053ef102818100e8b87e8ca3a329afedda121b2f005533749b067a3f9b38f43252f760ed18a9cdea42bd14a3b0ac599dc6c00fb873303713e030507fda557ab3de70864de60cba13dde108eedfe57df0a5fcbe3062b0cfce80aab3739e7f83b5534215c01830234bd439afdd02fd0755da8eb9c56466c762fb3c8cec5fa4229c8e94092db7b24102818100d49b649d2389770f18ffdd5b6368b9ea78cef9f60a17a148b558d43700e8c3250706588113e5b9f9a50014173ab2b2225cd50162e750230a693a37507fc4f1fc6d9d268a69cfd6b4f8ff494fcfd526d28a46cc92fbcde915256d076a9ea17e74ae747c4002eb56610c0caa47bca2373bdd7da66d7e050bb7d64885a60aa8004d02818100b1f67ee404a9f2b3b5e2fec97e4b8c72a4768c7b9a0d49abae0335a47912dc340d7e545b13c3569ee21074c0ba39f7b1a5c98e5bad105f7bf2f5651b68befaac698b8df7c5ba46150351c14625002cdb2571737a2b3cf8196c8af64cde309d482aed95867bd51bd86ed44f0687e35da787ed4c6bc3d0aab10e4ee9acaa7d6a31028181008991b992dac25c18d3f0da866d7fffd3f3d13853e869a4987557985fd3696f36139ab1bceec1d2b097f0fdf0e9beebbbe1b700e5a4bb61f7ad8005ac8ee8d8d08329734a80b3a90bb02cb6f7685cbec477973913d01bd30daece13db93d1e8699e0f23387a5c0ab7440831f22ec350ea80423e83154e8f1c99b674989d7bc3f5028180267c5167cd1f8dce4b15611b8ea0220e6be74efbf55e3bf4a775b1edf0e49b377c12f49fbf683f24e1850c455b8b7a96d0c7eff9f47661ec75004a2a435dd741e7d7bb6423fa576053a0677b2a0b714e7fadcc37c03dc9da053069477c1ce0afac316c1c63ffb510d30e11adc0865e94177f3545c0594860c10baa51bc074e4c tls-cert = 308202e4308201cc020101300d06092a864886f70d01010505003039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f7374301e170d3139303730323036353535365a170d3139303730323036353535365a3039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f737430820120300d06092a864886f70d01010105000382010d00308201080282010100c1460bf8018ceec075d67405e96e056e2e3acf9c7c2d7d28ee6edfe9ee8fbeef0e978ac874ceff3ee770dafde1d019d9920b2ff334a3ac115bcf95e2bdc0b70faf46b8f13c46335c4815c72d75b488de46b96f8582446e886c6b7fdfb479bc40a0da03b7c4e414fde9ab44b1957e39c5e5c167ba88a233854f29404a1f35aa29994bcd7a62b57fc2000850c37569a8a1bfa75e6e06c54c40633e0fee1672c1f97689aabee650285a41fd6df24f20cd94733aeccdae68debba30a3588b71625f9ec7669d3f4c51317192f5acdee9b968d1a6db4a98a9c0eeef63a969c2ecaba95a9ddfd5841d996977696e41a541393ba40ae44b71c00129a25b30f6c44e89d8d020111300d06092a864886f70d01010505000382010100706c7eb29939c38cfcbab592c62a3572e05dcaa4d54e24cce74a244972e74ac8ed6e0b3eb1add0d4de6007d392ac75a7fb9836a9a1d937d0b2c3f01a6b1994ac317328527c763eae26a6ca647752badcd09e73364ac7828d375b4966e510de1cdbd01a5be047e45533f5a3d81df00ffe9d13fe5d54e18584691abb3a9a3d423d348d7714382317547338a8e83d14f404348db41c10a05e57221eda1e220b265ae4237e59ab2db1facbe8cc8d2198ca5fe2ad074bb8c7c4dd675cbe3d60b9e29f6b12ab4c587c6576e1ce2d2512be035e4692100c6c3e47d4d84dbbc865804af1bd0240fb804ef99c7038191dae2fab73a1a1ffa09f536a0fbf49fa1a3234b62a idx = 2 diff --git a/hotstuff-sec3.conf b/hotstuff-sec3.conf index feed5f33..9c36b9ba 100644 --- a/hotstuff-sec3.conf +++ b/hotstuff-sec3.conf @@ -1,4 +1,4 @@ -privkey = 30a444081a5c13cbb9606908caeb7fe6611a4042bb2efb6de71e9f918d36592a +privkey = 3d0cdf598a2514649a5dedf626467716d04e22d2b6a83dc0f5ca810701f728f3 tls-privkey = 308204a20201000282010100de01b461213afa37d4aa68bdc7e1a6de12307440f1de6588e5362450694cbb4ba63b1f992a7dc88b999c7dec9088d17253ac278c33018ea8caa1f96c7d90bcb5a6a3f8568825bafa9a696699a4eaf0c6fcdd8ed7bc91a688ead564fb882a1c25c7f72bbe44eb44fda1d11d6ca090503e36de532f2fededff03da30f8f95f11b6472e9588fd6be69cad285915c68edaa7754c6524017bf08c3c336f04d0246d8e967a4de2824a3ac7486aaf9160540c63f75d36ecba9261ff6b859a7684b023ecfbc5408dc7c59942c76464040770c6097833dd770a7dffc6ed6a8716b1f683379843969f937d859d8f69a21362eda9dabd64dd6fb7131ee46b2654d3aa8dc9df02011102820100414bcba418d51c6ac61400b049d8f4d7e73b6d7c835f8746618865089770ebcaf4a7fa3c1b8e68290f0fe8cd1b7388e563e756ecfff16631a5027689521b82cc03d5dfa0faddebb31e5b3c4b4e9f73fe4a5f48215594400a26f3780dbea2f93849df4919d808f62c7ae326c598a2ea6ca6b9dc3b0e18cd873d5e4aa394a37dad88a49b91b7446343d03d4ea067b72c62ba622d68f7fb97c031a7f9259401318905e092b0aec27e643fb3efd9bf392050941d43fe06a87630412bf765a4800f57561a9fc339ff92a9b33e748efe5c6ddafe4069e99cf039794b4641ab4f199703860b4f8ee3669a04ad664379012650e68debe0ccc4c41a39e6bf8a3de15003f902818100f56482abd14db0f327311b376dc4cfac86cc3379036b6672713d296a0665797de7b115350d77a27193de1f5abd9e2b44eff6c5a323b1209c4aac68c86e3488abab89139a7cbb98a4f0c1e930c2bc276bbcf0efd47cf4dc6614b9c16c332a5f7ef339d5c746780884a66e087236ec784361fda7e72c21528c0427d7abbc9751f502818100e79a68542368e4295b8d3289c4f4da780e6597461952b9592221901b05bae53ece00df87ef7084340f28c71f188d400d0fcfbd504d0ae2bf101082214d9500b1f8480dc1ec3ea7900ece21b9e3e0c2b5279b1f21de585ff7a58eb330d841ef13107ce58c14a8a4a29b6cb438f4e551baac120603878a3ff9f00cda5589800403028181009ec890c9876e818e46892fba74340de81afc99c6c5fa333afdfa66176d8cf44268bde08bbd6b873a6ebce71c98cfc1a513bdcb2d53547e833f60800938401c32d867c163f65b44a6f6231e6ad85ba1097a418c20149e707e49a55f09c6c1109d70347b44b5207dfb7abfab1cba208a0d7ba4215958ca4478b7651314c552daad02818100cc5b10c2b5d5058de75e77e2f914484bd077c1b652944930878706ae6e77bb376a793db42d9f83b576c9a0a2f78bb0fc775cf255e9a0317b68870968adddd36fdb12667dee91a2e88588b458ba028daee6b60c692d99459e46c934b2a0b2a5c58704ca8aa8d109bca741cc32417f0be0f22e054e68890b45f1ed391e4c25a92f02818016d4c0a1d4cc7fadb7033ae8506221a7dde9c2437fe5989175e8de47791b4ff957fb485d6d04c85b9fd1d7734950dc4d032dd3fdf9c14193b04ea179839fb4560282d106b684b5712a9b140afbe4d92ff30c745a7bdca71de9808f6d2a88340e116cc4475e908993c27a27847601ec378d4357dc5e99a147c60d7258e282453e tls-cert = 308202e4308201cc020101300d06092a864886f70d01010505003039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f7374301e170d3139303730323036353535365a170d3139303730323036353535365a3039310b300906035504061302555331163014060355040a0c0d6c696273616c746963696461653112301006035504030c096c6f63616c686f737430820120300d06092a864886f70d01010105000382010d00308201080282010100de01b461213afa37d4aa68bdc7e1a6de12307440f1de6588e5362450694cbb4ba63b1f992a7dc88b999c7dec9088d17253ac278c33018ea8caa1f96c7d90bcb5a6a3f8568825bafa9a696699a4eaf0c6fcdd8ed7bc91a688ead564fb882a1c25c7f72bbe44eb44fda1d11d6ca090503e36de532f2fededff03da30f8f95f11b6472e9588fd6be69cad285915c68edaa7754c6524017bf08c3c336f04d0246d8e967a4de2824a3ac7486aaf9160540c63f75d36ecba9261ff6b859a7684b023ecfbc5408dc7c59942c76464040770c6097833dd770a7dffc6ed6a8716b1f683379843969f937d859d8f69a21362eda9dabd64dd6fb7131ee46b2654d3aa8dc9df020111300d06092a864886f70d010105050003820101007f9d4f2848059831e5ea7d727d9b09f826027c78fdc86d27ea83d32d727ac4a0484e55ed34851adcc8903a3ef39c1b0c447c28cd84cbc513cdcd607da3fa903495a70b7772e71873e3c8a734d3e8b9f82c7380604ccb8416bd92822e703a3b8839aff411f967d2bcc1cd96d158e7839a2bff6110ffd005808f7047fd57a7150c1e14ddcfd2e1a24a5878f99409b7ede1d5f4a385077b6f55f4818c854c6e64adb4789433667e672b9a615b680301a05852255cef958ff1031a489dd95327d045be0315359644ec51f2fd3cb724382ba2425da519dbf1d89098e10a1091f44c7a8e12733b7d0b1fce7c6d19adfee3cdac89f95ed1ae979093cb2793892724d7d9 idx = 3 diff --git a/hotstuff.conf b/hotstuff.conf index ba68173f..5cdd0905 100644 --- a/hotstuff.conf +++ b/hotstuff.conf @@ -1,9 +1,6 @@ block-size = 1 pace-maker = rr -master-pub = 8df60c260df14181197974051be16d9a8485c6c828b1d4f241da11bc60c7d068f0ad7e0c1d269fc7aa86f2b9204e1ca1 -replica = 127.0.0.1:10000;20000, 8a0f04a4d41e7a993336d3f5cb5f32d2fa468af5ceae179b1b9f1c6e698da5c98ccc8cfcc4226f8c3eaf466941c6c8f9, 542865a568784c4e77c172b82e99cb8a1a53b7bee5f86843b04960ea4157f420 -replica = 127.0.0.1:10001;20001, 03d1052326a84450c0086f64515a71524f8f5e13cd49ca0fddf692204bde34c7e036b201668704d9ba77cb62e38cae81, c261250345ebcd676a0edeea173526608604f626b2e8bc4fd2142d3bde1d44d5 -replica = 127.0.0.1:10002;20002, 842d687d00d36f21f971858ab7cb6d5fccc6f95c016abb9f69e3598ccb4d29efa998d5243308df0a107fb0369f59cfae, 065b010aed5629edfb5289e8b22fc6cc6b33c4013bfdd128caba80c3c02d6d78 -replica = 127.0.0.1:10003;20003, 81c8addfbeae6e7fc06dbad0f4db0b438dffd62cf235c770f776b3c96c866f7a74ad0ddda5281df2c3635a77a4bf7e85, 6540a0fea67efcb08f53ec3a952df4c3f0e2e07c2778fd92320807717e29a651 - - +replica = 127.0.0.1:10000;20000, 039f89215177475ac408d079b45acef4591fc477dd690f2467df052cf0c7baba23, 542865a568784c4e77c172b82e99cb8a1a53b7bee5f86843b04960ea4157f420 +replica = 127.0.0.1:10001;20001, 0278740a5bec75e333b3c93965b1609163b15d2e3c2fdef141d4859ec70c238e7a, c261250345ebcd676a0edeea173526608604f626b2e8bc4fd2142d3bde1d44d5 +replica = 127.0.0.1:10002;20002, 0269eb606576a315a630c2483deed35cc4bd845abae1c693f97c440c89503fa92e, 065b010aed5629edfb5289e8b22fc6cc6b33c4013bfdd128caba80c3c02d6d78 +replica = 127.0.0.1:10003;20003, 03e6911bf17e632eecdfa0dc9fc6efc9ddca60c0e3100db469a3d3d62008044a53, 6540a0fea67efcb08f53ec3a952df4c3f0e2e07c2778fd92320807717e29a651 \ No newline at end of file From 465f5525db9670aa6aa48923253d984813771c03 Mon Sep 17 00:00:00 2001 From: Ray Neiheiser Date: Mon, 22 Jun 2020 15:19:56 +0100 Subject: [PATCH 08/11] add gitignore for log files. --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index dfce86d5..551b03ae 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,5 @@ core hotstuff-keygen_bls hotstuff.cbp + +log* From 45fbaab8bd64c5afe8e215c86170612a61813c11 Mon Sep 17 00:00:00 2001 From: Ray Neiheiser Date: Mon, 22 Jun 2020 15:20:25 +0100 Subject: [PATCH 09/11] reset this to default --- examples/hotstuff_app.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/hotstuff_app.cpp b/examples/hotstuff_app.cpp index 3584400f..5edca006 100644 --- a/examples/hotstuff_app.cpp +++ b/examples/hotstuff_app.cpp @@ -63,7 +63,7 @@ using hotstuff::MsgRespCmd; using hotstuff::get_hash; using hotstuff::promise_t; -using HotStuff = hotstuff::HotStuffTH; +using HotStuff = hotstuff::HotStuffSecp256k1 ; class HotStuffApp: public HotStuff { double stat_period; From 5e191d2e7a51806156b3740280567d79fd4fd49c Mon Sep 17 00:00:00 2001 From: Ray Neiheiser Date: Tue, 23 Jun 2020 20:24:23 +0100 Subject: [PATCH 10/11] push --- bls/build/contrib/relic/lib/librelic_s.a | Bin 0 -> 1555590 bytes bls/build/libbls.a | Bin 0 -> 1869204 bytes bls/build/src/libbls.a | Bin 0 -> 9960 bytes bls/build/src/libblstmp.a | Bin 0 -> 313746 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 bls/build/contrib/relic/lib/librelic_s.a create mode 100644 bls/build/libbls.a create mode 100644 bls/build/src/libbls.a create mode 100644 bls/build/src/libblstmp.a diff --git a/bls/build/contrib/relic/lib/librelic_s.a b/bls/build/contrib/relic/lib/librelic_s.a new file mode 100644 index 0000000000000000000000000000000000000000..f41c2d2b8e7f9bdfdf89270ebb3a618fb8508ab2 GIT binary patch literal 1555590 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

q3V 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

~S<^wBP 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%0Dk$<@>tHKIk8n|EO@4A1wS+lCLqs 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

KF4UFZ}8||0t`7 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�^0Du$#a1sD~2LLt!fR6#d4*=kO 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

lX;%$ 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�%uS9qibSN)|>X>v-Fw6L*1d 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

{#_+N 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 P%dJJq3yDjsIsX3u1KIHh literal 0 HcmV?d00001 diff --git a/bls/build/src/libbls.a b/bls/build/src/libbls.a new file mode 100644 index 0000000000000000000000000000000000000000..f49fee19d4a0348dee9d72b92a688d7ad2f58d10 GIT binary patch literal 9960 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 A=>Px# literal 0 HcmV?d00001 diff --git a/bls/build/src/libblstmp.a b/bls/build/src/libblstmp.a new file mode 100644 index 0000000000000000000000000000000000000000..12b7349d00f4eb7bc530ed7f11f66a01820032bb GIT binary patch literal 313746 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 kHlY~v!Q(Sddmx?Nt; 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 literal 0 HcmV?d00001 From 50491ea020214f511f5b4e7ea5d8c2c524100623 Mon Sep 17 00:00:00 2001 From: Ray Neiheiser Date: Wed, 24 Jun 2020 09:10:21 +0100 Subject: [PATCH 11/11] fix file --- CMakeLists.txt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c7042f6..245e03a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,12 +23,15 @@ add_subdirectory(salticidae) include_directories(salticidae/include) INCLUDE_DIRECTORIES(bls/src) -LINK_DIRECTORIES(bls/build/src) - -LINK_DIRECTORIES(bls/build/contrib/relic/lib) INCLUDE_DIRECTORIES(bls/build/contrib/relic/include) INCLUDE_DIRECTORIES(bls/contrib/relic/include) +add_library( blstmp STATIC IMPORTED ) +set_target_properties( blstmp PROPERTIES IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/bls/build/src/libblstmp.a ) + +add_library( relic_s STATIC IMPORTED ) +set_target_properties( relic_s PROPERTIES IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/bls/build/contrib/relic/lib/librelic_s.a ) + find_package(OpenSSL REQUIRED) find_package(Threads REQUIRED)