├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── experiments ├── redraw-all.sh └── vcs │ ├── .gitignore │ ├── redraw.sh │ └── run-experiments.sh ├── libvectcom ├── CMakeLists.txt ├── app │ ├── CMakeLists.txt │ ├── ParamsGenPowers.cpp │ ├── ParamsGenTrapdoors.cpp │ └── ParamsValidate.cpp ├── bench │ ├── BenchAMT.cpp │ ├── BenchConvertAndMultiexp.cpp │ ├── BenchExp.cpp │ ├── BenchFFT.cpp │ ├── BenchFk.cpp │ ├── BenchMultiexp.cpp │ ├── BenchNtlConversion.cpp │ ├── BenchPairing.cpp │ ├── BenchPointproofs.cpp │ ├── BenchPolyDivideXnc.cpp │ ├── BenchPolynomialOps.cpp │ ├── BenchRootsOfUnityEval.cpp │ ├── CMakeLists.txt │ └── Utils.h ├── examples │ └── CMakeLists.txt ├── include │ └── vectcom │ │ ├── AccumulatorTree.h │ │ ├── BinaryTree.h │ │ ├── Configuration.h │ │ ├── FFT.h │ │ ├── KZG.h │ │ ├── KatePublicParameters.h │ │ ├── NtlLib.h │ │ ├── PolyCrypto.h │ │ ├── PolyOps.h │ │ ├── RootsOfUnityEval.h │ │ └── Utils.h ├── src │ ├── CMakeLists.txt │ ├── KatePublicParameters.cpp │ ├── Kzg.cpp │ ├── PolyCrypto.cpp │ ├── PolyOps.cpp │ └── Utils.cpp └── test │ ├── CMakeLists.txt │ ├── TestGroupFft.cpp │ ├── TestKatePublicParams.cpp │ ├── TestLibff.cpp │ ├── TestParallelPairing.cpp │ ├── TestPolyDivideXnc.cpp │ ├── TestPolyOps.cpp │ ├── TestRootsOfUnity.cpp │ └── TestRootsOfUnityEval.cpp ├── public-params ├── 65536 │ ├── 65536 │ ├── 65536-0 │ ├── 65536-0.log │ ├── 65536-1 │ ├── 65536-1.log │ ├── 65536-10 │ ├── 65536-10.log │ ├── 65536-11 │ ├── 65536-11.log │ ├── 65536-2 │ ├── 65536-2.log │ ├── 65536-3 │ ├── 65536-3.log │ ├── 65536-4 │ ├── 65536-4.log │ ├── 65536-5 │ ├── 65536-5.log │ ├── 65536-6 │ ├── 65536-6.log │ ├── 65536-7 │ ├── 65536-7.log │ ├── 65536-8 │ ├── 65536-8.log │ ├── 65536-9 │ └── 65536-9.log └── .gitignore └── scripts └── linux ├── cmake.sh ├── cols.sh ├── generate-qsdh-params.sh ├── install-deps.sh ├── install-libs.sh ├── make.sh ├── plot-vcs.py ├── rename-library.sh ├── set-env.sh ├── shlibs ├── check-env.sh └── os.sh ├── submodule-update.sh └── test.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.a 3 | *.so 4 | *.d 5 | depinst/ 6 | depsrc/ 7 | /build 8 | README.html 9 | CHANGELOG.html 10 | doxygen/ 11 | /Testing 12 | core 13 | *.png 14 | .DS_Store 15 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "depends/libff"] 2 | path = depends/libff 3 | url = git://github.com/scipr-lab/libff.git 4 | [submodule "depends/libfqfft"] 5 | path = depends/libfqfft 6 | url = https://github.com/scipr-lab/libfqfft.git 7 | [submodule "depends/xbyak"] 8 | path = depends/xbyak 9 | url = git://github.com/herumi/xbyak.git 10 | [submodule "depends/ate-pairing"] 11 | path = depends/ate-pairing 12 | url = git://github.com/herumi/ate-pairing.git 13 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.2) 2 | # project( VERSION LANGUAGES CXX) 3 | project(libvectcom VERSION 0.1.0.0 LANGUAGES CXX) 4 | 5 | # 6 | # Configuration options 7 | # 8 | set( 9 | CURVE 10 | "BN128" 11 | CACHE 12 | STRING 13 | "Default curve: one of ALT_BN128, BN128, EDWARDS, MNT4, MNT6" 14 | ) 15 | 16 | option( 17 | BINARY_OUTPUT 18 | "In serialization of elliptic curve points, output raw binary data (instead of decimal), which is smaller and faster." 19 | OFF 20 | ) 21 | 22 | add_definitions( 23 | -DCURVE_${CURVE} 24 | ) 25 | 26 | option( 27 | USE_MULTITHREADING 28 | "Enable parallelized execution of DKG protocols using OpenMP" 29 | OFF 30 | ) 31 | 32 | if(${CURVE} STREQUAL "BN128") 33 | add_definitions( 34 | -DBN_SUPPORT_SNARK=1 35 | ) 36 | endif() 37 | 38 | # 39 | # Configure CCache if available 40 | # 41 | find_program(CCACHE_FOUND ccache) 42 | if(CCACHE_FOUND) 43 | set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache) 44 | set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) 45 | endif(CCACHE_FOUND) 46 | 47 | #find_package(Threads REQUIRED) 48 | #find_package(Boost 1.65 COMPONENTS program_options REQUIRED) 49 | #include_directories(${Boost_INCLUDE_DIR}) 50 | 51 | # OS X Catalina fix 52 | include_directories(SYSTEM "/usr/local/include") 53 | link_directories("/usr/local/lib") 54 | 55 | set(vectcom_packages 56 | xassert 57 | xutils 58 | ) 59 | 60 | # 61 | # Dependencies 62 | # 63 | # TODO: Find ate-pairing, libff, libfqfft too or issue error with pointer to install script 64 | foreach(package ${vectcom_packages}) 65 | find_package(${package} QUIET) 66 | 67 | if(${package}_FOUND) 68 | message("${package} library is installed!") 69 | else() 70 | message("${package} library not installed locally, please download from https//github.com/alinush/lib${package}") 71 | endif() 72 | endforeach() 73 | 74 | # 75 | # C++ options 76 | # TODO: change to set_target_properties? 77 | # https://crascit.com/2015/03/28/enabling-cxx11-in-cmake/ 78 | # 79 | set(CMAKE_CXX_STANDARD 14) 80 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 81 | set(CMAKE_CXX_EXTENSIONS OFF) 82 | 83 | # 84 | # Compiler flags 85 | # 86 | 87 | # When you do 'a > b in 'C/C++, if a is unsigned and b is signed and equal to -1, C/C++ 88 | # actually casts b to unsigned (probably because casting unsigned to signed would require a bigger data type) 89 | # Thus, 1 > -1 will evaluate to false because during the cast -1 will be set to to 2^32 - 1 90 | # 91 | # WARNING: For the love of god, do not remove this flag or you will regret it. Instead, 92 | # just use signed types everywhere and cast your unsigned to signed when mixing unsigned 93 | # variables with signed ones. See: http://soundsoftware.ac.uk/c-pitfall-unsigned 94 | set(CXX_FLAGS_INTEGER_CORRECTNESS 95 | "-Wconversion -Wsign-conversion -Wsign-compare") 96 | set(CXX_FLAGS_FORMAT 97 | "-Wformat-y2k -Wno-format-extra-args -Wno-format-zero-length -Wformat-nonliteral -Wformat-security -Wformat=2") 98 | set(CXX_FLAGS_OPTIMIZATIONS "-O3") 99 | 100 | string(APPEND CXX_FLAGS " ${CXX_FLAGS_OPTIMIZATIONS}") 101 | string(APPEND CXX_FLAGS " ${CXX_FLAGS_FORMAT}") 102 | string(APPEND CXX_FLAGS " ${CXX_FLAGS_INTEGER_CORRECTNESS}") 103 | # TODO: use target_compile_features instead: 104 | # https://cmake.org/cmake/help/v3.1/command/target_compile_features.html#command:target_compile_features 105 | # https://cmake.org/cmake/help/v3.1/prop_gbl/CMAKE_CXX_KNOWN_FEATURES.html#prop_gbl:CMAKE_CXX_KNOWN_FEATURES 106 | string(APPEND CXX_FLAGS " -Wall") 107 | string(APPEND CXX_FLAGS " -Werror") 108 | string(APPEND CXX_FLAGS " -Wextra") 109 | 110 | 111 | # TODO: Figure out right way to deal with -fstrict-overflow / -Wstrict-overflow related errors 112 | string(APPEND CXX_FLAGS 113 | " -fno-strict-overflow") 114 | string(APPEND CXX_FLAGS_DEBUG 115 | " -O1") 116 | # "It turns out that some gcc builds (depends on the distro) set _FORTIFY_SOURCE internally, so you need to undefine it first. So if you used CFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2", it might go better." 117 | # https://github.com/neovim/neovim/issues/2557 118 | string(APPEND CXX_FLAGS_DEBUG 119 | " -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2") 120 | 121 | if("${USE_MULTITHREADING}") 122 | add_definitions(-DUSE_MULTITHREADING) 123 | string(APPEND CMAKE_CXX_FLAGS " -fopenmp") 124 | endif() 125 | 126 | # GNU and Clang-specific flags 127 | string(APPEND CMAKE_CXX_FLAGS 128 | " ${CXX_FLAGS}") 129 | string(APPEND CMAKE_CXX_FLAGS_DEBUG 130 | " ${CXX_FLAGS_DEBUG}") 131 | # When building with 'cmake -DCMAKE_BUILD_TYPE=Trace' 132 | string(APPEND CMAKE_CXX_FLAGS_TRACE 133 | " ${CXX_FLAGS_DEBUG} -DTRACE") 134 | 135 | # using Clang 136 | if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") 137 | # Clang-specific options 138 | string(APPEND CMAKE_CXX_FLAGS 139 | " -ferror-limit=3") 140 | string(APPEND CMAKE_CXX_FLAGS_DEBUG 141 | " -fstack-protector-all -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls") 142 | # TODO: doesn't seem to work on MacOS, getting strange linking errors 143 | #string(APPEND CMAKE_CXX_FLAGS_DEBUG 144 | # " -D_LIBCPP_DEBUG=0") 145 | #string(APPEND CMAKE_CXX_FLAGS_DEBUG 146 | # " -D_LIBCPP_DEBUG=1") 147 | 148 | # using GCC 149 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") 150 | # GCC-specific options 151 | string(APPEND CMAKE_CXX_FLAGS 152 | " -fmax-errors=3") 153 | string(APPEND CMAKE_CXX_FLAGS_DEBUG 154 | " -fstack-protector-all") 155 | # NOTE: define _GLIBCXX_DEBUG if you want bounds checking for std::vector::operator[] (but it seems to cause a segfault at the end of execution) 156 | # only works for libstdc++ from the GNU compiler, I think 157 | string(APPEND CMAKE_CXX_FLAGS_DEBUG 158 | " -D_GLIBCXX_DEBUG") 159 | 160 | # TODO: using Intel C++ 161 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") 162 | 163 | # TODO: using Visual Studio C++ 164 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") 165 | 166 | endif() 167 | 168 | # 169 | # Testing flags 170 | # 171 | enable_testing() 172 | 173 | # Subdirectories 174 | add_subdirectory(libvectcom) 175 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2020, Alin Tomescu 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libvectcom 2 | 3 | ## Build on Linux 4 | 5 | Step zero is to clone this repo and `cd` to the right directory: 6 | 7 | cd 8 | 9 | If you're running OS X, make sure you have the Xcode **and** the Xcode developer tools installed: 10 | 11 | xcode-select --install 12 | 13 | First, install deps using: 14 | 15 | scripts/linux/install-libs.sh 16 | scripts/linux/install-deps.sh 17 | 18 | Then, set up the environment. This **will store the built code in ~/builds/vectcom/**: 19 | 20 | . scripts/linux/set-env.sh release 21 | 22 | ...you can also use `debug`, `relwithdebug` or `trace` as an argument for `set-env.sh`. 23 | 24 | To build: 25 | 26 | make.sh 27 | 28 | ..tests, benchmarks and any other binaries are automatically added to `PATH` but can also be found in 29 | 30 | cd ~/builds/vectcom/master/release/libvectcom/bin/ 31 | 32 | (or replace `release` with `debug` or whatever you used in `set-env.sh`) 33 | 34 | ## Useful scripts 35 | 36 | There's a bunch of useful scripts in `scripts/linux/`: 37 | 38 | - `plot-*.py` for generating plots 39 | - `cols.sh` for viewing CSV data in the terminal 40 | - `generate-qsbdh-params.sh` for generating public parameters for the KZG/Pointproof code 41 | 42 | ## Git submodules 43 | 44 | This is just for reference purposes. 45 | No need to execute these. 46 | To fetch the submodules, just do: 47 | 48 | git submodule init 49 | git submodule update 50 | 51 | For historical purposes, (i.e., don't execute these), when I set up the submodules, I did: 52 | 53 | cd depends/ 54 | git submodule add git://github.com/herumi/ate-pairing.git 55 | git submodule add git://github.com/herumi/xbyak.git 56 | git submodule add git://github.com/scipr-lab/libff.git 57 | git submodule add https://github.com/scipr-lab/libfqfft.git 58 | 59 | To update your submodules with changes from their upstream github repos, do: 60 | 61 | git submodule foreach git pull origin master 62 | 63 | -------------------------------------------------------------------------------- /experiments/redraw-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | scriptdir=$(cd $(dirname $0); pwd -P) 5 | 6 | #echo "Script dir: $scriptdir" 7 | (cd $scriptdir/vcs/; ./redraw.sh ) 8 | -------------------------------------------------------------------------------- /experiments/vcs/.gitignore: -------------------------------------------------------------------------------- 1 | *.csv 2 | *.log 3 | -------------------------------------------------------------------------------- /experiments/vcs/redraw.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | scriptdir=$(cd $(dirname $0); pwd -P) 5 | 6 | plot_cmd=$scriptdir/../../scripts/linux/plot-vcs.py 7 | 8 | rm -f $scriptdir/fk-vs-pointproofs.png 9 | $plot_cmd $scriptdir/fk-vs-pointproofs.png 0 0 $scriptdir/*.csv 10 | -------------------------------------------------------------------------------- /experiments/vcs/run-experiments.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $# -lt 2 ]; then 4 | echo "Runs the VC proof computation benchmark for the specified scheme with increasing n = 2, 4, 8, 16, \dots, " 5 | echo 6 | echo "Usage: $0 []" 7 | echo 8 | echo "OPTIONS:" 9 | echo " can be either 'fk' or 'pointproofs'" 10 | echo " when is 'pointproofs', this can be either 'naive' or 'efficient' (defaults to 'efficient')" 11 | exit 1 12 | fi 13 | 14 | scriptdir=$(cd $(dirname $0); pwd -P) 15 | date=`date +%Y-%m-%d` # %H-%M-%S if you want hours, minutes & seconds 16 | machine=$1 17 | scheme=$2 18 | naive=${3:-"efficient"} 19 | 20 | if [ $scheme = "fk" ]; then 21 | : 22 | elif [ $scheme = "pointproofs" ]; then 23 | : 24 | else 25 | echo "ERROR: must be either 'fk' or 'pointproofs'" 26 | exit 1 27 | fi 28 | 29 | if [ $naive = "naive" ]; then 30 | wantNaive=1 31 | echo "Doing naive Pointproofs" 32 | elif [ $naive = "efficient" ]; then 33 | wantNaive=0 34 | echo "Doing efficient Pointproofs" 35 | else 36 | echo "ERROR: must be either 'naive' or 'efficient'" 37 | exit 1 38 | fi 39 | 40 | 41 | which BenchFk 2>&1 >/dev/null || { echo "ERROR: You did not set up the environment"; exit 1; } 42 | which BenchPointproofs 2>&1 >/dev/null || { echo "ERROR: You did not set up the environment"; exit 1; } 43 | 44 | # Format: 45 | benchmarks="\ 46 | fk 2 10 - 47 | fk 4 10 - 48 | fk 8 10 - 49 | fk 16 10 - 50 | fk 32 10 - 51 | fk 64 10 - 52 | fk 128 10 - 53 | fk 256 10 - 54 | fk 512 10 - 55 | fk 1024 10 - 56 | pointproofs 2 10 1 57 | pointproofs 2 10 0 58 | pointproofs 4 10 1 59 | pointproofs 4 10 0 60 | pointproofs 8 10 1 61 | pointproofs 8 10 0 62 | pointproofs 16 10 1 63 | pointproofs 16 10 0 64 | pointproofs 32 10 1 65 | pointproofs 32 10 0 66 | pointproofs 64 10 1 67 | pointproofs 64 10 0 68 | pointproofs 128 5 1 69 | pointproofs 128 10 0 70 | pointproofs 256 2 1 71 | pointproofs 256 10 0 72 | pointproofs 512 1 1 73 | pointproofs 512 10 0 74 | pointproofs 1024 1 1 75 | pointproofs 1024 10 0 76 | " 77 | 78 | test_benchmarks="\ 79 | fk 2 10 - 80 | fk 4 10 - 81 | pointproofs 2 10 1 82 | pointproofs 2 10 0 83 | pointproofs 4 10 1 84 | pointproofs 4 10 0 85 | " 86 | 87 | # sort by n 88 | filtered=`echo "$benchmarks" | grep ^$scheme` 89 | min_and_max=`echo "$filtered" | sort -t' ' -nk2 | awk 'NR==1; END{print}'` 90 | min_n=`echo "$min_and_max" | cut -d' ' -f 2 | head -n 1` 91 | max_n=`echo "$min_and_max" | cut -d' ' -f 2 | tail -n 1` 92 | echo "Min n: $min_n" 93 | echo "Max n: $max_n" 94 | 95 | pp_file=$scriptdir/../../public-params/65536/65536 96 | 97 | while read -r b; do 98 | sch=`echo $b | cut -d' ' -f 1` 99 | n=`echo $b | cut -d' ' -f 2` 100 | r=`echo $b | cut -d' ' -f 3` 101 | isNaive=`echo $b | cut -d' ' -f 4` 102 | 103 | 104 | if [ "$sch" != "$scheme" ]; then 105 | continue 106 | fi 107 | 108 | if [ "$isNaive" != "-" -a "$isNaive" != "$wantNaive" ]; then 109 | continue 110 | fi 111 | 112 | file=${date}-${sch}-vc-${min_n}-${max_n}-${machine}.csv 113 | logfile=${date}-${sch}-vc-${min_n}-${max_n}-${machine}.log 114 | if [ $sch == "pointproofs" ]; then 115 | echo "Running benchmark for $sch ($naive) with n = $n ($r iters)" 116 | echo " \--> Logging to $logfile ..." 117 | BenchPointproofs $pp_file $n $r $file $wantNaive 2>&1 | tee -a $logfile 118 | else 119 | echo "Running benchmark for $sch with n = $n ($r iters)" 120 | echo " \--> Logging to $logfile ..." 121 | BenchFk $pp_file $(($n-1)) $n $r $file 2>&1 | tee -a $logfile 122 | fi 123 | done <<< "$benchmarks" 124 | -------------------------------------------------------------------------------- /libvectcom/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(src) 2 | add_subdirectory(examples) 3 | add_subdirectory(test) 4 | add_subdirectory(bench) 5 | add_subdirectory(app) 6 | -------------------------------------------------------------------------------- /libvectcom/app/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(vectcom_app_sources 2 | ParamsGenTrapdoors.cpp 3 | ParamsGenPowers.cpp 4 | ParamsValidate.cpp 5 | ) 6 | 7 | foreach(appSrc ${vectcom_app_sources}) 8 | get_filename_component(appName ${appSrc} NAME_WE) 9 | set(appDir ../bin/app) 10 | 11 | add_executable(${appName} ${appSrc}) 12 | target_link_libraries(${appName} PUBLIC vectcom) 13 | 14 | set_target_properties(${appName} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${appDir}) 15 | endforeach() 16 | 17 | #install(TARGETS PlayApp DESTINATION bin) 18 | -------------------------------------------------------------------------------- /libvectcom/app/ParamsGenPowers.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | using namespace libvectcom; 8 | 9 | int main(int argc, char *argv[]) 10 | { 11 | libvectcom::initialize(nullptr, 0); 12 | 13 | if(argc < 5) { 14 | cout << "Usage: " << argv[0] << " " << endl; 15 | cout << endl; 16 | cout << "Reads 's' from and outputs q-SDH parameters (g_1^{s_i}) for i \\in [, ) to ." << endl; 17 | return 1; 18 | } 19 | 20 | string inFile(argv[1]); 21 | string outFile(argv[2]); 22 | size_t start = static_cast(std::stoi(argv[3])), 23 | end = static_cast(std::stoi(argv[4])); 24 | 25 | ifstream fin(inFile); 26 | 27 | if(fin.fail()) { 28 | throw std::runtime_error("Could not read trapdoors input file"); 29 | } 30 | 31 | Fr s; 32 | fin >> s; 33 | 34 | Dkg::KatePublicParameters::generate(start, end, s, outFile, true); 35 | 36 | 37 | loginfo << "All done!" << endl; 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /libvectcom/app/ParamsGenTrapdoors.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | using namespace std; 7 | using namespace libvectcom; 8 | 9 | int main(int argc, char *argv[]) 10 | { 11 | libvectcom::initialize(nullptr, 0); 12 | 13 | if(argc < 3) { 14 | cout << "Usage: " << argv[0] << " " << endl; 15 | cout << endl; 16 | cout << "Generates 's' and writes it and 'q' to " << endl; 17 | return 1; 18 | } 19 | 20 | string outFile(argv[1]); 21 | size_t q = static_cast(std::stoi(argv[2])); 22 | 23 | ofstream fout(outFile); 24 | 25 | if(fout.fail()) { 26 | std::cout << "ERROR: Could not open file: " << outFile << endl; 27 | throw std::runtime_error("Could not open trapdoor output file"); 28 | } 29 | 30 | Fr s = Fr::random_element(); 31 | fout << s << endl; 32 | fout << q << endl; 33 | 34 | loginfo << "All done!" << endl; 35 | 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /libvectcom/app/ParamsValidate.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | using namespace std; 8 | using namespace libvectcom; 9 | 10 | int main(int argc, char *argv[]) 11 | { 12 | libvectcom::initialize(nullptr, 0); 13 | 14 | if(argc < 2) { 15 | cout << "Usage: " << argv[0] << " " << endl; 16 | cout << endl; 17 | cout << "Reads 's', 'q' from and then reads the parameters from - for i = 0, 1, ..." << endl; 18 | return 1; 19 | } 20 | 21 | string inFile(argv[1]); 22 | 23 | Dkg::KatePublicParameters pp(inFile, 0, true, true); 24 | 25 | loginfo << "All done!" << endl; 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /libvectcom/bench/BenchAMT.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | using namespace std; 17 | using namespace libfqfft; 18 | using namespace libvectcom; 19 | 20 | void logMemUsage() { 21 | size_t vms, rss; 22 | getMemUsage(vms, rss); 23 | logperf << "VMS: " << Utils::humanizeBytes(vms) << endl; 24 | logperf << "RSS: " << Utils::humanizeBytes(rss) << endl; 25 | logperf << endl; 26 | } 27 | 28 | int main(int argc, char *argv[]) { 29 | libvectcom::initialize(nullptr, 0); 30 | 31 | if(argc < 5) { 32 | cout << "Usage: " << argv[0] << " " << endl; 33 | cout << endl; 34 | cout << "OPTIONS: " << endl; 35 | cout << " the Kate public parameters file" << endl; 36 | cout << " the degree of the evaluated polynomial" << endl; 37 | cout << " the # of points to evaluate at (i.e., # of AMT leaves)" << endl; 38 | cout << " the # of times to repeat the AMT auth + verif" << endl; 39 | cout << endl; 40 | 41 | return 1; 42 | } 43 | 44 | std::string ppFile = argv[1]; 45 | size_t deg = static_cast(std::stoi(argv[2])); 46 | size_t n = static_cast(std::stoi(argv[3])); 47 | size_t r = static_cast(std::stoi(argv[4])); 48 | 49 | std::unique_ptr kpp( 50 | new Dkg::KatePublicParameters(ppFile, deg)); 51 | 52 | loginfo << endl; 53 | loginfo << "Degree " << deg << " poly, evaluated at n = " << n << " points, iters = " << r << endl; 54 | 55 | AveragingTimer at("Accum tree"); 56 | at.startLap(); 57 | AccumulatorTree accs(n); 58 | auto mus = at.endLap(); 59 | 60 | logperf << " - AccumulatorTree: " << Utils::humanizeMicroseconds(mus, 2) << endl; 61 | 62 | // NOTE: Uncomment this to see beautiful roots-of-unity structure 63 | //std::cout << "Accumulator tree for n = " << n << endl; 64 | //std::cout << accs.toString() << endl; 65 | 66 | std::vector f = random_field_elems(deg + 1); 67 | 68 | // Step 1: Fast multipoint eval 69 | AveragingTimer et("Roots-of-unity eval "); 70 | et.startLap(); 71 | RootsOfUnityEvaluation eval(f, accs); 72 | std::vector evals = eval.getEvaluations(); 73 | mus = et.endLap(); 74 | 75 | logperf << " - Roots of unity eval: " << Utils::humanizeMicroseconds(mus, 2) << endl; 76 | 77 | // Step 2: Authenticate AccumulatorTree 78 | AveragingTimer aat("Auth accum tree"); 79 | aat.startLap(); 80 | AuthAccumulatorTree authAccs(accs, *kpp, deg+1); 81 | mus = aat.endLap(); 82 | 83 | logperf << " - AuthAccumulatorTree: " << Utils::humanizeMicroseconds(mus, 2) << endl; 84 | 85 | // Step 3: Authenticate Multipoint Evaluation 86 | AveragingTimer ars("Auth roots-of-unity eval (simulated)"); 87 | for(size_t i = 0; i < r; i++) { 88 | ars.startLap(); 89 | AuthRootsOfUnityEvaluation authEval(eval, *kpp, true); 90 | mus = ars.endLap(); 91 | 92 | logperf << " - AuthRootsOfUnityEval simulated (iter " << i << "): " << Utils::humanizeMicroseconds(mus, 2) << endl; 93 | } 94 | 95 | AveragingTimer ar("Auth roots-of-unity eval"); 96 | for(size_t i = 0; i < r; i++) { 97 | ar.startLap(); 98 | AuthRootsOfUnityEvaluation authEval(eval, *kpp, false); 99 | mus = ar.endLap(); 100 | 101 | logperf << " - AuthRootsOfUnityEval (iter " << i << "): " << Utils::humanizeMicroseconds(mus, 2) << endl; 102 | } 103 | 104 | logperf << endl; 105 | logperf << at << endl; 106 | logperf << aat << endl; 107 | logperf << et << endl; 108 | logperf << ar << endl; 109 | logperf << ars << endl; 110 | logperf << endl; 111 | 112 | // Step 4: Verify AMT proofs (TODO: implement) 113 | 114 | loginfo << "Exited succsessfully!" << endl; 115 | 116 | return 0; 117 | } 118 | -------------------------------------------------------------------------------- /libvectcom/bench/BenchConvertAndMultiexp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | 21 | using namespace std; 22 | using namespace libfqfft; 23 | using namespace libvectcom; 24 | 25 | int main() { 26 | initialize(nullptr, 0); 27 | std::vector bases; 28 | int count = 3, numBench = 0; 29 | double avgPctage = 0.0; 30 | size_t maxSize = 1024*128; 31 | 32 | loginfo << "Picking " << maxSize << " random G1 elements to bench multiexponentiation with..."; 33 | bases.resize(maxSize); 34 | for(size_t i = 0; i < bases.size(); i++) { 35 | bases[i] = G1::random_element(); 36 | } 37 | std::cout << endl; 38 | 39 | //for (size_t i = 1; i <= 1024*128; i *= 2) { 40 | for(size_t i = maxSize; i >= 1; i /= 2) { 41 | logperf << "poly degree = " << i-1 << ", iters = " << count 42 | << endl; 43 | numBench++; 44 | AveragingTimer conv, exp; 45 | 46 | ZZ_pX poly; 47 | std::vector ffpoly; 48 | 49 | bases.resize(i); 50 | 51 | for (int rep = 0; rep < count; rep++) { 52 | random(poly, static_cast(i)); 53 | 54 | conv.startLap(); 55 | //conv_zp_fr(poly, ffpoly); 56 | convNtlToLibff(poly, ffpoly); 57 | conv.endLap(); 58 | 59 | 60 | exp.startLap(); 61 | multiExp(bases, ffpoly); 62 | exp.endLap(); 63 | } 64 | 65 | auto avgConv = conv.averageLapTime(), avgExp = exp.averageLapTime(); 66 | double pctage = (double)avgConv/(double)(avgConv+avgExp)*100.0; 67 | logperf << " + Conv to libff: " << (double) avgConv / 1000000 << " seconds." << endl; 68 | logperf << " + Multiexp: " << (double) avgExp / 1000000 << " seconds." << endl; 69 | logperf << " + " << pctage << "% time spent converting" << endl; 70 | logperf << endl; 71 | 72 | avgPctage += pctage; 73 | } 74 | 75 | avgPctage /= numBench; 76 | 77 | logperf << endl; 78 | logperf << "On average, " << avgPctage << "% time spent converting" << endl; 79 | return 0; 80 | } 81 | -------------------------------------------------------------------------------- /libvectcom/bench/BenchExp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | using namespace libvectcom; 17 | 18 | int main(int argc, char *argv[]) { 19 | libvectcom::initialize(nullptr, 0); 20 | 21 | if(argc < 2) { 22 | cout << "Usage: " << argv[0] << " " << endl; 23 | cout << endl; 24 | cout << "OPTIONS: " << endl; 25 | cout << " the number of times to repeat the exponentiation" << endl; 26 | cout << endl; 27 | 28 | return 1; 29 | } 30 | 31 | size_t n = static_cast(std::stoi(argv[1])); 32 | 33 | loginfo << "Picking " << n << " random G1 elements..." << endl; 34 | auto a = random_group_elems(n); 35 | loginfo << "Picking " << n << " random G2 elements..." << endl; 36 | auto b = random_group_elems(n); 37 | loginfo << "Picking " << n << " random field elements..." << endl; 38 | auto e = random_field_elems(n); 39 | 40 | loginfo << "Doing " << n << " G1 exponentiations..." << endl; 41 | AveragingTimer tn("Exp G1"); 42 | G1 r; 43 | for(size_t i = 0; i < n; i++) { 44 | tn.startLap(); 45 | r = e[i]*a[i]; 46 | tn.endLap(); 47 | } 48 | 49 | logperf << tn << endl; 50 | logperf << "Total time: " << Utils::humanizeMicroseconds(tn.totalLapTime()) << endl; 51 | 52 | loginfo << "Doing " << n << " G2 exponentiations..." << endl; 53 | AveragingTimer tm("Exp G2"); 54 | G2 s; 55 | for(size_t i = 0; i < n; i++) { 56 | tm.startLap(); 57 | s = e[i]*b[i]; 58 | tm.endLap(); 59 | } 60 | 61 | logperf << tm << endl; 62 | 63 | logperf << "Total time: " << Utils::humanizeMicroseconds(tm.totalLapTime()) << endl; 64 | 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /libvectcom/bench/BenchFFT.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace libvectcom; 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | (void)argc; (void)argv; 16 | 17 | libvectcom::initialize(nullptr, 0); 18 | 19 | size_t count = 10; 20 | if(argc < 3) { 21 | cout << "Usage: " << argv[0] << " []" << endl; 22 | cout << endl; 23 | cout << "Measures an FFT of size on poly of degree times." << endl; 24 | return 1; 25 | } 26 | 27 | size_t d = static_cast(std::stoi(argv[1])); 28 | size_t n = static_cast(std::stoi(argv[2])); 29 | if(argc > 3) 30 | count = static_cast(std::stoi(argv[3])); 31 | 32 | AveragingTimer 33 | df("FFT"); 34 | 35 | // Step 0: Pick random polynomial 36 | vector p = random_field_elems(d+1), vals; 37 | 38 | for(size_t i = 0; i < count; i++) { 39 | loginfo << "d = " << d << ", n = " << n << endl; 40 | 41 | // Step 1: Do an FFT 42 | vector q, r, rhs; 43 | df.startLap(); 44 | poly_fft(p, n, vals); 45 | df.endLap(); 46 | } 47 | 48 | logperf << df << endl; 49 | 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /libvectcom/bench/BenchFk.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | using namespace std; 26 | using namespace libfqfft; 27 | using namespace libvectcom; 28 | 29 | int main(int argc, char *argv[]) { 30 | libvectcom::initialize(nullptr, 0); 31 | srand(static_cast(time(NULL))); 32 | 33 | if(argc < 6) { 34 | cout << "Usage: " << argv[0] << " " << endl; 35 | cout << endl; 36 | cout << "OPTIONS: " << endl; 37 | cout << " the Kate public parameters file" << endl; 38 | cout << " the degree of the evaluated polynomial (i.e., t-1)" << endl; 39 | cout << " the # of points to construct proofs for" << endl; 40 | cout << " the # of times to repeat the benchmark" << endl; 41 | cout << " output CSV file to write results in" << endl; 42 | cout << endl; 43 | 44 | return 1; 45 | } 46 | 47 | std::string ppFile = argv[1]; 48 | size_t deg = static_cast(std::stoi(argv[2])); 49 | size_t n = static_cast(std::stoi(argv[3])); 50 | size_t r = static_cast(std::stoi(argv[4])); 51 | std::string fileName = argv[5]; 52 | size_t N = Utils::smallestPowerOfTwoAbove(n); 53 | 54 | bool exists = Utils::fileExists(fileName); 55 | ofstream fout(fileName, std::ofstream::out | std::ofstream::app); 56 | 57 | if(fout.fail()) { 58 | throw std::runtime_error("Could not open " + fileName + " for writing"); 59 | } 60 | 61 | if(!exists) 62 | fout << "n,scheme,num_samples,h_usec,dft_usec,total_usec,h_hum,dft_hum,total_hum,date" << endl; 63 | 64 | // TODO: what happens if deg >= n? 65 | if (deg >= n) { 66 | logerror << "Uhm, not sure if this case is handled yet." << endl; 67 | return 1; 68 | } 69 | 70 | std::unique_ptr kpp( 71 | new Dkg::KatePublicParameters(ppFile, deg)); 72 | 73 | loginfo << endl; 74 | loginfo << "Degree " << deg << " poly, evaluated at n = " << n << " points, iters = " << r << endl; 75 | 76 | AveragingTimer ht("Computing h[i]'s"); 77 | AveragingTimer ft("FFT on h[i]'s"); 78 | 79 | for(size_t i = 0; i < r; i++) { 80 | std::vector f = random_field_elems(deg + 1); 81 | std::chrono::microseconds::rep mus; 82 | std::vector H; 83 | 84 | ht.startLap(); 85 | H = kpp->computeAllHis(f); 86 | mus = ht.endLap(); 87 | 88 | logperf << " - Computing h[i]'s (iter " << i << "): " << Utils::humanizeMicroseconds(mus, 2) << endl; 89 | 90 | // resize H to size n, since the degree of f < n 91 | H.resize(N, G1::zero()); 92 | 93 | ft.startLap(); 94 | FFT(H); 95 | mus = ft.endLap(); 96 | 97 | logperf << " - FFT on h[i]'s (iter " << i << "): " << Utils::humanizeMicroseconds(mus, 2) << endl; 98 | } 99 | 100 | logperf << endl; 101 | logperf << ht << endl; 102 | logperf << ft << endl; 103 | auto at = ht.averageLapTime() + ft.averageLapTime(); 104 | auto ht_hum = Utils::humanizeMicroseconds(ht.averageLapTime(), 2); 105 | auto ft_hum = Utils::humanizeMicroseconds(ft.averageLapTime(), 2); 106 | auto at_hum = Utils::humanizeMicroseconds(at, 2); 107 | logperf << "Overall time: " << at_hum << endl; 108 | logperf << endl; 109 | 110 | fout 111 | << n << "," 112 | << "fk" << "," 113 | << r << "," 114 | << ht.averageLapTime() << "," 115 | << ft.averageLapTime() << "," 116 | << at << "," 117 | << ht_hum << "," 118 | << ft_hum << "," 119 | << at_hum << "," 120 | << timeToString() 121 | << endl; 122 | 123 | loginfo << "Exited successfully!" << endl; 124 | 125 | return 0; 126 | } 127 | -------------------------------------------------------------------------------- /libvectcom/bench/BenchMultiexp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace std; 16 | 17 | using libvectcom::Fr; 18 | using libvectcom::G1; 19 | using libvectcom::random_group_elems; 20 | using libvectcom::random_field_elems; 21 | 22 | void benchAllRootsOfUnity(size_t n, size_t r) { 23 | if(n < 3) { 24 | logerror << "Need n bigger than 2" << endl; 25 | throw std::runtime_error("WTH"); 26 | } 27 | 28 | std::vector bases = random_group_elems(n); 29 | 30 | //size_t id = static_cast(rand()) % n; 31 | for(size_t id = 0; id < n; id++) { 32 | //loginfo << "Picking roots of unity exps for player #" << id << endl; 33 | std::string name = "Multiexp for #" + std::to_string(id); 34 | Fr wnid = libff::get_root_of_unity(1u << Utils::log2ceil(n)) ^ id; 35 | std::vector exp; 36 | exp.push_back(1); 37 | exp.push_back(wnid); 38 | for(size_t i = 0; i < n-2; i++) { 39 | exp.push_back(exp.back() * wnid); 40 | } 41 | 42 | //loginfo << " * picking random bases" << endl; 43 | 44 | AveragingTimer tn(name.c_str()); 45 | for(size_t i = 0; i < r; i++) { 46 | //loginfo << "Round #" << i+1 << endl; 47 | tn.startLap(); 48 | libvectcom::multiExp(bases, exp); 49 | tn.endLap(); 50 | } 51 | 52 | logperf << tn << endl; 53 | logperf << "Time per 1 exp: " << static_cast(tn.averageLapTime()) / static_cast(n) << " microseconds" << endl; 54 | } 55 | } 56 | 57 | int main(int argc, char *argv[]) { 58 | libvectcom::initialize(nullptr, 0); 59 | srand(static_cast(time(nullptr))); 60 | 61 | if(argc < 3) { 62 | cout << "Usage: " << argv[0] << " " << endl; 63 | cout << endl; 64 | cout << "OPTIONS: " << endl; 65 | cout << " the number of exponentiations to do in a single multiexp" << endl; 66 | cout << " the number of times to repeat the multiexps" << endl; 67 | cout << endl; 68 | 69 | return 1; 70 | } 71 | 72 | size_t n = static_cast(std::stoi(argv[1])); 73 | size_t r = static_cast(std::stoi(argv[2])); 74 | 75 | loginfo << "Picking " << n << " random exponents (only once)" << endl; 76 | std::vector exp = random_field_elems(n); 77 | 78 | //loginfo << "Picking all " << n << " " << n << "th roots of unity as the exponents (only once)" << endl; 79 | //exp = libvectcom::get_all_roots_of_unity(Utils::log2ceil(n)); 80 | //exp.resize(n); 81 | 82 | //int id = 14; 83 | //exp.push_back(id); 84 | //for(size_t i = 0; i < n-1; i++) { 85 | // exp.push_back(exp.back() * Fr(id)); 86 | //} 87 | std::vector bases = random_group_elems(n); 88 | 89 | AveragingTimer tn("Multiexp rand base & exp"); 90 | for(size_t i = 0; i < r; i++) { 91 | //loginfo << "Round #" << i+1 << endl; 92 | tn.startLap(); 93 | libvectcom::multiExp(bases, exp); 94 | tn.endLap(); 95 | } 96 | 97 | logperf << tn << endl; 98 | logperf << "Time per 1 exp: " << static_cast(tn.averageLapTime()) / static_cast(n) << " microseconds" << endl; 99 | 100 | return 0; 101 | } 102 | -------------------------------------------------------------------------------- /libvectcom/bench/BenchNtlConversion.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace NTL; 14 | using namespace std; 15 | using namespace libvectcom; 16 | 17 | int main() 18 | { 19 | initialize(nullptr, 0); 20 | 21 | // degree bound 22 | size_t sz = 1024*512; 23 | 24 | std::vector fr1, fr2; 25 | ZZ_pX zp, zp2; 26 | 27 | loginfo << "Picking random ZZ_pX... "; 28 | NTL::random(zp, static_cast(sz)); 29 | cout << "done." << endl; 30 | 31 | ManualTimer t1; 32 | 33 | t1.restart(); 34 | convNtlToLibff_slow(zp, fr1); 35 | auto delta = t1.stop().count(); 36 | logperf << sz << " NTL to libff conversions (slow; w/ stringstream): " << delta/1000 << " millisecs" << endl; 37 | 38 | t1.restart(); 39 | convNtlToLibff(zp, fr2); 40 | delta = t1.stop().count(); 41 | logperf << sz << " NTL to libff conversions (fast; w/ byte array): " << delta/1000 << " millisecs" << endl; 42 | 43 | t1.restart(); 44 | convLibffToNtl_slow(fr2, zp2); 45 | delta = t1.stop().count(); 46 | logperf << sz << " libff to NTL conversions: " << delta/1000 << " millisecs" << endl; 47 | 48 | if(fr1 != fr2) { 49 | logerror << "Our two implementation for converting from NTL to libff disagree" << endl; 50 | return 1; 51 | } 52 | 53 | if(zp != zp2) { 54 | logerror << "Converting from libff to NTL (slow; with byte array) failed" << endl; 55 | return 1; 56 | } 57 | 58 | //loginfo << "libff recovered polys: " << endl; 59 | //poly_print(std::cout, fr); 60 | //poly_print(std::cout, fr2); 61 | //poly_print(std::cout, fr3); 62 | 63 | loginfo << "All done!" << endl; 64 | 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /libvectcom/bench/BenchPairing.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | using libvectcom::Fr; 16 | using libvectcom::G1; 17 | using libvectcom::G2; 18 | 19 | int main(int argc, char *argv[]) { 20 | libvectcom::initialize(nullptr, 0); 21 | 22 | if(argc < 2) { 23 | cout << "Usage: " << argv[0] << " " << endl; 24 | cout << endl; 25 | cout << "OPTIONS: " << endl; 26 | cout << " the number of times to repeat the pairing computation" << endl; 27 | cout << endl; 28 | 29 | return 1; 30 | } 31 | 32 | int n = std::stoi(argv[1]); 33 | 34 | G1 a = G1::random_element(); 35 | G2 b = G2::random_element(); 36 | 37 | AveragingTimer tn("Same a, b"); 38 | for(int i = 0; i < n; i++) { 39 | tn.startLap(); 40 | libvectcom::ReducedPairing(a, b); 41 | tn.endLap(); 42 | } 43 | 44 | logperf << tn << endl; 45 | 46 | AveragingTimer td("Different a, b"); 47 | for(int i = 0; i < n; i++) { 48 | G1 x = G1::random_element(); 49 | G2 y = G2::random_element(); 50 | td.startLap(); 51 | libvectcom::ReducedPairing(x, y); 52 | td.endLap(); 53 | } 54 | 55 | logperf << td << endl; 56 | 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /libvectcom/bench/BenchPointproofs.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | using namespace std; 27 | using namespace libfqfft; 28 | using namespace libvectcom; 29 | 30 | // Takes the KZG public parameters as input (which we pretend to be PDH public parms) and 31 | // outputs the circulant matrix's vector representation, which is used to compute all proofs 32 | // fast. 33 | std::vector publicParamsToCirculant(const KatePublicParameters& kpp, size_t N) { 34 | std::vector c; 35 | 36 | // c = [ g_1^0 ]; 37 | c.push_back(G1::zero()); 38 | //loginfo << "g_1^0" << endl; 39 | 40 | // c = [ g_1^0, g_1^N, \dots, g_1^2 ]; 41 | for(size_t i = 1; i <= N-1; i++) { 42 | //loginfo << "N - " << (i-1) << endl; 43 | c.push_back(kpp.g1si[N - (i-1)]); 44 | } 45 | 46 | // c = [ g_1^0, g_1^N, \dots, g_1^2, g_1^0]; 47 | c.push_back(G1::zero()); 48 | //loginfo << "g_1^0" << endl; 49 | 50 | // c = [ g_1^0, g_1^N, \dots, g_1^2, g_1^0, g_1^{2N}, \dots, g_1^{N+2}]; 51 | for(size_t i = 1; i <= N-1; i++) { 52 | //loginfo << "2N - " << (i-1) << endl; 53 | c.push_back(kpp.g1si[2*N - (i-1)]); 54 | } 55 | 56 | testAssertEqual(c.size(), 2*N); 57 | 58 | return c; 59 | } 60 | 61 | // NOTE: We pass these by values since we need copies of them 62 | std::vector circulantMultiply(const std::vector& cn, std::vector x) { 63 | assertEqual(cn.size(), x.size()); 64 | size_t N = x.size(); 65 | // TODO: generalize like in FK, but don't need this for now 66 | assertTrue(Utils::isPowerOfTwo(N)); 67 | 68 | // Do an FFT on the field elements in the vector x 69 | Fr omega = libff::get_root_of_unity(N); 70 | // TODO: libfqfft supports other fft's of different sizes too 71 | libfqfft::_basic_serial_radix2_FFT(x, omega); 72 | 73 | // Do an FFT on the group elements in the matrix representation of C_N stored in cn 74 | std::vector y = cn; 75 | FFT(y); 76 | 77 | // Do a Hadamard product 78 | for(size_t i = 0; i < N; i++) { 79 | y[i] = x[i] * y[i]; 80 | } 81 | 82 | // Inverse FFT of the result 83 | invFFT(y); 84 | 85 | return y; 86 | } 87 | 88 | std::vector pointproofsProveAll(const KatePublicParameters& kpp, const std::vector& m) { 89 | // m' = m with N extra zeros 90 | std::vector mprime = m; 91 | size_t N = m.size(); 92 | testAssertEqual(mprime.size(), N); 93 | testAssertEqual(mprime, m); 94 | 95 | for(size_t i = 0; i < N; i++) 96 | mprime.push_back(Fr::zero()); 97 | testAssertEqual(mprime.size(), 2*N); 98 | 99 | std::vector c2n = publicParamsToCirculant(kpp, N); 100 | testAssertEqual(c2n.size(), 2*N); 101 | 102 | std::vector piprime = circulantMultiply(c2n, mprime); 103 | piprime.resize(N); 104 | 105 | return piprime; 106 | } 107 | 108 | G1 pointproofsCommit(const KatePublicParameters& kpp, const std::vector& m) { 109 | G1 c = G1::zero(); // zero() is the group's identity (in libff's additive notation) 110 | size_t N = m.size(); 111 | 112 | for(size_t j = 1; j <= N; j++) { 113 | G1 base = kpp.g1si.at(j); 114 | c = c + (m.at(j-1) * base); 115 | } 116 | return c; 117 | } 118 | 119 | G1 pointproofsProveOne(const KatePublicParameters& kpp, size_t i, const std::vector& m) { 120 | G1 pi = G1::zero(); // zero() is the group's identity (in libff's additive notation) 121 | size_t power; 122 | size_t N = m.size(); 123 | 124 | for(size_t j = 1; j <= N; j++) { 125 | if (j != i) { 126 | power = j + (N+1) - i; 127 | G1 base = kpp.g1si.at(power); 128 | 129 | pi = pi + (m.at(j-1) * base); 130 | } 131 | } 132 | return pi; 133 | } 134 | 135 | bool pointproofsVerifyOne(const KatePublicParameters& kpp, const G1& comm, size_t i, const Fr& m_i, const G1& pi, size_t N) { 136 | // Cheat and compute g_T^{\alpha^{n+1}} 137 | auto gtn1 = ReducedPairing(kpp.g1si[N + 1], kpp.g2si[0]); 138 | 139 | // verify proof 140 | return ReducedPairing(comm, kpp.g2si[(N + 1) - i]) == (ReducedPairing(pi, kpp.g2si[0]) * (gtn1^m_i)); 141 | } 142 | 143 | int main(int argc, char *argv[]) { 144 | libvectcom::initialize(nullptr, 0); 145 | srand(static_cast(time(NULL))); 146 | 147 | if(argc < 5) { 148 | cout << "Usage: " << argv[0] << " []" << endl; 149 | cout << endl; 150 | cout << "OPTIONS: " << endl; 151 | cout << " the Kate public parameters file" << endl; 152 | cout << " the # of points to construct proofs for" << endl; 153 | cout << " the # of times to repeat the benchmark" << endl; 154 | cout << " output CSV file to write results in" << endl; 155 | cout << " 1 if should compute proofs naively (default: 0)" << endl; 156 | cout << endl; 157 | 158 | return 1; 159 | } 160 | 161 | std::string ppFile = argv[1]; 162 | size_t n = static_cast(std::stoi(argv[2])); 163 | size_t r = static_cast(std::stoi(argv[3])); 164 | std::string fileName = argv[4]; 165 | bool naively = false; 166 | if (argc > 5 && std::stoi(argv[5]) == 1) 167 | naively = true; 168 | size_t N = Utils::smallestPowerOfTwoAbove(n); 169 | size_t deg = n*2; 170 | 171 | if (N != n) { 172 | logerror << "For now, sticking to powers of two for . You gave n = " << n << "." << endl; 173 | return 1; 174 | } 175 | 176 | bool exists = Utils::fileExists(fileName); 177 | ofstream fout(fileName, std::ofstream::out | std::ofstream::app); 178 | 179 | if(fout.fail()) { 180 | throw std::runtime_error("Could not open " + fileName + " for writing"); 181 | } 182 | 183 | if(!exists) 184 | fout << "n,scheme,num_samples,total_usec,total_hum,date" << endl; 185 | 186 | std::unique_ptr kpp( 187 | new Dkg::KatePublicParameters(ppFile, deg)); 188 | 189 | if (kpp->g1si.size() > 0 && n > (kpp->g1si.size() - 1) / 2) { 190 | logerror << "Need 2N public parameters for vectors of size N" << endl; 191 | return 1; 192 | } 193 | 194 | loginfo << endl; 195 | loginfo << "Computing all n = " << n << " Pointproofs, naive = " << naively << ", iters = " << r << endl; 196 | 197 | AveragingTimer t("Prove all"); 198 | for(size_t iter = 0; iter < r; iter++) { 199 | // f is the vector being committed to 200 | std::vector m = random_field_elems(n); 201 | auto c = pointproofsCommit(*kpp, m); 202 | //loginfo << "Commitment: " << c << endl; 203 | 204 | std::vector pi; 205 | t.startLap(); 206 | if (naively) { 207 | for(size_t i = 1; i <= N; i++) { 208 | pi.push_back(pointproofsProveOne(*kpp, i, m)); 209 | } 210 | } else { 211 | pi = pointproofsProveAll(*kpp, m); 212 | } 213 | t.endLap(); 214 | 215 | // sanity check proofs 216 | for(size_t i = 1; i <= N; i++) { 217 | auto pi_i = pi.at(i-1); 218 | 219 | if(!pointproofsVerifyOne(*kpp, c, i, m.at(i-1), pi_i, N)) { 220 | logerror << "Proof \\pi_" << i << " = " << pi_i << " for m_" << i << " did NOT verify!" << endl; 221 | return 1; 222 | } else { 223 | //loginfo << "Proof \\pi_" << i << " = " << pi_i << " for m_" << i << " = " << m.at(i-1) << " verified!" << endl; 224 | } 225 | } 226 | loginfo << "All proofs verified!" << endl; 227 | } 228 | 229 | logperf << t << endl; 230 | 231 | fout 232 | << n << "," 233 | << "pointproofs-" 234 | << (naively ? "naive" : "fast") << "," 235 | << r << "," 236 | << t.averageLapTime() << "," 237 | << Utils::humanizeMicroseconds(t.averageLapTime(), 2) << "," 238 | << timeToString() 239 | << endl; 240 | 241 | loginfo << "Exited successfully!" << endl; 242 | 243 | return 0; 244 | } 245 | -------------------------------------------------------------------------------- /libvectcom/bench/BenchPolyDivideXnc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace libvectcom; 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | (void)argc; (void)argv; 16 | 17 | libvectcom::initialize(nullptr, 0); 18 | 19 | size_t count = 10; 20 | if(argc < 3) { 21 | cout << "Usage: " << argv[0] << " []" << endl; 22 | cout << endl; 23 | cout << "Divides random poly a(x) (of deg n) by b(x) = x^m - c (of deg m) = " << count << " times." << endl; 24 | cout << "Measures how fast the optimized algorithm is relative to a naive one." << endl; 25 | return 1; 26 | } 27 | 28 | size_t n = static_cast(std::stoi(argv[1])); 29 | size_t m = static_cast(std::stoi(argv[2])); 30 | if(argc > 3) 31 | count = static_cast(std::stoi(argv[3])); 32 | 33 | loginfo << "Dividing a (of deg n) by b (of deg m) " << count << " times..." << endl << endl; 34 | 35 | AveragingTimer 36 | df("O(n) division "), 37 | dn("O(n log n) division"); 38 | for(size_t i = 0; i < count; i++) { 39 | 40 | loginfo << "n = " << n << ", m = " << m << endl; 41 | 42 | // Step 0: Pick random polynomials 43 | vector a = random_field_elems(n+1); 44 | 45 | XncPoly b(m, Fr::random_element()); 46 | //poly_print(a); std::cout << endl; 47 | 48 | // Step 1: Do our fast division 49 | vector q, r, rhs; 50 | df.startLap(); 51 | poly_divide_xnc(a, b, q, r); 52 | df.endLap(); 53 | 54 | // INVARIANT: deg(r) < deg(b) 55 | testAssertStrictlyLessThan(r.size(), m + 1); 56 | if(a.size() >= b.n + 1) { 57 | testAssertEqual(q.size(), n - m + 1); 58 | } 59 | 60 | auto bf = b.toLibff(); 61 | libfqfft::_polynomial_multiplication(rhs, bf, q); 62 | libfqfft::_polynomial_addition(rhs, rhs, r); 63 | 64 | //poly_print(a); std::cout << endl; 65 | //poly_print(rhs); std::cout << endl; 66 | testAssertEqual(a, rhs); 67 | 68 | // Step 2: Do libntl division 69 | ZZ_pX za, zb, zq, zr; 70 | convLibffToNtl_slow(a, za); 71 | convLibffToNtl_slow(bf, zb); 72 | dn.startLap(); 73 | NTL::DivRem(zq, zr, za, zb); 74 | dn.endLap(); 75 | 76 | std::vector rr, qq; 77 | convNtlToLibff(zr, rr); 78 | convNtlToLibff(zq, qq); 79 | 80 | testAssertEqual(rr, r); 81 | testAssertEqual(qq, q); 82 | } 83 | 84 | logperf << df << endl; 85 | logperf << dn << endl; 86 | 87 | return 0; 88 | } 89 | -------------------------------------------------------------------------------- /libvectcom/bench/BenchPolynomialOps.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | using namespace std; 21 | using namespace libfqfft; 22 | using namespace libvectcom; 23 | 24 | int main(int argc, char *argv[]) { 25 | libvectcom::initialize(nullptr, 0); 26 | 27 | loginfo << endl; 28 | loginfo << "Initial NTL numThreads: " << NTL::AvailableThreads() << endl; 29 | loginfo << endl; 30 | 31 | size_t startSz = 16; 32 | // 2^24 - 1 seems to be the max # of roots of unity supported by BN254 33 | // Also it seems to be the max degree for which libntl doesn't crash dvorak, but makes it very slow 34 | if(argc > 1) 35 | startSz = static_cast(std::stoi(argv[1])); 36 | 37 | int count = 2; 38 | if(argc > 2) 39 | count = std::stoi(argv[2]); 40 | 41 | if(argc > 3) { 42 | long numThreads = std::stoi(argv[3]); 43 | if(numThreads > static_cast(getNumCores())) { 44 | logerror << "Number of cores for libntl (" << numThreads << ") cannot be bigger than # of cores on machine, which is " << getNumCores() << endl; 45 | return 1; 46 | } 47 | 48 | if(numThreads > 1) { 49 | NTL::SetNumThreads(numThreads); 50 | loginfo << "Changed NTL NumThreads to " << numThreads << endl; 51 | loginfo << "NTL pool active: " << NTL::GetThreadPool()->active() << endl; 52 | loginfo << endl; 53 | } 54 | } 55 | 56 | loginfo << "Multiplication benchmark for degree " << startSz << ". Iterating " << count << " time(s)" << endl; 57 | loginfo << endl; 58 | 59 | for (size_t i = startSz; i <= startSz; i *= 2) { 60 | vector a, b; 61 | vector p1, p2, res; 62 | ZZ_pX polyX, polyA, polyB; 63 | 64 | bool noFFT = i > 32768; 65 | 66 | AveragingTimer c1, c2, c3, c4; 67 | for (int rep = 0; rep < count; rep++) { 68 | { 69 | //ScopedTimer<> t(std::cout, "Picking random polynomials took ", " microsecs\n"); 70 | NTL::random(polyA, static_cast(i+1)); 71 | NTL::random(polyB, static_cast(i+1)); 72 | convNtlToLibff(polyA, a); 73 | convNtlToLibff(polyB, b); 74 | } 75 | 76 | if(!noFFT) { 77 | c1.startLap(); 78 | _polynomial_multiplication(p1, a, b); 79 | c1.endLap(); 80 | } 81 | 82 | 83 | if(i <= 4096) { 84 | c2.startLap(); 85 | polynomial_multiplication_naive(p2, a, b); 86 | c2.endLap(); 87 | } 88 | 89 | c3.startLap(); 90 | { 91 | c4.startLap(); 92 | mul(polyX, polyA, polyB); 93 | c4.endLap(); 94 | } 95 | convNtlToLibff(polyX, p2); 96 | c3.endLap(); 97 | 98 | if(!noFFT) { 99 | _polynomial_subtraction(res, p1, p2); 100 | if (res.size() != 0) { 101 | logerror 102 | << "The two multiplication functions returned different products" 103 | << endl; 104 | throw std::runtime_error( 105 | "One of the multiplication implementations is wrong"); 106 | } 107 | } 108 | p1.clear(); 109 | p2.clear(); 110 | 111 | } 112 | logperf << "a.size() = " << a.size() << ", b.size() = " << b.size() << ", iters = " << count 113 | << endl; 114 | if(c1.numIterations() == 0) { 115 | //logperf << " + FFT: skipped" << endl; 116 | } else { 117 | logperf << " + FFT mult: " << (double) c1.averageLapTime() / 1000000 118 | << " seconds." << endl; 119 | } 120 | if(c2.numIterations() == 0) { 121 | //logperf << " + Naive: skipped" << endl; 122 | } else { 123 | logperf << " + Naive mult: " << (double) c2.averageLapTime() / 1000000 124 | << " seconds." << endl; 125 | } 126 | logperf << " + NTL mult: " 127 | << (double) c4.averageLapTime() / 1000000 << " +/- " << c4.stddev() / 1000000 << " seconds " << endl; 128 | logperf << " + NTL (with conv): " << (double) c3.averageLapTime() / 1000000 129 | << " seconds." << endl; 130 | logperf << endl; 131 | } 132 | return 0; 133 | } 134 | -------------------------------------------------------------------------------- /libvectcom/bench/BenchRootsOfUnityEval.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | using namespace std; 17 | using namespace libfqfft; 18 | using namespace libvectcom; 19 | 20 | int main(int argc, char *argv[]) { 21 | libvectcom::initialize(nullptr, 0); 22 | 23 | if(argc < 4) { 24 | cout << "Usage: " << argv[0] << " " << endl; 25 | cout << endl; 26 | cout << "OPTIONS: " << endl; 27 | cout << " the degree of the evaluated polynomial + 1" << endl; 28 | cout << " the number of points to evaluate at" << endl; 29 | cout << " the number of times to repeat the eval" << endl; 30 | cout << endl; 31 | 32 | return 1; 33 | } 34 | 35 | // Evaluating f at all points in u. 36 | std::vector f; 37 | std::vector evals, actualEvals, fftEvals; 38 | 39 | double maxEvalTime = 3.0; 40 | bool skipEval = false; 41 | size_t t = static_cast(std::stoi(argv[1])); 42 | size_t n = static_cast(std::stoi(argv[2])); 43 | long r = std::stoi(argv[3]); 44 | 45 | logperf << "Degree = " << t - 1 << ", # points evaluated = " << n << ", iters = " << r << endl; 46 | 47 | f.resize(t); 48 | actualEvals.resize(n); 49 | fftEvals.resize(n); 50 | 51 | AveragingTimer at("Accum tree"); 52 | at.startLap(); 53 | AccumulatorTree accs(n); 54 | at.endLap(); 55 | logperf << at << endl; 56 | 57 | std::vector omegas = accs.getAllNthRootsOfUnity(); 58 | assertEqual(omegas.size(), Utils::smallestPowerOfTwoAbove(n)); 59 | omegas.resize(n); 60 | 61 | AveragingTimer c1("Fast eval "), 62 | c2("FFT eval "), 63 | c3("Naive eval"); 64 | 65 | logperf << endl; 66 | for(int rep = 0; rep < r; rep++) { 67 | f = random_field_elems(t); 68 | 69 | // Step 1: Fast multipoint eval 70 | c1.startLap(); 71 | RootsOfUnityEvaluation eval(f, accs); 72 | evals = eval.getEvaluations(); 73 | auto lastLap = c1.endLap(); 74 | 75 | logperf << "Our eval (iter " << rep+1 << "): " << Utils::humanizeMicroseconds(lastLap) << endl; 76 | 77 | // Step 2: Direct FFT 78 | c2.startLap(); 79 | poly_fft(f, n, fftEvals); 80 | c2.endLap(); 81 | 82 | size_t vms, rss; 83 | getMemUsage(vms, rss); 84 | logperf << "VMS: " << Utils::humanizeBytes(vms) << endl; 85 | logperf << "RSS: " << Utils::humanizeBytes(rss) << endl; 86 | 87 | if(n > 4096 || skipEval) 88 | continue; 89 | 90 | // Step 3: Slow, libff evaluation 91 | c3.startLap(); 92 | for(size_t i = 0; i < omegas.size(); i++) { 93 | //logdbg << "w_n^" << i << " = " << omegas[i] << endl; 94 | actualEvals[i] = libfqfft::evaluate_polynomial(f.size(), f, omegas[i]); 95 | } 96 | c3.endLap(); 97 | 98 | assertEqual(evals.size(), actualEvals.size()); 99 | for(size_t k = 0; k < evals.size(); k++) { 100 | if(evals[k] != actualEvals[k] || evals[k] != fftEvals[k]) { 101 | logerror << "The multipoint evaluation function returned a different evaluation at " 102 | << k << "!" << endl; 103 | logerror << " * Eval at w_n^" << k << " = " << evals[k] << endl; 104 | logerror << " * Actual at w_n^" << k << " = " << actualEvals[k] << endl; 105 | logerror << " * FFT at w_n^" << k << " = " << fftEvals[k] << endl; 106 | 107 | throw std::runtime_error( 108 | "The multipoint evaluation function is wrong!"); 109 | } 110 | } 111 | } 112 | 113 | logperf << endl; 114 | logperf << c1 << endl; 115 | logperf << c2 << endl; 116 | 117 | if(c3.numIterations() > 0) { 118 | logperf << c3 << endl; 119 | 120 | if(static_cast(c3.averageLapTime()) / 1000000.0 >= maxEvalTime) { 121 | logperf << "libff eval exceeded " << maxEvalTime << " seconds, skipping from now on..." << endl; 122 | skipEval = true; 123 | } 124 | } 125 | 126 | logperf << endl; 127 | 128 | return 0; 129 | } 130 | -------------------------------------------------------------------------------- /libvectcom/bench/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(vectcom_bench_sources 2 | BenchAMT.cpp 3 | BenchConvertAndMultiexp.cpp 4 | BenchExp.cpp 5 | BenchFFT.cpp 6 | BenchFk.cpp 7 | BenchMultiexp.cpp 8 | BenchNtlConversion.cpp 9 | BenchPairing.cpp 10 | BenchPointproofs.cpp 11 | BenchPolyDivideXnc.cpp 12 | BenchPolynomialOps.cpp 13 | BenchRootsOfUnityEval.cpp 14 | ) 15 | 16 | foreach(appSrc ${vectcom_bench_sources}) 17 | get_filename_component(appName ${appSrc} NAME_WE) 18 | set(appDir ../bin/bench) 19 | 20 | add_executable(${appName} ${appSrc}) 21 | target_link_libraries(${appName} PRIVATE vectcom) 22 | 23 | set_target_properties(${appName} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${appDir}) 24 | endforeach() 25 | -------------------------------------------------------------------------------- /libvectcom/bench/Utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include // for boost::starts_with(str, pattern) 9 | 10 | bool needsKatePublicParams(const std::vector& types) { 11 | bool needsKpp = false; 12 | 13 | for(auto& t : types) { 14 | if(boost::starts_with(t, "amt") || boost::starts_with(t, "kate") || boost::starts_with(t, "fk")) { 15 | needsKpp = true; 16 | break; 17 | } 18 | } 19 | 20 | return needsKpp; 21 | } 22 | 23 | std::string sumAvgTimeOrNan(const std::vector& timers, bool humanize) { 24 | microseconds::rep sum = 0; 25 | 26 | for(const auto& t : timers) { 27 | if(t.numIterations() > 0) { 28 | sum += t.averageLapTime(); 29 | } else { 30 | return "nan"; 31 | } 32 | } 33 | 34 | if(humanize) 35 | return Utils::humanizeMicroseconds(sum, 2); 36 | else 37 | return std::to_string(sum); 38 | } 39 | 40 | std::string avgTimeOrNan(const AveragingTimer& t, bool humanize) { 41 | auto v = {t}; 42 | return sumAvgTimeOrNan(v, humanize); 43 | } 44 | 45 | std::string stddevOrNan(const AveragingTimer& t) { 46 | return t.numIterations() > 0 ? std::to_string(t.stddev()) : "nan"; 47 | } 48 | -------------------------------------------------------------------------------- /libvectcom/examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Targets 3 | # 4 | 5 | set(vectcom_example_sources 6 | ) 7 | 8 | foreach(appSrc ${vectcom_example_sources}) 9 | get_filename_component(appName ${appSrc} NAME_WE) 10 | set(appDir ../bin/examples) 11 | 12 | add_executable(${appName} ${appSrc}) 13 | target_link_libraries(${appName} PRIVATE vectcom) 14 | 15 | add_test(NAME ${appName} COMMAND ${appName}) 16 | 17 | set_target_properties(${appName} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${appDir}) 18 | endforeach() 19 | -------------------------------------------------------------------------------- /libvectcom/include/vectcom/AccumulatorTree.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include // libff::bitreverse(idx, numBits) 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | using namespace std; 26 | using namespace libfqfft; 27 | using Dkg::KatePublicParameters; 28 | using libvectcom::multiExp; 29 | using libvectcom::Fr; 30 | 31 | namespace libvectcom { 32 | 33 | /** 34 | * Let \omega denote an Nth primitive root of unity, where N is 2^k for some k. 35 | * Let n <= N be an integer. 36 | * This class stores an (unauthenticated) tree over "accumulator monomials." 37 | * It is used for evaluating a polynomial f at \omega^i for i = 0, ..., n-1. 38 | * Leaves are (x-\omega^0), (x-\omega^1), ..., (x-\omega^N) but in 'bitreverse(i)' order. 39 | * Parents are products of children. 40 | * Root is (x-\omega^0)(x-\omega^1)...(x-\omega^N). 41 | * 42 | * Recall that BinaryTree has a 'std::vector> tree' member 43 | * 44 | * tree[k][i] is the ith node at level k in the tree (k = 0 is the last level) 45 | * 46 | * The accumulators in the tree (let a[k][i] denote tree[k][i]): 47 | * a[0][i] = x - \omega^{bitreverse(i)} 48 | * a[k][i] = a[k-1][2*i] * a[k-1][2*i+1] 49 | * 50 | * TODO: can be multithreaded 51 | */ 52 | class AccumulatorTree : public BinaryTree { 53 | public: 54 | 55 | protected: 56 | size_t n; // number of points to evaluate at (see description above) 57 | size_t numBits; // log2ceil(N), where N is min 2^k such that n <= N 58 | std::vector omegas; // all Nth roots of unity (minimum N = 2^k such that n <= N) 59 | 60 | public: 61 | /** 62 | * Creates accumulators for evaluating the polynomial at all \omega^i for i = {0, ..., n-1}. 63 | */ 64 | AccumulatorTree(size_t n) 65 | : n(n) 66 | { 67 | if(n < 2) { 68 | throw std::runtime_error("If you want to do a single point evaluation, just evaluate the polynomial directly."); 69 | } 70 | 71 | // round n to the smallest N = 2^i such that n <= N 72 | size_t N = Utils::smallestPowerOfTwoAbove(n); 73 | numBits = Utils::log2ceil(N); 74 | 75 | // creates a full tree, with a single root node 76 | // WARNING: AuthAccumulatorTree uses this to deduce numBits, so do not make the max level smaller. 77 | size_t rootLevel = numBits; 78 | allocateTree(N, rootLevel); 79 | computeAccumulators(N); 80 | } 81 | 82 | protected: 83 | /** 84 | * @param N must always be a power of two 85 | */ 86 | void computeAccumulators(size_t N) { 87 | // initialize array of roots of unity 88 | omegas = get_all_roots_of_unity(N); 89 | 90 | // Initialize (x - \omega^i) monomials. 91 | // The ith leaf will store (x-\omega^{bitreverse(i)}) 92 | for (size_t i = 0; i < omegas.size(); i++) { 93 | auto &monom = tree[0][i]; 94 | 95 | monom.n = 1; 96 | 97 | size_t rev = libff::bitreverse(i, numBits); 98 | //logdbg << "Rev of " << i << " is " << rev << endl; 99 | assertStrictlyLessThan(rev, omegas.size()); 100 | monom.c = -omegas[rev]; 101 | 102 | //logdbg << "acc[" << 0 << "][" << i << "] = "; 103 | //poly_print_wnk(monom, omegas); 104 | //std::cout << endl; 105 | 106 | //assertEqual( 107 | // libfqfft::evaluate_polynomial(monom.size(), monom, omegas[rev]), 108 | // Fr::zero()); 109 | } 110 | 111 | // NOTE: already initialized accumulator monomials in last level 0 above 112 | size_t numLevels = getNumLevels(); 113 | for (size_t k = 1; k < numLevels; k++) { 114 | for (size_t i = 0; i < tree[k].size(); i++) { 115 | assertValidIndex(2*i + 1, tree[k - 1]); 116 | 117 | // NOTE: This is slower than using libntl's multiplication, but we don't care because 118 | // accumulators are only computed at startup. 119 | tree[k][i] = tree[k - 1][2*i] * tree[k - 1][2*i + 1]; 120 | 121 | //logdbg << "acc[" << k << "][" << i << "] = "; 122 | //poly_print_wnk(tree[k][i].toLibff(), omegas); 123 | //std::cout << endl; 124 | } 125 | } 126 | 127 | #ifndef NDEBUG 128 | auto& p = getRootPoly(); 129 | assertEqual(p.n, N); 130 | assertEqual(p.c, -Fr::one()); 131 | #endif 132 | } 133 | 134 | public: 135 | std::string toString() const { 136 | std::string s; 137 | 138 | for(size_t k = 0; k < getNumLevels(); k++) { 139 | s += "Level " + std::to_string(k) + ": "; 140 | for(size_t i = 0; i < tree[k].size(); i++) { 141 | s += tree[k][i].toString(omegas, true) + ", "; 142 | } 143 | s += "\n"; 144 | } 145 | 146 | return s; 147 | } 148 | 149 | size_t getNumLevels() const { return tree.size(); } 150 | 151 | size_t getNumBits() const { return numBits; } 152 | 153 | /** 154 | * Returns the number of points the polynomial is being evaluated at. 155 | * This is NOT big N. It's the small n. 156 | */ 157 | size_t getNumPoints() const { 158 | return n; 159 | } 160 | 161 | /** 162 | * Returns all Nth roots of unity, where N = 2^k is the smallest number such that n <= N. 163 | */ 164 | const std::vector& getAllNthRootsOfUnity() const { 165 | return omegas; 166 | } 167 | 168 | /** 169 | * Get root accumulator polynomial 170 | */ 171 | const XncPoly& getRootPoly() const { 172 | return getPoly(getNumLevels() - 1, 0); 173 | } 174 | 175 | /** 176 | * Returns the ith accumulator polynomial at level k. 177 | */ 178 | const XncPoly& getPoly(size_t k, size_t i) const { 179 | return tree[k][i]; 180 | } 181 | 182 | bool operator==(const AccumulatorTree& other) const { 183 | for(size_t i = 0; i < getNumPoints(); i++) { 184 | if(tree[0][i] != other.tree[0][i]) { 185 | return false; 186 | } 187 | } 188 | return true; 189 | } 190 | 191 | bool operator!=(const AccumulatorTree& other) const { 192 | return !operator==(other); 193 | } 194 | }; 195 | 196 | /** 197 | * Authenticated version of the accumulator tree: all accumulator polynomials are 198 | * committed to using Kate et al commitments. 199 | * 200 | * TODO: can be multithreaded 201 | */ 202 | class AuthAccumulatorTree : public BinaryTree { 203 | public: 204 | const AccumulatorTree& accs; 205 | const KatePublicParameters& kpp; 206 | 207 | public: 208 | AuthAccumulatorTree(const AccumulatorTree& accs, const KatePublicParameters& kpp, size_t t) 209 | : accs(accs), kpp(kpp) 210 | { 211 | size_t maxLevel = Utils::log2floor(t-1); 212 | size_t N = accs.getNumLeaves(); 213 | allocateTree(N, maxLevel); 214 | 215 | logdbg << "N = " << N << endl; 216 | logdbg << "numBits = " << accs.getNumBits() << endl; 217 | 218 | authenticate(); 219 | } 220 | 221 | public: 222 | /** 223 | * Returns the number of points the polynomial is being evaluated at. 224 | * This is NOT big N. It's the small n. 225 | */ 226 | //size_t getNumPoints() const { 227 | // return accs.getNumPoints(); 228 | //} 229 | 230 | const G2& getLeaf(size_t leafIdx) const { 231 | assertStrictlyLessThan(leafIdx, tree[0].size()); 232 | return tree[0][leafIdx]; 233 | } 234 | 235 | protected: 236 | void authenticate() { 237 | // caches g2^{w_N^j} given j 238 | size_t N = accs.getNumLeaves(); 239 | std::vector exp(N, G2::zero()); 240 | 241 | traversePreorder([this, N, &exp](size_t k, size_t idx) { 242 | size_t numBits = accs.getNumBits(); // log2ceil(N) 243 | auto& acc = accs.getPoly(k, idx); // the accumulator poly 244 | 245 | //loginfo << "Committing to acc of degree " << acc.size() - 1 << " at level " << k << endl; 246 | 247 | if(acc.n > kpp.g2si.size() - 1) { 248 | logerror << "At level " << k << ", need q-SDH params with q = " << acc.n << " but only have q = " << kpp.g2si.size() - 1 << endl; 249 | throw std::runtime_error("Not enough public params to commit to accumulators"); 250 | } 251 | 252 | // we memoize g2^{w_N^j} to speed this up! 253 | // if we are at idx, then it stores (x - w_N^{bitrev(idx)}) = (x + w_N^{(bitrev(idx) + N/2) % N}) 254 | size_t rev = libff::bitreverse(idx, numBits); 255 | size_t j = (rev + N/2) % N; 256 | 257 | // print the AccumulatorTree in bench/BenchAMT.cpp to see the beautiful structure of 258 | // these accumulator polynomials that we leverage here 259 | G2& e = exp[j]; 260 | if(e == G2::zero()) { 261 | e = acc.c * G2::one(); 262 | exp[rev] = -e; 263 | } else { 264 | assertEqual(e, acc.c * G2::one()); 265 | //logperf << "Re-using exp!" << endl; 266 | } 267 | 268 | // commit to a(x) = x^n - w_N^j 269 | // as g^{a(s)} = g^{s^n} * g^{-w_N^j} 270 | tree[k][idx] = kpp.g2si[acc.n] + e; 271 | }); 272 | } 273 | 274 | public: 275 | void _assertValid() { 276 | traversePreorder([this](size_t k, size_t idx) { 277 | auto& a = tree[k][idx]; // the accumulator poly commitment 278 | auto& monom = accs.tree[k][idx]; 279 | size_t numBits = accs.getNumBits(); 280 | 281 | const auto& omegas = accs.getAllNthRootsOfUnity(); 282 | testAssertEqual( 283 | a, 284 | kpp.g2si[monom.n] - omegas[libff::bitreverse(idx, numBits)] * G2::one()); 285 | }); 286 | } 287 | }; 288 | 289 | } // end of namespace libvectcom 290 | -------------------------------------------------------------------------------- /libvectcom/include/vectcom/BinaryTree.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | using namespace std; 18 | 19 | namespace libvectcom { 20 | 21 | /** 22 | * Base class used to represent a full binary tree. 23 | * Leaves are at level 0. 24 | * TODO: Should change to q-ary tree (for time/space trade-off) 25 | */ 26 | template 27 | class BinaryTree { 28 | public: 29 | /** 30 | * tree[k][i] is the ith node at level k in the tree (k = 0 is the last level with leaves) 31 | */ 32 | vector> tree; 33 | 34 | /** 35 | * WARNING: Lambdas that 'capture' variables cannot be passed as arguments where a function pointer is expected. 36 | * std::function must be used instead to pass in a lambda. 37 | */ 38 | //typedef void (*ComputeNodeFunc)(size_t, size_t); 39 | typedef std::function ComputeNodeFunc; 40 | 41 | public: 42 | friend std::ostream& operator<<(std::ostream& out, const BinaryTree& t) { 43 | for(size_t i = 0; i < t.tree.size(); i++) { 44 | for(size_t j = 0; j < t.tree[i].size(); j++) { 45 | out << t.tree[i][j] << "; "; 46 | } 47 | out << endl; 48 | } 49 | 50 | return out; 51 | } 52 | 53 | /** 54 | * Allocates a tree capable of storing the specified # of leaves. 55 | * 56 | * @param maxLevel instead of creating a full tree with a root node, stops creating nodes past 57 | * this level, resulting in a forest of trees, each with 2^maxLevel leaves 58 | */ 59 | void allocateTree(size_t numLeaves, size_t maxLevel) { 60 | testAssertIsPowerOfTwo(numLeaves); 61 | 62 | /** 63 | * Height of tree in # of levels, where levels are counted as nodes (not as edges) 64 | * For example, when numLeaves = 2, height is 2. 65 | * Or, when numLeaves = 3 or 4, height is 3. 66 | * Or, when numLeaves = 5, 6, 7 or 8, height is 4. 67 | * In general, height is ceil(log2(numLeaves)) + 1. 68 | */ 69 | size_t maxHeight = static_cast(Utils::log2ceil(numLeaves) + 1); 70 | if(maxLevel >= maxHeight) { 71 | logerror << "Cannot create tree with max level # " << maxLevel << endl; 72 | logerror << "Max possible level # (starting at 0) for tree with " << numLeaves << " leaves is " << maxHeight - 1 << endl; 73 | throw std::runtime_error("Invalid max level"); 74 | } 75 | 76 | size_t numLevels = maxLevel + 1; 77 | tree.resize(numLevels); 78 | tree[0].resize(numLeaves); 79 | 80 | for(size_t k = 1; k < numLevels; k++) { 81 | tree[k].resize(tree[k-1].size() / 2); 82 | } 83 | 84 | // Check the root level has size 1 85 | assertEqual(tree[maxLevel].size(), numLeaves / (1u << maxLevel)); 86 | } 87 | 88 | size_t getNumLeaves() const { 89 | return tree[0].size(); 90 | } 91 | 92 | /** 93 | * Returns the number of levels in the tree (e.g., a one-node tree has 1 level). 94 | */ 95 | //size_t getNumLevels() const { 96 | // return tree.size(); 97 | //} 98 | 99 | /** 100 | * Returns the path of nodes starting at the specified leaf all the way up to the root. 101 | * index 0 will store leaves and higher indices will store internal nodes. 102 | */ 103 | std::vector getPathFromLeaf(size_t leafIdx) const { 104 | std::vector nodes; 105 | logtrace << "Fetching path for " << leafIdx << endl; 106 | for(auto& lvl : tree) { 107 | assertValidIndex(leafIdx, lvl); 108 | 109 | logtrace << "Pushing one node" << endl; 110 | nodes.push_back(lvl[leafIdx]); 111 | 112 | leafIdx /= 2; 113 | } 114 | return nodes; 115 | } 116 | // TODO: maybe add a pathExec() that executes a function for each node on the path? 117 | 118 | /** 119 | * Pre-order traversal of the tree: (root, left child, right child) 120 | * Used when computing quotients in the tree and when committing to polynomials in the tree. 121 | */ 122 | void traversePreorder(const ComputeNodeFunc& func) { 123 | assertStrictlyGreaterThan(tree.size(), 0); 124 | 125 | size_t rootLevel = tree.size() - 1; 126 | size_t numRoots = tree.back().size(); 127 | for(size_t i = 0; i < numRoots; i++) 128 | traversePreorder(rootLevel, i, func); 129 | } 130 | 131 | void traversePreorder(size_t k, size_t idx, const ComputeNodeFunc& func) { 132 | func(k, idx); 133 | 134 | // if we haven't reached the last level yet, 135 | if(k > 0) { 136 | traversePreorder(k - 1, 2*idx, func); // go left 137 | if(2*idx + 1 < tree[k - 1].size()) { // and, if you can, 138 | traversePreorder(k - 1, 2*idx + 1, func); // go right 139 | } 140 | } 141 | } 142 | }; 143 | 144 | } // end of namespace libvectcom 145 | -------------------------------------------------------------------------------- /libvectcom/include/vectcom/Configuration.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | // NOTE: Instead of modifying this file, just build using `cmake -DCMAKE_BUILD_TYPE=Trace` which will define TRACE for you 6 | //#define TRACE 7 | 8 | // Some compilers have different #define's for C++11's noexcept 9 | 10 | #ifdef _GLIBCXX_NOEXCEPT 11 | # define _NOEXCEPT _GLIBCXX_USE_NOEXCEPT 12 | #else 13 | # ifndef _NOEXCEPT 14 | # error "_NOEXCEPT is not defined" 15 | # endif 16 | #endif 17 | -------------------------------------------------------------------------------- /libvectcom/include/vectcom/FFT.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #ifdef MULTICORE 7 | #include 8 | #endif 9 | 10 | #include 11 | #include 12 | 13 | /** 14 | * Let F_p denote a field of prime order p. 15 | * The Discrete Fourier Transform (DFT) of a vector 'a[0...(n-1)]' where n = 2^k and a_i \in F_p is defined as: 16 | * 17 | * a_i = \sum_{j=0}^{n-1} { \omega_n^{i j} \cdot a_j } 18 | * 19 | * Here, \omega is a primitive nth root of unity in F_p. 20 | * Typically, the a_i's are also from the field F_p. 21 | * However, in some cases we might want the a_j's to be elements of a group, say an elliptic curve. 22 | * In that case, \omega_n^{i j} \cdot a_j is actually a scalar multiplication in the elliptic curve group. 23 | * 24 | * This is why we use GroupType here to indicate the type of group elements the a_i's are. 25 | * Note: We refer to the DFT as FFT in this code. 26 | */ 27 | namespace libvectcom { 28 | 29 | using libfqfft::DomainSizeException; 30 | 31 | /** 32 | * A modification of libfqfft's code, which is based on pseudocode from [CLRS 2n Ed, pp. 864]. 33 | * This is the non-parallelized version. 34 | * Also, note that it's the caller's responsibility to multiply by 1/N when using this for an inverse DFT. 35 | */ 36 | template 37 | void FFT_serial(std::vector &a, const FieldT &omega) 38 | { 39 | const size_t n = a.size(), logn = libff::log2(n); 40 | if (n != (1u << logn)) 41 | throw DomainSizeException("expected n == (1u << logn)"); 42 | 43 | /* swapping in place (from Storer's book) */ 44 | for (size_t k = 0; k < n; ++k) 45 | { 46 | const size_t rk = libff::bitreverse(k, logn); 47 | if (k < rk) 48 | std::swap(a[k], a[rk]); 49 | } 50 | 51 | size_t m = 1; // invariant: m = 2^{s-1} 52 | for (size_t s = 1; s <= logn; ++s) 53 | { 54 | // w_m is 2^s-th root of unity now 55 | const FieldT w_m = omega^(n/(2*m)); 56 | 57 | asm volatile ("/* pre-inner */"); 58 | for (size_t k = 0; k < n; k += 2*m) 59 | { 60 | FieldT w = FieldT::one(); 61 | for (size_t j = 0; j < m; ++j) 62 | { 63 | const GroupT t = w * a[k+j+m]; 64 | a[k+j+m] = a[k+j] - t; 65 | a[k+j] = a[k+j] + t; 66 | w *= w_m; 67 | } 68 | } 69 | asm volatile ("/* post-inner */"); 70 | m *= 2; 71 | } 72 | } 73 | 74 | template 75 | void FFT(std::vector &a) 76 | { 77 | size_t n = libff::get_power_of_two(a.size()); 78 | FieldT omega = libff::get_root_of_unity(n); 79 | 80 | #ifdef MULTICORE 81 | # error "Did not test the parallel FFT path yet" 82 | #else 83 | FFT_serial(a, omega); 84 | #endif 85 | } 86 | 87 | template 88 | void invFFT(std::vector &a) 89 | { 90 | size_t n = libff::get_power_of_two(a.size()); 91 | FieldT omega = libff::get_root_of_unity(n); 92 | 93 | #ifdef MULTICORE 94 | # error "Did not test the parallel FFT path yet" 95 | #else 96 | FFT_serial(a, omega.inverse()); 97 | #endif 98 | 99 | const FieldT sconst = FieldT(static_cast(n)).inverse(); 100 | for(size_t i = 0; i < n; i++) { 101 | a[i] = sconst * a[i]; 102 | } 103 | } 104 | 105 | template 106 | void FFT_parallel(std::vector &a, const FieldT &omega) 107 | { 108 | #ifdef MULTICORE 109 | const size_t num_cpus = omp_get_max_threads(); 110 | #else 111 | const size_t num_cpus = 1; 112 | #endif 113 | const size_t log_cpus = ((num_cpus & (num_cpus - 1)) == 0 ? libff::log2(num_cpus) : libff::log2(num_cpus) - 1); 114 | 115 | if (log_cpus == 0) 116 | FFT_serial(a, omega); 117 | else 118 | FFT_parallel_inner(a, omega, log_cpus); 119 | } 120 | 121 | template 122 | void FFT_parallel_inner(std::vector &a, const FieldT &omega, const size_t log_cpus) 123 | { 124 | const size_t num_cpus = 1ul< > tmp(num_cpus); 138 | for (size_t j = 0; j < num_cpus; ++j) 139 | { 140 | tmp[j].resize(1ul<<(log_m-log_cpus), FieldT::zero()); 141 | } 142 | 143 | #ifdef MULTICORE 144 | #pragma omp parallel for 145 | #endif 146 | for (size_t j = 0; j < num_cpus; ++j) 147 | { 148 | const FieldT omega_j = omega^j; 149 | const FieldT omega_step = omega^(j<<(log_m - log_cpus)); 150 | 151 | FieldT elt = FieldT::one(); 152 | for (size_t i = 0; i < 1ul<<(log_m - log_cpus); ++i) 153 | { 154 | for (size_t s = 0; s < num_cpus; ++s) 155 | { 156 | // invariant: elt is omega^(j*idx) 157 | const size_t idx = (i + (s<<(log_m - log_cpus))) % (1u << log_m); 158 | tmp[j][i] += elt * a[idx]; 159 | elt *= omega_step; 160 | } 161 | elt *= omega_j; 162 | } 163 | } 164 | 165 | const FieldT omega_num_cpus = omega^num_cpus; 166 | 167 | #ifdef MULTICORE 168 | #pragma omp parallel for 169 | #endif 170 | for (size_t j = 0; j < num_cpus; ++j) 171 | { 172 | FFT_serial(tmp[j], omega_num_cpus); 173 | } 174 | 175 | #ifdef MULTICORE 176 | #pragma omp parallel for 177 | #endif 178 | for (size_t i = 0; i < num_cpus; ++i) 179 | { 180 | for (size_t j = 0; j < 1ul<<(log_m - log_cpus); ++j) 181 | { 182 | // now: i = idx >> (log_m - log_cpus) and j = idx % (1u << (log_m - log_cpus)), for idx = ((i<<(log_m-log_cpus))+j) % (1u << log_m) 183 | a[(j< 4 | #include 5 | 6 | using Dkg::KatePublicParameters; 7 | 8 | namespace libvectcom { 9 | namespace KZG { 10 | /** 11 | * Commits to the polynomial 'f' in the group 'Group' using KZG public params 'kpp'. 12 | */ 13 | template 14 | Group commit(const KatePublicParameters& kpp, std::vector& f) { 15 | return multiExp( 16 | kpp.g1si.begin(), 17 | kpp.g1si.begin() + static_cast(f.size()), 18 | f.begin(), 19 | f.end()); 20 | } 21 | 22 | /** 23 | * Evaluates f(x) at x = point by dividing: 24 | * 25 | * q = f / (x - point), 26 | * r = f mod (x - point) = f(point) 27 | * 28 | * Returns the quotient polynomial in q and the evaluation in r 29 | */ 30 | void naiveEval(const Fr& point, const std::vector& f, std::vector& q, Fr& eval); 31 | 32 | /** 33 | * Returns the proof for f_id(point) and f_id(point) itself. 34 | */ 35 | std::tuple naiveProve(const KatePublicParameters& kpp, const std::vector& f, const Fr& point); 36 | 37 | /** 38 | * Verifies that value = p(point), where p is committed in polyComm. 39 | * 40 | * @param g2toS g2^s verification key for reconstructing g2^{s - point} 41 | */ 42 | bool verifyProof(const G1& polyComm, const G1& proof, const Fr& value, const Fr& point, const G2& g2toS); 43 | 44 | /** 45 | * Verifies that valComm = g^p_j(z), where p_j is committed in polyComm and z is committed in acc = g2^{s - z}. 46 | */ 47 | bool verifyProof(const G1& polyComm, const G1& proof, const G1& valComm, const G2& acc); 48 | 49 | } // end of KZG 50 | } // end of libvectcom 51 | -------------------------------------------------------------------------------- /libvectcom/include/vectcom/KatePublicParameters.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | // TODO: move to KZG.h? Or just add KZG namespace here? 12 | 13 | namespace Dkg { 14 | 15 | using libvectcom::Fr; 16 | using libvectcom::G1; 17 | using libvectcom::G2; 18 | using libvectcom::ReducedPairing; 19 | using libvectcom::multiExp; 20 | using libvectcom::convNtlToLibff; 21 | 22 | class KatePublicParameters { 23 | public: 24 | size_t q; 25 | std::vector g1si; // g1si[i] = g1^{s^i} 26 | std::vector g2si; // g2si[i] = g2^{s^i} 27 | Fr s; 28 | 29 | public: 30 | /** 31 | * Generates Kate public parameters on the fly. Used for testing. 32 | */ 33 | KatePublicParameters(size_t q) 34 | : q(q) 35 | { 36 | resize(q); 37 | 38 | // pick trapdoor s 39 | s = Fr::random_element(); 40 | 41 | Fr si = s^0; 42 | int prevPct = -1; 43 | size_t c = 0; 44 | 45 | loginfo << "Generating q-SDH params, q = " << q << endl; 46 | for (size_t i = 0; i <= q; i++) { 47 | g1si[i] = si * G1::one(); 48 | g2si[i] = si * G2::one(); 49 | 50 | si *= s; 51 | 52 | c++; 53 | 54 | int pct = static_cast(static_cast(c)/static_cast(q + 1) * 100.0); 55 | if(pct > prevPct) { 56 | logdbg << pct << "% ... (i = " << i << " out of " << q << ")" << endl; 57 | prevPct = pct; 58 | } 59 | } 60 | } 61 | 62 | /** 63 | * Reads s, tau and q from trapFile. 64 | * Then reads the q-PKE parameters from trapFile + "-0", trapFile + "-1", ... 65 | * and so on, until q+1 parameters are read: g, g^s, \dots, g^{s^q}. 66 | */ 67 | KatePublicParameters(const std::string& trapFile, size_t maxQ = 0, bool progress = true, bool verify = false); 68 | 69 | public: 70 | static Fr generateTrapdoor(size_t q, const std::string& outFile); 71 | 72 | static void generate(size_t startIncl, size_t endExcl, const Fr& s, const std::string& outFile, bool progress); 73 | 74 | 75 | public: 76 | /** 77 | * Returns all the h[i]'s for precomputing Kate proofs fast 78 | * but cheats by using trapdoor to compute them very fast. 79 | * (see "Fast amortized Kate proofs" by Feist and Khovratovich) 80 | */ 81 | std::vector computeAllHisWithTrapdoor(const std::vector& f) { 82 | // make sure the degree of f is <= q 83 | testAssertLessThanOrEqual(f.size(), q + 1); 84 | 85 | std::vector h; 86 | if(f.size() == 0) 87 | throw std::invalid_argument("f must not be empty"); 88 | 89 | size_t deg = f.size() - 1; 90 | size_t k = deg; 91 | h.push_back(f[k] * g1si[0]); 92 | 93 | for(size_t i = 1; i < deg; i++) { 94 | k--; 95 | h.push_back(s * h.back() + f[k] * G1::one()); 96 | } 97 | 98 | // we computed the h[i]'s in reverse 99 | std::reverse(h.begin(), h.end()); 100 | 101 | assertEqual(h.size(), deg); 102 | 103 | return h; 104 | } 105 | 106 | /** 107 | * Returns all the h[i]'s for precomputing Kate proofs fast 108 | * without cheating by only using the g1^{s^i}'s. 109 | * (see "Fast amortized Kate proofs" by Feist and Khovratovich) 110 | */ 111 | std::vector computeAllHis(const std::vector& f) const; 112 | 113 | void resize(size_t q) { 114 | g1si.resize(q+1); // g1^{s^i} with i from 0 to q, including q 115 | g2si.resize(q+1); // g2^{s^i} with i from 0 to q, including q 116 | } 117 | 118 | G1 getG1toS() const { 119 | return g1si[1]; 120 | } 121 | 122 | G2 getG2toS() const { 123 | assertStrictlyGreaterThan(g2si.size(), 1); 124 | return g2si[1]; 125 | } 126 | 127 | const Fr& getTrapdoor() const { 128 | return s; 129 | } 130 | }; 131 | 132 | } 133 | -------------------------------------------------------------------------------- /libvectcom/include/vectcom/NtlLib.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | using NTL::ZZ_p; 21 | using NTL::ZZ_pX; 22 | using NTL::ZZ; 23 | using NTL::vec_ZZ_p; 24 | using namespace std; 25 | 26 | namespace libvectcom { 27 | 28 | /** 29 | * Some useful NTL functions to know (see https://www.shoup.net/ntl/doc/ZZ_pX.cpp.html) 30 | * NOTE: Unfortunately, as far as I can tell, there's no way to compute f(w_i) fast using FFT in libntl. 31 | * It seems that NTL uses a complicated representation for the f(w_i) values and doesn't expose them as ZZ_p's. 32 | * 33 | * ZZ_pX(INIT_SIZE, n) -> initializes to zero, but space is pre-allocated 34 | * 35 | * const ZZ_pX& ZZ_pX::zero() -> returns const reference to 0 polynomial 36 | * 37 | * void ZZ_pX::SetMaxLength(long n) -> f.SetMaxLength(n) pre-allocate spaces for n coefficients. The polynomial that f represents is unchanged. 38 | * 39 | * clear(ZZ_pX& x) -> x = 0 40 | * set(ZZ_pX& x) -> x = 1 41 | * random(ZZ_pX& x, long degBound) -> picks random poly of degree = degBound - 1 (documentation is confusing; it says < degBound, which is not precise; but code generates exactly degBound - 1) 42 | * 43 | * rem(r, a, b) -> r = a%b 44 | * DivRem(q, r, a, b) -> q = a/b, r = a%b 45 | * div(q, a, b) -> q = a/b 46 | * diff(d, f) -> d = derivative of f 47 | */ 48 | 49 | 50 | template 51 | void conv_single_fr_zp(const FieldT& a, ZZ_p& b, mpz_t& rop, ZZ& mid) { 52 | (a.as_bigint()).to_mpz(rop); 53 | char *s = mpz_get_str(NULL, 10, rop); 54 | 55 | mid = NTL::conv(s); 56 | b = NTL::conv(mid); 57 | 58 | void (*freefunc)(void *, size_t); 59 | mp_get_memory_functions(NULL, NULL, &freefunc); 60 | freefunc(s, strlen(s) + 1); 61 | } 62 | 63 | template 64 | void convLibffToNtl(const vector &a, ZZ_pX &pa) 65 | { 66 | (void)a; 67 | (void)pa; 68 | throw libxutils::NotImplementedException(); 69 | } 70 | 71 | /* 72 | * DEPRECATED: This uses strings and is slower than the implementation above. 73 | */ 74 | template 75 | void convLibffToNtl_slow(const vector &a, ZZ_pX &pa) 76 | { 77 | pa = ZZ_pX(NTL::INIT_MONO, (long)(a.size() - 1)); 78 | 79 | mpz_t rop; 80 | mpz_init(rop); 81 | ZZ mid; 82 | 83 | for (size_t i = 0; i < a.size(); i++) { 84 | conv_single_fr_zp(a[i], pa[static_cast(i)], rop, mid); 85 | } 86 | 87 | mpz_clear(rop); 88 | } 89 | 90 | /** 91 | * Converts an NTL vec_ZZ_p vector of field elements to a vector of libff field elements. 92 | */ 93 | template 94 | void convNtlToLibff(const ZZ_p& zzp, FieldT& ff) { 95 | long numBytes = NumBytes(ZZ_p::modulus()); 96 | AutoBuf buf(static_cast(numBytes)); 97 | buf.zeroize(); 98 | 99 | mpz_t interm; 100 | mpz_init(interm); 101 | 102 | const ZZ& rep = NTL::rep(zzp); 103 | 104 | // NOTE: Puts the least significant byte in buf[0] 105 | NTL::BytesFromZZ(buf, rep, numBytes); 106 | 107 | // convert byte array to mpz_t 108 | mpz_import(interm, 109 | /*count =*/static_cast(numBytes), 110 | /*order =*/-1, 111 | /*size =*/1, 112 | /*endian=*/0, 113 | /*nails =*/0, 114 | buf); 115 | 116 | ff = libff::bigint(interm); 117 | 118 | mpz_clear(interm); 119 | } 120 | 121 | template 122 | void convNtlToLibff(const vec_ZZ_p& pn, vector& pf) { 123 | // allocate enough space for libff polynomial 124 | pf.resize(static_cast(pn.length())); 125 | 126 | mpz_t interm; 127 | mpz_init(interm); 128 | 129 | long numBytes = NumBytes(ZZ_p::modulus()); 130 | AutoBuf buf(static_cast(numBytes)); 131 | buf.zeroize(); 132 | 133 | for (size_t i = 0; i < pf.size(); i++) { 134 | const ZZ_p& coeff = pn[static_cast(i)]; 135 | const ZZ& coeffRep = NTL::rep(coeff); 136 | 137 | // NOTE: Puts the least significant byte in buf[0] 138 | NTL::BytesFromZZ(buf, coeffRep, numBytes); 139 | 140 | // convert byte array to mpz_t 141 | mpz_import(interm, 142 | /*count =*/static_cast(numBytes), 143 | /*order =*/-1, 144 | /*size =*/1, 145 | /*endian=*/0, 146 | /*nails =*/0, 147 | buf); 148 | 149 | pf[i] = libff::bigint(interm); 150 | } 151 | 152 | mpz_clear(interm); 153 | } 154 | 155 | /** 156 | * Converts an NTL ZZ_pX polynomial to libff polynomial. 157 | */ 158 | template 159 | void convNtlToLibff(const ZZ_pX& pn, vector& pf) { 160 | convNtlToLibff(pn.rep, pf); 161 | } 162 | 163 | /** 164 | * DEPRECATED: Converts an NTL ZZ_pX polynomial to libff polynomial. 165 | * This uses string streams and is slower than the implementation above. 166 | */ 167 | template 168 | void convNtlToLibff_slow(const ZZ_pX &pa, vector &a) { 169 | a.resize((size_t)(NTL::deg(pa)+1)); 170 | 171 | stringstream ss; 172 | for (size_t i = 0; i < a.size(); i++) { 173 | ss << pa[(long)i]; 174 | 175 | a[i] = libff::bigint(ss.str().c_str()); 176 | ss.str(""); 177 | } 178 | } 179 | 180 | template 181 | Group multiExp( 182 | const std::vector& bases, 183 | const vec_ZZ_p& exps) 184 | { 185 | std::vector expsff; 186 | convNtlToLibff(exps, expsff); 187 | 188 | long minSize = static_cast(bases.size()); 189 | if(exps.length() < minSize) 190 | minSize = exps.length(); 191 | 192 | return multiExp(bases.cbegin(), bases.cbegin() + minSize, 193 | expsff.cbegin(), expsff.cbegin() + minSize); 194 | } 195 | 196 | template 197 | Group multiExp( 198 | const std::vector& bases, 199 | const ZZ_pX& exps) 200 | { 201 | return multiExp(bases, exps.rep); 202 | } 203 | 204 | } // end of namespace libvectcom 205 | -------------------------------------------------------------------------------- /libvectcom/include/vectcom/PolyCrypto.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | using namespace std; 10 | 11 | namespace libvectcom { 12 | 13 | // Type of group G1 14 | using G1 = typename libff::default_ec_pp::G1_type; 15 | // Type of group G2 16 | using G2 = typename libff::default_ec_pp::G2_type; 17 | // Type of group GT (recall pairing e : G1 x G2 -> GT) 18 | using GT = typename libff::default_ec_pp::GT_type; 19 | // Type of the finite field "in the exponent" of the EC group elements 20 | using Fr = typename libff::default_ec_pp::Fp_type; 21 | 22 | // Pairing function, takes an element in G1, another in G2 and returns the one in GT 23 | //using libff::default_ec_pp::reduced_pairing; 24 | //using ECPP::reduced_pairing; 25 | // Found this solution on SO: https://stackoverflow.com/questions/9864125/c11-how-to-alias-a-function 26 | // ('using ECPP::reduced_pairing;' doesn't work, even if you expand ECPP) 27 | template 28 | auto ReducedPairing( 29 | Args&&... args) -> decltype(libff::default_ec_pp::reduced_pairing(std::forward(args)...)) { 30 | return libff::default_ec_pp::reduced_pairing(std::forward(args)...); 31 | } 32 | 33 | /** 34 | * Initializes the library, including its randomness. 35 | */ 36 | void initialize(unsigned char * randSeed, int size = 0); 37 | 38 | /** 39 | * Picks num random field elements 40 | */ 41 | vector random_field_elems(size_t num); 42 | 43 | template 44 | vector random_group_elems(size_t n) { 45 | vector bases; 46 | for(size_t j = 0; j < n; j++) { 47 | bases.push_back(Group::random_element()); 48 | } 49 | return bases; 50 | } 51 | 52 | size_t getNumCores(); 53 | 54 | /** 55 | * Returns the first n Nth roots of unity where N = 2^k is the smallest number such that n <= N. 56 | */ 57 | vector get_all_roots_of_unity(size_t n); 58 | 59 | /** 60 | * Picks a random polynomial of degree deg. 61 | */ 62 | //vector random_poly(size_t degree); 63 | 64 | /** 65 | * Performs a multi-exponentiation using libfqfft 66 | */ 67 | template 68 | Group multiExp( 69 | typename std::vector::const_iterator base_begin, 70 | typename std::vector::const_iterator base_end, 71 | typename std::vector::const_iterator exp_begin, 72 | typename std::vector::const_iterator exp_end 73 | ) 74 | { 75 | long sz = base_end - base_begin; 76 | long expsz = exp_end - exp_begin; 77 | if(sz != expsz) 78 | throw std::runtime_error("multiExp needs the same number of bases as exponents"); 79 | //size_t numCores = getNumCores(); 80 | 81 | if(sz > 4) { 82 | if(sz > 16384) { 83 | return libff::multi_exp(base_begin, base_end, 84 | exp_begin, exp_end, 1);//numCores); 85 | } else { 86 | return libff::multi_exp(base_begin, base_end, 87 | exp_begin, exp_end, 1);//numCores); 88 | } 89 | } else { 90 | return libff::multi_exp(base_begin, base_end, 91 | exp_begin, exp_end, 1); 92 | } 93 | } 94 | 95 | /** 96 | * Performs a multi-exponentiation using libfqfft 97 | */ 98 | template 99 | Group multiExp( 100 | const std::vector& bases, 101 | const std::vector& exps) 102 | { 103 | assertEqual(bases.size(), exps.size()); 104 | return multiExp(bases.cbegin(), bases.cend(), 105 | exps.cbegin(), exps.cend()); 106 | } 107 | 108 | } // end of namespace libvectcom 109 | 110 | namespace boost { 111 | 112 | std::size_t hash_value(const libvectcom::Fr& f); 113 | 114 | } // end of boost namespace 115 | -------------------------------------------------------------------------------- /libvectcom/include/vectcom/PolyOps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | using namespace std; 17 | using namespace libfqfft; 18 | 19 | namespace libvectcom { 20 | 21 | /** 22 | * Polynomial of the (x^n + c) form, where c = w_N^j 23 | */ 24 | class XncPoly { 25 | public: 26 | XncPoly() : n(0) {} 27 | 28 | XncPoly(size_t n, const Fr& c) 29 | : n(n), c(c) 30 | {} 31 | 32 | public: 33 | size_t n; 34 | Fr c; 35 | 36 | public: 37 | /** 38 | * @param justRootOfUnity if true, only prints the w_N^j term 39 | */ 40 | std::string toString(const std::vector& omegas, bool justRootOfUnity = false) const { 41 | std::string s; 42 | size_t N = omegas.size(); 43 | assertIsPowerOfTwo(N); 44 | 45 | if(!justRootOfUnity) { 46 | switch(n) { 47 | case 0: 48 | break; 49 | case 1: 50 | s = "x"; 51 | break; 52 | default: 53 | s = "x^" + std::to_string(n); 54 | break; 55 | } 56 | s += " + "; 57 | } 58 | 59 | // identify if the coefficient is a root of unity 60 | auto it = std::find(omegas.begin(), omegas.end(), c); 61 | if(it == omegas.end()) { 62 | throw std::runtime_error("This is not a x^n + w_N^c polynomial"); 63 | } 64 | 65 | size_t pos = static_cast(it - omegas.begin()); 66 | 67 | std::string exp = "w_" + std::to_string(N) + "^" + std::to_string(pos); 68 | 69 | return justRootOfUnity ? exp : s + exp; 70 | } 71 | 72 | std::vector toLibff() const { 73 | std::vector f(n + 1); 74 | f[n] = 1; 75 | f[0] = c; 76 | return f; 77 | } 78 | 79 | bool operator==(const XncPoly& o) const { 80 | return n == o.n && c == o.c; 81 | } 82 | 83 | bool operator!=(const XncPoly& o) const { 84 | return !operator==(o); 85 | } 86 | }; 87 | 88 | XncPoly operator*(const XncPoly& lhs, const XncPoly& rhs); 89 | std::ostream& operator<<(std::ostream& out, const XncPoly& rhs); 90 | 91 | /** 92 | * Does an FFT: i.e., evaluates and returns p(\omega^i) for all i = 0, ..., N-1 93 | * 94 | * @param N specifies the primitive Nth root of unity \omega (must be 2^k) 95 | */ 96 | template 97 | void poly_fft(const std::vector& p, size_t N, std::vector& vals) { 98 | assertTrue(Utils::isPowerOfTwo(N)); 99 | FieldT omega = libff::get_root_of_unity(N); 100 | 101 | if(N < p.size()) 102 | throw std::runtime_error("N has to be greater than polynomial degree"); 103 | 104 | vals = p; 105 | vals.resize(N, FieldT::zero()); 106 | 107 | #ifdef MULTICORE 108 | _basic_parallel_radix2_FFT(vals, omega); 109 | #else 110 | _basic_serial_radix2_FFT(vals, omega); 111 | #endif 112 | } 113 | 114 | // WARNING: Slower than NTL::BuildFromRoots(), but not sure why 115 | ZZ_pX poly_from_roots_ntl(const vec_ZZ_p& roots, long startIncl, long endExcl); 116 | 117 | template 118 | std::vector poly_from_roots(const vector& r) { 119 | std::vector a; 120 | vec_ZZ_p roots; 121 | roots.SetLength(static_cast(r.size())); 122 | 123 | mpz_t rop; 124 | mpz_init(rop); 125 | ZZ mid; 126 | 127 | for(size_t i = 0; i < r.size(); i++) { 128 | libvectcom::conv_single_fr_zp(r[i], roots[static_cast(i)], rop, mid); 129 | } 130 | mpz_clear(rop); 131 | 132 | ZZ_pX acc(NTL::INIT_MONO, 0); 133 | NTL::BuildFromRoots(acc, roots); 134 | //acc = poly_from_roots_ntl(roots, 0, roots.length()); // WARNING: Slower than NTL::BuildFromRoots() 135 | 136 | libvectcom::convNtlToLibff(acc, a); 137 | 138 | return a; 139 | } 140 | 141 | // interp(roots[0,n)) = interp(roots[0, n/2)) * interp(roots[n/2+1, n)) 142 | template 143 | std::vector poly_from_roots_slow(const vector& roots, size_t startIncl, size_t endExcl) { 144 | // base case is startIncl == endExcl - 1, so return (x - root) 145 | if(startIncl == endExcl - 1) { 146 | std::vector monom(2); 147 | monom[0] = -roots[startIncl]; 148 | monom[1] = 1; 149 | return monom; 150 | } 151 | 152 | std::vector p; 153 | 154 | size_t middle = (startIncl + endExcl) / 2; 155 | 156 | libfqfft::_polynomial_multiplication_on_fft( 157 | p, 158 | poly_from_roots_slow(roots, startIncl, middle), 159 | poly_from_roots_slow(roots, middle, endExcl) 160 | ); 161 | 162 | return p; 163 | } 164 | 165 | template 166 | std::vector poly_from_roots_slow(const vector& roots) { 167 | return poly_from_roots(roots, 0, roots.size()); 168 | } 169 | 170 | /** 171 | Calculates derivative of polynomial f and stores in d 172 | */ 173 | template 174 | void poly_differentiate(const vector &f, vector &d) { 175 | assertStrictlyGreaterThan(f.size(), 0); 176 | 177 | d.resize(f.size() - 1); 178 | for (size_t i = 0; i < d.size(); i++) { 179 | d[i] = f[i + 1] * (static_cast(i) + 1); 180 | } 181 | } 182 | 183 | /** 184 | * O(n^2) naive polynomial multiplication 185 | */ 186 | template 187 | void polynomial_multiplication_naive(vector &c, const vector &b, const vector &a) { 188 | c.resize(a.size() + b.size() - 1, 0); 189 | for (size_t i = 0; i < a.size(); i++) 190 | for (size_t j = 0; j < b.size(); j++) 191 | c[i+j] += a[i] * b[j]; 192 | } 193 | 194 | /** 195 | * Returns true if the polynomial is of the type X^m - c, where m != 0 196 | */ 197 | template 198 | bool poly_is_xnc(const vector& p) { 199 | if(p.size() < 2) 200 | return false; 201 | 202 | if(p[p.size() - 1] != FieldT::one()) 203 | return false; 204 | 205 | for(size_t j = 1; j < p.size() - 1; j++) { 206 | if(p[j] != FieldT::zero()) 207 | return false; 208 | } 209 | 210 | return true; 211 | } 212 | 213 | /** 214 | * Divides a(X) (of degree n) by b(X) of (degree m), where b(X) is of the form X^m - c. 215 | * 216 | * Returns the quotient in q and the remainder in r. 217 | */ 218 | template 219 | void poly_divide_xnc(const vector& a, const XncPoly& b, vector& q, vector& r) { 220 | assertStrictlyGreaterThan(a.size(), 0); 221 | 222 | if(a.size() < b.n + 1) { 223 | q.resize(1); 224 | q[0] = 0; 225 | r = a; 226 | return; 227 | } 228 | 229 | size_t n = a.size() - 1; 230 | size_t m = b.n; // the degree of the xnc poly 231 | FieldT c = b.c; 232 | size_t hi = n, lo = n - m; 233 | q.resize((n - m) + 1, FieldT::zero()); 234 | r = a; 235 | 236 | //logdbg << "Dividing degree n = " << n << " by degree m = " << m << endl; 237 | //logdbg << "Remainder has degree m - 1 = " << m - 1 << endl; 238 | //logdbg << "Quotient has degree n - m = " << n - m << endl; 239 | 240 | // We are just executing naive polynomial division. Initially, q is all zeros. 241 | for(size_t i = 0; i < q.size(); i++) { 242 | q[q.size() - i - 1] = r[hi]; 243 | // r[hi] is removed and need to adjust r[lo] 244 | r[lo] = r[lo] - c*r[hi]; 245 | 246 | r.resize(r.size() - 1); 247 | 248 | hi--; 249 | lo--; 250 | 251 | //#ifndef NDEBUG 252 | // // assert a = q*b+r invariant holds 253 | // vector rhs; 254 | // libfqfft::_polynomial_multiplication(rhs, b.toLibff(), q); 255 | // libfqfft::_polynomial_addition(rhs, rhs, r); 256 | // 257 | // assertEqual(a, rhs); 258 | //#endif 259 | } 260 | 261 | assertEqual(r.size(), m); 262 | } 263 | 264 | template 265 | void poly_print(const std::vector& p) { 266 | size_t n = p.size(); 267 | 268 | for(size_t i = 0; i < n - 1; i++) { 269 | auto deg = (n-1) - i; 270 | auto c = p[deg]; 271 | 272 | if(deg == 1) 273 | std::cout << c << " x + "; 274 | else 275 | std::cout << c << " x^" << deg << " + "; 276 | } 277 | 278 | std::cout << p[0]; 279 | 280 | std::cout << " of degree " << n-1 << std::flush; 281 | } 282 | 283 | /** 284 | * Prints a polynomial in a more-user friendly way if it has coefficients that 285 | * are w_n^k roots of unity, where n = allRoots.size(). 286 | */ 287 | template 288 | void poly_print_wnk(const std::vector& p, const std::vector& allRoots) { 289 | size_t d = p.size(); 290 | FieldT minusOne = FieldT(-1); 291 | for(size_t i = 0; i < d; i++) { 292 | auto deg = (d-1) - i; 293 | auto c = p[deg]; 294 | 295 | // don't print (0 x^i) coeffs 296 | if(c == 0) 297 | continue; 298 | 299 | // identify if the coefficient is a root of unity (special treatment for 1 and -1) 300 | auto it = std::find(allRoots.begin(), allRoots.end(), c); 301 | 302 | // print the coefficient 303 | if(it != allRoots.end()) { 304 | std::string coeff; 305 | bool isPositive = (c != minusOne); 306 | 307 | if (c == FieldT::one() || c == minusOne) { 308 | if(deg == 0) { 309 | coeff = "1"; 310 | } else { 311 | coeff = ""; 312 | } 313 | } else { 314 | size_t pos = static_cast(it - allRoots.begin()); 315 | size_t n = allRoots.size(); 316 | coeff = "w_" + std::to_string(n) + "^" + std::to_string(pos); 317 | } 318 | 319 | if(deg != d-1 || !isPositive) { 320 | std::cout << (isPositive ? " + " : " - "); 321 | } 322 | 323 | std::cout << coeff; 324 | 325 | } else { 326 | throw std::runtime_error("Non-root-of-unity coefficient found"); 327 | } 328 | 329 | // print x^deg after the coefficient 330 | if(deg == 1) { 331 | std::cout << " x"; 332 | } else if(deg == 0) { 333 | // for the last coefficient we don't print any x^deg (because it would be x^0) 334 | } else { 335 | std::cout << " x^" << deg; 336 | } 337 | } 338 | 339 | std::cout << " of degree " << d-1 << std::flush; 340 | } 341 | 342 | } 343 | -------------------------------------------------------------------------------- /libvectcom/include/vectcom/RootsOfUnityEval.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | using namespace std; 21 | using namespace libfqfft; 22 | using Dkg::KatePublicParameters; 23 | using libvectcom::multiExp; 24 | 25 | namespace libvectcom { 26 | 27 | /** 28 | * Polynomials stored in the multipoint evaluation tree: quotient and remainder. 29 | */ 30 | class EvalPolys { 31 | public: 32 | std::vector quo; 33 | std::vector rem; // the remainders are not part of the proof, but we need them to compute quotients (and to get the final evaluations) 34 | }; 35 | 36 | /** 37 | * Class used to evaluate a polynomial at the first n Nth roots of unity. 38 | * n is given as a parameter and N = 2^k is the smallest number such that n <= N. 39 | * 40 | * TODO: can be multithreaded 41 | */ 42 | class RootsOfUnityEvaluation : public BinaryTree { 43 | protected: 44 | const AccumulatorTree& accs; 45 | 46 | public: 47 | /** 48 | * Executes an O(n \log{n}) multipoint evaluation of a polynomial f on the first n Nth roots-of-unity points (given in 'accs') 49 | * 50 | * @param poly the polynomial f being evaluated 51 | * @param accs the points to evaluate f at (wrapped as an AccumulatorTree) 52 | */ 53 | RootsOfUnityEvaluation(const std::vector& poly, const AccumulatorTree& accs) 54 | : accs(accs) 55 | { 56 | size_t n = accs.getNumPoints(); 57 | size_t N = accs.getNumLeaves(); 58 | size_t t = poly.size(); 59 | // it could be that t >> n 60 | size_t rootLevel = std::min(Utils::log2floor(t-1), accs.getNumLevels() - 1); 61 | 62 | assertStrictlyGreaterThan(n, 1); 63 | allocateTree(N, rootLevel); 64 | 65 | computeQuotients(poly, rootLevel); 66 | } 67 | 68 | protected: 69 | void computeQuotients(const std::vector& f, size_t rootLevel) { 70 | assertStrictlyGreaterThan(tree.size(), 0); 71 | size_t n = accs.getNumPoints(); 72 | size_t numBits = getNumBits(); 73 | 74 | // compute the root(s) of the multipoint evaluation tree 75 | size_t numRoots = tree.back().size(); 76 | for(size_t idx = 0; idx < numRoots; idx++) { 77 | poly_divide_xnc( 78 | f, 79 | accs.getPoly(rootLevel, idx), 80 | tree[rootLevel][idx].quo, 81 | tree[rootLevel][idx].rem 82 | ); 83 | } 84 | 85 | // compute the rest of the tree 86 | traversePreorder([rootLevel, n, numBits, this](size_t k, size_t idx) { 87 | // the root is a special case and was computed above 88 | if(k == rootLevel) 89 | return; 90 | 91 | // no need to compute quotient/remainder for the ith leaf if bitreverse(i) >= n 92 | // since we are only evaluating at points \omega^i, i = 0,...,n-1 93 | if(k == 0 && libff::bitreverse(idx, numBits) >= n) 94 | return; 95 | 96 | // divides the parent remainder poly by the accumulator of the current node 97 | poly_divide_xnc( 98 | tree[k+1][idx / 2].rem, 99 | accs.getPoly(k, idx), 100 | tree[k][idx].quo, 101 | tree[k][idx].rem 102 | ); 103 | }); 104 | } 105 | 106 | public: 107 | size_t getMaxLevel() const { 108 | return tree.size() - 1; 109 | } 110 | 111 | size_t getNumBits() const { 112 | return accs.getNumBits(); 113 | } 114 | 115 | size_t getNumPoints() const { 116 | return accs.getNumPoints(); 117 | } 118 | 119 | std::vector getEvaluations() const { 120 | std::vector values; 121 | getEvaluations(values); 122 | return values; 123 | } 124 | 125 | /** 126 | * Returns a vector of evaluations: values[i] = f(w_N^i). 127 | */ 128 | void getEvaluations(std::vector& values) const { 129 | size_t numBits = getNumBits(); 130 | values.resize(getNumPoints()); 131 | 132 | //logdbg << "Getting " << values.size() << " evaluations..." << endl; 133 | 134 | for(size_t i = 0; i < values.size(); i++) { 135 | size_t rev = libff::bitreverse(i, numBits); 136 | assertValidIndex(rev, tree[0]); 137 | //logdbg << "Rev of " << i << " is " << rev << endl; 138 | 139 | assertEqual(tree[0][rev].rem.size(), 1); 140 | values[i] = tree[0][rev].rem[0]; 141 | } 142 | } 143 | 144 | RootsOfUnityEvaluation& operator+=(const RootsOfUnityEvaluation& rhs) { 145 | if(accs != rhs.accs) { 146 | throw std::runtime_error("Can only merge multipoint evaluations if they were done at the same set of points"); 147 | } 148 | 149 | assertEqual(tree.size(), rhs.tree.size()); 150 | 151 | 152 | for(size_t k = 0; k < tree.size(); k++) { 153 | for (size_t i = 0; i < tree[k].size(); i++) { 154 | libfqfft::_polynomial_addition(tree[k][i].quo, tree[k][i].quo, rhs.tree[k][i].quo); 155 | libfqfft::_polynomial_addition(tree[k][i].rem, tree[k][i].rem, rhs.tree[k][i].rem); 156 | } 157 | } 158 | 159 | return *this; 160 | } 161 | 162 | // used for testing purposes only 163 | public: 164 | /** 165 | * Tests if the properties between the parent and the children polynomials hold. 166 | * The child's remainder should be its parent's remainder modulo the child's accumulator. 167 | * This property is verified by checking if the parent remainder = child accumulator * child quotient + child remainder. 168 | * (i.e., the polynomial remainder theorem) 169 | */ 170 | bool _testIsConsistent() const { 171 | //logdbg << "Checking consistency of multipoint evaluation of " << getNumPoints() << " points (and " << tree.size() << " levels)" << endl; 172 | 173 | size_t numRoots = tree.back().size(); 174 | for(size_t idx = 0; idx < numRoots; idx++) 175 | if( _testIsConsistent(tree.size() - 1, idx) == false) 176 | return false; 177 | 178 | return true; 179 | } 180 | 181 | bool _testIsConsistent(size_t k, size_t idx) const { 182 | //logdbg << "Checking level " << k << ", idx " << idx << endl; 183 | // reached the bottom level (checked in parent recursive call) 184 | if(k == 0) { 185 | return true; 186 | } 187 | 188 | size_t numBits = getNumBits(); 189 | size_t n = getNumPoints(); 190 | 191 | // Check polynomials are correctly computed in the multipoint evaluation tree 192 | // (e.g., for left child check if acc[k-1][2i]*quo[k-1][2i] + rem[k-1][2i] =?= rem[k][i]) 193 | std::vector parent; 194 | 195 | // Check left child, if it's a leaf for a \omega^i point we care about 196 | if(k - 1 != 0 || libff::bitreverse(2*idx, numBits) < n) { 197 | libfqfft::_polynomial_multiplication_on_fft(parent, 198 | accs.getPoly(k - 1, 2*idx).toLibff(), 199 | tree[k-1][2*idx].quo); 200 | 201 | libfqfft::_polynomial_addition(parent, 202 | parent, 203 | tree[k-1][2*idx].rem); 204 | 205 | if(parent != tree[k][idx].rem) 206 | return false; 207 | 208 | //logdbg << "Left child is consistent at level=" << k-1 << ", idx=" << 2*idx << endl; 209 | } 210 | 211 | // Check right child, if it's a leaf for a \omega^i point we care about 212 | if(k - 1 != 0 || libff::bitreverse(2*idx + 1, numBits) < n) { 213 | libfqfft::_polynomial_multiplication_on_fft(parent, 214 | accs.getPoly(k - 1, 2*idx + 1).toLibff(), 215 | tree[k-1][2*idx + 1].quo); 216 | 217 | libfqfft::_polynomial_addition(parent, 218 | parent, 219 | tree[k-1][2*idx + 1].rem); 220 | 221 | if(parent != tree[k][idx].rem) 222 | return false; 223 | 224 | //logdbg << "Right child is consistent at level=" << k-1 << ", idx=" << 2*idx+1 << endl; 225 | } 226 | 227 | bool rightCheck = _testIsConsistent(k-1, 2*idx + 1), 228 | leftCheck = _testIsConsistent(k-1, 2*idx); 229 | 230 | return leftCheck && rightCheck; 231 | } 232 | }; 233 | 234 | /** 235 | * Authenticated version of the roots-of-unity evaluation tree. 236 | * All quotient polynomials are committed to. 237 | */ 238 | class AuthRootsOfUnityEvaluation : public BinaryTree { 239 | protected: 240 | const KatePublicParameters& kpp; 241 | 242 | public: 243 | AuthRootsOfUnityEvaluation(const RootsOfUnityEvaluation& eval, const KatePublicParameters& kpp, bool simulate) 244 | : kpp(kpp) 245 | { 246 | allocateTree(eval.getNumLeaves(), eval.getMaxLevel()); 247 | authenticate(eval, simulate); 248 | } 249 | 250 | protected: 251 | void authenticate(const RootsOfUnityEvaluation& eval, bool simulate) { 252 | traversePreorder([eval, simulate, this](size_t k, size_t idx) { 253 | size_t numBits = eval.getNumBits(); 254 | size_t n = eval.getNumPoints(); 255 | 256 | // no need to commit to quotient in the ith leaf if bitreverse(i) >= n 257 | // since we are only evaluating at points \omega^i, i = 0, ..., n-1 258 | if(k == 0 && libff::bitreverse(idx, numBits) >= n) 259 | return; 260 | 261 | auto& quo = eval.tree[k][idx].quo; 262 | if(simulate) { 263 | Fr qOfS = libfqfft::evaluate_polynomial(quo.size(), quo, kpp.getTrapdoor()); 264 | tree[k][idx] = qOfS * G1::one(); 265 | } else { 266 | tree[k][idx] = multiExp( 267 | kpp.g1si.begin(), 268 | kpp.g1si.begin() + static_cast(quo.size()), 269 | quo.begin(), 270 | quo.end()); 271 | } 272 | }); 273 | } 274 | }; 275 | 276 | // TODO: abstract the proof itself, if that helps simplify code 277 | //class AuthEvalProof { 278 | //public: 279 | // const AuthRootsOfUnityEvaluation& authEval; 280 | // size_t leafIdx; 281 | // 282 | //public: 283 | // AuthEvalProof(const AuthRootsOfUnityEvaluation& authEval, size_t leafIdx) 284 | // : authEval(authEval), leafIdx(leafIdx) 285 | // { 286 | // } 287 | // 288 | //public: 289 | // bool verify(const AuthAccumulatorTree& authAccs) { 290 | // // NOTE: The auth accs might have bigger height than this tree 291 | // auto numLevels = authEval.height// which is now correct 292 | // } 293 | //}; 294 | 295 | } // end of namespace libvectcom 296 | -------------------------------------------------------------------------------- /libvectcom/include/vectcom/Utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | /** 9 | * Returns k unique random numbers in the range [0, n-1] as a vector 10 | */ 11 | vector random_subset(size_t k, size_t n); 12 | 13 | /** 14 | * Originally from: https://stackoverflow.com/questions/669438/how-to-get-memory-usage-at-runtime-using-c 15 | * 16 | * process_mem_usage(double &, double &) - takes two doubles by reference, 17 | * attempts to read the system-dependent data for a process' virtual memory 18 | * size and resident set size, and return the results in bytes. 19 | * 20 | * On failure, returns 0, 0; 21 | */ 22 | void printMemUsage(const char * headerMessage = nullptr); 23 | 24 | void getMemUsage(size_t& vm_usage, size_t& resident_set); 25 | -------------------------------------------------------------------------------- /libvectcom/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Targets 3 | # 4 | 5 | add_library(vectcom 6 | PolyCrypto.cpp 7 | KatePublicParameters.cpp 8 | Kzg.cpp 9 | PolyOps.cpp 10 | Utils.cpp 11 | ) 12 | 13 | target_include_directories(vectcom PUBLIC 14 | "$" 15 | "$" 16 | ) 17 | 18 | target_link_libraries(vectcom PUBLIC 19 | ntl ff pthread zm gmp gmpxx xutils xassert 20 | ) 21 | 22 | include(FindOpenMP) 23 | if(OPENMP_FOUND) 24 | target_link_libraries(vectcom PUBLIC gomp) 25 | endif() 26 | 27 | #target_link_libraries(vectcom PUBLIC Threads::Threads) 28 | 29 | # 30 | # Installation 31 | # TODO: Add Config[Version].cmake files so this package can be easily imported? 32 | # (See https://cmake.org/cmake/help/git-master/manual/cmake-packages.7.html#creating-packages) 33 | # 34 | 35 | # This creates the Config.cmake file and installs it 36 | install(TARGETS vectcom EXPORT vectcomConfig 37 | ARCHIVE DESTINATION lib) 38 | install(EXPORT vectcomConfig DESTINATION lib/cmake/vectcom) 39 | 40 | # This installs the static or (/and?) dynamic library 41 | install(TARGETS vectcom 42 | ARCHIVE DESTINATION lib 43 | LIBRARY DESTINATION lib 44 | ) 45 | 46 | # This installs the headers 47 | # WARNING: Don't add / at the end. No slash means vectcom/ directory is created in the destination path 48 | install(DIRECTORY include/vectcom DESTINATION include) 49 | -------------------------------------------------------------------------------- /libvectcom/src/KatePublicParameters.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | using libvectcom::FFT; 12 | using libvectcom::invFFT; 13 | 14 | namespace Dkg { 15 | 16 | KatePublicParameters::KatePublicParameters(const std::string& trapFile, size_t maxQ, bool progress, bool verify) { 17 | ifstream tin(trapFile); 18 | if(tin.fail()) { 19 | throw std::runtime_error("Could not open trapdoor file for reading"); 20 | } 21 | 22 | loginfo << "Reading back q-PKE parameters... (verify = " << verify << ")" << endl; 23 | 24 | tin >> s; 25 | tin >> q; // we read the q before so as to preallocate the std::vectors 26 | libff::consume_OUTPUT_NEWLINE(tin); 27 | 28 | loginfo << "available q = " << q << ", s = " << s << endl; 29 | 30 | if(maxQ > 0 && maxQ > q) { 31 | logerror << "You asked to read " << maxQ << " public parameters, but there are only " << q << " in the '" << trapFile << "-*' files" << endl; 32 | throw std::runtime_error("maxQ needs to be <= q"); 33 | } 34 | 35 | if(tin.fail() || tin.bad()) { 36 | throw std::runtime_error("Error reading full trapdoor file"); 37 | } 38 | 39 | tin.close(); 40 | 41 | // if maxQ is set to the default 0 value, read all q public params from the file 42 | q = maxQ == 0 ? q : maxQ; 43 | loginfo << "wanted q = " << maxQ << endl; 44 | resize(q); 45 | 46 | G1 g1 = G1::one(); 47 | G2 g2 = G2::one(); 48 | Fr si = Fr::one(); // will store s^i 49 | 50 | size_t i = 0; 51 | int iter = 0; 52 | G1 tmpG1si; 53 | G2 tmpG2si; 54 | int prevPct = -1; 55 | while(i <= q) { 56 | std::string inFile = trapFile + "-" + std::to_string(iter); 57 | loginfo << q - i << " params left to read, looking at " << inFile << " ..." << endl; 58 | ifstream fin(inFile); 59 | 60 | if(fin.fail()) { 61 | throw std::runtime_error("Could not open public parameters file for reading"); 62 | } 63 | 64 | size_t line = 0; 65 | while(i <= q) { 66 | line++; 67 | 68 | // read g1^{s^i} 69 | fin >> tmpG1si; 70 | if(fin.eof()) { 71 | logdbg << "Reached end of '" << inFile << "' at line " << line << endl; 72 | break; 73 | } 74 | 75 | g1si[i] = tmpG1si; 76 | libff::consume_OUTPUT_NEWLINE(fin); 77 | 78 | // read g2^{s^i} 79 | fin >> tmpG2si; 80 | if(fin.eof()) { 81 | logdbg << "Reached end of '" << inFile << "' at line " << line << endl; 82 | break; 83 | } 84 | 85 | g2si[i] = tmpG2si; 86 | libff::consume_OUTPUT_NEWLINE(fin); 87 | 88 | // Check what we're reading against trapdoors 89 | 90 | //logtrace << g1si[i] << endl; 91 | //logtrace << si*g1 << endl << endl; 92 | //logtrace << g2si[i] << endl; 93 | //logtrace << si*g2 << endl << endl; 94 | 95 | // Fully verify the parameters, if verify is true 96 | if(verify) { 97 | testAssertEqual(g1si[i], si*g1); 98 | testAssertEqual(g2si[i], si*g2); 99 | } 100 | 101 | if(progress) { 102 | //int pct = static_cast(static_cast(c)/static_cast(endExcl-startIncl) * 10000.0); 103 | int pct = static_cast(static_cast(i)/static_cast(q+1) * 100.0); 104 | if(pct > prevPct) { 105 | logdbg << pct << "% ... (i = " << i << " out of " << q+1 << ")" << endl; 106 | prevPct = pct; 107 | 108 | // Occasionally check the parameters 109 | testAssertEqual(g1si[i], si*g1); 110 | testAssertEqual(g2si[i], si*g2); 111 | } 112 | } 113 | 114 | si = si * s; 115 | i++; 116 | 117 | } 118 | 119 | fin.close(); 120 | iter++; // move to the next file 121 | } 122 | 123 | if(i < q) { 124 | throw std::runtime_error("Did not read all parameters."); 125 | } 126 | 127 | if(i != q+1) { 128 | throw std::runtime_error("Expected to read exactly q parameters."); 129 | } 130 | } 131 | 132 | Fr KatePublicParameters::generateTrapdoor(size_t q, const std::string& outFile) 133 | { 134 | ofstream fout(outFile); 135 | 136 | if(fout.fail()) { 137 | throw std::runtime_error("Could not open trapdoors file for writing"); 138 | } 139 | 140 | // pick trapdoor s 141 | Fr s = Fr::random_element(); 142 | 143 | loginfo << "Writing q-SDH trapdoor..." << endl; 144 | loginfo << "q = " << q << ", s = " << s << endl; 145 | // WARNING: SECURITY: Insecure implementation currently outputs the 146 | // trapdoors! 147 | fout << s << endl; 148 | fout << q << endl; 149 | 150 | fout.close(); 151 | 152 | return s; 153 | } 154 | 155 | void KatePublicParameters::generate(size_t startIncl, size_t endExcl, const Fr& s, const std::string& outFile, bool progress) 156 | { 157 | if(startIncl >= endExcl) { 158 | logwarn << "Nothing to generate in range [" << startIncl << ", " << endExcl << ")" << endl; 159 | return; 160 | } 161 | 162 | ofstream fout(outFile); 163 | 164 | if(fout.fail()) { 165 | throw std::runtime_error("Could not open public parameters file for writing"); 166 | } 167 | 168 | //logdbg << "i \\in [" << startIncl << ", " << endExcl << "), s = " << s << endl; 169 | 170 | // generate q-SDH powers and write to file 171 | Fr si = s ^ startIncl; 172 | int prevPct = -1; 173 | size_t c = 0; 174 | for (size_t i = startIncl; i < endExcl; i++) { 175 | G1 g1si = si * G1::one(); 176 | G2 g2si = si * G2::one(); 177 | 178 | fout << g1si << "\n"; 179 | fout << g2si << "\n"; 180 | 181 | si *= s; 182 | 183 | if(progress) { 184 | int pct = static_cast(static_cast(c)/static_cast(endExcl-startIncl) * 100.0); 185 | if(pct > prevPct) { 186 | loginfo << pct << "% ... (i = " << i << " out of " << endExcl-1 << ")" << endl; 187 | prevPct = pct; 188 | 189 | fout << std::flush; 190 | } 191 | } 192 | 193 | c++; 194 | } 195 | 196 | fout.close(); 197 | } 198 | 199 | std::vector KatePublicParameters::computeAllHis(const std::vector& f) const { 200 | // make sure the degree of f is <= q 201 | testAssertLessThanOrEqual(f.size(), q + 1); 202 | 203 | if(f.size() == 0) 204 | throw std::invalid_argument("f must not be empty"); 205 | 206 | size_t m = f.size() - 1; // the degree of f 207 | size_t M = Utils::smallestPowerOfTwoAbove(m); 208 | 209 | /** 210 | * Recall that for all i\in[1, m]: 211 | * h_i = \prod_{j = 0}^{m - i} (g^{s^{m-(i+j)})^f_{m-j} 212 | * 213 | * For i > m: 214 | * h_i = G1::zero() 215 | * 216 | * Also recall that the upper-triangular m\times m Toeplitz matrix has: 217 | * f_m on the diagonal 218 | * f_{m-1} on the diagonal above it 219 | * ... 220 | * f_1 in the upper right corner 221 | * 222 | * And the size-m vector we're multiplying it by is: 223 | * [ g^{s^{m-1}, g^{s^{m-2}, \dots, g^s, g ]^T 224 | * 225 | * The circulant matrix which we'll embed the Toeplitz matrix in has vector representative c: 226 | * [ f_m, \vec{0_{m-1}}, f_m, f_1, f_2, f_3, \dots, f_{m-1} ]^T 227 | */ 228 | 229 | // Note: We handle non-powers of two by making the Toeplitz matrix size a power of two (and padding the vector we're multiplying it by with zeros). 230 | 231 | std::vector c(2*M, Fr::zero()); 232 | if(m == M) { 233 | // if no padding, then f_m lands in top-left corner of Toeplitz matrix 234 | c[0] = f[m]; 235 | c[m] = f[m]; 236 | } 237 | 238 | size_t i = M+1; 239 | size_t len = (m == M) ? m-1 : m; 240 | for(size_t j = 1; j <= len; j++) 241 | c.at(i++) = f[j]; 242 | 243 | std::vector x(2*M, G1::zero()); 244 | size_t shift = M - m; 245 | for(size_t i = 0; i < m; i++) 246 | // x[m-1] = g1si[0] 247 | // x[m-2] = g1si[1] 248 | // .. 249 | // x[1] = g1si[m-2] 250 | // x[0] = g1si[m-1] 251 | x[shift + (m-1) - i] = g1si[i]; 252 | 253 | // FFT on x 254 | FFT(x); 255 | 256 | // FFT on c 257 | Fr omega = libff::get_root_of_unity(2*M); 258 | // TODO: libfqfft supports other fft's of different sizes too 259 | libfqfft::_basic_serial_radix2_FFT(c, omega); 260 | 261 | // Hadamard (entry-wise) product of the two 262 | for(size_t i = 0; i < 2*M; i++) { 263 | x[i] = c[i] * x[i]; 264 | } 265 | 266 | // Inverse FFT of the result 267 | invFFT(x); 268 | 269 | x.resize(m); 270 | 271 | return x; 272 | } 273 | 274 | } 275 | -------------------------------------------------------------------------------- /libvectcom/src/Kzg.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace libvectcom { 8 | namespace KZG { 9 | 10 | void naiveEval(const Fr& point, const std::vector& f, std::vector& q, Fr& eval) { 11 | std::vector monom(2), rem(1); 12 | 13 | // set the (x - point) divisor 14 | monom[0] = -point; 15 | monom[1] = Fr::one(); 16 | 17 | // divides f by (x - point) 18 | libfqfft::_polynomial_division(q, rem, f, monom); 19 | assertEqual(q.size(), f.size() - 1); 20 | assertEqual(rem.size(), 1); 21 | 22 | eval = rem[0]; 23 | } 24 | 25 | std::tuple naiveProve(const KatePublicParameters& kpp, const std::vector& f, const Fr& point) { 26 | std::vector q; 27 | Fr r; 28 | 29 | naiveEval(point, f, q, r); 30 | 31 | // commit to quotient polynomial 32 | auto proof = commit(kpp, q); 33 | 34 | return std::make_tuple(proof, r); 35 | } 36 | 37 | bool verifyProof(const G1& polyComm, const G1& proof, const Fr& value, const Fr& point, const G2& g2toS) { 38 | return verifyProof(polyComm, proof, value * G1::one(), g2toS - point * G2::one()); 39 | } 40 | 41 | bool verifyProof(const G1& polyComm, const G1& proof, const G1& valComm, const G2& acc) { 42 | return ReducedPairing(polyComm - valComm, G2::one()) == 43 | ReducedPairing(proof, acc); 44 | } 45 | } // end of KZG 46 | } // end of libvectcom 47 | -------------------------------------------------------------------------------- /libvectcom/src/PolyCrypto.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include // get_root_of_unity 14 | 15 | #ifdef USE_MULTITHREADING 16 | # include 17 | #endif 18 | 19 | using namespace std; 20 | using namespace NTL; 21 | 22 | namespace libvectcom { 23 | 24 | void initialize(unsigned char * randSeed, int size) { 25 | (void)randSeed; // TODO: initialize entropy source 26 | (void)size; // TODO: initialize entropy source 27 | 28 | // Apparently, libff logs some extra info when computing pairings 29 | libff::inhibit_profiling_info = true; 30 | 31 | // Initializes the default EC curve, so as to avoid "surprises" 32 | libff::default_ec_pp::init_public_params(); 33 | 34 | // Initializes the NTL finite field 35 | ZZ p = conv ("21888242871839275222246405745257275088548364400416034343698204186575808495617"); 36 | ZZ_p::init(p); 37 | 38 | NTL::SetSeed(randSeed, size); 39 | 40 | #ifdef USE_MULTITHREADING 41 | // NOTE: See https://stackoverflow.com/questions/11095309/openmp-set-num-threads-is-not-working 42 | loginfo << "Using " << getNumCores() << " threads" << endl; 43 | omp_set_dynamic(0); // Explicitly disable dynamic teams 44 | omp_set_num_threads(static_cast(getNumCores())); // Use 4 threads for all consecutive parallel regions 45 | #else 46 | //loginfo << "NOT using multithreading" << endl; 47 | #endif 48 | } 49 | 50 | vector random_field_elems(size_t num) { 51 | vector p(num); 52 | for (size_t i = 0; i < p.size(); i++) { 53 | p[i] = Fr::random_element(); 54 | } 55 | return p; 56 | } 57 | 58 | size_t getNumCores() { 59 | static size_t numCores = std::thread::hardware_concurrency(); 60 | if(numCores == 0) 61 | throw std::runtime_error("Could not get number of cores"); 62 | return numCores; 63 | } 64 | 65 | vector get_all_roots_of_unity(size_t n) { 66 | if(n < 1) 67 | throw std::runtime_error("Cannot get 0th root-of-unity"); 68 | 69 | size_t N = Utils::smallestPowerOfTwoAbove(n); 70 | 71 | // initialize array of roots of unity 72 | Fr omega = libff::get_root_of_unity(N); 73 | std::vector omegas(n); 74 | omegas[0] = Fr::one(); 75 | 76 | if(n > 1) { 77 | omegas[1] = omega; 78 | for(size_t i = 2; i < n; i++) { 79 | omegas[i] = omega * omegas[i-1]; 80 | } 81 | } 82 | 83 | return omegas; 84 | } 85 | 86 | //vector random_poly(size_t deg) { 87 | // return random_field_elems(deg+1); 88 | //} 89 | 90 | } // end of namespace libvectcom 91 | 92 | namespace boost { 93 | 94 | std::size_t hash_value(const libvectcom::Fr& f) 95 | { 96 | size_t size; 97 | mpz_t rop; 98 | mpz_init(rop); 99 | f.as_bigint().to_mpz(rop); 100 | 101 | //char *s = mpz_get_str(NULL, 10, rop); 102 | //size = strlen(s); 103 | //auto h = boost::hash_range(s, s + size); 104 | 105 | //void (*freefunc)(void *, size_t); 106 | //mp_get_memory_functions(NULL, NULL, &freefunc); 107 | //freefunc(s, size); 108 | 109 | 110 | mpz_export(NULL, &size, 1, 1, 1, 0, rop); 111 | AutoBuf buf(static_cast(size)); 112 | 113 | mpz_export(buf, &size, 1, 1, 1, 0, rop); 114 | auto h = boost::hash_range(buf, buf + buf.size()); 115 | 116 | mpz_clear(rop); 117 | return h; 118 | } 119 | 120 | } // end of boost namespace 121 | -------------------------------------------------------------------------------- /libvectcom/src/PolyOps.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | using namespace std; 9 | using namespace NTL; 10 | 11 | namespace libvectcom { 12 | 13 | ZZ_pX poly_from_roots_ntl(const vec_ZZ_p& roots, long startIncl, long endExcl) { 14 | // base case is startIncl == endExcl - 1, so return (x - root) 15 | if(startIncl == endExcl - 1) { 16 | ZZ_pX monom(NTL::INIT_MONO, 1); 17 | monom[0] = -roots[startIncl]; 18 | monom[1] = 1; 19 | assertEqual(NTL::deg(monom), 1); 20 | return monom; 21 | } 22 | 23 | ZZ_pX p; 24 | 25 | long middle = (startIncl + endExcl) / 2; 26 | 27 | NTL::mul( 28 | p, 29 | poly_from_roots_ntl(roots, startIncl, middle), 30 | poly_from_roots_ntl(roots, middle, endExcl) 31 | ); 32 | 33 | return p; 34 | } 35 | 36 | XncPoly operator*(const XncPoly& lhs, const XncPoly& rhs) { 37 | return XncPoly(lhs.n + rhs.n, lhs.c*rhs.c); 38 | } 39 | 40 | std::ostream& operator<<(std::ostream& out, const XncPoly& rhs) { 41 | out << "x^" << rhs.n << " + " << rhs.c; 42 | return out; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /libvectcom/src/Utils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #ifndef __APPLE__ 9 | # include 10 | # include 11 | # include 12 | # include 13 | # include 14 | #else 15 | # include 16 | #endif 17 | 18 | vector random_subset(size_t k, size_t n) { 19 | vector x(n); 20 | Utils::randomSubset(x, static_cast(n), static_cast(k)); 21 | return x; 22 | } 23 | 24 | void printMemUsage(const char * headerMessage) { 25 | size_t vms, rss; 26 | getMemUsage(vms, rss); 27 | if(headerMessage != nullptr) { 28 | loginfo << headerMessage << ": " << endl; 29 | } 30 | 31 | loginfo << "VMS: " << Utils::humanizeBytes(vms) << endl; 32 | loginfo << "RSS: " << Utils::humanizeBytes(rss) << endl; 33 | } 34 | 35 | void getMemUsage(size_t& vm_usage, size_t& resident_set) 36 | { 37 | vm_usage = 0; 38 | resident_set = 0; 39 | #ifndef __APPLE__ 40 | using std::ios_base; 41 | using std::ifstream; 42 | using std::string; 43 | 44 | vm_usage = 0; 45 | resident_set = 0; 46 | 47 | // 'file' stat seems to give the most reliable results 48 | // 49 | ifstream stat_stream("/proc/self/stat",ios_base::in); 50 | 51 | // dummy vars for leading entries in stat that we don't care about 52 | // 53 | string pid, comm, state, ppid, pgrp, session, tty_nr; 54 | string tpgid, flags, minflt, cminflt, majflt, cmajflt; 55 | string utime, stime, cutime, cstime, priority, nice; 56 | string O, itrealvalue, starttime; 57 | 58 | // the two fields we want 59 | // 60 | unsigned long vsize; 61 | long rss; 62 | 63 | stat_stream >> pid >> comm >> state >> ppid >> pgrp >> session >> tty_nr 64 | >> tpgid >> flags >> minflt >> cminflt >> majflt >> cmajflt 65 | >> utime >> stime >> cutime >> cstime >> priority >> nice 66 | >> O >> itrealvalue >> starttime >> vsize >> rss; // don't care about the rest 67 | 68 | stat_stream.close(); 69 | 70 | long page_size_bytes = sysconf(_SC_PAGE_SIZE); // in case x86-64 is configured to use 2MB pages 71 | vm_usage = vsize; 72 | resident_set = static_cast(rss * page_size_bytes); 73 | #else 74 | struct proc_taskinfo pti; 75 | pid_t pid = getpid(); 76 | 77 | //long page_size_bytes = sysconf(_SC_PAGE_SIZE); // in case x86-64 is configured to use 2MB pages 78 | 79 | if(sizeof(pti) == proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti))) { 80 | vm_usage = pti.pti_virtual_size; // / 1024 / PAGE_SIZE_KB; 81 | resident_set = pti.pti_resident_size; // / 1024 / PAGE_SIZE_KB; 82 | } else { 83 | throw std::runtime_error("proc_pidinfo failed"); 84 | } 85 | #endif 86 | } 87 | -------------------------------------------------------------------------------- /libvectcom/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(vectcom_test_sources 2 | TestGroupFft.cpp 3 | TestKatePublicParams.cpp 4 | TestPolyOps.cpp 5 | TestLibff.cpp 6 | TestParallelPairing.cpp 7 | TestPolyDivideXnc.cpp 8 | TestRootsOfUnity.cpp 9 | TestRootsOfUnityEval.cpp 10 | ) 11 | 12 | foreach(appSrc ${vectcom_test_sources}) 13 | get_filename_component(appName ${appSrc} NAME_WE) 14 | set(appDir ../bin/test) 15 | 16 | add_executable(${appName} ${appSrc}) 17 | target_link_libraries(${appName} PRIVATE vectcom) 18 | 19 | add_test(NAME ${appName} COMMAND ${appName}) 20 | set_target_properties(${appName} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${appDir}) 21 | endforeach() 22 | -------------------------------------------------------------------------------- /libvectcom/test/TestGroupFft.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | using namespace std; 26 | using namespace libfqfft; 27 | using namespace libvectcom; 28 | 29 | int main(int argc, char *argv[]) { 30 | libvectcom::initialize(nullptr, 0); 31 | srand(static_cast(time(NULL))); 32 | 33 | if(argc > 1 && (std::string(argv[1]) == "-h" || std::string(argv[1]) == "--help")) { 34 | cout << "Usage: " << argv[0] << "[] [] []" << endl; 35 | cout << endl; 36 | cout << "OPTIONS: " << endl; 37 | cout << " the # of points to compute proofs for" << endl; 38 | cout << " the degree of the polynomial" << endl; 39 | cout << " the public params file to use; if not provided, will generate random params" << endl; 40 | cout << endl; 41 | 42 | return 1; 43 | } 44 | 45 | size_t n = argc > 1 ? static_cast(std::stoi(argv[1])) : 32; 46 | size_t N = Utils::smallestPowerOfTwoAbove(n); 47 | 48 | size_t deg = argc > 2 ? static_cast(std::stoi(argv[2])) : n / 2; 49 | bool generateParams = argc <= 3; 50 | 51 | std::unique_ptr kpp; 52 | if(generateParams) 53 | kpp.reset(new KatePublicParameters(deg)); 54 | else 55 | kpp.reset(new KatePublicParameters(argv[3], deg)); 56 | 57 | loginfo << "Picking random, degree " << deg << " polynomial... "; 58 | std::vector f = random_field_elems(deg + 1); 59 | std::cout << " done." << endl; 60 | 61 | loginfo << "Evaluating polynomial using FFT... "; 62 | std::vector y; 63 | poly_fft(f, N, y); 64 | std::cout << " done." << endl; 65 | 66 | loginfo << "Committing to polynomial..."; 67 | G1 c = multiExp( 68 | kpp->g1si.begin(), 69 | kpp->g1si.begin() + static_cast(f.size()), 70 | f.begin(), 71 | f.end()); 72 | std::cout << " done." << endl; 73 | 74 | //loginfo << "Computing " << deg << " h_i's in G1 (using trapdoor)... " << endl; 75 | //std::vector h = kpp->computeAllHisWithTrapdoor(f); 76 | ////for(size_t i = 0; i < h.size(); i++) { 77 | //// logdbg << "h[i]: " << h[i] << endl; 78 | ////} 79 | //loginfo << " ...done!" << endl; 80 | 81 | loginfo << "Computing " << deg << " h_i's in G1 normally... " << endl; 82 | std::vector H; 83 | { 84 | ScopedTimer t(std::cout, "DFT on group elems time: ", " ms\n"); 85 | H = kpp->computeAllHis(f); 86 | } 87 | for(size_t i = 0; i < H.size(); i++) { 88 | logdbg << "H[" << i << "]: " << H[i] << endl; 89 | //testAssertEqual(h[i], H[i]); 90 | } 91 | loginfo << " ...done!" << endl; 92 | 93 | loginfo << "Computing proofs fast via FFT... " << endl; 94 | // resize H to size N, since the degree of f < N 95 | H.resize(N, G1::zero()); 96 | //H[0]=H[N+2]; // ensure DEBUG mode actually catches this out-of-bounds error 97 | { 98 | ScopedTimer t(std::cout, "DFT on group elems time: ", " ms\n"); 99 | FFT(H); 100 | } 101 | for(size_t i = 0; i < n; i++) { 102 | logdbg << "proof[" << i << "]: " << H[i] << endl; 103 | } 104 | loginfo << " ...done!" << endl; 105 | 106 | loginfo << "Verifying proofs..." << endl; 107 | Fr omega = libff::get_root_of_unity(N); 108 | Fr w = Fr::one(); 109 | for(size_t i = 0; i < n; i++) { 110 | if(KZG::verifyProof(c, H[i], y[i], w, kpp->g2si[1]) == false) { 111 | logerror << "The proof for w^" << i << " did NOT verify." << endl; 112 | auto q = std::get<0>(KZG::naiveProve(*kpp, f, w)); 113 | logerror << " \\-> Real proof: " << q << endl; 114 | logerror << " \\-> Our proof: " << H[i] << endl; 115 | return 1; 116 | } 117 | 118 | w *= omega; 119 | } 120 | loginfo << " ...done!" << endl; 121 | 122 | loginfo << "Exited succsessfully!" << endl; 123 | 124 | return 0; 125 | } 126 | -------------------------------------------------------------------------------- /libvectcom/test/TestKatePublicParams.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace libvectcom; 13 | using namespace Dkg; 14 | using std::endl; 15 | 16 | int main(int argc, char *argv[]) 17 | { 18 | (void)argc; (void)argv; 19 | initialize(nullptr, 0); 20 | srand(42); 21 | 22 | size_t q = argc < 2 ? 4096 : static_cast(std::stoi(argv[1])); 23 | 24 | size_t numChunks = 5; 25 | if(q < numChunks) 26 | throw std::runtime_error("q must be bigger than the # of chunks"); 27 | size_t chunkSize = q / numChunks; 28 | 29 | std::string trapFile = "/tmp/libvectcom-test-trapFile"; 30 | Fr s = KatePublicParameters::generateTrapdoor(q, trapFile); 31 | 32 | for(size_t i = 0; i < numChunks; i++) { 33 | size_t start = i*chunkSize; 34 | size_t end = (i < numChunks-1) ? (i+1)*chunkSize : q+1; 35 | 36 | logdbg << "Writing chunk #" << i+1 << ": [" << start << ", " << end << ") ..." << endl; 37 | KatePublicParameters::generate(start, end, s, trapFile + "-" + std::to_string(i), false); 38 | } 39 | 40 | KatePublicParameters pp(trapFile, 0, true, true); 41 | 42 | std::cout << "Test '" << argv[0] << "' finished successfully" << std::endl; 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /libvectcom/test/TestLibff.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | using namespace libvectcom; 9 | 10 | int main(int argc, char *argv[]) 11 | { 12 | (void)argc; (void)argv; 13 | 14 | libvectcom::initialize(nullptr, 0); 15 | 16 | // libff naming weirdness that I'm trying to understand: 17 | // zero() is the group's identity (since ECs use additive notation) 18 | // one() is the group's generator 19 | 20 | std::clog << "G1 zero: " << G1::zero() << std::endl; 21 | std::clog << "G1 one: " << G1::one() << std::endl; 22 | testAssertNotEqual(G1::one(), G1::zero()); 23 | 24 | std::clog << "G2 zero: " << G2::zero() << std::endl; 25 | std::clog << "G2 one: " << G2::one() << std::endl; 26 | testAssertNotEqual(G2::one(), G2::zero()); 27 | 28 | // a, b <-$- random 29 | Fr a = Fr::random_element(), b = Fr::random_element(); 30 | // compute (ab) 31 | Fr ab = a * b; 32 | // g1^a 33 | G1 g1a = a * G1::one(); 34 | // g2^a 35 | G2 g2b = b * G2::one(); 36 | // gt^(ab) 37 | 38 | // test some simple arithmetic 39 | testAssertEqual(b*g1a, (ab)*G1::one()); 40 | testAssertEqual(a*g2b, (ab)*G2::one()); 41 | 42 | // Get generator in GT 43 | GT gt = ReducedPairing(G1::one(), G2::one()); 44 | 45 | // test pairing 46 | GT gt_ab = gt^(ab); 47 | 48 | testAssertEqual( 49 | gt_ab, 50 | ReducedPairing(g1a, g2b)); 51 | 52 | testAssertEqual( 53 | gt_ab, 54 | ReducedPairing(g1a, G2::one())^b); 55 | 56 | testAssertEqual( 57 | gt_ab, 58 | ReducedPairing(G1::one(), g2b)^a); 59 | 60 | std::cout << "Test '" << argv[0] << "' finished successfully" << std::endl; 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /libvectcom/test/TestParallelPairing.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | using namespace libvectcom; 15 | 16 | int main(int argc, char *argv[]) { 17 | (void)argc; 18 | (void)argv; 19 | libvectcom::initialize(nullptr, 0); 20 | 21 | size_t numIters = 100; 22 | 23 | #ifdef USE_MULTITHREADING 24 | loginfo << "Multithreading enabled!" << endl; 25 | #else 26 | loginfo << "Multithreading disabled!" << endl; 27 | #endif 28 | 29 | std::vector a(numIters); 30 | std::vector b(numIters); 31 | 32 | #ifdef USE_MULTITHREADING 33 | #pragma omp parallel for 34 | #endif 35 | for(size_t i = 0; i < numIters; i++) { 36 | a[i] = G1::random_element(); 37 | b[i] = G2::random_element(); 38 | } 39 | 40 | loginfo << "Picked " << numIters << " random group elements in G1 and G2" << endl; 41 | 42 | #ifdef USE_MULTITHREADING 43 | #pragma omp parallel for 44 | #endif 45 | for(size_t i = 0; i < numIters; i++) { 46 | // TODO: this seems to crash for some reason. 47 | //ReducedPairing(a[i], b[i]); 48 | libff::default_ec_pp::reduced_pairing(a[i], b[i]); 49 | } 50 | 51 | loginfo << "All tests succeeded!" << endl; 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /libvectcom/test/TestPolyDivideXnc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | using namespace libvectcom; 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | (void)argc; (void)argv; 14 | 15 | libvectcom::initialize(nullptr, 0); 16 | 17 | size_t count = 100; 18 | if(argc > 1 && strcmp(argv[1], "-h") == 0) { 19 | cout << "Usage: " << argv[0] << " " << endl; 20 | cout << endl; 21 | cout << "Divides random poly a(x) (of deg n) by b(x) = x^m - c (of deg m), doubles their degrees and repeats " << count << " times." << endl; 22 | return 1; 23 | } 24 | 25 | size_t a_deg = argc < 3 ? 8 : static_cast(std::stoi(argv[1])); 26 | size_t b_deg = argc < 3 ? 4 : static_cast(std::stoi(argv[2])); 27 | 28 | loginfo << "Dividing a (of deg n) by b (of deg m)..." << endl << endl; 29 | 30 | for(size_t i = 0; i < count; i++) { 31 | size_t n = a_deg*(i+1); // degree of a 32 | size_t m = b_deg*(i+1); // degree of b 33 | 34 | loginfo << "n = " << n << ", m = " << m << endl; 35 | 36 | vector a = random_field_elems(n+1); 37 | 38 | XncPoly b(m, Fr::random_element()); 39 | //poly_print(a); std::cout << endl; 40 | 41 | vector q, r, rhs; 42 | poly_divide_xnc(a, b, q, r); 43 | 44 | // INVARIANT: deg(r) < deg(b) 45 | testAssertStrictlyLessThan(r.size(), m + 1); 46 | if(a.size() >= b.n + 1) { 47 | testAssertEqual(q.size(), n - m + 1); 48 | } 49 | 50 | libfqfft::_polynomial_multiplication(rhs, b.toLibff(), q); 51 | libfqfft::_polynomial_addition(rhs, rhs, r); 52 | 53 | //poly_print(a); std::cout << endl; 54 | //poly_print(rhs); std::cout << endl; 55 | testAssertEqual(a, rhs); 56 | } 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /libvectcom/test/TestPolyOps.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | 7 | 8 | #include 9 | #include 10 | 11 | using namespace libvectcom; 12 | 13 | std::vector poly_from_roots_naive(const std::vector& roots) { 14 | std::vector monom(2), acc(1, Fr::one()); 15 | for(size_t i = 0; i < roots.size(); i++) { 16 | Fr r = roots[i]; 17 | //logdbg << "Multiplying in root " << r << endl; 18 | 19 | monom[0] = -r; 20 | monom[1] = 1; 21 | libfqfft::_polynomial_multiplication_on_fft(acc, acc, monom); 22 | 23 | testAssertEqual(acc.size(), i+2); 24 | 25 | //poly_print(acc); 26 | } 27 | 28 | return acc; 29 | } 30 | 31 | int main(int argc, char *argv[]) 32 | { 33 | (void)argc; (void)argv; 34 | 35 | libvectcom::initialize(nullptr, 0); 36 | 37 | const size_t maxSize = 64; 38 | std::vector roots; 39 | for(size_t i = 0; i < maxSize; i++) { 40 | roots.push_back(Fr::random_element()); 41 | loginfo << "Testing interpolation from " << i+1 << " roots..." << endl; 42 | 43 | auto expected = poly_from_roots_naive(roots); 44 | auto computed = poly_from_roots(roots); 45 | 46 | testAssertEqual(computed.size(), roots.size() + 1); 47 | testAssertEqual(expected, computed); 48 | } 49 | 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /libvectcom/test/TestRootsOfUnity.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | using namespace libvectcom; 18 | 19 | void print_all_accumulators(std::vector roots, const std::vector& allRoots); 20 | void print_all_accumulators(std::vector roots, const std::vector& allRoots, const std::vector& p, std::string nodeName); 21 | 22 | std::vector even_or_odd(const std::vector& p, bool even); 23 | 24 | std::vector poly_from_roots(std::vector::const_iterator beg, std::vector::const_iterator end); 25 | 26 | int main(int argc, char *argv[]) 27 | { 28 | (void)argc; (void)argv; 29 | 30 | libvectcom::initialize(nullptr, 0); 31 | 32 | // test roots of unity 33 | size_t n = 128; 34 | //Fr w_n = libff::get_root_of_unity(n); 35 | std::vector allRoots = get_all_roots_of_unity(n); 36 | //for(size_t i = 0; i < n; i++) { 37 | // Fr w_ni = w_n^i; 38 | // 39 | // if(std::find(allRoots.begin(), allRoots.end(), w_ni) != allRoots.end()) { 40 | // logerror << i << "th" << n << "th root of unity is not unique" << endl; 41 | // assertFail("Something's wrong with the roots of unity"); 42 | // } 43 | 44 | // allRoots.push_back(w_ni); 45 | //} 46 | 47 | //testAssertEqual(w_n^n, Fr(1)); 48 | 49 | auto checkCoeffs = [&allRoots](const std::vector& p, const std::string& poly) { 50 | size_t d = p.size(); 51 | loginfo << poly << " of degree " << d-1 << " coeffs: "; 52 | poly_print_wnk(p, allRoots); 53 | std::cout << endl; 54 | }; 55 | 56 | // test \prod_{i=0}{n-1} (x-w_n^i) = x^n - 1 57 | std::vector xn_minus_1 = poly_from_roots(allRoots.begin(), allRoots.end()); 58 | testAssertEqual(xn_minus_1.size(), n + 1); 59 | checkCoeffs(xn_minus_1, "x^n - 1"); 60 | testAssertEqual(xn_minus_1[0], Fr(-1)); 61 | testAssertEqual(xn_minus_1[n], Fr::one()); 62 | 63 | // test \prod_{i=0}{n/2-1} (x-(w_n^i)^2) = x^{n/2} - 1 64 | // NOTE: (w_n^i)^2 will be the roots of unity at even indices in 'allRoots' 65 | // Example: For n = 4, we have the principal 4th root of unity w_4 = i 66 | // ...and w_4^0 = i^0 = 1, w_4^1 = i^1 = i, w_4^2 = i^2 = -1, w_4^3 = -i 67 | // The 2nd roots of unity will be (w_4^0)^2 = 1 = w_4^0 and (w_4^1)^2 = -1 = w_4^2 68 | auto even = even_or_odd(allRoots, true); 69 | std::vector xn2_minus_1 = poly_from_roots(even.begin(), even.end()); 70 | testAssertEqual(xn2_minus_1.size(), n/2 + 1); 71 | checkCoeffs(xn2_minus_1, "x^{n/2} - 1"); 72 | testAssertEqual(xn2_minus_1[0], Fr(-1)); 73 | testAssertEqual(xn2_minus_1[n/2], Fr::one()); 74 | 75 | // test \prod_{i=n/2-1}{n-1} (x-w_n^i) = x^{n/2} + 1 76 | auto odd = even_or_odd(allRoots, false); 77 | std::vector xn2_plus_1 = poly_from_roots(odd.begin(), odd.end()); 78 | testAssertEqual(xn2_plus_1.size(), n/2 + 1); 79 | checkCoeffs(xn2_plus_1, "x^{n/2} + 1"); 80 | testAssertEqual(xn2_plus_1[0], Fr::one()); 81 | testAssertEqual(xn2_plus_1[n/2], Fr::one()); 82 | 83 | logdbg << "All accumulator polys for n = " << n << ": " << endl; 84 | print_all_accumulators(allRoots, allRoots); 85 | 86 | std::cout << "Test '" << argv[0] << "' finished successfully" << std::endl; 87 | return 0; 88 | } 89 | 90 | void checkMiddleCoeffs(const std::vector& p) { 91 | size_t d = p.size(); 92 | for(size_t i = 1; i < d - 1; i++) { 93 | testAssertEqual(p[(d-1) - i], Fr::zero()); 94 | } 95 | }; 96 | 97 | void print_all_accumulators(std::vector roots, const std::vector& allRoots) { 98 | std::vector p = poly_from_roots(roots.begin(), roots.end()); 99 | 100 | print_all_accumulators(roots, allRoots, p, ""); 101 | } 102 | 103 | void print_all_accumulators(std::vector roots, const std::vector& allRoots, const std::vector& p, std::string nodeName) { 104 | checkMiddleCoeffs(p); 105 | 106 | std::cout 107 | << std::endl 108 | << std::left 109 | << std::setw(static_cast(Utils::log2ceil(allRoots.size()))) 110 | << (nodeName.empty() ? "root" : nodeName) 111 | << " -> "; 112 | 113 | poly_print_wnk(p, allRoots); 114 | std::cout << endl; 115 | 116 | if(roots.size() == 1) 117 | return; 118 | 119 | std::vector even = even_or_odd(roots, true); 120 | std::vector odd = even_or_odd(roots, false); 121 | 122 | // print children below parent (this is just because I'm curious what they look like) 123 | std::cout << " \\-0->"; 124 | auto p_even = poly_from_roots(even.begin(), even.end()); 125 | poly_print_wnk(p_even, allRoots); 126 | std::cout << endl; 127 | 128 | std::cout << " \\-1->"; 129 | auto p_odd = poly_from_roots(odd.begin(), odd.end()); 130 | poly_print_wnk(p_odd, allRoots); 131 | std::cout << endl; 132 | 133 | // make sure left * right = parent 134 | std::vector p_exp; 135 | libfqfft::_polynomial_multiplication(p_exp, p_even, p_odd); 136 | testAssertEqual(p, p_exp); 137 | 138 | print_all_accumulators(even, allRoots, p_even, nodeName + "0"); 139 | print_all_accumulators(odd, allRoots, p_odd, nodeName + "1"); 140 | } 141 | 142 | std::vector poly_from_roots(std::vector::const_iterator beg, std::vector::const_iterator end) 143 | { 144 | std::queue> merge; 145 | while(beg != end) { 146 | auto r = *beg; 147 | merge.push({-r, 1}); 148 | beg++; 149 | } 150 | 151 | while(merge.size() > 1) { 152 | std::vector res, left, right; 153 | 154 | left = merge.front(); 155 | merge.pop(); 156 | right = merge.front(); 157 | merge.pop(); 158 | 159 | libfqfft::_polynomial_multiplication(res, left, right); 160 | merge.push(res); 161 | } 162 | 163 | return merge.front(); 164 | } 165 | 166 | std::vector even_or_odd(const std::vector& p, bool even) { 167 | std::vector v; 168 | 169 | size_t rem = even ? 0 : 1; 170 | for(size_t i = 0; i < p.size(); i++) { 171 | if(i % 2 == rem) { 172 | v.push_back(p[i]); 173 | } 174 | } 175 | 176 | return v; 177 | } 178 | -------------------------------------------------------------------------------- /libvectcom/test/TestRootsOfUnityEval.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | using namespace std; 21 | using namespace libfqfft; 22 | using namespace libvectcom; 23 | 24 | void assertEvals(const std::vector& f, const std::vector& evals, size_t numPoints); 25 | 26 | void testRootsOfUnityEvaluation(size_t deg, const AccumulatorTree& accs) { 27 | size_t numPoints = accs.getNumPoints(); 28 | 29 | std::vector f = random_field_elems(deg+1); 30 | 31 | RootsOfUnityEvaluation eval(f, accs); 32 | 33 | testAssertTrue(eval._testIsConsistent()); 34 | 35 | std::vector evals = eval.getEvaluations(); 36 | assertEvals(f, evals, numPoints); 37 | } 38 | 39 | void testMultipointMerging(size_t deg, const AccumulatorTree& accs) { 40 | size_t numPoints = accs.getNumPoints(); 41 | 42 | std::vector f1, f2, f3; 43 | f1 = random_field_elems(deg+1); 44 | f2 = random_field_elems(deg+1); 45 | 46 | libfqfft::_polynomial_addition(f3, f1, f2); 47 | 48 | // evaluate f1 and f2 49 | RootsOfUnityEvaluation eval1(f1, accs); 50 | RootsOfUnityEvaluation eval2(f2, accs); 51 | 52 | testAssertTrue(eval1._testIsConsistent()); 53 | testAssertTrue(eval2._testIsConsistent()); 54 | assertEvals(f1, eval1.getEvaluations(), numPoints); 55 | assertEvals(f2, eval2.getEvaluations(), numPoints); 56 | 57 | // merge the evaluation of f1(x) and f2(x) to get the evaluation tree of their sum (f1+f2)(x) 58 | eval1 += eval2; 59 | 60 | testAssertTrue(eval1._testIsConsistent()); 61 | assertEvals(f3, eval1.getEvaluations(), numPoints); 62 | } 63 | 64 | int main() { 65 | libvectcom::initialize(nullptr, 0); 66 | 67 | for (size_t numPoints = 2; numPoints <= 32; numPoints++) { 68 | for (size_t deg = 1; deg <= 32; deg++) { 69 | loginfo << "Evaluating degree " << deg << " polynomials at the first " << numPoints << " roots of unity" << endl; 70 | AccumulatorTree accs(numPoints); 71 | testRootsOfUnityEvaluation(deg, accs); 72 | testMultipointMerging(deg, accs); 73 | } 74 | } 75 | 76 | loginfo << "Test passed!" << endl; 77 | 78 | return 0; 79 | } 80 | 81 | void assertEvals(const std::vector& f, const std::vector& evals, size_t numPoints) { 82 | std::vector actual; 83 | 84 | auto omegas = get_all_roots_of_unity(numPoints); 85 | for(size_t i = 0; i < numPoints; i++) { 86 | Fr v = libfqfft::evaluate_polynomial(f.size(), f, omegas[i]); 87 | actual.push_back(v); 88 | } 89 | 90 | for(size_t i = 0; i < evals.size(); i++) { 91 | if(evals[i] != actual[i]) { 92 | logdbg << "The multipoint evaluation function returned a different f(\\omega^" 93 | << i << ")!" << endl; 94 | logdbg << " * Eval: " << evals[i] << endl; 95 | logdbg << " * Actual: " << actual[i] << endl; 96 | throw std::runtime_error("The multipoint evaluation function is wrong!"); 97 | } else { 98 | //logdbg << "At point w_n^" << i << " = " << evals[i] << endl; 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /public-params/.gitignore: -------------------------------------------------------------------------------- 1 | /1048576 2 | -------------------------------------------------------------------------------- /public-params/65536/65536: -------------------------------------------------------------------------------- 1 | 9755664001534477976373346953458667014047014860280947403107771413787640486060 2 | 65536 3 | -------------------------------------------------------------------------------- /public-params/65536/65536-0.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alinush/libvectcom/7d95a1d55ea24b301d1b064e2488a739a401ed73/public-params/65536/65536-0.log -------------------------------------------------------------------------------- /public-params/65536/65536-1.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alinush/libvectcom/7d95a1d55ea24b301d1b064e2488a739a401ed73/public-params/65536/65536-1.log -------------------------------------------------------------------------------- /public-params/65536/65536-10.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alinush/libvectcom/7d95a1d55ea24b301d1b064e2488a739a401ed73/public-params/65536/65536-10.log -------------------------------------------------------------------------------- /public-params/65536/65536-11.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alinush/libvectcom/7d95a1d55ea24b301d1b064e2488a739a401ed73/public-params/65536/65536-11.log -------------------------------------------------------------------------------- /public-params/65536/65536-2.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alinush/libvectcom/7d95a1d55ea24b301d1b064e2488a739a401ed73/public-params/65536/65536-2.log -------------------------------------------------------------------------------- /public-params/65536/65536-3.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alinush/libvectcom/7d95a1d55ea24b301d1b064e2488a739a401ed73/public-params/65536/65536-3.log -------------------------------------------------------------------------------- /public-params/65536/65536-4.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alinush/libvectcom/7d95a1d55ea24b301d1b064e2488a739a401ed73/public-params/65536/65536-4.log -------------------------------------------------------------------------------- /public-params/65536/65536-5.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alinush/libvectcom/7d95a1d55ea24b301d1b064e2488a739a401ed73/public-params/65536/65536-5.log -------------------------------------------------------------------------------- /public-params/65536/65536-6.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alinush/libvectcom/7d95a1d55ea24b301d1b064e2488a739a401ed73/public-params/65536/65536-6.log -------------------------------------------------------------------------------- /public-params/65536/65536-7.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alinush/libvectcom/7d95a1d55ea24b301d1b064e2488a739a401ed73/public-params/65536/65536-7.log -------------------------------------------------------------------------------- /public-params/65536/65536-8.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alinush/libvectcom/7d95a1d55ea24b301d1b064e2488a739a401ed73/public-params/65536/65536-8.log -------------------------------------------------------------------------------- /public-params/65536/65536-9.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alinush/libvectcom/7d95a1d55ea24b301d1b064e2488a739a401ed73/public-params/65536/65536-9.log -------------------------------------------------------------------------------- /scripts/linux/cmake.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | scriptdir=$(cd $(dirname $0); pwd -P) 5 | sourcedir=$(cd $scriptdir/../..; pwd -P) 6 | . $scriptdir/shlibs/check-env.sh 7 | . $scriptdir/shlibs/os.sh 8 | 9 | $scriptdir/submodule-update.sh 10 | 11 | builddir=$VECTCOM_BUILD_DIR 12 | mkdir -p "$builddir" 13 | cd "$builddir" 14 | 15 | #if [ "$OS" = "Linux" ]; then 16 | # export CXX=clang++ 17 | #fi 18 | cmake $VECTCOM_CMAKE_ARGS $@ "$sourcedir" 19 | -------------------------------------------------------------------------------- /scripts/linux/cols.sh: -------------------------------------------------------------------------------- 1 | print_usage() { 2 | echo "Usage: $0 [ ...] " 3 | echo 4 | echo "You can use 'all' for ." 5 | echo 6 | echo "Example: $0 some-file.csv other-file.csv 1,4,5" 7 | echo "Example: $0 some-file.csv all" 8 | } 9 | 10 | get_num_cols() { 11 | file1=$1 12 | num_cols=0; 13 | for f in `cat "$file1" | head -n 1 | tr ',' '\n'`; do 14 | num_cols=$((num_cols+1)) 15 | done 16 | echo $num_cols 17 | } 18 | 19 | get_cols() { 20 | file1=$1 21 | echo 22 | num_cols=0; 23 | for f in `cat "$file1" | head -n 1 | tr ',' '\n'`; do 24 | num_cols=$((num_cols+1)) 25 | echo $num_cols - $f 26 | done 27 | } 28 | 29 | assert_same_cols() { 30 | prev_file=$1 31 | prev_cols=`get_cols $prev_file` 32 | shift 33 | 34 | while [ $# -gt 0 ]; do 35 | cols=`get_cols $1` 36 | 37 | if [ "$prev_cols" != "$cols" ]; then 38 | echo "ERROR: '$file1' and '$1' have different columns!" 39 | echo 40 | echo "$prev_file:" 41 | echo "$prev_cols" 42 | echo 43 | echo "$1:" 44 | echo "$cols" 45 | 46 | exit 1 47 | fi 48 | 49 | shift 50 | done 51 | } 52 | 53 | hscroll_size=20 54 | 55 | file1=$1 56 | shift 57 | files=$file1 58 | 59 | while [ -f $1 ] && [ $# -gt 0 ]; do 60 | files="$files $1" 61 | shift 62 | done 63 | 64 | # INVARIANT: every file in $files exists and we might have extra argument(s) that are NOT files 65 | 66 | # if we parsed all files from command args and no columns were specified as args, then print usage, then print the columns, then exit (see next chunks) 67 | if [ $# -eq 0 ]; then 68 | print_usage 69 | if [ -z "$files" ]; then 70 | exit 71 | fi 72 | fi 73 | 74 | if [ $# -gt 1 ]; then 75 | shift 76 | echo "ERROR: You gave $(($#-1)) extra argument(s): $@" 77 | echo 78 | print_usage 79 | exit 1 80 | fi 81 | 82 | assert_same_cols $files 83 | 84 | arg_cols=$1 85 | num_cols=`get_num_cols $file1` 86 | 87 | # print fields of CSV file, even if args are bad 88 | echo 89 | echo "Columns in files $files:" 90 | echo "$(get_cols $file1)" 91 | 92 | # exit, if no columns were specified 93 | if [ $# -lt 1 ]; then 94 | exit 1 95 | fi 96 | 97 | # if 'all' columns were specified then build comma separated list of all columns 98 | if [ "$arg_cols" == "all" ]; then 99 | sel_cols="1" 100 | for c in `seq 2 $num_cols`; do 101 | sel_cols="$sel_cols,$c" 102 | done 103 | else 104 | sel_cols=$arg_cols 105 | fi 106 | first_col=`echo $sel_cols | cut -f1 -d,` 107 | 108 | echo "Columns: $sel_cols" 109 | echo "Sort by column: $first_col" 110 | echo "Files: $files" 111 | 112 | ( head -n 1 $file1; for f in $files; do tail -n +2 $f; done | sort -g -t',' -k$first_col ) | cut -d',' -f$sel_cols | sed -e 's/,,/, ,/g' | column -s, -t | less -#$hscroll_size -N -S 113 | -------------------------------------------------------------------------------- /scripts/linux/generate-qsdh-params.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | scriptdir=$(cd $(dirname $0); pwd -P) 6 | . $scriptdir/shlibs/os.sh 7 | 8 | if [ $# -ne 2 ]; then 9 | echo "Usage: $0 " 10 | exit 1 11 | fi 12 | 13 | trap_file=$1; shift 1; 14 | q=$1; shift 1; 15 | num_chunks=$NUM_CPUS 16 | 17 | if [ $q -lt $num_chunks ]; then 18 | num_chunks=$q 19 | fi 20 | 21 | chunk_size=$(($q/$num_chunks)) 22 | 23 | echo "Generating q-SDH params in '$trap_file' (q = $q, numChunks = $NUM_CPUS, chunk_size = $chunk_size) ..." 24 | 25 | ParamsGenTrapdoors "$trap_file" $q 26 | 27 | for i in `seq 0 $(($num_chunks-1))`; do 28 | start=$(($i * $chunk_size)) 29 | if [ $i -lt $(($num_chunks - 1)) ]; then 30 | end=$((($i+1) * $chunk_size)) 31 | else 32 | end=$(($q+1)) 33 | fi 34 | 35 | echo "Generating [$start, $end) ..." 36 | # Send to background 37 | out_file=${trap_file}-$i 38 | ParamsGenPowers "$trap_file" "$out_file" $start $end &>$out_file.log & 39 | done 40 | -------------------------------------------------------------------------------- /scripts/linux/install-deps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | scriptdir=$(cd $(dirname $0); pwd -P) 5 | sourcedir=$(cd $scriptdir/../..; pwd -P) 6 | 7 | . $scriptdir/shlibs/os.sh 8 | 9 | if [ "$OS" == "OSX" ]; then 10 | brew install cmake openssl pkg-config ntl 11 | elif [ "$OS" == "Linux" ]; then 12 | sudo apt-get install cmake clang 13 | else 14 | echo "Unsupported OS!" 15 | fi 16 | -------------------------------------------------------------------------------- /scripts/linux/install-libs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | scriptdir=$(cd $(dirname $0); pwd -P) 5 | sourcedir=$(cd $scriptdir/../..; pwd -P) 6 | 7 | . $scriptdir/shlibs/os.sh 8 | 9 | CMAKE_CXX_FLAGS= 10 | if [ "$OS" = "OSX" -a "$OS_FLAVOR" = "Catalina" ]; then 11 | echo "Setting proper env. vars for compiling against OpenSSL in OS X Catalina" 12 | export PKG_CONFIG_PATH="/usr/local/opt/openssl@1.1/lib/pkgconfig" 13 | 14 | # NOTE: None of these seem to help cmake find OpenSSL 15 | #export LDFLAGS="-L/usr/local/opt/openssl@1.1/lib" 16 | #export CXXFLAGS="-I/usr/local/opt/openssl@1.1/include" 17 | #CMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS -I/usr/local/opt/openssl@1.1/include" 18 | fi 19 | 20 | CLEAN_BUILD=0 21 | if [ "$1" == "debug" ]; then 22 | echo "Debug build..." 23 | echo 24 | ATE_PAIRING_FLAGS="DBG=on" 25 | elif [ "$1" == "clean" ]; then 26 | CLEAN_BUILD=1 27 | fi 28 | 29 | # NOTE: Seemed like setting this to OFF caused a simple cout << G1::zero(); to segfault but it was just that I forgot to call init_public_params() 30 | BINARY_OUTPUT=OFF 31 | NO_PT_COMPRESSION=ON 32 | MULTICORE=ON 33 | if [ "$OS" == "OSX" ]; then 34 | # libff's multicore implementation uses OpenMP which clang on OS X apparently doesn't support 35 | MULTICORE=OFF 36 | fi 37 | 38 | ( 39 | cd $sourcedir/ 40 | git submodule init 41 | git submodule update 42 | ) 43 | 44 | # install libxassert and libxutils 45 | 46 | ( 47 | cd /tmp 48 | mkdir -p libvectcom-deps/ 49 | cd libvectcom-deps/ 50 | 51 | for lib in `echo libxassert; echo libxutils`; do 52 | if [ ! -d $lib ]; then 53 | git clone https://github.com/alinush/$lib.git 54 | fi 55 | 56 | echo 57 | echo "Installing $lib..." 58 | echo 59 | 60 | ( 61 | cd $lib/ 62 | mkdir -p build/ 63 | cd build/ 64 | cmake -DCMAKE_BUILD_TYPE=Release .. 65 | cmake --build . 66 | sudo cmake --build . --target install 67 | ) 68 | done 69 | 70 | ) 71 | 72 | cd $sourcedir/depends 73 | 74 | # NOTE TO SELF: After one day of trying to get CMake to add these using ExternalProject_Add (or add_subdirectory), I give up. 75 | 76 | echo "Installing ate-pairing..." 77 | ( 78 | cd ate-pairing/ 79 | if [ $CLEAN_BUILD -eq 1 ]; then 80 | echo "Cleaning previous build..." 81 | echo 82 | make clean 83 | fi 84 | make -j $NUM_CPUS -C src \ 85 | SUPPORT_SNARK=1 \ 86 | $ATE_PAIRING_FLAGS 87 | 88 | INCL_DIR=/usr/local/include/ate-pairing 89 | sudo mkdir -p "$INCL_DIR" 90 | sudo cp include/bn.h "$INCL_DIR" 91 | sudo cp include/zm.h "$INCL_DIR" 92 | sudo cp include/zm2.h "$INCL_DIR" 93 | # WARNING: Need this because (the newer 'develop' branch of) libff uses #include "ate-pairing/include/bn.h" 94 | #sudo ln -sf "$INCL_DIR" "$INCL_DIR/include" 95 | # WARNING: Need this due to a silly #include "depends/[...]" directive from libff 96 | # (/usr/local/include/libff/algebra/curves/bn128/bn128_g1.hpp:12:44: fatal error: depends/ate-pairing/include/bn.h: No such file or directory) 97 | sudo mkdir -p "$INCL_DIR/../depends/ate-pairing/" 98 | sudo ln -sf "$INCL_DIR" "$INCL_DIR/../depends/ate-pairing/include" 99 | 100 | LIB_DIR=/usr/local/lib 101 | sudo cp lib/libzm.a "$LIB_DIR" 102 | # NOTE: Not sure why, but getting error at runtime that this cannot be loaded. Maybe it should be zm.so? 103 | #sudo cp lib/zm.so "$LIB_DIR/libzm.so" 104 | ) 105 | 106 | echo "Installing libff..." 107 | ( 108 | cd libff/ 109 | if [ $CLEAN_BUILD -eq 1 ]; then 110 | echo "Cleaning previous build..." 111 | echo 112 | rm -rf build/ 113 | fi 114 | 115 | #git submodule init && git submodule update 116 | 117 | mkdir -p build/ 118 | cd build/ 119 | # WARNING: Does not link correctly with -DPERFORMANCE=ON 120 | cmake \ 121 | -DCMAKE_BUILD_TYPE=RelWithDebInfo \ 122 | -DCMAKE_INSTALL_PREFIX=/usr/local \ 123 | -DIS_LIBFF_PARENT=OFF \ 124 | -DBINARY_OUTPUT=$BINARY_OUTPUT \ 125 | -DNO_PT_COMPRESSION=$NO_PT_COMPRESSION \ 126 | -DCMAKE_CXX_FLAGS="-Wno-unused-parameter -Wno-unused-value -Wno-unused-variable -I$sourcedir $CMAKE_CXX_FLAGS" \ 127 | -DUSE_ASM=ON \ 128 | -DPERFORMANCE=OFF \ 129 | -DMULTICORE=$MULTICORE \ 130 | -DCURVE="BN128" \ 131 | -DWITH_PROCPS=OFF .. 132 | 133 | make -j $NUM_CPUS 134 | sudo make install 135 | ) 136 | 137 | echo "Installing libfqfft..." 138 | ( 139 | # NOTE: Headers-only library 140 | cd libfqfft/ 141 | 142 | INCL_DIR=/usr/local/include/libfqfft 143 | sudo mkdir -p "$INCL_DIR" 144 | sudo cp -r libfqfft/* "$INCL_DIR/" 145 | sudo rm "$INCL_DIR/CMakeLists.txt" 146 | ) 147 | -------------------------------------------------------------------------------- /scripts/linux/make.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | scriptdir=$(cd $(dirname $0); pwd -P) 5 | sourcedir=$(cd $scriptdir/../..; pwd -P) 6 | . $scriptdir/shlibs/os.sh 7 | . $scriptdir/shlibs/check-env.sh 8 | 9 | builddir=$VECTCOM_BUILD_DIR 10 | 11 | echo "Making in '$builddir' ..." 12 | echo 13 | [ ! -d "$builddir" ] && $scriptdir/cmake.sh 14 | cd "$builddir" 15 | make -j $NUM_CPUS $@ 16 | -------------------------------------------------------------------------------- /scripts/linux/plot-vcs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import matplotlib.pyplot as plt 4 | import matplotlib.ticker as plticker 5 | from cycler import cycler 6 | import pandas 7 | import sys 8 | import time 9 | import numpy as np 10 | 11 | setTitle=False 12 | 13 | if len(sys.argv) < 4: 14 | print("Usage:", sys.argv[0], " [] ...") 15 | print() 16 | sys.exit(0) 17 | 18 | del sys.argv[0] 19 | 20 | out_png_file = sys.argv[0] 21 | del sys.argv[0] 22 | 23 | minN = int(sys.argv[0]) 24 | del sys.argv[0] 25 | 26 | maxN = int(sys.argv[0]) 27 | del sys.argv[0] 28 | 29 | data_files = [f for f in sys.argv] 30 | if len(data_files) == 0: 31 | print("ERROR: You did not give me any CSV files") 32 | sys.exit(1) 33 | 34 | print("Reading CSV files:", data_files, "...") 35 | 36 | csv_data = pandas.concat((pandas.read_csv(f) for f in data_files)) 37 | csv_data.sort_values('n', inplace=True) # WARNING: Otherwise, plotting unsorted CSV file be messed up, with incorrect y-values for a x-coordinates 38 | 39 | #print "Raw:" 40 | #print csv_data.to_string() 41 | #print csv_data.columns 42 | #print csv_data['dictSize'].values 43 | 44 | #print "Averaged:" 45 | 46 | if minN == 0: 47 | minN = csv_data.n.unique().min(); 48 | if maxN == 0: 49 | maxN = csv_data.n.unique().max(); 50 | 51 | print("min N:", minN) 52 | print("max N:", maxN) 53 | 54 | csv_data.scheme.replace('fk', 'TAB+20 (quasilinear, fast)', inplace=True) 55 | csv_data.scheme.replace('pointproofs-naive', 'Pointproofs (quadratic, slow)', inplace=True) 56 | csv_data.scheme.replace('pointproofs-fast', 'Pointproofs (quasilinear, fast)', inplace=True) 57 | 58 | #csv_data = csv_data[csv_data.dkg != 'Feldman'] 59 | csv_data = csv_data[csv_data.n >= minN] 60 | csv_data = csv_data[csv_data.n <= maxN] 61 | 62 | #print(csv_data.to_string()) # print all data 63 | 64 | #SMALL_SIZE = 10 65 | MEDIUM_SIZE = 20 66 | BIG_SIZE = 24 67 | BIGGER_SIZE = 28 68 | BIGGEST_SIZE = 32 69 | 70 | plt.rc('lines', linewidth=4, markersize=10, markeredgewidth=4) # width of graph line & size of marker on graph line for data point 71 | plt.rc('font', size= BIGGER_SIZE) # controls default text sizes 72 | #plt.rc('axes', titlesize= BIGGER_SIZE) # fontsize of the axes title 73 | #plt.rc('axes', labelsize= MEDIUM_SIZE) # fontsize of the x and y labels 74 | plt.rc('xtick', labelsize= BIG_SIZE) 75 | plt.rc('ytick', labelsize= BIG_SIZE) 76 | plt.rc('legend', fontsize= BIG_SIZE) 77 | #plt.rc('figure', titlesize=BIGGER_SIZE) # fontsize of the figure title 78 | 79 | ##plt.rcParams['axes.prop_cycle'] = cycler(color='bgrcmyk') 80 | #plt.rcParams['axes.prop_cycle'] = cycler(color=[ 81 | # # for naive Lagrange lines 82 | # '#1f77b4', # blue 83 | # #'#9467bd', # purple/magenta/whatever, 84 | # '#1f77b4', # blue 85 | # 86 | # # for fast Lagrange lines 87 | # '#ff7f0e', # orange 88 | # '#ff7f0e', # orange 89 | # #'#d62728', # red 90 | 91 | # # for multiexp line 92 | # #'#bcbd22', # yellow 93 | # #'#d62728', # red 94 | # '#2ca02c', # green 95 | # ]) 96 | 97 | plt.rcParams['axes.prop_cycle'] = cycler(color=[ 98 | # for TAB+20 line 99 | '#ff7f0e', # orange 100 | # for Pointproofs slow line 101 | '#d62728', # red 102 | # for Pointproofs fast line 103 | '#2ca02c', # green 104 | ]) 105 | 106 | def plotNumbers(data): 107 | #logBase = 10 108 | logBase = 2 109 | 110 | #print "Plotting with log base", logBase 111 | 112 | # adjust the size of the plot: (20, 10) is bigger than (10, 5) in the 113 | # sense that fonts will look smaller on (20, 10) 114 | fig, ax1 = plt.subplots(figsize=(12,7.5)) 115 | ax1.set_xscale("log", base=logBase) 116 | ax1.set_yscale("log") 117 | if setTitle: 118 | ax1.set_title('Time to compute all proofs') 119 | 120 | ax1.grid(True) 121 | #ax1.set_xlabel("Total # of signers n") 122 | #ax1.set_ylabel("Time (in seconds)") #, fontsize=fontsize) 123 | 124 | plots = [] 125 | names = [] 126 | 127 | fileSuffix = "" 128 | 129 | # NOTE: see 'marker' and 'linestyle' and 'linewidth' options here 130 | # https://matplotlib.org/3.1.1/api/markers_api.html#module-matplotlib.markers 131 | # https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.lines.Line2D.html#matplotlib.lines.Line2D.set_linestyle 132 | # https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.lines.Line2D.html#matplotlib.lines.Line2D.set_linewidth 133 | 134 | # plot multiexp 135 | marker = 'o' 136 | x = data.n.unique() 137 | ax1.set_xticks(x) 138 | 139 | ax1.set_xticklabels(np.log2(x).astype(int), rotation=30) 140 | #locmaj = plticker.LogLocator(base=10,numticks=12) 141 | #ax1.yaxis.set_major_locator(locmaj) 142 | #locmin = plticker.LogLocator(base=10.0,numticks=12) #,subs=(0.2,0.4,0.6,0.8) 143 | #ax1.yaxis.set_minor_locator(locmin) 144 | #ax1.yaxis.set_minor_formatter(plticker.NullFormatter()) 145 | 146 | # plot Lagr and total times for each scheme 147 | schemes = data.scheme.unique() 148 | for scheme in schemes: 149 | print("Plotting scheme type: ", scheme) 150 | 151 | filtered = data[data.scheme == scheme] 152 | # NOTE: In case, we don't have enough numbers for one of the schemes 153 | x = filtered.n.unique() #.unique() # x-axis is the number of players aggregating 154 | print("n = ", x) 155 | 156 | col1 = filtered.total_usec.values 157 | 158 | assert len(x) == len(col1) 159 | 160 | plt2, = ax1.plot(x, filtered.total_usec.values, linestyle="-", marker=marker) #, markersize=10, linewidth=2.0) 161 | plots.append(plt2) 162 | names.append(scheme) 163 | 164 | ax1.legend(plots, 165 | names, 166 | loc='upper left')#, fontsize=fontsize 167 | 168 | plt.tight_layout() 169 | 170 | out_file = out_png_file 171 | print("Saving graph to", out_file) 172 | 173 | #date = time.strftime("%Y-%m-%d-%H-%M-%S") 174 | plt.savefig(out_file, bbox_inches='tight') 175 | plt.close() 176 | 177 | plotNumbers(csv_data) 178 | 179 | #plt.xticks(fontsize=fontsize) 180 | #plt.yticks(fontsize=fontsize) 181 | plt.show() 182 | -------------------------------------------------------------------------------- /scripts/linux/rename-library.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | scriptdir=$(cd $(dirname $0); pwd -P) 5 | sourcedir=$(cd $scriptdir/../..; pwd -P) 6 | 7 | . $scriptdir/shlibs/os.sh 8 | 9 | if [ $# -lt 2 ]; then 10 | echo "Usage: $0 " 11 | echo 12 | echo "Example: $0 polycrypto vectcom" 13 | exit 1 14 | fi 15 | 16 | old_name=$1 17 | new_name=$2 18 | 19 | sed_cmd=sed 20 | if [ "$OS" = "OSX" ]; then 21 | sed_cmd=gsed 22 | fi 23 | 24 | find $sourcedir \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 $sed_cmd -i "s/lib$old_name/lib$new_name/g" 25 | find $sourcedir \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 $sed_cmd -i "s/$old_name/$new_name/g" 26 | 27 | OLD_NAME=`echo $old_name | tr [a-z] [A-Z]` 28 | NEW_NAME=`echo $new_name | tr [a-z] [A-Z]` 29 | 30 | find $sourcedir \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 $sed_cmd -i "s/$OLD_NAME/$NEW_NAME/g" 31 | -------------------------------------------------------------------------------- /scripts/linux/set-env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $# -lt 1 ]; then 4 | name=${BASH_SOURCE[@]} 5 | echo "Usage: source $name [ ...]" 6 | echo 7 | echo "Examples:" 8 | echo 9 | echo "source $name debug" 10 | echo "source $name trace" 11 | echo "source $name release" 12 | echo "source $name relwithdebug" 13 | echo 14 | if [ -n "$VECTCOM_HAS_ENV_SET" ]; then 15 | echo "Currently-set environment" 16 | echo "=========================" 17 | echo "Build directory: $VECTCOM_BUILD_DIR" 18 | echo "CMake args: $VECTCOM_CMAKE_ARGS" 19 | fi 20 | else 21 | # WARNING: Need to exit using control-flow rather than 'exit 1' because this script is sourced 22 | invalid_buildtype=0 23 | 24 | buildtype=`echo "$1" | tr '[:upper:]' '[:lower:]'` 25 | shift; 26 | 27 | extra_cmake_args=$@ 28 | 29 | scriptdir=$(cd $(dirname ${BASH_SOURCE[@]}); pwd -P) 30 | sourcedir=$(cd $scriptdir/../..; pwd -P) 31 | 32 | . $scriptdir/shlibs/os.sh 33 | #echo "Source dir: $sourcedir" 34 | 35 | branch=`git branch | grep "\*"` 36 | branch=${branch/\* /} 37 | builddir_base=~/builds/vectcom/$branch 38 | case "$buildtype" in 39 | trace) 40 | builddir=$builddir_base/trace 41 | cmake_args="-DCMAKE_BUILD_TYPE=Trace" 42 | ;; 43 | debug) 44 | builddir=$builddir_base/debug 45 | cmake_args="-DCMAKE_BUILD_TYPE=Debug" 46 | ;; 47 | release) 48 | builddir=$builddir_base/release 49 | cmake_args="-DCMAKE_BUILD_TYPE=Release" 50 | ;; 51 | relwithdebug) 52 | builddir=$builddir_base/relwithdebug 53 | cmake_args="-DCMAKE_BUILD_TYPE=RelWithDebInfo" 54 | ;; 55 | *) 56 | invalid_buildtype=1 57 | ;; 58 | esac 59 | 60 | cmake_args="$cmake_args $extra_cmake_args" 61 | 62 | # only for OS X Catalina 63 | #if [ "$OS" = "OSX" -a "$OS_FLAVOR" = "Catalina" ]; then 64 | # echo "Setting extra env. vars for OS X Catalina..." 65 | # cmake_args="$cmake_args -DCMAKE_CXX_FLAGS=-I/usr/local/include" 66 | #fi 67 | 68 | # 69 | # grep-code alias 70 | # 71 | alias grep-code='grep --exclude-dir=.git --exclude=".gitignore" --exclude="*.html"' 72 | 73 | if [ $invalid_buildtype -eq 0 ]; then 74 | echo "Configuring for build type '$buildtype' ..." 75 | echo 76 | 77 | export PATH="$scriptdir:$PATH" 78 | export PATH="$builddir/libvectcom/bin:$PATH" 79 | export PATH="$builddir/libvectcom/bin/test:$PATH" 80 | export PATH="$builddir/libvectcom/bin/bench:$PATH" 81 | export PATH="$builddir/libvectcom/bin/app:$PATH" 82 | export PATH="$builddir/libvectcom/bin/examples:$PATH" 83 | 84 | echo "Build directory: $builddir" 85 | echo "CMake args: $cmake_args" 86 | echo "PATH envvar: $PATH" 87 | 88 | export VECTCOM_BUILD_DIR=$builddir 89 | export VECTCOM_CMAKE_ARGS=$cmake_args 90 | export VECTCOM_HAS_ENV_SET=1 91 | export VECTCOM_SOURCE_DIR=$sourcedir 92 | else 93 | echo "ERROR: Invalid build type '$buildtype'" 94 | fi 95 | fi 96 | -------------------------------------------------------------------------------- /scripts/linux/shlibs/check-env.sh: -------------------------------------------------------------------------------- 1 | if [ -z "$VECTCOM_HAS_ENV_SET" ]; then 2 | echo "ERROR: You must call 'source set-env.sh ' first" 3 | exit 1 4 | fi 5 | 6 | #which clang++ 2>&1 >/dev/null || { echo "ERROR: Clang is not installed."; exit 1; } 7 | #which parallel 2>&1 >/dev/null || { echo "ERROR: GNU parallel needs to be installed."; exit 1; } 8 | -------------------------------------------------------------------------------- /scripts/linux/shlibs/os.sh: -------------------------------------------------------------------------------- 1 | OS_FLAVOR="Unknown" 2 | NUM_CPUS= 3 | 4 | if [ "$(uname -s)" = "Darwin" ]; then 5 | OS="OSX" 6 | if sw_vers -productVersion | grep "^10\.15" >/dev/null; then 7 | OS_FLAVOR="Catalina" 8 | fi 9 | NUM_CPUS=`sysctl -n hw.ncpu` 10 | elif [ "$(uname -s)" = "Linux" ]; then 11 | OS="Linux" 12 | NUM_CPUS=`grep -c ^processor /proc/cpuinfo` 13 | if [ -f /etc/issue ]; then 14 | if grep Fedora /etc/issue >/dev/null; then 15 | OS_FLAVOR="Fedora" 16 | elif grep Ubuntu /etc/issue >/dev/null; then 17 | OS_FLAVOR="Ubuntu" 18 | fi 19 | fi 20 | fi 21 | 22 | #echo "OS: $OS" 23 | #echo "OS Flavor: $OS_FLAVOR" 24 | -------------------------------------------------------------------------------- /scripts/linux/submodule-update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | scriptdir=$(cd $(dirname $0); pwd -P) 5 | sourcedir=$(cd $scriptdir/../..; pwd -P) 6 | . $scriptdir/shlibs/check-env.sh 7 | . $scriptdir/shlibs/os.sh 8 | 9 | builddir=$VECTCOM_BUILD_DIR 10 | 11 | ( 12 | cd $sourcedir; 13 | git submodule init; 14 | git submodule update; 15 | ) 16 | -------------------------------------------------------------------------------- /scripts/linux/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | scriptdir=$(cd $(dirname $0); pwd -P) 5 | sourcedir=$(cd $scriptdir/../..; pwd -P) 6 | . $scriptdir/shlibs/check-env.sh 7 | 8 | builddir=$VECTCOM_BUILD_DIR 9 | 10 | cd "$builddir" 11 | ctest --verbose 12 | --------------------------------------------------------------------------------