├── .gitignore ├── .travis.yml ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── LICENSE ├── Makefile ├── README.md ├── cascade ├── algorithm.cpp ├── block.cpp ├── classical_session.cpp ├── iteration.cpp ├── key.cpp ├── mock_classical_session.cpp ├── pending_item.cpp ├── random.cpp ├── reconciliation.cpp ├── report.cpp ├── shuffle.cpp ├── shuffled_key.cpp └── stats.cpp ├── docs └── figures │ ├── andre-reis-thesis-figure-5-1-original.png │ ├── andre-reis-thesis-figure-5-1-reproduced.png │ ├── andre-reis-thesis-figure-5-10-original.png │ ├── andre-reis-thesis-figure-5-2-original.png │ ├── andre-reis-thesis-figure-5-2-reproduced.png │ ├── andre-reis-thesis-figure-5-3-original.png │ ├── andre-reis-thesis-figure-5-3-reproduced.png │ ├── andre-reis-thesis-figure-5-4-original.png │ ├── andre-reis-thesis-figure-5-5-a-reproduced.png │ ├── andre-reis-thesis-figure-5-5-b-reproduced.png │ ├── andre-reis-thesis-figure-5-5-original.png │ ├── andre-reis-thesis-figure-5-5a-reproduced.png │ ├── andre-reis-thesis-figure-5-5b-reproduced.png │ ├── andre-reis-thesis-figure-5-6-original.png │ ├── andre-reis-thesis-figure-5-7-original.png │ ├── andre-reis-thesis-figure-5-8-original.png │ ├── andre-reis-thesis-figure-5-9-original.png │ ├── demystifying-figure-1-original.png │ ├── demystifying-figure-1-reproduced.png │ ├── demystifying-figure-10-original.png │ ├── demystifying-figure-10-reproduced.png │ ├── demystifying-figure-11-original.png │ ├── demystifying-figure-11-reproduced.png │ ├── demystifying-figure-11-reproduced.png.png │ ├── demystifying-figure-12-original.png │ ├── demystifying-figure-13-original.png │ ├── demystifying-figure-13-reproduced.png │ ├── demystifying-figure-2-original.png │ ├── demystifying-figure-2-reproduced.png │ ├── demystifying-figure-3-original.png │ ├── demystifying-figure-3-reproduced.png │ ├── demystifying-figure-4-original.png │ ├── demystifying-figure-4-reproduced.png │ ├── demystifying-figure-5-original.png │ ├── demystifying-figure-5-reproduced.png │ ├── demystifying-figure-6-original.png │ ├── demystifying-figure-7-original.png │ ├── demystifying-figure-8-original.png │ ├── demystifying-figure-8-reproduced.png │ ├── demystifying-figure-9-original.png │ └── demystifying-figure-9-reproduced.png ├── include ├── algorithm.h ├── block.h ├── classical_session.h ├── debug.h ├── iteration.h ├── key.h ├── mock_classical_session.h ├── pending_item.h ├── random.h ├── reconciliation.h ├── report.h ├── shuffle.h ├── shuffled_key.h └── stats.h ├── src └── block.cpp ├── study ├── aggregate_stats.cpp ├── aggregate_stats.h ├── data │ ├── debug │ │ └── data__algorithm=biconf-cascade;key_size=vary;error_rate=0.1 │ ├── papers │ │ ├── data__algorithm=biconf;key_size=10000;error_rate=vary │ │ ├── data__algorithm=biconf;key_size=1000;error_rate=vary │ │ ├── data__algorithm=biconf;key_size=2000;error_rate=vary │ │ ├── data__algorithm=biconf;key_size=vary;error_rate=0.05 │ │ ├── data__algorithm=option3;key_size=10000;error_rate=vary │ │ ├── data__algorithm=option3;key_size=1000;error_rate=vary │ │ ├── data__algorithm=option3;key_size=2000;error_rate=vary │ │ ├── data__algorithm=option3;key_size=vary;error_rate=0.05 │ │ ├── data__algorithm=option4;key_size=10000;error_rate=vary │ │ ├── data__algorithm=option4;key_size=1000;error_rate=vary │ │ ├── data__algorithm=option4;key_size=2000;error_rate=vary │ │ ├── data__algorithm=option4;key_size=vary;error_rate=0.05 │ │ ├── data__algorithm=option7;key_size=10000;error_rate=vary │ │ ├── data__algorithm=option7;key_size=1000;error_rate=vary │ │ ├── data__algorithm=option7;key_size=2000;error_rate=vary │ │ ├── data__algorithm=option7;key_size=vary;error_rate=0.05 │ │ ├── data__algorithm=option8;key_size=10000;error_rate=vary │ │ ├── data__algorithm=option8;key_size=1000;error_rate=vary │ │ ├── data__algorithm=option8;key_size=2000;error_rate=vary │ │ ├── data__algorithm=option8;key_size=vary;error_rate=0.05 │ │ ├── data__algorithm=original;key_size=10000;error_rate=vary │ │ ├── data__algorithm=original;key_size=1000;error_rate=vary │ │ ├── data__algorithm=original;key_size=2000;error_rate=vary │ │ ├── data__algorithm=original;key_size=vary;error_rate=0.01 │ │ ├── data__algorithm=original;key_size=vary;error_rate=0.02 │ │ ├── data__algorithm=original;key_size=vary;error_rate=0.05 │ │ ├── data__algorithm=yanetal;key_size=10000;error_rate=vary │ │ ├── data__algorithm=yanetal;key_size=1000;error_rate=vary │ │ ├── data__algorithm=yanetal;key_size=2000;error_rate=vary │ │ └── data__algorithm=yanetal;key_size=vary;error_rate=0.05 │ ├── performance │ │ ├── data__algorithm=biconf;key_size=10000;error_rate=vary │ │ ├── data__algorithm=biconf;key_size=vary;error_rate=0.02 │ │ ├── data__algorithm=option7;key_size=10000;error_rate=vary │ │ ├── data__algorithm=option7;key_size=vary;error_rate=0.02 │ │ ├── data__algorithm=original;key_size=10000;error_rate=vary │ │ ├── data__algorithm=original;key_size=vary;error_rate=0.02 │ │ ├── data__algorithm=yanetal;key_size=10000;error_rate=vary │ │ └── data__algorithm=yanetal;key_size=vary;error_rate=0.02 │ └── zero_handling │ │ ├── data__algorithm=biconf;key_size=10000;error_rate=vary │ │ └── data__algorithm=original;key_size=10000;error_rate=vary ├── data_point.cpp ├── data_point.h ├── experiments.cpp ├── experiments.h ├── experiments_debug.json ├── experiments_papers.json ├── experiments_performance.json ├── experiments_profile.json ├── experiments_zero_handling.json ├── graphs_andre_reis_thesis.json ├── graphs_demystifying.json ├── graphs_performance.json ├── graphs_zero_handling.json ├── options.cpp ├── options.h ├── run_experiments.cpp ├── series.cpp └── series.h └── tests ├── test_algorithm.cpp ├── test_block.cpp ├── test_key.cpp ├── test_main.cpp └── test_reconciliation.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | *.dSYM/* 19 | 20 | # Fortran module files 21 | *.mod 22 | *.smod 23 | 24 | # Compiled Static libraries 25 | *.lai 26 | *.la 27 | *.a 28 | *.lib 29 | 30 | # Executables 31 | *.exe 32 | *.out 33 | *.app 34 | 35 | # Executables 36 | bin/* 37 | 38 | # Code coverage, profiling, and memory leak files 39 | coverage/* 40 | valgrind.log 41 | callgrind.out.* -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | dist: bionic 3 | compiler: 4 | - clang 5 | os: 6 | - linux 7 | install: 8 | - make ubuntu-get-dependencies 9 | script: 10 | - make test-coverage 11 | after_success: 12 | - bash <(curl -s https://codecov.io/bash) 13 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Test", 9 | "request": "launch", 10 | "program": "make", 11 | "args": ["test"], 12 | "cwd": "${workspaceFolder}", 13 | "externalConsole": false, 14 | }, 15 | { 16 | "name": "Debug", 17 | "type": "cppdbg", 18 | "request": "launch", 19 | "program": "${workspaceFolder}/bin/test-coverage", 20 | "args": ["study/experiments_papers.json"], 21 | "stopAtEntry": false, 22 | "cwd": "${workspaceFolder}", 23 | "environment": [], 24 | "externalConsole": false, 25 | "MIMode": "lldb", 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | ".fantomasignore": "ignore", 4 | "random": "cpp", 5 | "__bit_reference": "cpp", 6 | "__config": "cpp", 7 | "__debug": "cpp", 8 | "__errc": "cpp", 9 | "__functional_base": "cpp", 10 | "__hash_table": "cpp", 11 | "__locale": "cpp", 12 | "__mutex_base": "cpp", 13 | "__node_handle": "cpp", 14 | "__nullptr": "cpp", 15 | "__split_buffer": "cpp", 16 | "__string": "cpp", 17 | "__threading_support": "cpp", 18 | "__tree": "cpp", 19 | "__tuple": "cpp", 20 | "algorithm": "cpp", 21 | "array": "cpp", 22 | "atomic": "cpp", 23 | "bitset": "cpp", 24 | "cctype": "cpp", 25 | "chrono": "cpp", 26 | "clocale": "cpp", 27 | "cmath": "cpp", 28 | "complex": "cpp", 29 | "condition_variable": "cpp", 30 | "csignal": "cpp", 31 | "cstdarg": "cpp", 32 | "cstddef": "cpp", 33 | "cstdint": "cpp", 34 | "cstdio": "cpp", 35 | "cstdlib": "cpp", 36 | "cstring": "cpp", 37 | "ctime": "cpp", 38 | "cwchar": "cpp", 39 | "cwctype": "cpp", 40 | "deque": "cpp", 41 | "exception": "cpp", 42 | "optional": "cpp", 43 | "fstream": "cpp", 44 | "functional": "cpp", 45 | "initializer_list": "cpp", 46 | "iomanip": "cpp", 47 | "ios": "cpp", 48 | "iosfwd": "cpp", 49 | "iostream": "cpp", 50 | "istream": "cpp", 51 | "iterator": "cpp", 52 | "limits": "cpp", 53 | "list": "cpp", 54 | "locale": "cpp", 55 | "map": "cpp", 56 | "memory": "cpp", 57 | "mutex": "cpp", 58 | "new": "cpp", 59 | "numeric": "cpp", 60 | "ostream": "cpp", 61 | "queue": "cpp", 62 | "ratio": "cpp", 63 | "set": "cpp", 64 | "sstream": "cpp", 65 | "stdexcept": "cpp", 66 | "streambuf": "cpp", 67 | "string": "cpp", 68 | "string_view": "cpp", 69 | "system_error": "cpp", 70 | "thread": "cpp", 71 | "tuple": "cpp", 72 | "type_traits": "cpp", 73 | "typeinfo": "cpp", 74 | "unordered_map": "cpp", 75 | "utility": "cpp", 76 | "vector": "cpp", 77 | "bit": "cpp", 78 | "*.tcc": "cpp", 79 | "memory_resource": "cpp", 80 | "cinttypes": "cpp", 81 | "unordered_set": "cpp", 82 | "__functional_03": "cpp", 83 | "strstream": "cpp", 84 | "typeindex": "cpp", 85 | "variant": "cpp", 86 | "cfenv": "cpp", 87 | "codecvt": "cpp", 88 | "stack": "cpp", 89 | "filesystem": "cpp", 90 | "span": "cpp" 91 | }, 92 | "cSpell.words": [ 93 | "Reis", 94 | "Serie", 95 | "Wunused", 96 | "biconf", 97 | "cppdbg", 98 | "dvec", 99 | "lldb", 100 | "ptree", 101 | "unshuffled", 102 | "yanetal" 103 | ], 104 | "gitlens.currentLine.enabled": false, 105 | "gitlens.hovers.currentLine.over": "line", 106 | "gitlens.codeLens.enabled": false 107 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | { 4 | "type": "shell", 5 | "label": "Unit test", 6 | "command": "make", 7 | "args": [ 8 | "test" 9 | ], 10 | "group": { 11 | "kind": "build", 12 | "isDefault": true 13 | } 14 | } 15 | ], 16 | "version": "2.0.0" 17 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Bruno Rijsman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | INCLUDE_DIRS = -Iinclude 2 | 3 | UNAME_S := $(shell uname -s) 4 | 5 | CXX := clang++ 6 | CXX_FLAGS := -Wall -Wextra -Weffc++ -Werror -gdwarf-4 -std=c++14 -pthread $(INCLUDE_DIRS) 7 | CXX_FLAGS_PROD := -O2 8 | CXX_FLAGS_COV := -fprofile-instr-generate -fcoverage-mapping 9 | CXX_FLAGS_DEBUG := -O0 -DENABLE_DEBUG 10 | 11 | LD_FLAGS := 12 | 13 | 14 | ifeq ($(UNAME_S),Darwin) 15 | CASCADE_PYTHON_DIR=$(HOME)/git-personal/cascade-python 16 | LLVM_PROFDATA := /Library/Developer/CommandLineTools/usr/bin/llvm-profdata 17 | LLVM_COV := /Library/Developer/CommandLineTools/usr/bin/llvm-cov 18 | OPEN := open 19 | else 20 | CASCADE_PYTHON_DIR=$(HOME)/cascade-python 21 | LLVM_PROFDATA := llvm-profdata 22 | LLVM_COV := llvm-cov 23 | OPEN := true 24 | endif 25 | 26 | CASCADE_SRCS := $(shell find cascade -name "*.cpp") 27 | CASCADE_OBJECTS := $(patsubst cascade/%.cpp, obj/%.o, $(CASCADE_SRCS)) 28 | CASCADE_OBJECTS_COV := $(patsubst cascade/%.cpp, obj-cov/%.o, $(CASCADE_SRCS)) 29 | CASCADE_OBJECTS_DEBUG := $(patsubst cascade/%.cpp, obj-debug/%.o, $(CASCADE_SRCS)) 30 | CASCADE_DEPS := $(CASCADE_SRCS:.cpp=.d) 31 | 32 | TEST_SRCS := $(shell find tests -name "*.cpp") 33 | TEST_OBJECTS := $(patsubst tests/%.cpp, obj/%.o, $(TEST_SRCS)) 34 | TEST_OBJECTS_COV := $(patsubst tests/%.cpp, obj-cov/%.o, $(TEST_SRCS)) 35 | TEST_OBJECTS_DEBUG := $(patsubst tests/%.cpp, obj-debug/%.o, $(TEST_SRCS)) 36 | TEST_DEPS := $(TEST_SRCS:.cpp=.d) 37 | 38 | RUNEXP_SRCS := $(shell find study -name "*.cpp") 39 | RUNEXP_OBJECTS := $(patsubst study/%.cpp, obj/%.o, $(RUNEXP_SRCS)) 40 | RUNEXP_OBJECTS_COV := $(patsubst study/%.cpp, obj-cov/%.o, $(RUNEXP_SRCS)) 41 | RUNEXP_OBJECTS_DEBUG := $(patsubst study/%.cpp, obj-debug/%.o, $(RUNEXP_SRCS)) 42 | RUNEXP_DEPS := $(RUNEXP_SRCS:.cpp=.d) 43 | 44 | NODEPS := clean default ubuntu-get-dependencies 45 | 46 | ifeq (0, $(words $(findstring $(MAKECMDGOALS), $(NODEPS)))) 47 | -include $(CASCADE_DEPS) 48 | -include $(RUNEXP_DEPS) 49 | -include $(TEST_DEPS) 50 | endif 51 | 52 | default: 53 | @echo Please specify a make target 54 | 55 | bin/test: $(TEST_OBJECTS) $(CASCADE_OBJECTS) 56 | mkdir -p bin && \ 57 | $(CXX) $(CXX_FLAGS) $(CXX_FLAGS_PROD) -o bin/test $(TEST_OBJECTS) $(CASCADE_OBJECTS) \ 58 | -lgtest -lpthread $(LD_FLAGS) 59 | 60 | test: bin/test 61 | bin/test 62 | 63 | bin/test_coverage: $(TEST_OBJECTS_COV) $(CASCADE_OBJECTS_COV) bin/test_coverage 64 | mkdir -p bin && \ 65 | $(CXX) $(CXX_FLAGS) $(CXX_FLAGS_PROD) $(CXX_FLAGS_COV) -o bin/test_coverage \ 66 | $(TEST_OBJECTS_COV) $(CASCADE_OBJECTS_COV) -lgtest -lpthread $(LD_FLAGS) 67 | 68 | test-coverage: bin/test_coverage 69 | mkdir -p coverage 70 | LLVM_PROFILE_FILE="coverage/coverage-test.profraw" bin/test_coverage 71 | $(LLVM_PROFDATA) merge -sparse coverage/coverage-test.profraw \ 72 | -o coverage/coverage-test.profdata 73 | $(LLVM_COV) show bin/test_coverage -instr-profile=coverage/coverage-test.profdata \ 74 | -format=text > coverage/coverage-test.txt 75 | $(LLVM_COV) show bin/test_coverage -instr-profile=coverage/coverage-test.profdata \ 76 | -format=html > coverage/coverage-test.html 77 | $(OPEN) coverage/coverage-test.html 78 | 79 | # This will report false positives on macOS 80 | test-valgrind: bin/test 81 | rm -f valgrind.log 82 | valgrind -v --tool=memcheck --leak-check=full --show-leak-kinds=all --error-exitcode=1 \ 83 | --log-file=valgrind.log bin/test || \ 84 | ( echo "Valgrind failed for bin/test -- see valgrind.log for details" ; \ 85 | cat valgrind.log \ 86 | false ) 87 | 88 | bin/run_experiments: $(RUNEXP_OBJECTS) $(CASCADE_OBJECTS) 89 | mkdir -p bin 90 | $(CXX) $(CXX_FLAGS) $(CXX_FLAGS_PROD) -o bin/run_experiments $(RUNEXP_OBJECTS) \ 91 | $(CASCADE_OBJECTS) -lboost_program_options -lboost_filesystem -lboost_system $(LD_FLAGS) 92 | 93 | bin/run_experiments_debug: $(RUNEXP_OBJECTS_DEBUG) $(CASCADE_OBJECTS_DEBUG) 94 | mkdir -p bin 95 | $(CXX) $(CXX_FLAGS) $(CXX_FLAGS_DEBUG) -o bin/run_experiments_debug \ 96 | $(RUNEXP_OBJECTS_DEBUG) $(CASCADE_OBJECTS_DEBUG) -lboost_program_options \ 97 | -lboost_filesystem -lboost_system $(LD_FLAGS) 98 | 99 | debug: bin/run_experiments_debug 100 | mkdir -p study/data/debug 101 | rm -f study/data/debug/data__* 102 | bin/run_experiments_debug study/experiments_debug.json --output-dir study/data/debug 103 | 104 | data: data-papers data-performance data-zero-handling 105 | 106 | data-papers: bin/run_experiments 107 | mkdir -p study/data/papers 108 | rm -f study/data/papers/data__* 109 | bin/run_experiments study/experiments_papers.json --output-dir study/data/papers 110 | 111 | data-papers-subset: bin/run_experiments 112 | mkdir -p study/data/papers 113 | rm -f study/data/papers/data__* 114 | bin/run_experiments study/experiments_papers.json --output-dir study/data/papers --max-runs 3 115 | 116 | data-performance: bin/run_experiments 117 | mkdir -p study/data/performance 118 | rm -f study/data/performance/data__* 119 | bin/run_experiments study/experiments_performance.json --output-dir study/data/performance 120 | 121 | data-zero-handling: bin/run_experiments 122 | mkdir -p study/data/zero_handling 123 | rm -f study/data/zero_handling/data__* 124 | bin/run_experiments study/experiments_zero_handling.json --output-dir study/data/zero_handling 125 | 126 | graphs: graphs-papers graphs-performance graphs-zero-handling 127 | 128 | graphs-papers: 129 | mkdir -p study/graphs/papers 130 | rm -f study/graphs/papers/*.png 131 | source $(CASCADE_PYTHON_DIR)/venv/bin/activate && \ 132 | python $(CASCADE_PYTHON_DIR)/study/make_graphs.py study/graphs_demystifying.json \ 133 | --data-dir study/data/papers 134 | source $(CASCADE_PYTHON_DIR)/venv/bin/activate && \ 135 | python $(CASCADE_PYTHON_DIR)/study/make_graphs.py study/graphs_andre_reis_thesis.json \ 136 | --data-dir study/data/papers 137 | 138 | graphs-performance: 139 | mkdir -p study/graphs/performance 140 | rm -f study/graphs/performance/*.png 141 | source $(CASCADE_PYTHON_DIR)/env/bin/activate && \ 142 | python $(CASCADE_PYTHON_DIR)/study/make_graphs.py study/graphs_performance.json \ 143 | --data-dir study/data/performance 144 | 145 | graphs-zero-handling: 146 | mkdir -p study/graphs/zero_handling 147 | rm -f study/graphs/zero_handling/*.png 148 | source $(CASCADE_PYTHON_DIR)/env/bin/activate && \ 149 | python $(CASCADE_PYTHON_DIR)/study/make_graphs.py study/graphs_zero_handling.json \ 150 | --data-dir study/data/zero_handling 151 | 152 | ubuntu-get-dependencies: 153 | # Gtest 154 | sudo apt-get update -y 155 | sudo apt-get install -y libgtest-dev 156 | sudo apt-get install -y cmake 157 | sudo apt-get install -y clang 158 | sudo apt-get install -y llvm 159 | sudo apt-get install -y libboost-all-dev 160 | sudo apt-get install -y valgrind 161 | cd /usr/src/gtest && \ 162 | sudo cmake CMakeLists.txt && \ 163 | sudo make && \ 164 | sudo mkdir -p /usr/local/lib/googletest && \ 165 | sudo ln -s -f /usr/lib/libgtest.a /usr/local/lib/googletest/libgtest.a && \ 166 | sudo ln -s -f /usr/lib/libgtest_main.a /usr/local/lib/googletest/libgtest_main.a 167 | 168 | clean: 169 | rm -rf obj 170 | rm -rf obj-cov 171 | rm -rf obj-debug 172 | rm -rf bin 173 | rm -rf profile 174 | rm -rf coverage 175 | rm -f cascade/*.d 176 | rm -f study/*.d 177 | rm -f tests/*.d 178 | rm -rf *.dSYM 179 | 180 | cascade/%.d: cascade/%.cpp 181 | $(CXX) $(CXX_FLAGS) $(CXX_FLAGS_PROD) -MM -MT '$(patsubst cascade/%.cpp,obj/%.o,$<)' $< -MF $@ 182 | 183 | study/%.d: study/%.cpp 184 | $(CXX) $(CXX_FLAGS) $(CXX_FLAGS_PROD) -MM -MT '$(patsubst study/%.cpp,obj/%.o,$<)' $< -MF $@ 185 | 186 | tests/%.d: tests/%.cpp 187 | $(CXX) $(CXX_FLAGS) $(CXX_FLAGS_PROD) -MM -MT '$(patsubst tests/%.cpp,obj/%.o,$<)' $< -MF $@ 188 | 189 | obj/%.o: cascade/%.cpp cascade/%.d 190 | mkdir -p obj 191 | $(CXX) $(CXX_FLAGS) $(CXX_FLAGS_PROD) -c $< -o $@ 192 | 193 | obj/%.o: study/%.cpp study/%.d 194 | mkdir -p obj 195 | $(CXX) $(CXX_FLAGS) $(CXX_FLAGS_PROD) -c $< -o $@ 196 | 197 | obj/%.o: tests/%.cpp tests/%.d 198 | mkdir -p obj 199 | $(CXX) $(CXX_FLAGS) $(CXX_FLAGS_PROD) -c $< -o $@ 200 | 201 | obj-cov/%.o: cascade/%.cpp cascade/%.d 202 | mkdir -p obj-cov 203 | $(CXX) $(CXX_FLAGS) $(CXX_FLAGS_PROD) $(CXX_FLAGS_COV) -c $< -o $@ 204 | 205 | obj-cov/%.o: study/%.cpp study/%.d 206 | mkdir -p obj-cov 207 | $(CXX) $(CXX_FLAGS) $(CXX_FLAGS_PROD) $(CXX_FLAGS_COV) -c $< -o $@ 208 | 209 | obj-cov/%.o: tests/%.cpp tests/%.d 210 | mkdir -p obj-cov 211 | $(CXX) $(CXX_FLAGS) $(CXX_FLAGS_PROD) $(CXX_FLAGS_COV) -c $< -o $@ 212 | 213 | obj-debug/%.o: cascade/%.cpp cascade/%.d 214 | mkdir -p obj-debug 215 | $(CXX) $(CXX_FLAGS) $(CXX_FLAGS_DEBUG) -c $< -o $@ 216 | 217 | obj-debug/%.o: study/%.cpp study/%.d 218 | mkdir -p obj-debug 219 | $(CXX) $(CXX_FLAGS) $(CXX_FLAGS_DEBUG) -c $< -o $@ 220 | 221 | obj-debug/%.o: tests/%.cpp tests/%.d 222 | mkdir -p obj-debug 223 | $(CXX) $(CXX_FLAGS) $(CXX_FLAGS_DEBUG) -c $< -o $@ 224 | 225 | .PHONY: clean get-dependencies 226 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/brunorijsman/cascade-cpp.svg?branch=master)](https://travis-ci.org/brunorijsman/cascade-cpp) [![Code Coverage](https://codecov.io/gh/brunorijsman/cascade-cpp/branch/master/graph/badge.svg)](https://codecov.io/gh/brunorijsman/cascade-cpp) 2 | 3 | # What is Cascade-CPP? 4 | 5 | [This repository](https://github.com/brunorijsman/cascade-cpp) contains a C++ implementation of 6 | Cascade information reconciliation protocol for Quantum Key Distribution (QKD). 7 | 8 | [This tutorial](https://cascade-python.readthedocs.io/en/latest/protocol.html) provides a detailed 9 | description of the Cascade information reconciliation protocol and its relation to Quantum Key 10 | Distribution. 11 | 12 | 13 | # Comparison between Cascade-Python and Cascade-CPP 14 | 15 | The C++ code in this repository is modeled after my earlier Python implementation in GitHub 16 | repository [Cascade-Python](https://github.com/brunorijsman/cascade-python), which 17 | is documented on [ReadTheDocs](https://cascade-python.readthedocs.io/en/latest/). 18 | 19 | The C++ code is orders of magnitude faster than the Python code. This is because the C++ code was 20 | carefully optimized based on the insights from profiling the code. In particular, the decision to 21 | cache Shuffle objects made a huge impact on the performance. 22 | 23 | The "make data-papers" target in the Python code does 1,000 Cascade iterations per data point and 24 | takes more than 5 days of continuous running on an AWS m5.2xlarge instance (120 hours x US$ 0.40 25 | per hour = US$ 48 in compute cost). 26 | By contrast, the "make data-papers" target the C++ code does 10,000 Cascade iterations per data 27 | point (10x better accuracy) only takes ten hours to complete (US$ 4). 28 | 29 | The C++ was more carefully debugged than the Python code. The C++ code has a "make debug" target 30 | that produces color-coded representations of the blocks at each step in the algorithm (bit errors 31 | are shown in red). This makes it much easier to follow what is going on in the algorithm. Beyond 32 | debugging, this is also a good tool for learning the Cascade algorithm. 33 | 34 | As a result of the better debugging in the C++ code, the data produced by the C++ is more consistent 35 | with the results published in 36 | [Demystifying the Information Reconciliation Protocol Cascade](https://arxiv.org/abs/1407.3257) 37 | and [Quantum Key Distribution Post Processing - A study on the Information Reconciliation Cascade Protocol](https://repositorio-aberto.up.pt/bitstream/10216/121965/2/347567.pdf). 38 | 39 | # How to install, compile and run the Cascade-CPP code 40 | 41 | To install on Ubuntu 22.04: 42 | 43 | git clone https://github.com/brunorijsman/cascade-cpp.git 44 | cd cascade-cpp 45 | sudo apt install -y make 46 | make ubuntu-get-dependencies 47 | 48 | To build and run unit tests: 49 | 50 | make test 51 | 52 | To build and run unit tests, and produce code coverage report in coverage/coverage-test.html (on a 53 | Mac this also opens the coverage report in the browser): 54 | 55 | make test-coverage 56 | 57 | To produce the data for all experiments: 58 | 59 | make data 60 | 61 | To produce the data for specific set of experiments: 62 | 63 | # Choose one of these 64 | make data-papers 65 | make data-papers-subset 66 | make data-performance 67 | make data-zero-handling 68 | 69 | To produce graphs, you need to have [Cascade-Python](https://github.com/brunorijsman/cascade-python) 70 | installed in the $HOME/cascade-python directory. 71 | 72 | The produce the graphs for specific set of experiments (this assumes that that the data has already 73 | been produced): 74 | 75 | make graphs 76 | 77 | To produce the graphs for all experiments: 78 | 79 | # Choose one of these 80 | make graphs-papers 81 | make graphs-performance 82 | make graphs-zero-handling 83 | 84 | To run a small reconciliation with full debug prints: 85 | 86 | make debug 87 | 88 | # Running experiments 89 | 90 | Under the hood, when you issue `make data-papers` the Makefile executes the following command: 91 | 92 | bin/run_experiments study/experiments_papers.json --output-dir study/data/papers 93 | 94 | The executable `run_experiments` does the following: 95 | 96 | 1. It reads an experiments JSON file which describes which experiments to run. 97 | 98 | 2. It runs the requested experiments in a multi-threaded fashion using all available CPU cores. 99 | 100 | 3. It writes the results into one or more data JSON files that can later be visualized into 101 | graphs. 102 | 103 | The executable `run_experiments` uses the following syntax: 104 | 105 | $ run_experiments --help 106 | Usage: run_experiments [options] experiments-file 107 | 108 | Options: 109 | --help Display help 110 | -d [ --disable-multi-processing ] Disable multi-processing 111 | -m [ --max-runs ] arg Maximum number of reconciliation runs per 112 | data point 113 | -s [ --seed ] arg Random seed 114 | -o [ --output-directory ] arg Output directory where to store data__* 115 | files 116 | 117 | Here is an example of an experiments JSON file (this is `experiments_papers.json`): 118 | 119 | [ 120 | { 121 | "independent_variable": "error_rate", 122 | "algorithm": ["original", "biconf", "yanetal", "option3", "option4", "option7", "option8"], 123 | "error_rate": [ 124 | {"start": 0.0000, "end": 0.0050, "step_size": 0.00005}, 125 | {"start": 0.0050, "end": 0.1100, "step_size": 0.00050} 126 | ], 127 | "key_size": [1000, 2000, 10000], 128 | "runs": 10000 129 | }, 130 | { 131 | "independent_variable": "key_size", 132 | "algorithm": ["original", "biconf", "yanetal", "option3", "option4", "option7", "option8"], 133 | "error_rate": 0.05, 134 | "key_size": { 135 | "start": 1e3, 136 | "end": 1e5, 137 | "step_factor": 1.05 138 | }, 139 | "runs": 10000 140 | }, 141 | { 142 | "independent_variable": "key_size", 143 | "algorithm": "original", 144 | "error_rate": [0.01, 0.02], 145 | "key_size": { 146 | "start": 1e3, 147 | "end": 1e5, 148 | "step_factor": 1.05 149 | }, 150 | "runs": 10000 151 | } 152 | ] 153 | 154 | The experiments JSON file consists of a list of records, each describing a single experiment. In 155 | this example there are three experiments. 156 | 157 | Each experiment has the following arguments. 158 | 159 | * `independent_variable`: This must be `error_rate` or `key_size`. 160 | 161 | * If it is set to `error_rate`, then one separate data file is produced for each requested 162 | `key_size` (for example `data__algorithm=option3;key_size=10000;error_rate=vary`) and the 163 | `error_rate` is varied within each data file. 164 | 165 | * If it is set to `key_size`, then one separate data file is produced for each requested 166 | `error_rate` (for example `data__algorithm=option3;key_size=vary;error_rate=0.05`) and the 167 | `key_size` is varied within each data file. 168 | 169 | * `algorithm`: Either a single algorithm or a list of algorithms. Each algorithm is plotted as a line 170 | in the graph. The available algorithms are `original`, `biconf`, `biconf-cascade`, 171 | `biconf-no-complement`, `yanetal`, `option3`, `option4`, `option7`, and `option8`. See source 172 | file `algorithm.cpp` for the detailed parameters for each algorithm. 173 | 174 | * `error_rate`: The error rates to be used in the experiment in the form of a numerical list (see 175 | below). 176 | 177 | * `key_size`: The key sizes to be used in the experiment in the form of a numerical list (see 178 | below). 179 | 180 | * `run`: The number of reconciliation runs per data point in the results. 181 | 182 | A numerical list is one of the following: 183 | 184 | * A list of numbers, for example `[1, 2, 3, 4]` 185 | 186 | * A linear range of numbers, for example `{"start": 100.0, "end": 200.0, "step": 5.0}` 187 | 188 | * A log range of numbers, for example `{"start": 10.0, "end": 10000.0, "step_factor": 3.0}` 189 | 190 | * A list of any of the above. 191 | 192 | The executable `run_experiments` produces a set of data JSON files in the requested output 193 | directory, for example: 194 | 195 | $ ls -1 study/data/papers/ 196 | data__algorithm=biconf;key_size=10000;error_rate=vary 197 | data__algorithm=biconf;key_size=1000;error_rate=vary 198 | data__algorithm=biconf;key_size=2000;error_rate=vary 199 | data__algorithm=biconf;key_size=vary;error_rate=0.05 200 | ... 201 | data__algorithm=yanetal;key_size=2000;error_rate=vary 202 | data__algorithm=yanetal;key_size=vary;error_rate=0.05 203 | 204 | Each data JSON file consists of a list of JSON records, one for each data point. Here is an 205 | example data point record: 206 | 207 | { 208 | "actual_bit_error_rate": {"average": 0.000050, "deviation": 0.000050}, 209 | "actual_bit_errors": {"average": 0.502200, "deviation": 0.502200}, 210 | "algorithm_name": "biconf", 211 | "ask_parity_bits": {"average": 2828.808000, "deviation": 2828.808000}, 212 | "ask_parity_blocks": {"average": 35.360100, "deviation": 35.360100}, 213 | "ask_parity_messages": {"average": 37.360100, "deviation": 37.360100}, 214 | "biconf_iterations": {"average": 10.000000, "deviation": 10.000000}, 215 | "elapsed_process_time": {"average": 0.001794, "deviation": 0.001794}, 216 | "elapsed_real_time": {"average": 0.001795, "deviation": 0.001795}, 217 | "execution_time": "2020-04-08 20:20:49 UTC", 218 | "infer_parity_blocks": {"average": 6.919900, "deviation": 6.919900}, 219 | "key_size": 10000, 220 | "normal_iterations": {"average": 2.000000, "deviation": 2.000000}, 221 | "reconciliation_bits_per_key_bit": {"average": 510.625974, "deviation": 510.625974}, 222 | "reconciliations": 10000, 223 | "remaining_bit_error_rate": {"average": 0.000000, "deviation": 0.000000}, 224 | "remaining_bit_errors": {"average": 0.000000, "deviation": 0.000000}, 225 | "remaining_frame_error_rate": {"average": 0.000000, "deviation": 0.000000}, 226 | "reply_parity_bits": {"average": 35.360100, "deviation": 35.360100}, 227 | "requested_bit_error_rate": 0.000050, 228 | "efficiency": {"average": 4.495774, "deviation": 4.495774} 229 | } 230 | 231 | 232 | # Producing graphs 233 | 234 | We rely on the Python scripts in Cascade-Python to produce graphs from the results stored in the 235 | data file produced by the executable `run_experiments`. 236 | 237 | Under the hood, when you issue `make graphs-papers` the Makefile activates a Python3 virtual 238 | environment and executes the following Python script: 239 | 240 | python $(CASCADE_PYTHON_DIR)/study/make_graphs.py study/graphs_demystifying.json \ 241 | --data-dir study/data/papers 242 | 243 | The graph JSON file (in this example `graphs_demystifying.json`) describes which variables 244 | should be plotted in the graph and other attributes that influence the appearance of the graph. 245 | 246 | This is an example of a graph file (namely the first graph in `graphs_demystifying.json`): 247 | 248 | [ 249 | { 250 | "graph_name": "demystifying_figure_1", 251 | "title": "Figure 1 from \"Demystifying the Information Reconciliation Protocol Cascade\"", 252 | "x_axis": { 253 | "title": "Quantum Bit Error Rate (QBER)", 254 | "variable": "requested_bit_error_rate" 255 | }, 256 | "y_axis": { 257 | "title": "Reconciliation efficiency", 258 | "variable": "efficiency", 259 | "range": [1.0, 1.3] 260 | }, 261 | "series": [ 262 | { 263 | "data_file": "data__algorithm=original;key_size=10000;error_rate=vary", 264 | "legend": "Cascade orig.", 265 | "line_color": "black", 266 | "deviation_color": "lightgray" 267 | }, 268 | { 269 | "data_file": "data__algorithm=biconf;key_size=10000;error_rate=vary", 270 | "legend": "Cascade mod. (1)", 271 | "line_color": "blue", 272 | "deviation_color": "lightblue" 273 | } 274 | ] 275 | }, 276 | ... 277 | ] 278 | 279 | This produces the following graph: 280 | 281 | ![Demystifying Figure 1 Reproduced](docs/figures/demystifying-figure-1-reproduced.png) 282 | 283 | # Comparing the data produced by Cascade-CPP with published literature. 284 | 285 | In this section we compare the data produced 286 | 287 | We used Github version 288 | [c4d2194bcae4580f329597677ba2e2538bb53c81](https://github.com/brunorijsman/cascade-cpp/commit/c4d2194bcae4580f329597677ba2e2538bb53c81) (8 April 2020) of Cascade-CPP 289 | to produce the data in these graphs. 290 | 291 | ## Comparison with Demystifying the Information Reconciliation Protocol Cascade. 292 | 293 | In this section we compare the data produced by Cascade-CPP with the results reported in: 294 | 295 | [Demystifying the Information Reconciliation Protocol Cascade](https://arxiv.org/abs/1407.3257).
296 | _Jesus Martinez-Mateo, Christoph Pacher, Momtchil Peev, Alex Ciurana, and Vicente Martin._
297 | arXiv:1407.3257 \[quant-ph\], Jul 2014. 298 | 299 | ### Figure 1. 300 | 301 | Results reported in paper: 302 | 303 | ![Demystifying Figure 1](docs/figures/demystifying-figure-1-original.png) 304 | 305 | Results produced by Cascade-CPP: 306 | 307 | ![Demystifying Figure 1 Reproduced](docs/figures/demystifying-figure-1-reproduced.png) 308 | 309 | ### Figure 2. 310 | 311 | Results reported in paper: 312 | 313 | ![Demystifying Figure 2](docs/figures/demystifying-figure-2-original.png) 314 | 315 | Results produced by Cascade-CPP: 316 | 317 | ![Demystifying Figure 2 Reproduced](docs/figures/demystifying-figure-2-reproduced.png) 318 | 319 | ### Figure 3. 320 | 321 | Results reported in paper: 322 | 323 | ![Demystifying Figure 3](docs/figures/demystifying-figure-3-original.png) 324 | 325 | Results produced by Cascade-CPP: 326 | 327 | ![Demystifying Figure 3 Reproduced](docs/figures/demystifying-figure-3-reproduced.png) 328 | 329 | ### Figure 4. 330 | 331 | Results reported in paper: 332 | 333 | ![Demystifying Figure 4](docs/figures/demystifying-figure-4-original.png) 334 | 335 | Results produced by Cascade-CPP: 336 | 337 | ![Demystifying Figure 4 Reproduced](docs/figures/demystifying-figure-4-reproduced.png) 338 | 339 | ### Figure 5. 340 | 341 | Results reported in paper: 342 | 343 | ![Demystifying Figure 5](docs/figures/demystifying-figure-5-original.png) 344 | 345 | Results produced by Cascade-CPP: 346 | 347 | ![Demystifying Figure 5 Reproduced](docs/figures/demystifying-figure-5-reproduced.png) 348 | 349 | ### Figure 6. 350 | 351 | Results reported in paper: 352 | 353 | ![Demystifying Figure 6](docs/figures/demystifying-figure-6-original.png) 354 | 355 | Results not produced by Cascade-CPP. 356 | 357 | ### Figure 7. 358 | 359 | Results reported in paper: 360 | 361 | ![Demystifying Figure 7](docs/figures/demystifying-figure-7-original.png) 362 | 363 | Results not produced by Cascade-CPP. 364 | 365 | ### Figure 8. 366 | 367 | Results reported in paper: 368 | 369 | ![Demystifying Figure 8](docs/figures/demystifying-figure-8-original.png) 370 | 371 | Results produced by Cascade-CPP: 372 | 373 | ![Demystifying Figure 8 Reproduced](docs/figures/demystifying-figure-8-reproduced.png) 374 | 375 | ### Figure 9. 376 | 377 | Results reported in paper: 378 | 379 | ![Demystifying Figure 9](docs/figures/demystifying-figure-9-original.png) 380 | 381 | Results produced by Cascade-CPP: 382 | 383 | ![Demystifying Figure 9 Reproduced](docs/figures/demystifying-figure-9-reproduced.png) 384 | 385 | ### Figure 10. 386 | 387 | Results reported in paper: 388 | 389 | ![Demystifying Figure 10](docs/figures/demystifying-figure-10-original.png) 390 | 391 | Results produced by Cascade-CPP: 392 | 393 | ![Demystifying Figure 10 Reproduced](docs/figures/demystifying-figure-10-reproduced.png) 394 | 395 | ### Figure 11. 396 | 397 | Results reported in paper: 398 | 399 | ![Demystifying Figure 11](docs/figures/demystifying-figure-11-original.png) 400 | 401 | Results produced by Cascade-CPP: 402 | 403 | ![Demystifying Figure 11 Reproduced](docs/figures/demystifying-figure-11-reproduced.png) 404 | 405 | ### Figure 12. 406 | 407 | Results reported in paper: 408 | 409 | ![Demystifying Figure 12](docs/figures/demystifying-figure-12-original.png) 410 | 411 | Results not produced by Cascade-CPP. 412 | 413 | ### Figure 13. 414 | 415 | Results reported in paper: 416 | 417 | ![Demystifying Figure 13](docs/figures/demystifying-figure-13-original.png) 418 | 419 | Results produced by Cascade-CPP: 420 | 421 | ![Demystifying Figure 13 Reproduced](docs/figures/demystifying-figure-13-reproduced.png) 422 | 423 | ## Comparison with Quantum Key Distribution Post Processing. 424 | 425 | In this section we compare the data produced by Cascade-CPP with the results reported in: 426 | 427 | [Quantum Key Distribution Post Processing - A study on the Information Reconciliation Cascade Protocol.](https://repositorio-aberto.up.pt/bitstream/10216/121965/2/347567.pdf.
428 | _André Reis._
429 | Master’s Thesis, Faculdade de Engenharia da Universidade do Porto, Jul 2019. 430 | 431 | ### Figure 5.1. 432 | 433 | Results reported in thesis: 434 | 435 | ![Thesis Figure 5.1](docs/figures/andre-reis-thesis-figure-5-1-original.png) 436 | 437 | Results produced by Cascade-CPP: 438 | 439 | ![Thesis Figure 5.1 Reproduced](docs/figures/andre-reis-thesis-figure-5-1-reproduced.png) 440 | 441 | ### Figure 5.2. 442 | 443 | Results reported in thesis: 444 | 445 | ![Thesis Figure 5.2](docs/figures/andre-reis-thesis-figure-5-2-original.png) 446 | 447 | Results produced by Cascade-CPP: 448 | 449 | ![Thesis Figure 5.2 Reproduced](docs/figures/andre-reis-thesis-figure-5-2-reproduced.png) 450 | 451 | ### Figure 5.3. 452 | 453 | Results reported in thesis: 454 | 455 | ![Thesis Figure 5.3](docs/figures/andre-reis-thesis-figure-5-3-original.png) 456 | 457 | Results produced by Cascade-CPP: 458 | 459 | ![Thesis Figure 5.3 Reproduced](docs/figures/andre-reis-thesis-figure-5-3-reproduced.png) 460 | 461 | ### Figure 5.4. 462 | 463 | Results reported in thesis: 464 | 465 | ![Thesis Figure 5.4](docs/figures/andre-reis-thesis-figure-5-4-original.png) 466 | 467 | Results not produced by Cascade-CPP. 468 | 469 | ### Figure 5.5. 470 | 471 | Results reported in thesis: 472 | 473 | ![Thesis Figure 5.5](docs/figures/andre-reis-thesis-figure-5-5-original.png) 474 | 475 | Results produced by Cascade-CPP: 476 | 477 | ![Thesis Figure 5.5a Reproduced](docs/figures/andre-reis-thesis-figure-5-5-a-reproduced.png) 478 | 479 | ![Thesis Figure 5.5b Reproduced](docs/figures/andre-reis-thesis-figure-5-5-b-reproduced.png) 480 | 481 | ### Figure 5.6. 482 | 483 | Results reported in thesis: 484 | 485 | ![Thesis Figure 5.6](docs/figures/andre-reis-thesis-figure-5-6-original.png) 486 | 487 | Results not yet produced by Cascade-CPP. 488 | 489 | ### Figure 5.7. 490 | 491 | Results reported in thesis: 492 | 493 | ![Thesis Figure 5.7](docs/figures/andre-reis-thesis-figure-5-7-original.png) 494 | 495 | Results not yet produced by Cascade-CPP. 496 | 497 | ### Figure 5.8. 498 | 499 | Results reported in thesis: 500 | 501 | ![Thesis Figure 5.8](docs/figures/andre-reis-thesis-figure-5-8-original.png) 502 | 503 | Results not yet produced by Cascade-CPP. 504 | 505 | ### Figure 5.9. 506 | 507 | Results reported in thesis: 508 | 509 | ![Thesis Figure 5.9](docs/figures/andre-reis-thesis-figure-5-9-original.png) 510 | 511 | Results not yet produced by Cascade-CPP. 512 | 513 | ### Figure 5.10. 514 | 515 | Results reported in thesis: 516 | 517 | ![Thesis Figure 5.10](docs/figures/andre-reis-thesis-figure-5-10-original.png) 518 | 519 | Results not yet produced by Cascade-CPP. 520 | -------------------------------------------------------------------------------- /cascade/algorithm.cpp: -------------------------------------------------------------------------------- 1 | #include "algorithm.h" 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | using namespace Cascade; 8 | 9 | typedef std::map Algorithms; 10 | 11 | static Algorithms algorithms; 12 | 13 | static double min_estimated_bit_error_rate = 0.00001; 14 | 15 | Algorithm::Algorithm(std::string name, 16 | int nr_cascade_iterations, 17 | int (*block_size_function)(int iteration_nr, 18 | double estimated_bit_error_rate, int key_size), 19 | int nr_biconf_iterations, 20 | bool biconf_error_free_streak, 21 | bool biconf_correct_complement, 22 | bool biconf_cascade, 23 | bool ask_correct_parity_using_shuffle_seed, 24 | bool cache_shuffles): 25 | name(name), 26 | nr_cascade_iterations(nr_cascade_iterations), 27 | block_size_function(block_size_function), 28 | nr_biconf_iterations(nr_biconf_iterations), 29 | biconf_error_free_streak(biconf_error_free_streak), 30 | biconf_correct_complement(biconf_correct_complement), 31 | biconf_cascade(biconf_cascade), 32 | ask_correct_parity_using_shuffle_seed(ask_correct_parity_using_shuffle_seed), 33 | cache_shuffles(cache_shuffles) 34 | { 35 | algorithms[name] = this; 36 | } 37 | 38 | Algorithm* Algorithm::get_by_name(std::string name) 39 | { 40 | Algorithms::const_iterator it = algorithms.find(name); 41 | if (it == algorithms.end()) { 42 | return NULL; 43 | } else { 44 | return it->second; 45 | } 46 | } 47 | 48 | std::vector Algorithm::get_all_algorithm_names() 49 | { 50 | std::vector names; 51 | for (auto pair: algorithms) { 52 | names.push_back(pair.first); 53 | } 54 | return names; 55 | 56 | } 57 | 58 | static int original_block_size_function(int iteration_nr, double estimated_bit_error_rate, 59 | int key_size) 60 | { 61 | if (estimated_bit_error_rate < min_estimated_bit_error_rate) { 62 | estimated_bit_error_rate = min_estimated_bit_error_rate; 63 | } 64 | if (iteration_nr == 1) { 65 | return ceil(0.73 / estimated_bit_error_rate); 66 | } 67 | return 2 * original_block_size_function(iteration_nr - 1, estimated_bit_error_rate, key_size); 68 | } 69 | 70 | Algorithm original_algorithm( 71 | "original", 72 | 4, // nr_cascade_iterations 73 | original_block_size_function, // block_size_function 74 | 0, // nr_biconf_iterations 75 | false, // biconf_error_free_streak 76 | false, // biconf_correct_complement 77 | false, // biconf_cascade 78 | true, // ask_correct_parity_using_shuffle_seed 79 | true); // cache_shuffles 80 | 81 | // Name in Demystifying paper: Cascade mod. (1) 82 | // Name in Andre Reis Thesis : biconf 83 | 84 | static int biconf_block_size_function(int iteration_nr, double estimated_bit_error_rate, 85 | int key_size) 86 | { 87 | if (estimated_bit_error_rate < min_estimated_bit_error_rate) { 88 | estimated_bit_error_rate = min_estimated_bit_error_rate; 89 | } 90 | if (iteration_nr == 1) { 91 | return ceil(0.92 / estimated_bit_error_rate); 92 | } 93 | return 3 * biconf_block_size_function(iteration_nr - 1, estimated_bit_error_rate, key_size); 94 | } 95 | 96 | Algorithm biconf_algorithm( 97 | "biconf", 98 | 2, // nr_cascade_iterations 99 | biconf_block_size_function, // block_size_function 100 | 10, // nr_biconf_iterations 101 | true, // biconf_error_free_streak 102 | true, // biconf_correct_complement 103 | false, // biconf_cascade 104 | true, // ask_correct_parity_using_shuffle_seed 105 | true); // cache_shuffles 106 | 107 | // Name in Demystifying paper: - 108 | // Name in Andre Reis Thesis : - 109 | 110 | Algorithm biconf_cascade_algorithm( 111 | "biconf-cascade", 112 | 2, // nr_cascade_iterations 113 | biconf_block_size_function, // block_size_function 114 | 10, // nr_biconf_iterations 115 | true, // biconf_error_free_streak 116 | true, // biconf_correct_complement 117 | true, // biconf_cascade 118 | true, // ask_correct_parity_using_shuffle_seed 119 | true); // cache_shuffles 120 | 121 | // Name in Demystifying paper: - 122 | // Name in Andre Reis Thesis : - 123 | 124 | Algorithm biconf_complement_algorithm( 125 | "biconf-no-complement", 126 | 2, // nr_cascade_iterations 127 | biconf_block_size_function, // block_size_function 128 | 10, // nr_biconf_iterations 129 | true, // biconf_error_free_streak 130 | false, // biconf_correct_complement 131 | false, // biconf_cascade 132 | true, // ask_correct_parity_using_shuffle_seed 133 | true); // cache_shuffles 134 | 135 | // Name in Demystifying paper: Cascade opt. (2) 136 | // Name in Andre Reis Thesis : yanetal (Yan et al.) 137 | 138 | static int yanetal_block_size_function(int iteration_nr, double estimated_bit_error_rate, 139 | int key_size) 140 | { 141 | if (estimated_bit_error_rate < min_estimated_bit_error_rate) { 142 | estimated_bit_error_rate = min_estimated_bit_error_rate; 143 | } 144 | if (iteration_nr == 1) { 145 | return ceil(0.80 / estimated_bit_error_rate); 146 | } 147 | if (iteration_nr == 2) { 148 | return 5 * yanetal_block_size_function(iteration_nr - 1, estimated_bit_error_rate, 149 | key_size); 150 | } 151 | return key_size / 2; 152 | } 153 | 154 | Algorithm yanetal_algorithm( 155 | "yanetal", 156 | 10, // nr_cascade_iterations 157 | yanetal_block_size_function, // block_size_function 158 | 0, // nr_biconf_iterations 159 | false, // biconf_error_free_streak 160 | false, // biconf_correct_complement 161 | false, // biconf_cascade 162 | true, // ask_correct_parity_using_shuffle_seed 163 | true); // cache_shuffles 164 | 165 | // Name in Demystifying paper: Cascade opt. (3) 166 | // Name in Andre Reis Thesis : - 167 | 168 | static int option3456_block_size_function(int iteration_nr, double estimated_bit_error_rate, 169 | int key_size) 170 | { 171 | if (estimated_bit_error_rate < min_estimated_bit_error_rate) { 172 | estimated_bit_error_rate = min_estimated_bit_error_rate; 173 | } 174 | if (iteration_nr == 1) { 175 | return ceil(1.00 / estimated_bit_error_rate); 176 | } 177 | if (iteration_nr == 2) { 178 | return 2 * option3456_block_size_function(iteration_nr - 1, estimated_bit_error_rate, 179 | key_size); 180 | } 181 | return key_size / 2; 182 | } 183 | 184 | Algorithm option3_algorithm( 185 | "option3", 186 | 16, // nr_cascade_iterations 187 | option3456_block_size_function, // block_size_function 188 | 0, // nr_biconf_iterations 189 | false, // biconf_error_free_streak 190 | false, // biconf_correct_complement 191 | false, // biconf_cascade 192 | true, // ask_correct_parity_using_shuffle_seed 193 | true); // cache_shuffles 194 | 195 | // Name in Demystifying paper: Cascade opt. (4) 196 | // Name in Andre Reis Thesis : - 197 | 198 | Algorithm option4_algorithm( 199 | "option4", 200 | 16, // nr_cascade_iterations 201 | option3456_block_size_function, // block_size_function 202 | 0, // nr_biconf_iterations 203 | false, // biconf_error_free_streak 204 | false, // biconf_correct_complement 205 | false, // biconf_cascade 206 | true, // ask_correct_parity_using_shuffle_seed 207 | true); // cache_shuffles 208 | 209 | // Note: Cascade opt. (5) from the Demystifying paper is not supported yet: 210 | // Need to add support for deterministic shuffling 211 | 212 | // Note: Cascade opt. (6) from the Demystifying paper is not supported yet: 213 | // Need to add support for singleton block removal 214 | 215 | // Name in Demystifying paper: Cascade opt. (7) 216 | // Name in Andre Reis Thesis : option-7 217 | 218 | static int option7_block_size_function(int iteration_nr, double estimated_bit_error_rate, 219 | int key_size) 220 | { 221 | if (estimated_bit_error_rate < min_estimated_bit_error_rate) { 222 | estimated_bit_error_rate = min_estimated_bit_error_rate; 223 | } 224 | if (iteration_nr == 1) { 225 | return ceil(pow(2.0, ceil(log2(1.00 / estimated_bit_error_rate)))); 226 | } 227 | if (iteration_nr == 2) { 228 | return 4 * option7_block_size_function(iteration_nr - 1, estimated_bit_error_rate, 229 | key_size); 230 | } 231 | return key_size / 2; 232 | } 233 | 234 | Algorithm option7_algorithm( 235 | "option7", 236 | 14, // nr_cascade_iterations 237 | option7_block_size_function, // block_size_function 238 | 0, // nr_biconf_iterations 239 | false, // biconf_error_free_streak 240 | false, // biconf_correct_complement 241 | false, // biconf_cascade 242 | true, // ask_correct_parity_using_shuffle_seed 243 | true); // cache_shuffles 244 | 245 | // Name in Demystifying paper: Cascade opt. (8) 246 | // Name in Andre Reis Thesis : option-8 247 | 248 | static int option8_block_size_function(int iteration_nr, double estimated_bit_error_rate, 249 | int key_size) 250 | { 251 | if (estimated_bit_error_rate < min_estimated_bit_error_rate) { 252 | estimated_bit_error_rate = min_estimated_bit_error_rate; 253 | } 254 | double alpha = log2(1.00 / estimated_bit_error_rate) - 0.5; 255 | if (iteration_nr == 1) { 256 | return ceil(pow(2.0, ceil(alpha))); 257 | } 258 | if (iteration_nr == 2) { 259 | return ceil(pow(2.0, ceil((alpha + 12.0) / 2.0))); 260 | } 261 | if (iteration_nr == 3) { 262 | return 4096; 263 | } 264 | return key_size / 2; 265 | } 266 | 267 | Algorithm option8_algorithm( 268 | "option8", 269 | 14, // nr_cascade_iterations 270 | option8_block_size_function, // block_size_function 271 | 0, // nr_biconf_iterations 272 | false, // biconf_error_free_streak 273 | false, // biconf_correct_complement 274 | false, // biconf_cascade 275 | true, // ask_correct_parity_using_shuffle_seed 276 | true); // cache_shuffles 277 | -------------------------------------------------------------------------------- /cascade/block.cpp: -------------------------------------------------------------------------------- 1 | #include "block.h" 2 | #include "debug.h" 3 | #include "iteration.h" 4 | #include "reconciliation.h" 5 | #include "shuffled_key.h" 6 | #include 7 | 8 | using namespace Cascade; 9 | 10 | const int Block::unknown_parity = -1; 11 | 12 | Block::Block(Iteration& iteration, int start_bit_nr, int end_bit_nr, Block* parent_block, 13 | int block_nr): 14 | iteration(iteration), 15 | shuffled_key(iteration.get_shuffled_key()), 16 | start_bit_nr(start_bit_nr), 17 | end_bit_nr(end_bit_nr), 18 | current_parity(Block::unknown_parity), 19 | correct_parity(Block::unknown_parity), 20 | parent_block(parent_block), 21 | block_nr(block_nr), 22 | left_sub_block(NULL), 23 | right_sub_block(NULL) 24 | { 25 | DEBUG("Create Block " << debug_str()); 26 | } 27 | 28 | Block::~Block() 29 | { 30 | DEBUG("Destroy Block " << debug_str()); 31 | } 32 | 33 | Iteration& Block::get_iteration() const 34 | { 35 | return iteration; 36 | } 37 | 38 | int Block::get_nr_bits() const 39 | { 40 | return end_bit_nr - start_bit_nr + 1; 41 | } 42 | 43 | int Block::get_start_bit_nr() const 44 | { 45 | return start_bit_nr; 46 | } 47 | 48 | int Block::get_end_bit_nr() const 49 | { 50 | return end_bit_nr; 51 | } 52 | 53 | std::string Block::compute_name() const 54 | { 55 | std::string name; 56 | if (parent_block) { 57 | name = parent_block->compute_name(); 58 | if (block_nr == 0) { 59 | name += "L"; 60 | } else { 61 | name += "R"; 62 | } 63 | return name; 64 | } 65 | if (iteration.get_biconf()) { 66 | name = "b:"; 67 | } else { 68 | name = "c:"; 69 | } 70 | name += std::to_string(iteration.get_iteration_nr()) + ":" + 71 | std::to_string(block_nr); 72 | return name; 73 | } 74 | 75 | std::string Block::debug_str() const 76 | { 77 | const Key* correct_key = iteration.get_reconciliation().get_correct_key(); 78 | std::string str = compute_name() + "["; 79 | for (int bit_nr = start_bit_nr; bit_nr <= end_bit_nr; ++bit_nr) { 80 | int current_bit = shuffled_key.get_bit(bit_nr); 81 | if (correct_key) { 82 | int orig_bit_nr = shuffled_key.get_shuffle()->shuffle_to_orig(bit_nr); 83 | int orig_bit = correct_key->get_bit(orig_bit_nr); 84 | if (current_bit == orig_bit) 85 | str += ANSI_GREEN; 86 | else 87 | str += ANSI_RED; 88 | } else { 89 | // Correctness of key bit is unknown 90 | str += ANSI_BLUE; 91 | } 92 | str += shuffled_key.get_bit(bit_nr) ? "1" : "0"; 93 | str += ANSI_RESET; 94 | } 95 | str += "]"; 96 | return str; 97 | } 98 | 99 | int Block::get_correct_parity() 100 | { 101 | return correct_parity; 102 | } 103 | 104 | int Block::get_or_compute_current_parity() 105 | { 106 | #pragma clang diagnostic push 107 | #pragma clang diagnostic ignored "-Wunused-but-set-variable" 108 | const char* action; 109 | if (current_parity == Block::unknown_parity) { 110 | action = "Compute"; 111 | current_parity = shuffled_key.compute_range_parity(start_bit_nr, end_bit_nr); 112 | } else { 113 | action = "Get"; 114 | } 115 | #pragma clang diagnostic pop 116 | DEBUG(action << " current parity:" << 117 | " block=" << debug_str() << 118 | " current_parity=" << current_parity); 119 | return current_parity; 120 | } 121 | 122 | void Block::flip_current_parity() 123 | { 124 | if (current_parity == Block::unknown_parity) { 125 | // We can get here in a valid but rare race condition. This block is pending for its first 126 | // try-correct (so the current parity is unknown) when some other block containing the same 127 | // bit had a single bit correction. It that case we leave this block alone (its current 128 | // parity will be computed in due time). 129 | return; 130 | } 131 | current_parity = 1 - current_parity; 132 | DEBUG("Flips current parity: block=" << debug_str() << 133 | " new_current_parity=" << current_parity); 134 | } 135 | 136 | void Block::set_correct_parity(int parity) 137 | { 138 | correct_parity = parity; 139 | } 140 | 141 | bool Block::correct_parity_is_known() const 142 | { 143 | return correct_parity != unknown_parity; 144 | } 145 | 146 | bool Block::try_to_infer_correct_parity() 147 | { 148 | assert(correct_parity == unknown_parity); 149 | 150 | // Try to do a very limited type of inference, using only the parity of the parent block and 151 | // the sibling block. 152 | 153 | // Cannot infer if there is no parent block. 154 | if (!parent_block) 155 | return false; 156 | 157 | // Cannot infer if there is no sibling block (yet). 158 | BlockPtr sibling_block; 159 | if (parent_block->left_sub_block.get() == this) 160 | sibling_block = parent_block->right_sub_block; 161 | else 162 | sibling_block = parent_block->left_sub_block; 163 | if (!sibling_block) 164 | return false; 165 | 166 | // Cannot infer if the correct parity of the parent or sibling block is unknown. 167 | if (parent_block->correct_parity == Block::unknown_parity) 168 | return false; 169 | if (sibling_block->correct_parity == Block::unknown_parity) 170 | return false; 171 | 172 | // We have everything we need. Infer the correct parity. 173 | int correct_block_parity; 174 | if (parent_block->correct_parity == 1) 175 | correct_block_parity = 1 - sibling_block->correct_parity; 176 | else 177 | correct_block_parity = sibling_block->correct_parity; 178 | set_correct_parity(correct_block_parity); 179 | return true; 180 | } 181 | 182 | int Block::get_error_parity() 183 | { 184 | assert(correct_parity != unknown_parity); 185 | int current_parity = get_or_compute_current_parity(); 186 | int error_parity; 187 | if (correct_parity == current_parity) { 188 | error_parity = 0; 189 | } else { 190 | error_parity = 1; 191 | } 192 | DEBUG("Compute error parity:" << 193 | " block=" << debug_str() << 194 | " current_parity=" << current_parity << 195 | " correct_parity=" << correct_parity << 196 | " error_parity=" << error_parity); 197 | return error_parity; 198 | } 199 | 200 | Block* Block::get_parent_block() const 201 | { 202 | return parent_block; 203 | } 204 | 205 | BlockPtr Block::get_left_sub_block() const 206 | { 207 | return left_sub_block; 208 | } 209 | 210 | BlockPtr Block::create_left_sub_block() 211 | { 212 | int sub_start_bit_nr = start_bit_nr; 213 | int sub_end_bit_nr = sub_start_bit_nr + (get_nr_bits() / 2) - 1; 214 | BlockPtr block(new Block(iteration, sub_start_bit_nr, sub_end_bit_nr, this, 0)); 215 | left_sub_block = block; 216 | return block; 217 | } 218 | 219 | BlockPtr Block::get_right_sub_block() const 220 | { 221 | return right_sub_block; 222 | } 223 | 224 | BlockPtr Block::create_right_sub_block() 225 | { 226 | int sub_start_bit_nr = start_bit_nr + (get_nr_bits() / 2); 227 | int sub_end_bit_nr = end_bit_nr; 228 | BlockPtr block(new Block(iteration, sub_start_bit_nr, sub_end_bit_nr, this, 1)); 229 | right_sub_block = block; 230 | return block; 231 | } 232 | -------------------------------------------------------------------------------- /cascade/classical_session.cpp: -------------------------------------------------------------------------------- 1 | #include "classical_session.h" 2 | 3 | using namespace Cascade; 4 | 5 | ClassicalSession::~ClassicalSession() 6 | { 7 | } 8 | -------------------------------------------------------------------------------- /cascade/iteration.cpp: -------------------------------------------------------------------------------- 1 | #include "iteration.h" 2 | #include "algorithm.h" 3 | #include "debug.h" 4 | #include "reconciliation.h" 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace Cascade; 10 | 11 | Iteration::Iteration(Reconciliation& reconciliation, int iteration_nr, bool biconf): 12 | reconciliation(reconciliation), 13 | iteration_nr(iteration_nr), 14 | biconf(biconf), 15 | nr_key_bits(reconciliation.get_nr_key_bits()), 16 | shuffle(init_shuffle(reconciliation, iteration_nr)), 17 | shuffled_key(reconciliation.get_reconciled_key(), shuffle) 18 | { 19 | if (biconf) { 20 | block_size = nr_key_bits / 2; 21 | } else { 22 | block_size = reconciliation.get_algorithm().block_size_function(iteration_nr, 23 | reconciliation.get_estimated_bit_error_rate(), nr_key_bits); 24 | } 25 | DEBUG("Start " << (biconf ? "biconf" : "cascade") << " iteration " << iteration_nr); 26 | } 27 | 28 | ShufflePtr Iteration::init_shuffle(Reconciliation& reconciliation, int iteration_nr) 29 | { 30 | int nr_key_bits = reconciliation.get_nr_key_bits(); 31 | const Algorithm& algorithm = reconciliation.get_algorithm(); 32 | bool assign_seed = algorithm.ask_correct_parity_using_shuffle_seed; 33 | bool cache = algorithm.cache_shuffles; 34 | return Shuffle::new_random_shuffle(iteration_nr, nr_key_bits, assign_seed, cache); 35 | } 36 | 37 | Iteration::~Iteration() 38 | { 39 | } 40 | 41 | Reconciliation& Iteration::get_reconciliation() const 42 | { 43 | return reconciliation; 44 | } 45 | 46 | int Iteration::get_iteration_nr() const 47 | { 48 | return iteration_nr; 49 | } 50 | 51 | bool Iteration::get_biconf() const 52 | { 53 | return biconf; 54 | } 55 | 56 | ShufflePtr Iteration::get_shuffle() const 57 | { 58 | return shuffle; 59 | } 60 | 61 | ShuffledKey& Iteration::get_shuffled_key() 62 | { 63 | return shuffled_key; 64 | } 65 | 66 | void Iteration::schedule_initial_work() 67 | { 68 | if (biconf) { 69 | schedule_initial_work_biconf(); 70 | } else { 71 | schedule_initial_work_cascade(); 72 | } 73 | } 74 | 75 | void Iteration::schedule_initial_work_cascade() 76 | { 77 | // Create top blocks, and schedule each one for "ask correct parity". 78 | int block_nr = 0; 79 | int start_bit_nr = 0; 80 | while (start_bit_nr < nr_key_bits) { 81 | int end_bit_nr = std::min(start_bit_nr + block_size, nr_key_bits) - 1; 82 | BlockPtr block(new Block(*this, start_bit_nr, end_bit_nr, NULL, block_nr)); 83 | top_blocks.push_back(block); 84 | reconciliation.schedule_ask_correct_parity(block, false); 85 | block_nr += 1; 86 | start_bit_nr += block_size; 87 | } 88 | } 89 | 90 | void Iteration::schedule_initial_work_biconf() 91 | { 92 | // Randomly select half of the bits in the key. Since the key was shuffled for this iteration, 93 | // just selecting the first half of the bits in the shuffled key is the same as randomly 94 | // selecting half of the bits in the original unshuffled key. 95 | BlockPtr block(new Block(*this, 0, block_size-1, NULL, 0)); 96 | top_blocks.push_back(block); 97 | 98 | // Ask Alice what the correct parity of the selected block is. 99 | reconciliation.schedule_ask_correct_parity(block, false); 100 | 101 | // If the algorithm wants it, also create the complementary block and ask Alice for it's parity. 102 | if (reconciliation.get_algorithm().biconf_correct_complement) { 103 | BlockPtr complement_block(new Block(*this, block_size, nr_key_bits-1, NULL, 1)); 104 | top_blocks.push_back(complement_block); 105 | reconciliation.schedule_ask_correct_parity(complement_block, false); 106 | } 107 | } 108 | 109 | int Iteration::try_correct_block(BlockPtr block, bool correct_right_sibling, bool cascade) 110 | { 111 | DEBUG("Try to correct block " << block->debug_str()); 112 | 113 | // If we don't know the correct parity of the block, we cannot make progress on this block 114 | // until Alice has told us what the correct parity is. 115 | if (block->correct_parity_is_known()) { 116 | DEBUG("Correct parity is known: correct_parity=" << block->get_correct_parity()); 117 | } else { 118 | if (block->try_to_infer_correct_parity()) { 119 | Stats& stats = reconciliation.get_stats(); 120 | stats.infer_parity_blocks += 1; 121 | DEBUG("Correct parity was inferred: correct_parity=" << block->get_correct_parity()); 122 | } else { 123 | DEBUG("Correct parity is unknown"); 124 | reconciliation.schedule_ask_correct_parity(block, correct_right_sibling); 125 | return 0; 126 | } 127 | } 128 | 129 | // If there is an even number of errors in this block, we don't attempt to fix any errors 130 | // in this block. But if asked to do so, we will attempt to fix an error in the right 131 | // sibling block. 132 | int error_parity = block->get_error_parity(); 133 | assert(error_parity != Block::unknown_parity); 134 | if (error_parity == 0) { 135 | if (correct_right_sibling) { 136 | DEBUG("Even error parity: try to correct right sibling"); 137 | return try_correct_right_sibling_block(block, cascade); 138 | } else { 139 | DEBUG("Even error parity: do nothing"); 140 | return 0; 141 | } 142 | } 143 | 144 | // If this block contains a single bit, we have finished the recursion and found an error. 145 | // Correct the error by flipping the key bit that corresponds to this block. 146 | if (block->get_nr_bits() == 1) { 147 | int orig_key_bit_nr = shuffle->shuffle_to_orig(block->get_start_bit_nr()); 148 | DEBUG("Correct single bit: block=" << block->debug_str()); 149 | reconciliation.correct_orig_key_bit(orig_key_bit_nr, iteration_nr, cascade); 150 | return 1; 151 | } 152 | 153 | // If we get here, it means that there is an odd number of errors in this block and that the 154 | // block is bigger than 1 bit. 155 | DEBUG("Recurse into left sub-block"); 156 | BlockPtr left_sub_block = block->get_left_sub_block(); 157 | if (!left_sub_block) { 158 | left_sub_block = block->create_left_sub_block(); 159 | } 160 | return try_correct_block(left_sub_block, true, cascade); 161 | } 162 | 163 | int Iteration::try_correct_right_sibling_block(BlockPtr block, bool cascade) 164 | { 165 | Block* parent_block = block->get_parent_block(); 166 | assert(parent_block); 167 | BlockPtr right_sibling_block = parent_block->get_right_sub_block(); 168 | if (!right_sibling_block) { 169 | right_sibling_block = parent_block->create_right_sub_block(); 170 | } 171 | DEBUG("Right sibling is " << right_sibling_block->debug_str()); 172 | return try_correct_block(right_sibling_block, false, cascade); 173 | } 174 | 175 | BlockPtr Iteration::get_cascade_block(int orig_key_bit_nr) const 176 | { 177 | int shuffled_key_bit_nr = shuffle->orig_to_shuffle(orig_key_bit_nr); 178 | int block_nr = shuffled_key_bit_nr / block_size; 179 | BlockPtr block; 180 | try { 181 | block = top_blocks.at(block_nr); 182 | } 183 | catch (const std::out_of_range&) { 184 | // Corner case: when running BICONF with cascading enabled and complementary blocks disabled 185 | // it is possible that iteration X corrects a bit, but that bit is not part of the chosen //// block in some other iteration Y. 186 | block = NULL; 187 | } 188 | DEBUG("Select cascading block for iteration:" << 189 | " iteration_nr=" << iteration_nr << 190 | " block=" << (block ? block->debug_str() : "null")); 191 | return block; 192 | } 193 | 194 | void Iteration::flip_parity_in_all_blocks_containing_bit(int orig_key_bit_nr) 195 | { 196 | int shuffled_key_bit_nr = shuffle->orig_to_shuffle(orig_key_bit_nr); 197 | int block_nr = shuffled_key_bit_nr / block_size; 198 | BlockPtr block; 199 | try { 200 | block = top_blocks.at(block_nr); 201 | } 202 | catch (const std::out_of_range&) { 203 | return; 204 | } 205 | block->flip_current_parity(); 206 | while (true) { 207 | BlockPtr sub_block = block->get_left_sub_block(); 208 | if (!sub_block) 209 | break; 210 | assert(shuffled_key_bit_nr >= sub_block->get_start_bit_nr()); 211 | if (shuffled_key_bit_nr <= sub_block->get_end_bit_nr()) { 212 | sub_block->flip_current_parity(); 213 | block = sub_block; 214 | continue; 215 | } 216 | sub_block = block->get_right_sub_block(); 217 | if (!sub_block) 218 | break; 219 | assert(shuffled_key_bit_nr >= sub_block->get_start_bit_nr()); 220 | assert(shuffled_key_bit_nr <= sub_block->get_end_bit_nr()); 221 | sub_block->flip_current_parity(); 222 | block = sub_block; 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /cascade/key.cpp: -------------------------------------------------------------------------------- 1 | #include "key.h" 2 | #include "random.h" 3 | #include "shuffle.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace Cascade; 10 | 11 | // Key bits are stored into 64-bit int "words" as follows: 12 | // 13 | // +----+----+----+-//-+----+----+----+ +----+----+----+-//-+----+----+----+ +---... 14 | // | 63 | 62 | 61 | | 2 | 1 | 0 | | 127| 126| 125| | 66 | 65 | 64 | | 15 | // +----+----+----+-//-+----+----+----+ +----+----+----+-//-+----+----+----+ +---... 16 | // 63 62 61 2 1 0 63 62 61 2 1 0 17 | // MSB LSB MSB LSB 18 | // Word 0 Word 1 19 | // 20 | // Note: we use the term "word" instead of te more natural term "block" to avoid confusion with 21 | // cascade blocks. 22 | 23 | static uint64_t start_word_mask(int start_bit_nr) 24 | { 25 | int nr_unused_bits = start_bit_nr % 64; 26 | return 0xffffffffffffffffull << nr_unused_bits; 27 | } 28 | 29 | static uint64_t end_word_mask(int end_bit_nr) 30 | { 31 | int nr_unused_bits = 64 - ((end_bit_nr + 1) % 64); 32 | uint64_t mask = 0xffffffffffffffffull; 33 | if (nr_unused_bits != 64) { 34 | mask >>= nr_unused_bits; 35 | } 36 | return mask; 37 | } 38 | 39 | static int word_parity(uint64_t word) 40 | { 41 | static int byte_parity[256] = {0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 42 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 43 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 44 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 45 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 46 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 47 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 48 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 49 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 50 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 51 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 52 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 53 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 54 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 55 | 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 56 | 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0}; 57 | int parity = 0; 58 | parity ^= byte_parity[word & 0xff]; 59 | parity ^= byte_parity[word >> 8 & 0xff]; 60 | parity ^= byte_parity[word >> 16 & 0xff]; 61 | parity ^= byte_parity[word >> 24 & 0xff]; 62 | parity ^= byte_parity[word >> 32 & 0xff]; 63 | parity ^= byte_parity[word >> 40 & 0xff]; 64 | parity ^= byte_parity[word >> 48 & 0xff]; 65 | parity ^= byte_parity[word >> 56 & 0xff]; 66 | return parity; 67 | } 68 | 69 | Key::Key(int nr_bits_param) 70 | { 71 | // Construct a key with the bits set to random values. 72 | nr_bits = nr_bits_param; 73 | nr_words = (nr_bits_param - 1) / 64 + 1; 74 | words = new uint64_t[nr_words]; 75 | for (int word_nr = 0; word_nr < nr_words; word_nr++) { 76 | words[word_nr] = uint64_t(random_uint32()) << 32 | random_uint32(); 77 | } 78 | words[nr_words - 1] &= end_word_mask(nr_bits - 1); 79 | } 80 | 81 | Key::Key(const Key& key) 82 | { 83 | nr_bits = key.nr_bits; 84 | nr_words = key.nr_words; 85 | words = new uint64_t[nr_words]; 86 | std::memcpy(words, key.words, nr_words * sizeof(words[0])); 87 | } 88 | 89 | Key::~Key() 90 | { 91 | delete[] words; 92 | } 93 | 94 | std::string Key::to_string() const 95 | { 96 | // LSB: bit_nr=0 MSB: bit_nr=nr_bits-1 97 | // v v 98 | // 01011010010110010010101001 99 | std::string string = ""; 100 | int bit_nr = 0; 101 | while (bit_nr < nr_bits) { 102 | string += get_bit(bit_nr) ? "1" : "0"; 103 | bit_nr += 1; 104 | } 105 | return string; 106 | } 107 | 108 | int Key::get_nr_bits() const 109 | { 110 | return nr_bits; 111 | } 112 | 113 | int Key::get_bit(int bit_nr) const 114 | { 115 | assert(bit_nr < nr_bits); 116 | int word_nr = bit_nr / 64; 117 | int bit_nr_in_word = bit_nr % 64; 118 | uint64_t mask = 1ull << bit_nr_in_word; 119 | return (words[word_nr] & mask) ? 1 : 0; 120 | } 121 | 122 | void Key::set_bit(int bit_nr, int value) 123 | { 124 | assert(bit_nr < nr_bits); 125 | int word_nr = bit_nr / 64; 126 | int bit_nr_in_word = bit_nr % 64; 127 | uint64_t mask = 1ull << bit_nr_in_word; 128 | if (value == 1) { 129 | words[word_nr] |= mask; 130 | } else if (value == 0) { 131 | words[word_nr] &= ~mask; 132 | } else { 133 | assert(false); 134 | } 135 | } 136 | 137 | void Key::flip_bit(int bit_nr) 138 | { 139 | assert(bit_nr < nr_bits); 140 | int word_nr = bit_nr / 64; 141 | int bit_nr_in_word = bit_nr % 64; 142 | uint64_t mask = 1ull << bit_nr_in_word; 143 | words[word_nr] ^= mask; 144 | } 145 | 146 | void Key::apply_noise(double bit_error_rate) 147 | { 148 | // Uses Bob Floyd sampling to select a sample of bits to flip. 149 | // See https://stackoverflow.com/questions/28287138 for details. 150 | int nr_bit_errors = bit_error_rate * nr_bits + 0.5; 151 | std::unordered_set error_bits; 152 | for (int d = nr_bits - nr_bit_errors; d < nr_bits; ++d) { 153 | int t = random_bit_nr(0, d); 154 | if (error_bits.find(t) == error_bits.end()) { 155 | error_bits.insert(t); 156 | } else { 157 | error_bits.insert(d); 158 | } 159 | } 160 | for (auto it = error_bits.begin(); it != error_bits.end(); ++it) { 161 | flip_bit(*it); 162 | } 163 | } 164 | 165 | int Key::compute_range_parity(int start_bit_nr, int end_bit_nr) const 166 | { 167 | assert(start_bit_nr < nr_bits); 168 | assert(end_bit_nr < nr_bits); 169 | int start_word_nr = start_bit_nr / 64; 170 | int end_word_nr = end_bit_nr / 64; 171 | uint64_t xor_words = 0; 172 | for (int word_nr = start_word_nr; word_nr <= end_word_nr; ++word_nr) { 173 | xor_words ^= words[word_nr]; 174 | } 175 | // Undo bits that we did not want to include in first word. 176 | uint64_t unwanted_mask = ~start_word_mask(start_bit_nr); 177 | uint64_t unwanted_bits = words[start_word_nr] & unwanted_mask; 178 | xor_words ^= unwanted_bits; 179 | // Undo bits that we did not want to include in first word. 180 | unwanted_mask = ~end_word_mask(end_bit_nr); 181 | unwanted_bits = words[end_word_nr] & unwanted_mask; 182 | xor_words ^= unwanted_bits; 183 | return word_parity(xor_words); 184 | } 185 | 186 | int Key::nr_bits_different(const Key& other_key) const 187 | { 188 | assert(nr_bits == other_key.nr_bits); 189 | int difference = 0; 190 | for (int word_nr = 0; word_nr < nr_words; word_nr++) { 191 | uint64_t xor_word = words[word_nr] ^ other_key.words[word_nr]; 192 | difference += __builtin_popcount(xor_word); 193 | } 194 | return difference; 195 | } 196 | -------------------------------------------------------------------------------- /cascade/mock_classical_session.cpp: -------------------------------------------------------------------------------- 1 | #include "mock_classical_session.h" 2 | #include "debug.h" 3 | #include "iteration.h" 4 | #include "key.h" 5 | #include "shuffle.h" 6 | #include "shuffled_key.h" 7 | 8 | using namespace Cascade; 9 | 10 | MockClassicalSession::MockClassicalSession(Key& correct_key, bool cache_shuffles): 11 | correct_key(correct_key), 12 | cache_shuffles(cache_shuffles) 13 | { 14 | DEBUG("Create MockClassicalSession: correct_key=" << correct_key.to_string()); 15 | } 16 | 17 | MockClassicalSession::~MockClassicalSession() 18 | { 19 | } 20 | 21 | void MockClassicalSession::start_iteration_with_shuffle_seed(int iteration_nr, 22 | uint64_t shuffle_seed) 23 | { 24 | int nr_key_bits = correct_key.get_nr_bits(); 25 | ShufflePtr shuffle; 26 | shuffle = Shuffle::new_shuffle_from_seed(iteration_nr, nr_key_bits, shuffle_seed, 27 | cache_shuffles); 28 | ShuffledKeyPtr shuffled_key(new ShuffledKey(correct_key, shuffle)); 29 | shuffled_keys[iteration_nr] = shuffled_key; 30 | } 31 | 32 | void MockClassicalSession::start_iteration_with_shuffle(int iteration_nr, ShufflePtr shuffle) 33 | { 34 | ShuffledKeyPtr shuffled_key(new ShuffledKey(correct_key, shuffle)); 35 | shuffled_keys[iteration_nr] = shuffled_key; 36 | } 37 | 38 | void MockClassicalSession::ask_correct_parities(PendingItemQueue& ask_correct_parity_blocks) 39 | { 40 | // Once we implement the real classical session, we will need to keep track of the blocks 41 | // for which we asked Alice the correct parity, but for which we have not yet received the 42 | // answer from Alice. For now, assume we get the answer immediately. 43 | for (auto it = ask_correct_parity_blocks.begin(); it != ask_correct_parity_blocks.end(); ++it) { 44 | PendingItem pending_item(*it); 45 | BlockPtr block = pending_item.block; 46 | int iteration_nr = block->get_iteration().get_iteration_nr(); 47 | ShuffledKeyPtr shuffled_key = shuffled_keys[iteration_nr]; 48 | int correct_parity = shuffled_key->compute_range_parity(block->get_start_bit_nr(), 49 | block->get_end_bit_nr()); 50 | block->set_correct_parity(correct_parity); 51 | DEBUG("Ask correct parity:" << 52 | " block=" << block->debug_str() << 53 | " correct_parity=" << correct_parity); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /cascade/pending_item.cpp: -------------------------------------------------------------------------------- 1 | #include "pending_item.h" 2 | 3 | using namespace Cascade; 4 | 5 | PendingItem::PendingItem(BlockPtr block, bool correct_right_sibling): 6 | block(block), 7 | correct_right_sibling(correct_right_sibling) 8 | { 9 | } 10 | -------------------------------------------------------------------------------- /cascade/random.cpp: -------------------------------------------------------------------------------- 1 | #include "random.h" 2 | #include 3 | 4 | namespace Cascade { 5 | 6 | static std::random_device rd; 7 | static std::mt19937 mt(rd()); 8 | 9 | void set_random_uint32_seed(uint32_t seed) 10 | { 11 | mt.seed(seed); 12 | } 13 | 14 | uint32_t random_uint32() 15 | { 16 | return mt(); 17 | } 18 | 19 | int random_bit_nr(int start_bit_nr, int end_bit_nr) 20 | { 21 | // Don't use std::uniform_int_distribution because the sequence of random numbers that is 22 | // generated for given seed is not the same across different compilers 23 | // (see https://stackoverflow.com/questions/61069954) 24 | int nr_bits = end_bit_nr - start_bit_nr + 1; 25 | return start_bit_nr + random_uint32() % nr_bits; 26 | } 27 | 28 | } /* namespace Cascade */ -------------------------------------------------------------------------------- /cascade/reconciliation.cpp: -------------------------------------------------------------------------------- 1 | #include "reconciliation.h" 2 | #include "algorithm.h" 3 | #include "classical_session.h" 4 | #include "debug.h" 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace Cascade; 10 | 11 | Reconciliation::Reconciliation(const Algorithm& algorithm, 12 | ClassicalSession& classical_session, 13 | const Key& noisy_key, 14 | double estimated_bit_error_rate, 15 | const Key* correct_key): 16 | algorithm(algorithm), 17 | classical_session(classical_session), 18 | estimated_bit_error_rate(estimated_bit_error_rate), 19 | reconciled_key(noisy_key), 20 | correct_key(correct_key), 21 | nr_key_bits(noisy_key.get_nr_bits()) 22 | { 23 | DEBUG("Start reconciliation: noisy_key=" << noisy_key.to_string()); 24 | } 25 | 26 | Reconciliation::~Reconciliation() 27 | { 28 | DEBUG("End reconciliation"); 29 | } 30 | 31 | const Algorithm& Reconciliation::get_algorithm() const 32 | { 33 | return algorithm; 34 | } 35 | 36 | double Reconciliation::get_estimated_bit_error_rate() const 37 | { 38 | return estimated_bit_error_rate; 39 | } 40 | 41 | Key& Reconciliation::get_reconciled_key() 42 | { 43 | return reconciled_key; 44 | } 45 | 46 | const Key* Reconciliation::get_correct_key() const 47 | { 48 | return correct_key; 49 | } 50 | 51 | int Reconciliation::get_nr_key_bits() const 52 | { 53 | return nr_key_bits; 54 | } 55 | 56 | Stats& Reconciliation::get_stats() 57 | { 58 | return stats; 59 | } 60 | 61 | static double elapsed_time(const struct timespec& start, const struct timespec& end) 62 | { 63 | double d_start = double(start.tv_sec) + double(start.tv_nsec) / 1000000000.0; 64 | double d_end = double(end.tv_sec) + double(end.tv_nsec) / 1000000000.0; 65 | return d_end - d_start; 66 | } 67 | 68 | double Reconciliation::compute_efficiency(long reconciliation_bits) const 69 | { 70 | double eps = estimated_bit_error_rate; 71 | double shannon_efficiency = -eps * log2(eps) - (1.0 - eps) * log2(1.0 - eps); 72 | int key_size = reconciled_key.get_nr_bits(); 73 | double efficiency = double(reconciliation_bits) / (double(key_size) * shannon_efficiency); 74 | return efficiency; 75 | } 76 | 77 | void Reconciliation::reconcile() 78 | { 79 | // Record start time. 80 | struct timespec start_process_time; 81 | int rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &start_process_time); 82 | assert(rc == 0); 83 | struct timespec start_real_time; 84 | rc = clock_gettime(CLOCK_MONOTONIC, &start_real_time); 85 | assert(rc == 0); 86 | 87 | // Normal cascade iterations. 88 | all_normal_cascade_iterations(); 89 | 90 | // BICONF iterations (if any). 91 | all_biconf_iterations(); 92 | 93 | // Record end time. 94 | struct timespec end_process_time; 95 | rc = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end_process_time); 96 | assert(rc == 0); 97 | struct timespec end_real_time; 98 | rc = clock_gettime(CLOCK_MONOTONIC, &end_real_time); 99 | assert(rc == 0); 100 | 101 | // Compute elapsed time. 102 | stats.elapsed_process_time = elapsed_time(start_process_time, end_process_time); 103 | stats.elapsed_real_time = elapsed_time(start_real_time, end_real_time); 104 | 105 | // Compute efficiency. 106 | stats.efficiency = compute_efficiency(stats.ask_parity_blocks); 107 | 108 | // Compute number of reconciliation message bits per key bit. 109 | stats.reconciliation_bits = stats.start_iteration_bits + stats.ask_parity_bits + 110 | stats.reply_parity_bits; 111 | stats.reconciliation_bits_per_key_bit = (double) stats.reconciliation_bits / 112 | (double) this->nr_key_bits; 113 | } 114 | 115 | void Reconciliation::all_normal_cascade_iterations() 116 | { 117 | int iteration_nr = 0; 118 | for (int i = 0; i < algorithm.nr_cascade_iterations; ++i) { 119 | ++stats.normal_iterations; 120 | ++iteration_nr; 121 | start_iteration_common(iteration_nr, false); 122 | service_all_pending_work(true); 123 | } 124 | } 125 | 126 | void Reconciliation::all_biconf_iterations() 127 | { 128 | if (algorithm.nr_biconf_iterations == 0) 129 | return; 130 | int iterations_to_go = algorithm.nr_biconf_iterations; 131 | int iteration_nr = algorithm.nr_cascade_iterations; 132 | while (iterations_to_go > 0) { 133 | ++stats.biconf_iterations; 134 | ++iteration_nr; 135 | start_iteration_common(iteration_nr, true); 136 | int errors_corrected = service_all_pending_work(algorithm.biconf_cascade); 137 | if (algorithm.biconf_error_free_streak and errors_corrected > 0) 138 | iterations_to_go = algorithm.nr_biconf_iterations; 139 | else 140 | iterations_to_go -= 1; 141 | } 142 | } 143 | 144 | void Reconciliation::start_iteration_common(int iteration_nr, bool biconf) 145 | { 146 | IterationPtr iteration(new Iteration(*this, iteration_nr, biconf)); 147 | iterations.push_back(iteration); 148 | stats.start_iteration_messages += 1; 149 | if (algorithm.ask_correct_parity_using_shuffle_seed) { 150 | classical_session.start_iteration_with_shuffle_seed(iteration_nr, 151 | iteration->get_shuffle()->get_seed()); 152 | stats.start_iteration_bits += 32 + 64; 153 | } else { 154 | ShufflePtr shuffle = iteration->get_shuffle(); 155 | classical_session.start_iteration_with_shuffle(iteration_nr, shuffle); 156 | stats.start_iteration_bits += 32 + 32 * shuffle->get_nr_bits(); 157 | } 158 | iteration->schedule_initial_work(); 159 | } 160 | 161 | void Reconciliation::schedule_try_correct(BlockPtr block, bool correct_right_sibling) 162 | { 163 | DEBUG("Schedule try_correct: block=" << block->debug_str()); 164 | PendingItem pending_item(block, correct_right_sibling); 165 | pending_try_correct_blocks.push_back(pending_item); 166 | } 167 | 168 | void Reconciliation::schedule_ask_correct_parity(BlockPtr block, bool correct_right_sibling) 169 | { 170 | DEBUG("Schedule ask_correct_parity: block=" << block->debug_str()); 171 | PendingItem pending_item(block, correct_right_sibling); 172 | pending_ask_correct_parity_blocks.push_back(pending_item); 173 | 174 | } 175 | 176 | void Reconciliation::correct_orig_key_bit(int orig_key_bit_nr, int triggering_iteration_nr, 177 | bool cascade) 178 | { 179 | reconciled_key.flip_bit(orig_key_bit_nr); 180 | for (IterationPtr iteration: iterations) 181 | iteration->flip_parity_in_all_blocks_containing_bit(orig_key_bit_nr); 182 | if (cascade) 183 | cascade_effect(orig_key_bit_nr, triggering_iteration_nr); 184 | } 185 | 186 | void Reconciliation::cascade_effect(int orig_key_bit_nr, int triggering_iteration_nr) 187 | { 188 | // Re-visit every cascade iteration up to now, except the one that triggered this cascade. 189 | for (IterationPtr iteration: iterations) { 190 | if (iteration->get_iteration_nr() != triggering_iteration_nr) { 191 | // Each iteration can contribute at most one block to cascade into. If there is 192 | // such a block, schedule it for a try-correct. 193 | BlockPtr block(iteration->get_cascade_block(orig_key_bit_nr)); 194 | if (block) { 195 | schedule_try_correct(block, false); 196 | } 197 | } 198 | } 199 | } 200 | 201 | int Reconciliation::service_all_pending_work(bool cascade) 202 | { 203 | int errors_corrected = 0; 204 | while (!pending_ask_correct_parity_blocks.empty() || !pending_try_correct_blocks.empty()) { 205 | errors_corrected += service_pending_try_correct(cascade); 206 | service_pending_ask_correct_parity(); 207 | } 208 | return errors_corrected; 209 | } 210 | 211 | int Reconciliation::service_pending_try_correct(bool cascade) 212 | { 213 | int errors_corrected = 0; 214 | while (!pending_try_correct_blocks.empty()) { 215 | PendingItem pending_item = pending_try_correct_blocks.front(); 216 | pending_try_correct_blocks.pop_front(); 217 | Iteration& iteration = pending_item.block->get_iteration(); 218 | errors_corrected += iteration.try_correct_block(pending_item.block, 219 | pending_item.correct_right_sibling, 220 | cascade); 221 | } 222 | return errors_corrected; 223 | } 224 | 225 | static long block_bits() 226 | { 227 | return 16 + // 16 bits for iteration nr 228 | 32 + // 32 bits for start bit index 229 | 32; // 32 bits for end bit index 230 | } 231 | 232 | static long ask_parity_message_bits(long nr_blocks) 233 | { 234 | return 16 + // Assumed overhead for header 235 | nr_blocks * block_bits(); // Size of blocks that parity is being asked for 236 | } 237 | 238 | static long reply_parity_message_bits(long nr_blocks) 239 | { 240 | return 16 + // Assumed overhead for header 241 | nr_blocks; // One parity bit for each block 242 | } 243 | 244 | void Reconciliation::service_pending_ask_correct_parity() 245 | { 246 | // Ask Alice for the correct parity for each block on the ask-parity list. 247 | long nr_blocks = pending_ask_correct_parity_blocks.size(); 248 | if (nr_blocks == 0) { 249 | return; 250 | } 251 | stats.ask_parity_messages += 1; 252 | stats.ask_parity_blocks += nr_blocks; 253 | stats.ask_parity_bits += ask_parity_message_bits(nr_blocks); 254 | stats.reply_parity_bits += reply_parity_message_bits(nr_blocks); 255 | classical_session.ask_correct_parities(pending_ask_correct_parity_blocks); 256 | 257 | // Move all blocks over to the try-correct list. 258 | while (!pending_ask_correct_parity_blocks.empty()) { 259 | PendingItem pending_item = pending_ask_correct_parity_blocks.front(); 260 | pending_ask_correct_parity_blocks.pop_front(); 261 | schedule_try_correct(pending_item.block, pending_item.correct_right_sibling); 262 | } 263 | } 264 | -------------------------------------------------------------------------------- /cascade/report.cpp: -------------------------------------------------------------------------------- 1 | #include "report.h" 2 | 3 | std::mutex report_mutex; 4 | -------------------------------------------------------------------------------- /cascade/shuffle.cpp: -------------------------------------------------------------------------------- 1 | #include "shuffle.h" 2 | #include "random.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace Cascade; 9 | 10 | static std::random_device rd; 11 | static std::mt19937 global_mt(rd()); 12 | 13 | // Creating a new shuffle is expensive in terms of CPU usage, so optionally keep a cache of 14 | // previously created shuffles. 15 | 16 | struct ShuffleIndex { 17 | ShuffleIndex(int iteration_nr, int nr_bits, bool has_seed); 18 | int iteration_nr; 19 | int nr_bits; 20 | // For a given iteration and key size, the cache may contain shuffles with and without a seed. 21 | // But for the shuffles with a seed, the must all have the same seed value. 22 | bool has_seed; 23 | }; 24 | 25 | ShuffleIndex::ShuffleIndex(int iteration_nr, int nr_bits, bool has_seed): 26 | iteration_nr(iteration_nr), 27 | nr_bits(nr_bits), 28 | has_seed(has_seed) 29 | { 30 | } 31 | 32 | bool operator<(const ShuffleIndex& lhs, const ShuffleIndex& rhs) { 33 | if (lhs.iteration_nr < rhs.iteration_nr) 34 | return true; 35 | if (lhs.iteration_nr > rhs.iteration_nr) 36 | return false; 37 | if (lhs.nr_bits < rhs.nr_bits) 38 | return true; 39 | if (lhs.nr_bits > rhs.nr_bits) 40 | return false; 41 | if (lhs.has_seed < rhs.has_seed) 42 | return true; 43 | return false; 44 | } 45 | 46 | typedef std::map ShuffleCache; 47 | 48 | static ShuffleCache cache; 49 | 50 | static std::mutex cache_mutex; 51 | 52 | ShufflePtr Shuffle::new_random_shuffle(int iteration_nr, int nr_bits, bool assign_seed, bool cache) 53 | { 54 | std::lock_guard guard(cache_mutex); 55 | ShufflePtr shuffle; 56 | if (cache) { 57 | shuffle = cache_search(iteration_nr, nr_bits, assign_seed); 58 | if (shuffle) 59 | return shuffle; 60 | } 61 | shuffle = ShufflePtr(new Shuffle(iteration_nr, nr_bits, assign_seed)); 62 | if (cache) 63 | cache_add(shuffle); 64 | return shuffle; 65 | } 66 | 67 | ShufflePtr Shuffle::new_shuffle_from_seed(int iteration_nr, int nr_bits, uint64_t seed, bool cache) 68 | { 69 | std::lock_guard guard(cache_mutex); 70 | ShufflePtr shuffle; 71 | if (cache) { 72 | shuffle = cache_search(iteration_nr, nr_bits, true); 73 | if (shuffle) 74 | return shuffle; 75 | } 76 | shuffle = ShufflePtr(new Shuffle(iteration_nr, nr_bits, seed)); 77 | if (cache) 78 | cache_add(shuffle); 79 | return shuffle; 80 | } 81 | 82 | Shuffle::Shuffle(int iteration_nr, int nr_bits, bool assign_seed): 83 | iteration_nr(iteration_nr), 84 | nr_bits(nr_bits), 85 | has_seed(false), 86 | seed(0), 87 | orig_to_shuffled_map(nr_bits, -1) 88 | { 89 | initialize(assign_seed); 90 | } 91 | 92 | Shuffle::Shuffle(int iteration_nr, int nr_bits, uint64_t seed): 93 | iteration_nr(iteration_nr), 94 | nr_bits(nr_bits), 95 | has_seed(true), 96 | seed(seed), 97 | orig_to_shuffled_map(nr_bits, -1) 98 | { 99 | initialize(false); 100 | } 101 | 102 | void Shuffle::initialize(bool assign_seed) 103 | { 104 | // The initial mapping of shuffled key bits to original key bits is one-on-one. 105 | shuffled_to_orig_map.reserve(nr_bits); 106 | for (int bit_nr = 0; bit_nr < nr_bits; ++bit_nr) { 107 | shuffled_to_orig_map.push_back(bit_nr); 108 | } 109 | 110 | // Shuffle (except in iteration 1). 111 | if (iteration_nr != 1) { 112 | if (assign_seed) { 113 | assert(!has_seed); 114 | has_seed = true; 115 | seed = random_uint32(); 116 | } 117 | if (has_seed) { 118 | std::mt19937 local_mt(rd()); 119 | local_mt.seed(seed); 120 | std::shuffle(std::begin(shuffled_to_orig_map), 121 | std::end(shuffled_to_orig_map), 122 | local_mt); 123 | } else { 124 | // If we are not using a seed avoid constructing a local random generator because it 125 | // is expensive (performance wise). 126 | std::shuffle(std::begin(shuffled_to_orig_map), 127 | std::end(shuffled_to_orig_map), 128 | global_mt); 129 | } 130 | } 131 | 132 | // Compute the reverse mapping of original key bits to shuffled key bits. 133 | orig_to_shuffled_map.reserve(nr_bits); 134 | for (int shuffled_bit_nr = 0; shuffled_bit_nr < nr_bits; ++shuffled_bit_nr) { 135 | int orig_bit_nr = shuffled_to_orig_map[shuffled_bit_nr]; 136 | orig_to_shuffled_map[orig_bit_nr] = shuffled_bit_nr; 137 | } 138 | } 139 | 140 | Shuffle::~Shuffle() 141 | { 142 | } 143 | 144 | ShufflePtr Shuffle::cache_search(int iteration_nr, int nr_bits, bool has_seed) 145 | { 146 | ShuffleIndex index(iteration_nr, nr_bits, has_seed); 147 | ShuffleCache::iterator it = cache.find(index); 148 | if (it == cache.end()) 149 | return NULL; 150 | else 151 | return it->second; 152 | } 153 | 154 | void Shuffle::cache_add(ShufflePtr shuffle) 155 | { 156 | ShuffleIndex index(shuffle->iteration_nr, shuffle->nr_bits, shuffle->has_seed); 157 | cache[index] = shuffle; 158 | } 159 | 160 | uint64_t Shuffle::get_seed() const 161 | { 162 | return seed; 163 | } 164 | 165 | int Shuffle::get_nr_bits() const 166 | { 167 | return nr_bits; 168 | } 169 | 170 | int Shuffle::orig_to_shuffle(int orig_bit_nr) const 171 | { 172 | return orig_to_shuffled_map.at(orig_bit_nr); 173 | } 174 | 175 | int Shuffle::shuffle_to_orig(int shuffle_bit_nr) const 176 | { 177 | return shuffled_to_orig_map.at(shuffle_bit_nr); 178 | } 179 | -------------------------------------------------------------------------------- /cascade/shuffled_key.cpp: -------------------------------------------------------------------------------- 1 | #include "shuffled_key.h" 2 | #include "key.h" 3 | #include "shuffle.h" 4 | 5 | using namespace Cascade; 6 | 7 | ShuffledKey::ShuffledKey(Key& key, ShufflePtr shuffle): 8 | key(key), 9 | shuffle(shuffle) 10 | { 11 | } 12 | 13 | std::string ShuffledKey::to_string() const 14 | { 15 | std::string string = ""; 16 | int bit_nr = 0; 17 | while (bit_nr < get_nr_bits()) { 18 | string += get_bit(bit_nr) ? "1" : "0"; 19 | bit_nr += 1; 20 | } 21 | return string; 22 | } 23 | 24 | int ShuffledKey::get_nr_bits() const 25 | { 26 | return key.get_nr_bits(); 27 | } 28 | 29 | int ShuffledKey::get_bit(int bit_nr) const 30 | { 31 | int orig_bit_nr = shuffle->shuffle_to_orig(bit_nr); 32 | return key.get_bit(orig_bit_nr); 33 | } 34 | 35 | void ShuffledKey::set_bit(int bit_nr, int value) 36 | { 37 | int orig_bit_nr = shuffle->shuffle_to_orig(bit_nr); 38 | key.set_bit(orig_bit_nr, value); 39 | } 40 | 41 | void ShuffledKey::flip_bit(int bit_nr) 42 | { 43 | int orig_bit_nr = shuffle->shuffle_to_orig(bit_nr); 44 | key.flip_bit(orig_bit_nr); 45 | } 46 | 47 | int ShuffledKey::compute_range_parity(int start_bit_nr, int end_bit_nr) const 48 | { 49 | int parity = 0; 50 | for (int bit_nr = start_bit_nr; bit_nr <= end_bit_nr; ++bit_nr) { 51 | int orig_bit_nr = shuffle->shuffle_to_orig(bit_nr); 52 | if (key.get_bit(orig_bit_nr)) 53 | parity = 1 - parity; 54 | } 55 | return parity; 56 | } 57 | 58 | ShufflePtr ShuffledKey::get_shuffle() const 59 | { 60 | return shuffle; 61 | } 62 | -------------------------------------------------------------------------------- /cascade/stats.cpp: -------------------------------------------------------------------------------- 1 | #include "stats.h" 2 | 3 | using namespace Cascade; 4 | 5 | Stats::Stats(): 6 | elapsed_process_time(0.0), 7 | elapsed_real_time(0.0), 8 | normal_iterations(0), 9 | biconf_iterations(0), 10 | start_iteration_messages(0), 11 | start_iteration_bits(0), 12 | ask_parity_messages(0), 13 | ask_parity_blocks(0), 14 | ask_parity_bits(0), 15 | reply_parity_bits(0), 16 | reconciliation_bits(0), 17 | efficiency(0.0), 18 | reconciliation_bits_per_key_bit(0.0), 19 | infer_parity_blocks(0) 20 | { 21 | } 22 | -------------------------------------------------------------------------------- /docs/figures/andre-reis-thesis-figure-5-1-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/andre-reis-thesis-figure-5-1-original.png -------------------------------------------------------------------------------- /docs/figures/andre-reis-thesis-figure-5-1-reproduced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/andre-reis-thesis-figure-5-1-reproduced.png -------------------------------------------------------------------------------- /docs/figures/andre-reis-thesis-figure-5-10-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/andre-reis-thesis-figure-5-10-original.png -------------------------------------------------------------------------------- /docs/figures/andre-reis-thesis-figure-5-2-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/andre-reis-thesis-figure-5-2-original.png -------------------------------------------------------------------------------- /docs/figures/andre-reis-thesis-figure-5-2-reproduced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/andre-reis-thesis-figure-5-2-reproduced.png -------------------------------------------------------------------------------- /docs/figures/andre-reis-thesis-figure-5-3-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/andre-reis-thesis-figure-5-3-original.png -------------------------------------------------------------------------------- /docs/figures/andre-reis-thesis-figure-5-3-reproduced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/andre-reis-thesis-figure-5-3-reproduced.png -------------------------------------------------------------------------------- /docs/figures/andre-reis-thesis-figure-5-4-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/andre-reis-thesis-figure-5-4-original.png -------------------------------------------------------------------------------- /docs/figures/andre-reis-thesis-figure-5-5-a-reproduced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/andre-reis-thesis-figure-5-5-a-reproduced.png -------------------------------------------------------------------------------- /docs/figures/andre-reis-thesis-figure-5-5-b-reproduced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/andre-reis-thesis-figure-5-5-b-reproduced.png -------------------------------------------------------------------------------- /docs/figures/andre-reis-thesis-figure-5-5-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/andre-reis-thesis-figure-5-5-original.png -------------------------------------------------------------------------------- /docs/figures/andre-reis-thesis-figure-5-5a-reproduced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/andre-reis-thesis-figure-5-5a-reproduced.png -------------------------------------------------------------------------------- /docs/figures/andre-reis-thesis-figure-5-5b-reproduced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/andre-reis-thesis-figure-5-5b-reproduced.png -------------------------------------------------------------------------------- /docs/figures/andre-reis-thesis-figure-5-6-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/andre-reis-thesis-figure-5-6-original.png -------------------------------------------------------------------------------- /docs/figures/andre-reis-thesis-figure-5-7-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/andre-reis-thesis-figure-5-7-original.png -------------------------------------------------------------------------------- /docs/figures/andre-reis-thesis-figure-5-8-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/andre-reis-thesis-figure-5-8-original.png -------------------------------------------------------------------------------- /docs/figures/andre-reis-thesis-figure-5-9-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/andre-reis-thesis-figure-5-9-original.png -------------------------------------------------------------------------------- /docs/figures/demystifying-figure-1-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/demystifying-figure-1-original.png -------------------------------------------------------------------------------- /docs/figures/demystifying-figure-1-reproduced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/demystifying-figure-1-reproduced.png -------------------------------------------------------------------------------- /docs/figures/demystifying-figure-10-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/demystifying-figure-10-original.png -------------------------------------------------------------------------------- /docs/figures/demystifying-figure-10-reproduced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/demystifying-figure-10-reproduced.png -------------------------------------------------------------------------------- /docs/figures/demystifying-figure-11-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/demystifying-figure-11-original.png -------------------------------------------------------------------------------- /docs/figures/demystifying-figure-11-reproduced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/demystifying-figure-11-reproduced.png -------------------------------------------------------------------------------- /docs/figures/demystifying-figure-11-reproduced.png.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/demystifying-figure-11-reproduced.png.png -------------------------------------------------------------------------------- /docs/figures/demystifying-figure-12-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/demystifying-figure-12-original.png -------------------------------------------------------------------------------- /docs/figures/demystifying-figure-13-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/demystifying-figure-13-original.png -------------------------------------------------------------------------------- /docs/figures/demystifying-figure-13-reproduced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/demystifying-figure-13-reproduced.png -------------------------------------------------------------------------------- /docs/figures/demystifying-figure-2-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/demystifying-figure-2-original.png -------------------------------------------------------------------------------- /docs/figures/demystifying-figure-2-reproduced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/demystifying-figure-2-reproduced.png -------------------------------------------------------------------------------- /docs/figures/demystifying-figure-3-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/demystifying-figure-3-original.png -------------------------------------------------------------------------------- /docs/figures/demystifying-figure-3-reproduced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/demystifying-figure-3-reproduced.png -------------------------------------------------------------------------------- /docs/figures/demystifying-figure-4-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/demystifying-figure-4-original.png -------------------------------------------------------------------------------- /docs/figures/demystifying-figure-4-reproduced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/demystifying-figure-4-reproduced.png -------------------------------------------------------------------------------- /docs/figures/demystifying-figure-5-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/demystifying-figure-5-original.png -------------------------------------------------------------------------------- /docs/figures/demystifying-figure-5-reproduced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/demystifying-figure-5-reproduced.png -------------------------------------------------------------------------------- /docs/figures/demystifying-figure-6-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/demystifying-figure-6-original.png -------------------------------------------------------------------------------- /docs/figures/demystifying-figure-7-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/demystifying-figure-7-original.png -------------------------------------------------------------------------------- /docs/figures/demystifying-figure-8-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/demystifying-figure-8-original.png -------------------------------------------------------------------------------- /docs/figures/demystifying-figure-8-reproduced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/demystifying-figure-8-reproduced.png -------------------------------------------------------------------------------- /docs/figures/demystifying-figure-9-original.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/demystifying-figure-9-original.png -------------------------------------------------------------------------------- /docs/figures/demystifying-figure-9-reproduced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/docs/figures/demystifying-figure-9-reproduced.png -------------------------------------------------------------------------------- /include/algorithm.h: -------------------------------------------------------------------------------- 1 | #ifndef ALGORITHM_H 2 | #define ALGORITHM_H 3 | 4 | #include 5 | #include 6 | 7 | namespace Cascade { 8 | 9 | class Algorithm 10 | { 11 | public: 12 | Algorithm(std::string name, 13 | int nr_cascade_iterations, 14 | int (*block_size_function)(int iteration_nr, double estimated_bit_error_rate, 15 | int key_size), 16 | int nr_biconf_iterations, 17 | bool biconf_error_free_streak, 18 | bool biconf_correct_complement, 19 | bool biconf_cascade, 20 | bool ask_correct_parity_using_shuffle_seed, 21 | bool cache_shuffles); 22 | static Algorithm *get_by_name(std::string name); 23 | static std::vector get_all_algorithm_names(); 24 | std::string name; 25 | int nr_cascade_iterations; 26 | int (*block_size_function)(int iteration_nr, double estimated_bit_error_rate, int key_size); 27 | int nr_biconf_iterations; 28 | bool biconf_error_free_streak; 29 | bool biconf_correct_complement; 30 | bool biconf_cascade; 31 | bool ask_correct_parity_using_shuffle_seed; 32 | bool cache_shuffles; 33 | }; 34 | 35 | } /* namespace Cascade */ 36 | 37 | #endif /* ifndef ALGORITHM_H */ 38 | -------------------------------------------------------------------------------- /include/block.h: -------------------------------------------------------------------------------- 1 | #ifndef BLOCK_H 2 | #define BLOCK_H 3 | 4 | #include 5 | #include 6 | 7 | namespace Cascade { 8 | 9 | class Block; 10 | typedef std::shared_ptr BlockPtr; 11 | 12 | class Iteration; 13 | class ShuffledKey; 14 | 15 | class Block 16 | { 17 | public: 18 | static const int unknown_parity; 19 | Block(Iteration& iteration, int start_bit_nr, int end_bit_nr, Block* parent_block, 20 | int block_nr); 21 | ~Block(); 22 | Iteration& get_iteration() const; 23 | int get_nr_bits() const; 24 | int get_start_bit_nr() const; 25 | int get_end_bit_nr() const; 26 | std::string compute_name() const; 27 | std::string debug_str() const; 28 | int get_correct_parity(); 29 | int get_or_compute_current_parity(); 30 | void flip_current_parity(); 31 | void set_correct_parity(int parity); 32 | bool correct_parity_is_known() const; 33 | bool try_to_infer_correct_parity(); 34 | int get_error_parity(); 35 | Block* get_parent_block() const; 36 | BlockPtr get_left_sub_block() const; 37 | BlockPtr create_left_sub_block(); 38 | BlockPtr get_right_sub_block() const; 39 | BlockPtr create_right_sub_block(); 40 | private: 41 | Iteration& iteration; 42 | ShuffledKey& shuffled_key; 43 | int start_bit_nr; 44 | int end_bit_nr; 45 | int current_parity; 46 | int correct_parity; 47 | Block* parent_block; 48 | int block_nr; 49 | BlockPtr left_sub_block; 50 | BlockPtr right_sub_block; 51 | }; 52 | 53 | } /* namespace Cascade */ 54 | 55 | #endif /* ifndef BLOCK_H */ 56 | -------------------------------------------------------------------------------- /include/classical_session.h: -------------------------------------------------------------------------------- 1 | #ifndef CLASSICAL_SESSION_H 2 | #define CLASSICAL_SESSION_H 3 | 4 | #include "block.h" 5 | #include "pending_item.h" 6 | #include "shuffle.h" 7 | #include 8 | 9 | namespace Cascade { 10 | 11 | class ClassicalSession 12 | { 13 | public: 14 | virtual ~ClassicalSession() = 0; 15 | virtual void start_iteration_with_shuffle_seed(int iteration_nr, uint64_t shuffle_seed) = 0; 16 | virtual void start_iteration_with_shuffle(int iteration_nr, ShufflePtr shuffle) = 0; 17 | virtual void ask_correct_parities(PendingItemQueue& ask_correct_parity_blocks) = 0; 18 | }; 19 | 20 | } /* namespace Cascade */ 21 | 22 | #endif /* ifndef CLASSICAL_SESSION_H */ 23 | -------------------------------------------------------------------------------- /include/debug.h: -------------------------------------------------------------------------------- 1 | #ifndef DEBUG_H 2 | #define DEBUG_H 3 | 4 | #include "report.h" 5 | 6 | namespace Cascade { 7 | 8 | #define ANSI_BLACK "\u001b[30m" 9 | #define ANSI_RED "\u001b[31m" 10 | #define ANSI_GREEN "\u001b[32m" 11 | #define ANSI_BLUE "\u001b[34m" 12 | #define ANSI_RESET "\u001b[0m" 13 | 14 | #ifdef ENABLE_DEBUG 15 | #include 16 | #define DEBUG(msg) REPORT(msg) 17 | #else 18 | #define DEBUG(msg) 19 | #endif 20 | 21 | } /* namespace Cascade */ 22 | 23 | #endif /* ifndef DEBUG_H */ 24 | -------------------------------------------------------------------------------- /include/iteration.h: -------------------------------------------------------------------------------- 1 | #ifndef ITERATION_H 2 | #define ITERATION_H 3 | 4 | #include "block.h" 5 | #include "key.h" 6 | #include "shuffle.h" 7 | #include "shuffled_key.h" 8 | #include 9 | #include 10 | 11 | namespace Cascade { 12 | 13 | class Reconciliation; 14 | 15 | class Iteration 16 | { 17 | public: 18 | Iteration(Reconciliation& reconciliation, int iteration_nr, bool biconf); 19 | static ShufflePtr init_shuffle(Reconciliation& reconciliation, int iteration_nr); 20 | ~Iteration(); 21 | Reconciliation& get_reconciliation() const; 22 | int get_iteration_nr() const; 23 | bool get_biconf() const; 24 | ShufflePtr get_shuffle() const; 25 | ShuffledKey& get_shuffled_key(); 26 | void schedule_initial_work(); 27 | int try_correct_block(BlockPtr block, bool correct_right_sibling, bool cascade); 28 | BlockPtr get_cascade_block(int orig_key_bit_nr) const; 29 | void flip_parity_in_all_blocks_containing_bit(int orig_key_bit_nr); 30 | private: 31 | void schedule_initial_work_cascade(); 32 | void schedule_initial_work_biconf(); 33 | int try_correct_right_sibling_block(BlockPtr block, bool cascade); 34 | Reconciliation& reconciliation; 35 | int iteration_nr; 36 | bool biconf; 37 | int nr_key_bits; 38 | ShufflePtr shuffle; 39 | ShuffledKey shuffled_key; 40 | int block_size; 41 | std::vector top_blocks; 42 | }; 43 | 44 | typedef std::shared_ptr IterationPtr; 45 | 46 | } /* namespace Cascade */ 47 | 48 | #endif /* ifndef ITERATION_H */ 49 | -------------------------------------------------------------------------------- /include/key.h: -------------------------------------------------------------------------------- 1 | #ifndef KEY_H 2 | #define KEY_H 3 | 4 | #include 5 | #include 6 | 7 | namespace Cascade { 8 | 9 | class Key 10 | { 11 | public: 12 | Key(int nr_bits); 13 | Key(const Key& key); 14 | ~Key(); 15 | std::string to_string() const; 16 | int get_nr_bits() const; 17 | int get_bit(int bit_nr) const; 18 | void set_bit(int bit_nr, int value); 19 | void flip_bit(int bit_nr); 20 | void apply_noise(double bit_error_rate); 21 | int compute_range_parity(int start_bit_nr, int end_bit_nr) const; 22 | int nr_bits_different(const Key& other_key) const; 23 | private: 24 | int nr_bits; 25 | int nr_words; 26 | uint64_t *words; 27 | }; 28 | 29 | typedef std::shared_ptr KeyPtr; 30 | 31 | } /* namespace Cascade */ 32 | 33 | #endif /* ifndef KEY_H */ 34 | -------------------------------------------------------------------------------- /include/mock_classical_session.h: -------------------------------------------------------------------------------- 1 | #ifndef MOCK_CLASSICAL_SESSION_H 2 | #define MOCK_CLASSICAL_SESSION_H 3 | 4 | #include "classical_session.h" 5 | #include "shuffled_key.h" 6 | #include 7 | 8 | namespace Cascade { 9 | 10 | class MockClassicalSession : public ClassicalSession 11 | { 12 | public: 13 | MockClassicalSession(Key& correct_key, bool cache_shuffles); 14 | virtual ~MockClassicalSession(); 15 | virtual void start_iteration_with_shuffle_seed(int iteration_nr, uint64_t shuffle_seed); 16 | virtual void start_iteration_with_shuffle(int iteration_nr, ShufflePtr shuffle); 17 | virtual void ask_correct_parities(PendingItemQueue& ask_correct_parity_blocks); 18 | private: 19 | Key& correct_key; 20 | bool cache_shuffles; 21 | std::map shuffled_keys; 22 | }; 23 | 24 | } /* namespace Cascade */ 25 | 26 | #endif /* ifndef MOCK_CLASSICAL_SESSION_H */ 27 | -------------------------------------------------------------------------------- /include/pending_item.h: -------------------------------------------------------------------------------- 1 | #ifndef PENDING_ITEM_H 2 | #define PENDING_ITEM_H 3 | 4 | #include "block.h" 5 | #include 6 | 7 | namespace Cascade { 8 | 9 | class PendingItem { 10 | public: 11 | PendingItem(BlockPtr block, bool correct_right_sibling); 12 | BlockPtr block; 13 | bool correct_right_sibling; 14 | }; 15 | 16 | typedef std::deque PendingItemQueue; 17 | 18 | } /* namespace Cascade */ 19 | 20 | #endif /* ifndef PENDING_ITEM_H */ 21 | -------------------------------------------------------------------------------- /include/random.h: -------------------------------------------------------------------------------- 1 | #ifndef RANDOM_H 2 | #define RANDOM_H 3 | 4 | #include 5 | 6 | namespace Cascade { 7 | 8 | void set_random_uint32_seed(uint32_t seed); 9 | uint32_t random_uint32(); 10 | int random_bit_nr(int start_bit_nr, int end_bit_nr); 11 | 12 | } /* namespace Cascade */ 13 | 14 | #endif /* ifndef RANDOM_H */ 15 | -------------------------------------------------------------------------------- /include/reconciliation.h: -------------------------------------------------------------------------------- 1 | #ifndef RECONCILIATION_H 2 | #define RECONCILIATION_H 3 | 4 | #include "key.h" 5 | #include "iteration.h" 6 | #include "pending_item.h" 7 | #include "stats.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace Cascade { 14 | 15 | class Algorithm; 16 | class ClassicalSession; 17 | 18 | class Reconciliation 19 | { 20 | public: 21 | Reconciliation(const Algorithm& algorithm, 22 | ClassicalSession& classical_session, 23 | const Key& noisy_key, 24 | double estimated_bit_error_rate, 25 | const Key* correct_key = NULL); 26 | ~Reconciliation(); 27 | const Algorithm& get_algorithm() const; 28 | double get_estimated_bit_error_rate() const; 29 | Key& get_reconciled_key(); 30 | const Key* get_correct_key() const; 31 | int get_nr_key_bits() const; 32 | Stats& get_stats(); 33 | void reconcile(); 34 | void schedule_try_correct(BlockPtr block, bool correct_right_sibling); 35 | void schedule_ask_correct_parity(BlockPtr block, bool correct_right_sibling); 36 | void correct_orig_key_bit(int orig_key_bit_nr, int triggering_iteration_nr, bool cascade); 37 | private: 38 | int service_all_pending_work(bool cascade); 39 | int service_pending_try_correct(bool cascade); 40 | void service_pending_ask_correct_parity(); 41 | double compute_efficiency(long reconciliation_bits) const; 42 | void cascade_effect(int orig_key_bit_nr, int triggering_iteration_nr); 43 | void all_normal_cascade_iterations(); 44 | void all_biconf_iterations(); 45 | void start_iteration_common(int iteration_nr, bool biconf); 46 | const Algorithm& algorithm; 47 | ClassicalSession& classical_session; 48 | double estimated_bit_error_rate; 49 | Key reconciled_key; 50 | const Key *correct_key; // For debugging only 51 | int nr_key_bits; 52 | std::vector iterations; 53 | PendingItemQueue pending_ask_correct_parity_blocks; 54 | PendingItemQueue pending_try_correct_blocks; 55 | Stats stats; 56 | }; 57 | 58 | } /* namespace Cascade */ 59 | 60 | #endif /* ifndef RECONCILIATION_H */ 61 | -------------------------------------------------------------------------------- /include/report.h: -------------------------------------------------------------------------------- 1 | #ifndef REPORT_H 2 | #define REPORT_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | extern std::mutex report_mutex; 9 | 10 | #define REPORT(msg) \ 11 | do { \ 12 | std::lock_guard guard(report_mutex); \ 13 | std::cerr << msg << std::endl; \ 14 | } while (false) 15 | 16 | #endif /* ifndef REPORT_H */ 17 | -------------------------------------------------------------------------------- /include/shuffle.h: -------------------------------------------------------------------------------- 1 | #ifndef SHUFFLE_H 2 | #define SHUFFLE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace Cascade { 10 | 11 | class Shuffle; 12 | 13 | typedef std::shared_ptr ShufflePtr; 14 | 15 | class Shuffle 16 | { 17 | public: 18 | static ShufflePtr new_random_shuffle(int iteration_nr, int nr_bits, bool assign_seed, 19 | bool cache); 20 | static ShufflePtr new_shuffle_from_seed(int iteration_nr, int nr_bits, uint64_t seed, 21 | bool); 22 | ~Shuffle(); 23 | uint64_t get_seed() const; 24 | int get_nr_bits() const; 25 | int orig_to_shuffle(int orig_bit_nr) const; 26 | int shuffle_to_orig(int shuffle_bit_nr) const; 27 | private: 28 | Shuffle(int iteration_nr, int nr_bits, bool assign_seed); 29 | Shuffle(int iteration_nr, int nr_bits, uint64_t seed); 30 | void initialize(bool assign_seed); 31 | static ShufflePtr cache_search(int iteration_nr, int nr_bits, bool has_seed); 32 | static void cache_add(ShufflePtr shuffle); 33 | int iteration_nr; 34 | int nr_bits; 35 | bool has_seed; 36 | uint64_t seed; 37 | typedef std::vector BitMap; 38 | BitMap shuffled_to_orig_map; 39 | BitMap orig_to_shuffled_map; 40 | }; 41 | 42 | } /* namespace Cascade */ 43 | 44 | #endif /* ifndef SHUFFLE_H */ 45 | -------------------------------------------------------------------------------- /include/shuffled_key.h: -------------------------------------------------------------------------------- 1 | #ifndef SHUFFLED_KEY_H 2 | #define SHUFFLED_KEY_H 3 | 4 | #include 5 | #include 6 | #include "shuffle.h" 7 | 8 | namespace Cascade { 9 | 10 | class Key; 11 | 12 | class ShuffledKey 13 | { 14 | public: 15 | ShuffledKey(Key& key, ShufflePtr shuffle); 16 | std::string to_string() const; 17 | int get_nr_bits() const; 18 | int get_bit(int bit_nr) const; 19 | void set_bit(int bit_nr, int value); 20 | void flip_bit(int bit_nr); 21 | int compute_range_parity(int start_bit_nr, int end_bit_nr) const; 22 | ShufflePtr get_shuffle() const; 23 | private: 24 | Key& key; 25 | ShufflePtr shuffle; 26 | }; 27 | 28 | typedef std::shared_ptr ShuffledKeyPtr; 29 | 30 | } /* namespace Cascade */ 31 | 32 | #endif /* ifndef SHUFFLED_KEY_H */ 33 | -------------------------------------------------------------------------------- /include/stats.h: -------------------------------------------------------------------------------- 1 | #ifndef STATS_H 2 | #define STATS_H 3 | 4 | namespace Cascade { 5 | 6 | class Stats 7 | { 8 | public: 9 | Stats(); 10 | double elapsed_process_time; 11 | double elapsed_real_time; 12 | long normal_iterations; 13 | long biconf_iterations; 14 | long start_iteration_messages; 15 | long start_iteration_bits; 16 | long ask_parity_messages; 17 | long ask_parity_blocks; 18 | long ask_parity_bits; 19 | long reply_parity_bits; 20 | long reconciliation_bits; 21 | double efficiency; 22 | double reconciliation_bits_per_key_bit; 23 | long infer_parity_blocks; // Only simple inference; not yet Full Block Parity Inference (BPI) 24 | 25 | }; 26 | 27 | } /* namespace Cascade */ 28 | 29 | #endif /* ifndef STATS_H */ 30 | -------------------------------------------------------------------------------- /src/block.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunorijsman/cascade-cpp/8240cab83831408ae7092c0aed96a76c5d641578/src/block.cpp -------------------------------------------------------------------------------- /study/aggregate_stats.cpp: -------------------------------------------------------------------------------- 1 | #include "aggregate_stats.h" 2 | #include 3 | #include 4 | 5 | AggregateStats::AggregateStats(): 6 | count(0), 7 | sum(0.0), 8 | square_sum(0.0) 9 | { 10 | } 11 | 12 | void AggregateStats::record_value(double value) 13 | { 14 | count += 1; 15 | sum += value; 16 | square_sum += value * value; 17 | } 18 | 19 | double AggregateStats::average() const 20 | { 21 | if (count == 0) 22 | return std::numeric_limits::quiet_NaN(); 23 | return sum / count; 24 | } 25 | 26 | double AggregateStats::deviation() const 27 | { 28 | // Compute the corrected standard deviation. 29 | // See https://en.wikipedia.org/wiki/Bessel%27s_correction. 30 | if (count < 2) 31 | return std::numeric_limits::quiet_NaN(); 32 | double variance = square_sum / (count - 1); 33 | variance -= (sum * sum) / ((count - 1) * count); 34 | // Variance can up being some vary small negative number due to rounding errors 35 | if (variance <= 0.0) 36 | variance = 0.0; 37 | double deviation = sqrt(variance); 38 | return deviation; 39 | } 40 | 41 | std::string AggregateStats::to_json() const 42 | { 43 | std::string json = "{"; 44 | double avg = average(); 45 | std::string avg_str; 46 | if (std::isnan(avg)) 47 | avg_str = "NaN"; // Python program to produce graphs insists on capital N's 48 | else 49 | avg_str = std::to_string(avg); 50 | json += "\"average\": " + avg_str + ", "; 51 | double dev = deviation(); 52 | std::string dev_str; 53 | if (std::isnan(dev)) 54 | dev_str = "NaN"; // Python program to produce graphs insists on capital N's 55 | else 56 | dev_str = std::to_string(dev); 57 | json += "\"deviation\": " + dev_str; 58 | json += "}"; 59 | return json; 60 | } 61 | -------------------------------------------------------------------------------- /study/aggregate_stats.h: -------------------------------------------------------------------------------- 1 | #ifndef AGGREGATE_STATS_H 2 | #define AGGREGATE_STATS_H 3 | 4 | #include 5 | 6 | class AggregateStats 7 | { 8 | public: 9 | AggregateStats(); 10 | void record_value(double value); 11 | double average() const; 12 | double deviation() const; 13 | std::string to_json() const; 14 | private: 15 | long count; 16 | double sum; 17 | double square_sum; 18 | }; 19 | 20 | #endif /* ifndef AGGREGATE_STATS_H */ 21 | -------------------------------------------------------------------------------- /study/data/debug/data__algorithm=biconf-cascade;key_size=vary;error_rate=0.1: -------------------------------------------------------------------------------- 1 | {"actual_bit_error_rate": {"average": 0.100000, "deviation": NaN}, "actual_bit_errors": {"average": 5.000000, "deviation": NaN}, "algorithm_name": "biconf-cascade", "ask_parity_bits": {"average": 2960.000000, "deviation": NaN}, "ask_parity_blocks": {"average": 37.000000, "deviation": NaN}, "ask_parity_messages": {"average": 33.000000, "deviation": NaN}, "biconf_iterations": {"average": 10.000000, "deviation": NaN}, "elapsed_process_time": {"average": 0.010446, "deviation": NaN}, "elapsed_real_time": {"average": 0.010441, "deviation": NaN}, "execution_time": "2020-03-31 17:46:48 UTC", "infer_parity_blocks": {"average": 12.000000, "deviation": NaN}, "key_size": 50, "normal_iterations": {"average": 2.000000, "deviation": NaN}, "reconciliation_bits_per_key_bit": {"average": 127.805039, "deviation": NaN}, "reconciliations": 1, "remaining_bit_error_rate": {"average": 0.000000, "deviation": NaN}, "remaining_bit_errors": {"average": 0.000000, "deviation": NaN}, "remaining_frame_error_rate": {"average": 0.000000, "deviation": NaN}, "reply_parity_bits": {"average": 37.000000, "deviation": NaN}, "requested_bit_error_rate": 0.100000, "efficiency": {"average": 1.577840, "deviation": NaN}} 2 | -------------------------------------------------------------------------------- /study/data/performance/data__algorithm=biconf;key_size=10000;error_rate=vary: -------------------------------------------------------------------------------- 1 | {"actual_bit_error_rate": {"average": 0.000000, "deviation": 0.000000}, "actual_bit_errors": {"average": 0.000000, "deviation": 0.000000}, "algorithm_name": "biconf", "ask_parity_bits": {"average": 1952.000000, "deviation": 0.000000}, "ask_parity_blocks": {"average": 22.000000, "deviation": 0.000000}, "ask_parity_messages": {"average": 12.000000, "deviation": 0.000000}, "biconf_iterations": {"average": 10.000000, "deviation": 0.000000}, "elapsed_process_time": {"average": 0.001632, "deviation": 0.000091}, "elapsed_real_time": {"average": 0.001634, "deviation": 0.000091}, "execution_time": "2025-02-21 00:56:01 UTC", "infer_parity_blocks": {"average": 0.000000, "deviation": 0.000000}, "key_size": 10000, "normal_iterations": {"average": 2.000000, "deviation": 0.000000}, "reconciliation_bits": {"average": 3318.000000, "deviation": 0.000000}, "reconciliation_bits_per_key_bit": {"average": 0.331800, "deviation": 0.000000}, "reconciliations": 10, "remaining_bit_error_rate": {"average": 0.000000, "deviation": 0.000000}, "remaining_bit_errors": {"average": 0.000000, "deviation": 0.000000}, "remaining_frame_error_rate": {"average": 0.000000, "deviation": 0.000000}, "reply_parity_bits": {"average": 214.000000, "deviation": 0.000000}, "requested_bit_error_rate": 0.000000, "efficiency": {"average": NaN, "deviation": NaN}} 2 | {"actual_bit_error_rate": {"average": 0.005090, "deviation": 0.000373}, "actual_bit_errors": {"average": 50.900000, "deviation": 3.725289}, "algorithm_name": "biconf", "ask_parity_bits": {"average": 73465.600000, "deviation": 2656.997938}, "ask_parity_blocks": {"average": 896.200000, "deviation": 27.631705}, "ask_parity_messages": {"average": 110.600000, "deviation": 42.690618}, "biconf_iterations": {"average": 13.500000, "deviation": 4.143268}, "elapsed_process_time": {"average": 0.003374, "deviation": 0.001217}, "elapsed_real_time": {"average": 0.003374, "deviation": 0.001217}, "execution_time": "2025-02-21 00:56:01 UTC", "infer_parity_blocks": {"average": 380.800000, "deviation": 10.358035}, "key_size": 10000, "normal_iterations": {"average": 2.000000, "deviation": 0.000000}, "reconciliation_bits": {"average": 77619.400000, "deviation": 3575.097643}, "reconciliation_bits_per_key_bit": {"average": 7.761940, "deviation": 0.357510}, "reconciliations": 10, "remaining_bit_error_rate": {"average": 0.000000, "deviation": 0.000000}, "remaining_bit_errors": {"average": 0.000000, "deviation": 0.000000}, "remaining_frame_error_rate": {"average": 0.000000, "deviation": 0.000000}, "reply_parity_bits": {"average": 2665.800000, "deviation": 699.037402}, "requested_bit_error_rate": 0.010000, "efficiency": {"average": 1.109253, "deviation": 0.034201}} 3 | {"actual_bit_error_rate": {"average": 0.010180, "deviation": 0.000808}, "actual_bit_errors": {"average": 101.800000, "deviation": 8.080154}, "algorithm_name": "biconf", "ask_parity_bits": {"average": 123296.000000, "deviation": 1138.988245}, "ask_parity_blocks": {"average": 1521.700000, "deviation": 14.181757}, "ask_parity_messages": {"average": 97.500000, "deviation": 19.207927}, "biconf_iterations": {"average": 10.700000, "deviation": 1.636392}, "elapsed_process_time": {"average": 0.002956, "deviation": 0.000336}, "elapsed_real_time": {"average": 0.002956, "deviation": 0.000336}, "execution_time": "2025-02-21 00:56:01 UTC", "infer_parity_blocks": {"average": 651.100000, "deviation": 18.064391}, "key_size": 10000, "normal_iterations": {"average": 2.000000, "deviation": 0.000000}, "reconciliation_bits": {"average": 127596.900000, "deviation": 1351.046956}, "reconciliation_bits_per_key_bit": {"average": 12.759690, "deviation": 0.135105}, "reconciliations": 10, "remaining_bit_error_rate": {"average": 0.000000, "deviation": 0.000000}, "remaining_bit_errors": {"average": 0.000000, "deviation": 0.000000}, "remaining_frame_error_rate": {"average": 0.000000, "deviation": 0.000000}, "reply_parity_bits": {"average": 3081.700000, "deviation": 305.935741}, "requested_bit_error_rate": 0.020000, "efficiency": {"average": 1.075858, "deviation": 0.010027}} 4 | {"actual_bit_error_rate": {"average": 0.024780, "deviation": 0.001017}, "actual_bit_errors": {"average": 247.800000, "deviation": 10.174041}, "algorithm_name": "biconf", "ask_parity_bits": {"average": 250355.200000, "deviation": 1232.653218}, "ask_parity_blocks": {"average": 3109.800000, "deviation": 14.687863}, "ask_parity_messages": {"average": 98.200000, "deviation": 22.714655}, "biconf_iterations": {"average": 10.500000, "deviation": 0.849837}, "elapsed_process_time": {"average": 0.004045, "deviation": 0.000149}, "elapsed_real_time": {"average": 0.004045, "deviation": 0.000150}, "execution_time": "2025-02-21 00:56:01 UTC", "infer_parity_blocks": {"average": 1319.900000, "deviation": 20.261896}, "key_size": 10000, "normal_iterations": {"average": 2.000000, "deviation": 0.000000}, "reconciliation_bits": {"average": 256236.200000, "deviation": 1443.061776}, "reconciliation_bits_per_key_bit": {"average": 25.623620, "deviation": 0.144306}, "reconciliations": 10, "remaining_bit_error_rate": {"average": 0.000000, "deviation": 0.000000}, "remaining_bit_errors": {"average": 0.000000, "deviation": 0.000000}, "remaining_frame_error_rate": {"average": 0.000000, "deviation": 0.000000}, "reply_parity_bits": {"average": 4681.000000, "deviation": 363.845511}, "requested_bit_error_rate": 0.050000, "efficiency": {"average": 1.085836, "deviation": 0.005128}} 5 | {"actual_bit_error_rate": {"average": 0.049810, "deviation": 0.001504}, "actual_bit_errors": {"average": 498.100000, "deviation": 15.044010}, "algorithm_name": "biconf", "ask_parity_bits": {"average": 420622.400000, "deviation": 7576.474278}, "ask_parity_blocks": {"average": 5228.300000, "deviation": 86.292848}, "ask_parity_messages": {"average": 147.400000, "deviation": 50.938307}, "biconf_iterations": {"average": 17.800000, "deviation": 7.757434}, "elapsed_process_time": {"average": 0.007185, "deviation": 0.001782}, "elapsed_real_time": {"average": 0.007185, "deviation": 0.001782}, "execution_time": "2025-02-21 00:56:01 UTC", "infer_parity_blocks": {"average": 2148.100000, "deviation": 46.808000}, "key_size": 10000, "normal_iterations": {"average": 2.000000, "deviation": 0.000000}, "reconciliation_bits": {"average": 430109.900000, "deviation": 9066.101397}, "reconciliation_bits_per_key_bit": {"average": 43.010990, "deviation": 0.906610}, "reconciliations": 10, "remaining_bit_error_rate": {"average": 0.000000, "deviation": 0.000000}, "remaining_bit_errors": {"average": 0.000000, "deviation": 0.000000}, "remaining_frame_error_rate": {"average": 0.000000, "deviation": 0.000000}, "reply_parity_bits": {"average": 7586.700000, "deviation": 886.120766}, "requested_bit_error_rate": 0.100000, "efficiency": {"average": 1.114787, "deviation": 0.018400}} 6 | -------------------------------------------------------------------------------- /study/data/performance/data__algorithm=option7;key_size=10000;error_rate=vary: -------------------------------------------------------------------------------- 1 | {"actual_bit_error_rate": {"average": 0.000000, "deviation": 0.000000}, "actual_bit_errors": {"average": 0.000000, "deviation": 0.000000}, "algorithm_name": "option7", "ask_parity_bits": {"average": 2304.000000, "deviation": 0.000000}, "ask_parity_blocks": {"average": 26.000000, "deviation": 0.000000}, "ask_parity_messages": {"average": 14.000000, "deviation": 0.000000}, "biconf_iterations": {"average": 0.000000, "deviation": 0.000000}, "elapsed_process_time": {"average": 0.001834, "deviation": 0.000031}, "elapsed_real_time": {"average": 0.001850, "deviation": 0.000050}, "execution_time": "2025-02-21 00:56:01 UTC", "infer_parity_blocks": {"average": 0.000000, "deviation": 0.000000}, "key_size": 10000, "normal_iterations": {"average": 14.000000, "deviation": 0.000000}, "reconciliation_bits": {"average": 3898.000000, "deviation": 0.000000}, "reconciliation_bits_per_key_bit": {"average": 0.389800, "deviation": 0.000000}, "reconciliations": 10, "remaining_bit_error_rate": {"average": 0.000000, "deviation": 0.000000}, "remaining_bit_errors": {"average": 0.000000, "deviation": 0.000000}, "remaining_frame_error_rate": {"average": 0.000000, "deviation": 0.000000}, "reply_parity_bits": {"average": 250.000000, "deviation": 0.000000}, "requested_bit_error_rate": 0.000000, "efficiency": {"average": NaN, "deviation": NaN}} 2 | {"actual_bit_error_rate": {"average": 0.004980, "deviation": 0.000336}, "actual_bit_errors": {"average": 49.800000, "deviation": 3.359894}, "algorithm_name": "option7", "ask_parity_bits": {"average": 75236.800000, "deviation": 4312.157820}, "ask_parity_blocks": {"average": 909.700000, "deviation": 53.985698}, "ask_parity_messages": {"average": 153.800000, "deviation": 47.191807}, "biconf_iterations": {"average": 0.000000, "deviation": 0.000000}, "elapsed_process_time": {"average": 0.003099, "deviation": 0.000439}, "elapsed_real_time": {"average": 0.003117, "deviation": 0.000455}, "execution_time": "2025-02-21 00:56:01 UTC", "infer_parity_blocks": {"average": 400.200000, "deviation": 25.917819}, "key_size": 10000, "normal_iterations": {"average": 14.000000, "deviation": 0.000000}, "reconciliation_bits": {"average": 79951.300000, "deviation": 4486.722809}, "reconciliation_bits_per_key_bit": {"average": 7.995130, "deviation": 0.448672}, "reconciliations": 10, "remaining_bit_error_rate": {"average": 0.000000, "deviation": 0.000000}, "remaining_bit_errors": {"average": 0.000000, "deviation": 0.000000}, "remaining_frame_error_rate": {"average": 0.000000, "deviation": 0.000000}, "reply_parity_bits": {"average": 3370.500000, "deviation": 751.794039}, "requested_bit_error_rate": 0.010000, "efficiency": {"average": 1.125962, "deviation": 0.066820}} 3 | {"actual_bit_error_rate": {"average": 0.009990, "deviation": 0.000463}, "actual_bit_errors": {"average": 99.900000, "deviation": 4.629615}, "algorithm_name": "option7", "ask_parity_bits": {"average": 127387.200000, "deviation": 6202.728805}, "ask_parity_blocks": {"average": 1557.000000, "deviation": 75.592475}, "ask_parity_messages": {"average": 176.700000, "deviation": 33.806804}, "biconf_iterations": {"average": 0.000000, "deviation": 0.000000}, "elapsed_process_time": {"average": 0.003678, "deviation": 0.000536}, "elapsed_real_time": {"average": 0.003684, "deviation": 0.000552}, "execution_time": "2025-02-21 00:56:01 UTC", "infer_parity_blocks": {"average": 696.500000, "deviation": 50.553052}, "key_size": 10000, "normal_iterations": {"average": 14.000000, "deviation": 0.000000}, "reconciliation_bits": {"average": 133115.400000, "deviation": 6474.726064}, "reconciliation_bits_per_key_bit": {"average": 13.311540, "deviation": 0.647473}, "reconciliations": 10, "remaining_bit_error_rate": {"average": 0.000000, "deviation": 0.000000}, "remaining_bit_errors": {"average": 0.000000, "deviation": 0.000000}, "remaining_frame_error_rate": {"average": 0.000000, "deviation": 0.000000}, "reply_parity_bits": {"average": 4384.200000, "deviation": 564.291257}, "requested_bit_error_rate": 0.020000, "efficiency": {"average": 1.100816, "deviation": 0.053445}} 4 | {"actual_bit_error_rate": {"average": 0.025080, "deviation": 0.001348}, "actual_bit_errors": {"average": 250.800000, "deviation": 13.480851}, "algorithm_name": "option7", "ask_parity_bits": {"average": 257875.200000, "deviation": 10341.226886}, "ask_parity_blocks": {"average": 3144.300000, "deviation": 139.123486}, "ask_parity_messages": {"average": 395.700000, "deviation": 138.993245}, "biconf_iterations": {"average": 0.000000, "deviation": 0.000000}, "elapsed_process_time": {"average": 0.004909, "deviation": 0.000438}, "elapsed_real_time": {"average": 0.004922, "deviation": 0.000439}, "execution_time": "2025-02-21 00:56:01 UTC", "infer_parity_blocks": {"average": 1428.900000, "deviation": 49.124445}, "key_size": 10000, "normal_iterations": {"average": 14.000000, "deviation": 0.000000}, "reconciliation_bits": {"average": 268694.700000, "deviation": 10122.666173}, "reconciliation_bits_per_key_bit": {"average": 26.869470, "deviation": 1.012267}, "reconciliations": 10, "remaining_bit_error_rate": {"average": 0.000000, "deviation": 0.000000}, "remaining_bit_errors": {"average": 0.000000, "deviation": 0.000000}, "remaining_frame_error_rate": {"average": 0.000000, "deviation": 0.000000}, "reply_parity_bits": {"average": 9475.500000, "deviation": 2166.001860}, "requested_bit_error_rate": 0.050000, "efficiency": {"average": 1.097882, "deviation": 0.048577}} 5 | {"actual_bit_error_rate": {"average": 0.050670, "deviation": 0.001981}, "actual_bit_errors": {"average": 506.700000, "deviation": 19.810491}, "algorithm_name": "option7", "ask_parity_bits": {"average": 425764.800000, "deviation": 10313.508518}, "ask_parity_blocks": {"average": 5257.400000, "deviation": 123.911438}, "ask_parity_messages": {"average": 323.300000, "deviation": 63.270232}, "biconf_iterations": {"average": 0.000000, "deviation": 0.000000}, "elapsed_process_time": {"average": 0.005701, "deviation": 0.001392}, "elapsed_real_time": {"average": 0.005701, "deviation": 0.001392}, "execution_time": "2025-02-21 00:56:01 UTC", "infer_parity_blocks": {"average": 2375.200000, "deviation": 50.148225}, "key_size": 10000, "normal_iterations": {"average": 14.000000, "deviation": 0.000000}, "reconciliation_bits": {"average": 437539.000000, "deviation": 10916.481830}, "reconciliation_bits_per_key_bit": {"average": 43.753900, "deviation": 1.091648}, "reconciliations": 10, "remaining_bit_error_rate": {"average": 0.000000, "deviation": 0.000000}, "remaining_bit_errors": {"average": 0.000000, "deviation": 0.000000}, "remaining_frame_error_rate": {"average": 0.000000, "deviation": 0.000000}, "reply_parity_bits": {"average": 10430.200000, "deviation": 1062.367879}, "requested_bit_error_rate": 0.100000, "efficiency": {"average": 1.120991, "deviation": 0.026421}} 6 | -------------------------------------------------------------------------------- /study/data/performance/data__algorithm=original;key_size=10000;error_rate=vary: -------------------------------------------------------------------------------- 1 | {"actual_bit_error_rate": {"average": 0.000000, "deviation": 0.000000}, "actual_bit_errors": {"average": 0.000000, "deviation": 0.000000}, "algorithm_name": "original", "ask_parity_bits": {"average": 384.000000, "deviation": 0.000000}, "ask_parity_blocks": {"average": 4.000000, "deviation": 0.000000}, "ask_parity_messages": {"average": 4.000000, "deviation": 0.000000}, "biconf_iterations": {"average": 0.000000, "deviation": 0.000000}, "elapsed_process_time": {"average": 0.000535, "deviation": 0.000159}, "elapsed_real_time": {"average": 0.000535, "deviation": 0.000159}, "execution_time": "2025-02-21 00:56:01 UTC", "infer_parity_blocks": {"average": 0.000000, "deviation": 0.000000}, "key_size": 10000, "normal_iterations": {"average": 4.000000, "deviation": 0.000000}, "reconciliation_bits": {"average": 836.000000, "deviation": 0.000000}, "reconciliation_bits_per_key_bit": {"average": 0.083600, "deviation": 0.000000}, "reconciliations": 10, "remaining_bit_error_rate": {"average": 0.000000, "deviation": 0.000000}, "remaining_bit_errors": {"average": 0.000000, "deviation": 0.000000}, "remaining_frame_error_rate": {"average": 0.000000, "deviation": 0.000000}, "reply_parity_bits": {"average": 68.000000, "deviation": 0.000000}, "requested_bit_error_rate": 0.000000, "efficiency": {"average": NaN, "deviation": NaN}} 2 | {"actual_bit_error_rate": {"average": 0.005030, "deviation": 0.000447}, "actual_bit_errors": {"average": 50.300000, "deviation": 4.473378}, "algorithm_name": "original", "ask_parity_bits": {"average": 74230.400000, "deviation": 661.986774}, "ask_parity_blocks": {"average": 920.200000, "deviation": 7.885289}, "ask_parity_messages": {"average": 38.400000, "deviation": 6.003703}, "biconf_iterations": {"average": 0.000000, "deviation": 0.000000}, "elapsed_process_time": {"average": 0.001292, "deviation": 0.000044}, "elapsed_real_time": {"average": 0.001292, "deviation": 0.000044}, "execution_time": "2025-02-21 00:56:01 UTC", "infer_parity_blocks": {"average": 353.700000, "deviation": 18.797458}, "key_size": 10000, "normal_iterations": {"average": 4.000000, "deviation": 0.000000}, "reconciliation_bits": {"average": 76149.000000, "deviation": 712.570776}, "reconciliation_bits_per_key_bit": {"average": 7.614900, "deviation": 0.071257}, "reconciliations": 10, "remaining_bit_error_rate": {"average": 0.000000, "deviation": 0.000000}, "remaining_bit_errors": {"average": 0.000000, "deviation": 0.000000}, "remaining_frame_error_rate": {"average": 0.000000, "deviation": 0.000000}, "reply_parity_bits": {"average": 1534.600000, "deviation": 98.375923}, "requested_bit_error_rate": 0.010000, "efficiency": {"average": 1.138958, "deviation": 0.009760}} 3 | {"actual_bit_error_rate": {"average": 0.009930, "deviation": 0.000790}, "actual_bit_errors": {"average": 99.300000, "deviation": 7.902883}, "algorithm_name": "original", "ask_parity_bits": {"average": 131774.400000, "deviation": 891.463117}, "ask_parity_blocks": {"average": 1638.800000, "deviation": 10.952422}, "ask_parity_messages": {"average": 41.900000, "deviation": 8.171087}, "biconf_iterations": {"average": 0.000000, "deviation": 0.000000}, "elapsed_process_time": {"average": 0.001836, "deviation": 0.000080}, "elapsed_real_time": {"average": 0.001838, "deviation": 0.000077}, "execution_time": "2025-02-21 00:56:01 UTC", "infer_parity_blocks": {"average": 618.000000, "deviation": 15.797327}, "key_size": 10000, "normal_iterations": {"average": 4.000000, "deviation": 0.000000}, "reconciliation_bits": {"average": 134467.600000, "deviation": 935.650718}, "reconciliation_bits_per_key_bit": {"average": 13.446760, "deviation": 0.093565}, "reconciliations": 10, "remaining_bit_error_rate": {"average": 0.000000, "deviation": 0.000000}, "remaining_bit_errors": {"average": 0.000000, "deviation": 0.000000}, "remaining_frame_error_rate": {"average": 0.000000, "deviation": 0.000000}, "reply_parity_bits": {"average": 2309.200000, "deviation": 131.666076}, "requested_bit_error_rate": 0.020000, "efficiency": {"average": 1.158649, "deviation": 0.007743}} 4 | {"actual_bit_error_rate": {"average": 0.025000, "deviation": 0.000807}, "actual_bit_errors": {"average": 250.000000, "deviation": 8.069146}, "algorithm_name": "original", "ask_parity_bits": {"average": 272790.400000, "deviation": 1442.490686}, "ask_parity_blocks": {"average": 3401.000000, "deviation": 18.123036}, "ask_parity_messages": {"average": 44.400000, "deviation": 8.181279}, "biconf_iterations": {"average": 0.000000, "deviation": 0.000000}, "elapsed_process_time": {"average": 0.002844, "deviation": 0.000268}, "elapsed_real_time": {"average": 0.002844, "deviation": 0.000268}, "execution_time": "2025-02-21 00:56:01 UTC", "infer_parity_blocks": {"average": 1139.300000, "deviation": 25.232475}, "key_size": 10000, "normal_iterations": {"average": 4.000000, "deviation": 0.000000}, "reconciliation_bits": {"average": 277285.800000, "deviation": 1464.822082}, "reconciliation_bits_per_key_bit": {"average": 27.728580, "deviation": 0.146482}, "reconciliations": 10, "remaining_bit_error_rate": {"average": 0.000000, "deviation": 0.000000}, "remaining_bit_errors": {"average": 0.000000, "deviation": 0.000000}, "remaining_frame_error_rate": {"average": 0.000000, "deviation": 0.000000}, "reply_parity_bits": {"average": 4111.400000, "deviation": 130.320289}, "requested_bit_error_rate": 0.050000, "efficiency": {"average": 1.187513, "deviation": 0.006328}} 5 | {"actual_bit_error_rate": {"average": 0.050510, "deviation": 0.001596}, "actual_bit_errors": {"average": 505.100000, "deviation": 15.961412}, "algorithm_name": "original", "ask_parity_bits": {"average": 453667.200000, "deviation": 1470.720217}, "ask_parity_blocks": {"average": 5663.200000, "deviation": 18.201343}, "ask_parity_messages": {"average": 38.200000, "deviation": 6.390966}, "biconf_iterations": {"average": 0.000000, "deviation": 0.000000}, "elapsed_process_time": {"average": 0.004199, "deviation": 0.000288}, "elapsed_real_time": {"average": 0.004200, "deviation": 0.000288}, "execution_time": "2025-02-21 00:56:01 UTC", "infer_parity_blocks": {"average": 1689.200000, "deviation": 19.685302}, "key_size": 10000, "normal_iterations": {"average": 4.000000, "deviation": 0.000000}, "reconciliation_bits": {"average": 460325.600000, "deviation": 1510.246573}, "reconciliation_bits_per_key_bit": {"average": 46.032560, "deviation": 0.151025}, "reconciliations": 10, "remaining_bit_error_rate": {"average": 0.000000, "deviation": 0.000000}, "remaining_bit_errors": {"average": 0.000000, "deviation": 0.000000}, "remaining_frame_error_rate": {"average": 0.000000, "deviation": 0.000000}, "reply_parity_bits": {"average": 6274.400000, "deviation": 105.789308}, "requested_bit_error_rate": 0.100000, "efficiency": {"average": 1.207517, "deviation": 0.003881}} 6 | -------------------------------------------------------------------------------- /study/data/performance/data__algorithm=yanetal;key_size=10000;error_rate=vary: -------------------------------------------------------------------------------- 1 | {"actual_bit_error_rate": {"average": 0.000000, "deviation": 0.000000}, "actual_bit_errors": {"average": 0.000000, "deviation": 0.000000}, "algorithm_name": "yanetal", "ask_parity_bits": {"average": 1600.000000, "deviation": 0.000000}, "ask_parity_blocks": {"average": 18.000000, "deviation": 0.000000}, "ask_parity_messages": {"average": 10.000000, "deviation": 0.000000}, "biconf_iterations": {"average": 0.000000, "deviation": 0.000000}, "elapsed_process_time": {"average": 0.001393, "deviation": 0.000292}, "elapsed_real_time": {"average": 0.001391, "deviation": 0.000292}, "execution_time": "2025-02-21 00:56:01 UTC", "infer_parity_blocks": {"average": 0.000000, "deviation": 0.000000}, "key_size": 10000, "normal_iterations": {"average": 10.000000, "deviation": 0.000000}, "reconciliation_bits": {"average": 2738.000000, "deviation": 0.000000}, "reconciliation_bits_per_key_bit": {"average": 0.273800, "deviation": 0.000000}, "reconciliations": 10, "remaining_bit_error_rate": {"average": 0.000000, "deviation": 0.000000}, "remaining_bit_errors": {"average": 0.000000, "deviation": 0.000000}, "remaining_frame_error_rate": {"average": 0.000000, "deviation": 0.000000}, "reply_parity_bits": {"average": 178.000000, "deviation": 0.000000}, "requested_bit_error_rate": 0.000000, "efficiency": {"average": NaN, "deviation": NaN}} 2 | {"actual_bit_error_rate": {"average": 0.004670, "deviation": 0.000544}, "actual_bit_errors": {"average": 46.700000, "deviation": 5.437524}, "algorithm_name": "yanetal", "ask_parity_bits": {"average": 71478.400000, "deviation": 2069.157381}, "ask_parity_blocks": {"average": 874.900000, "deviation": 24.964197}, "ask_parity_messages": {"average": 92.900000, "deviation": 21.465476}, "biconf_iterations": {"average": 0.000000, "deviation": 0.000000}, "elapsed_process_time": {"average": 0.002326, "deviation": 0.000269}, "elapsed_real_time": {"average": 0.002330, "deviation": 0.000271}, "execution_time": "2025-02-21 00:56:01 UTC", "infer_parity_blocks": {"average": 388.300000, "deviation": 18.251636}, "key_size": 10000, "normal_iterations": {"average": 10.000000, "deviation": 0.000000}, "reconciliation_bits": {"average": 74799.700000, "deviation": 2216.956375}, "reconciliation_bits_per_key_bit": {"average": 7.479970, "deviation": 0.221696}, "reconciliations": 10, "remaining_bit_error_rate": {"average": 0.000000, "deviation": 0.000000}, "remaining_bit_errors": {"average": 0.000000, "deviation": 0.000000}, "remaining_frame_error_rate": {"average": 0.000000, "deviation": 0.000000}, "reply_parity_bits": {"average": 2361.300000, "deviation": 347.513725}, "requested_bit_error_rate": 0.010000, "efficiency": {"average": 1.082889, "deviation": 0.030899}} 3 | {"actual_bit_error_rate": {"average": 0.009920, "deviation": 0.000764}, "actual_bit_errors": {"average": 99.200000, "deviation": 7.641989}, "algorithm_name": "yanetal", "ask_parity_bits": {"average": 125273.600000, "deviation": 3017.565877}, "ask_parity_blocks": {"average": 1543.500000, "deviation": 33.123506}, "ask_parity_messages": {"average": 112.100000, "deviation": 27.738661}, "biconf_iterations": {"average": 0.000000, "deviation": 0.000000}, "elapsed_process_time": {"average": 0.002862, "deviation": 0.000239}, "elapsed_real_time": {"average": 0.002862, "deviation": 0.000239}, "execution_time": "2025-02-21 00:56:01 UTC", "infer_parity_blocks": {"average": 675.900000, "deviation": 18.235801}, "key_size": 10000, "normal_iterations": {"average": 10.000000, "deviation": 0.000000}, "reconciliation_bits": {"average": 129570.700000, "deviation": 3436.176106}, "reconciliation_bits_per_key_bit": {"average": 12.957070, "deviation": 0.343618}, "reconciliations": 10, "remaining_bit_error_rate": {"average": 0.000000, "deviation": 0.000000}, "remaining_bit_errors": {"average": 0.000000, "deviation": 0.000000}, "remaining_frame_error_rate": {"average": 0.000000, "deviation": 0.000000}, "reply_parity_bits": {"average": 3337.100000, "deviation": 470.805563}, "requested_bit_error_rate": 0.020000, "efficiency": {"average": 1.091271, "deviation": 0.023419}} 4 | {"actual_bit_error_rate": {"average": 0.024740, "deviation": 0.001006}, "actual_bit_errors": {"average": 247.400000, "deviation": 10.057612}, "algorithm_name": "yanetal", "ask_parity_bits": {"average": 246609.600000, "deviation": 2770.156642}, "ask_parity_blocks": {"average": 3060.700000, "deviation": 30.066778}, "ask_parity_messages": {"average": 109.600000, "deviation": 34.849518}, "biconf_iterations": {"average": 0.000000, "deviation": 0.000000}, "elapsed_process_time": {"average": 0.003691, "deviation": 0.000139}, "elapsed_real_time": {"average": 0.003692, "deviation": 0.000139}, "execution_time": "2025-02-21 00:56:01 UTC", "infer_parity_blocks": {"average": 1213.200000, "deviation": 33.485652}, "key_size": 10000, "normal_iterations": {"average": 10.000000, "deviation": 0.000000}, "reconciliation_bits": {"average": 252383.900000, "deviation": 3220.040112}, "reconciliation_bits_per_key_bit": {"average": 25.238390, "deviation": 0.322004}, "reconciliations": 10, "remaining_bit_error_rate": {"average": 0.000000, "deviation": 0.000000}, "remaining_bit_errors": {"average": 0.000000, "deviation": 0.000000}, "remaining_frame_error_rate": {"average": 0.000000, "deviation": 0.000000}, "reply_parity_bits": {"average": 4814.300000, "deviation": 575.784692}, "requested_bit_error_rate": 0.050000, "efficiency": {"average": 1.068692, "deviation": 0.010498}} 5 | {"actual_bit_error_rate": {"average": 0.050070, "deviation": 0.001970}, "actual_bit_errors": {"average": 500.700000, "deviation": 19.697998}, "algorithm_name": "yanetal", "ask_parity_bits": {"average": 410502.400000, "deviation": 3269.008793}, "ask_parity_blocks": {"average": 5109.700000, "deviation": 39.299562}, "ask_parity_messages": {"average": 107.900000, "deviation": 25.330921}, "biconf_iterations": {"average": 0.000000, "deviation": 0.000000}, "elapsed_process_time": {"average": 0.005118, "deviation": 0.000468}, "elapsed_real_time": {"average": 0.005118, "deviation": 0.000468}, "execution_time": "2025-02-21 00:56:01 UTC", "infer_parity_blocks": {"average": 1929.800000, "deviation": 42.946478}, "key_size": 10000, "normal_iterations": {"average": 10.000000, "deviation": 0.000000}, "reconciliation_bits": {"average": 418298.500000, "deviation": 3475.837653}, "reconciliation_bits_per_key_bit": {"average": 41.829850, "deviation": 0.347584}, "reconciliations": 10, "remaining_bit_error_rate": {"average": 0.000000, "deviation": 0.000000}, "remaining_bit_errors": {"average": 0.000000, "deviation": 0.000000}, "remaining_frame_error_rate": {"average": 0.000000, "deviation": 0.000000}, "reply_parity_bits": {"average": 6836.100000, "deviation": 416.867805}, "requested_bit_error_rate": 0.100000, "efficiency": {"average": 1.089499, "deviation": 0.008380}} 6 | -------------------------------------------------------------------------------- /study/data_point.cpp: -------------------------------------------------------------------------------- 1 | #include "data_point.h" 2 | #include "stats.h" 3 | #include 4 | #include 5 | #include 6 | 7 | DataPoint::DataPoint(const std::string& algorithm_name, int key_size, 8 | double requested_bit_error_rate): 9 | algorithm_name(algorithm_name), 10 | key_size(key_size), 11 | requested_bit_error_rate(requested_bit_error_rate), 12 | reconciliations(0) 13 | { 14 | } 15 | 16 | void DataPoint::record_reconciliation_stats(const Cascade::Stats& stats) 17 | { 18 | reconciliations += 1; 19 | elapsed_process_time.record_value(stats.elapsed_process_time); 20 | elapsed_real_time.record_value(stats.elapsed_real_time); 21 | normal_iterations.record_value(stats.normal_iterations); 22 | biconf_iterations.record_value(stats.biconf_iterations); 23 | ask_parity_messages.record_value(stats.ask_parity_messages); 24 | ask_parity_blocks.record_value(stats.ask_parity_blocks); 25 | ask_parity_bits.record_value(stats.ask_parity_bits); 26 | reply_parity_bits.record_value(stats.reply_parity_bits); 27 | // Don't record efficiency NaN values. This happens when the bit error rate is zero. 28 | if (!std::isnan(stats.efficiency)) { 29 | efficiency.record_value(stats.efficiency); 30 | } 31 | reconciliation_bits.record_value(stats.reconciliation_bits); 32 | reconciliation_bits_per_key_bit.record_value(stats.reconciliation_bits_per_key_bit); 33 | infer_parity_blocks.record_value(stats.infer_parity_blocks); 34 | } 35 | 36 | std::string DataPoint::to_json() const 37 | { 38 | std::string json = "{"; 39 | 40 | auto t = std::time(nullptr); 41 | auto tm = *std::localtime(&t); 42 | std::stringstream now_str; 43 | now_str << std::put_time(&tm, "%Y-%m-%d %H:%M:%S %Z"); 44 | 45 | json += "\"actual_bit_error_rate\": " + actual_bit_error_rate.to_json() + ", "; 46 | json += "\"actual_bit_errors\": " + actual_bit_errors.to_json() + ", "; 47 | json += "\"algorithm_name\": \"" + algorithm_name + "\", "; 48 | json += "\"ask_parity_bits\": " + ask_parity_bits.to_json() + ", "; 49 | json += "\"ask_parity_blocks\": " + ask_parity_blocks.to_json() + ", "; 50 | json += "\"ask_parity_messages\": " + ask_parity_messages.to_json() + ", "; 51 | json += "\"biconf_iterations\": " + biconf_iterations.to_json() + ", "; 52 | json += "\"elapsed_process_time\": " + elapsed_process_time.to_json() + ", "; 53 | json += "\"elapsed_real_time\": " + elapsed_real_time.to_json() + ", "; 54 | json += "\"execution_time\": \"" + now_str.str() + "\", "; 55 | json += "\"infer_parity_blocks\": " + infer_parity_blocks.to_json() + ", "; 56 | json += "\"key_size\": " + std::to_string(key_size) + ", "; 57 | json += "\"normal_iterations\": " + normal_iterations.to_json() + ", "; 58 | json += "\"reconciliation_bits\": " + reconciliation_bits.to_json() + ", "; 59 | json += "\"reconciliation_bits_per_key_bit\": " + reconciliation_bits_per_key_bit.to_json() + ", "; 60 | json += "\"reconciliations\": " + std::to_string(reconciliations) + ", "; 61 | json += "\"remaining_bit_error_rate\": " + remaining_bit_error_rate.to_json() + ", "; 62 | json += "\"remaining_bit_errors\": " + remaining_bit_errors.to_json() + ", "; 63 | json += "\"remaining_frame_error_rate\": " + remaining_frame_error_rate.to_json() + ", "; 64 | json += "\"reply_parity_bits\": " + reply_parity_bits.to_json() + ", "; 65 | json += "\"requested_bit_error_rate\": " + std::to_string(requested_bit_error_rate) + ", "; 66 | json += "\"efficiency\": " + efficiency.to_json(); 67 | json += "}"; 68 | return json; 69 | } 70 | -------------------------------------------------------------------------------- /study/data_point.h: -------------------------------------------------------------------------------- 1 | #ifndef DATA_POINT_H 2 | #define DATA_POINT_H 3 | 4 | #include "aggregate_stats.h" 5 | #include 6 | 7 | namespace Cascade { 8 | class Stats; 9 | } 10 | 11 | class DataPoint 12 | { 13 | public: 14 | DataPoint(const std::string& algorithm_name, int key_size, double requested_bit_error_rate); 15 | void record_reconciliation_stats(const Cascade::Stats& stats); 16 | std::string to_json() const; 17 | std::string algorithm_name; 18 | int key_size; 19 | double requested_bit_error_rate; 20 | long reconciliations; 21 | AggregateStats actual_bit_errors; 22 | AggregateStats actual_bit_error_rate; 23 | AggregateStats elapsed_process_time; 24 | AggregateStats elapsed_real_time; 25 | AggregateStats normal_iterations; 26 | AggregateStats biconf_iterations; 27 | AggregateStats ask_parity_messages; 28 | AggregateStats ask_parity_blocks; 29 | AggregateStats ask_parity_bits; 30 | AggregateStats reply_parity_bits; 31 | AggregateStats efficiency; 32 | AggregateStats reconciliation_bits; 33 | AggregateStats reconciliation_bits_per_key_bit; 34 | AggregateStats infer_parity_blocks; 35 | AggregateStats remaining_bit_errors; 36 | AggregateStats remaining_bit_error_rate; 37 | AggregateStats remaining_frame_error_rate; 38 | }; 39 | 40 | #endif /* ifndef DATA_POINT_H */ 41 | -------------------------------------------------------------------------------- /study/experiments.cpp: -------------------------------------------------------------------------------- 1 | #include "experiments.h" 2 | 3 | #include 4 | #include 5 | 6 | // This code for parsing for the experiments json file is not robust. We just did the bare minimum 7 | // to be able to correctly parse the same json files that cascade-python is using. 8 | 9 | Experiments::Experiments(std::string file_name) 10 | { 11 | pt::ptree root; 12 | pt::read_json(file_name, root); 13 | for (auto iter = root.begin(); iter != root.end(); iter++) { 14 | pt::ptree tree = iter->second; 15 | Experiment experiment; 16 | experiment.independent_variable = tree.get("independent_variable"); 17 | experiment.runs = tree.get("runs"); 18 | experiment.algorithms = parse_strings_attrib(tree, "algorithm"); 19 | experiment.key_sizes = parse_scalars_attrib(tree, "key_size"); 20 | experiment.error_rates = parse_scalars_attrib(tree, "error_rate"); 21 | experiments.push_back(experiment); 22 | } 23 | } 24 | 25 | std::vector Experiments::parse_strings_attrib(pt::ptree& tree, std::string attribute) 26 | { 27 | assert (tree.count(attribute) == 1); 28 | std::vector values; 29 | 30 | // Try parsing as a list of strings. 31 | auto sub_tree = tree.get_child(attribute); 32 | for (auto it = sub_tree.begin(); it != sub_tree.end(); ++it) { 33 | std::string value = it->second.get_value(); 34 | values.push_back(value); 35 | } 36 | if (!values.empty()) { 37 | return values; 38 | } 39 | 40 | // If attribute is a scalar value, return a list with that value only. 41 | try { 42 | std::string value = tree.get(attribute); 43 | values.push_back(value); 44 | return values; 45 | } 46 | catch (boost::exception const&) { 47 | } 48 | 49 | assert(false); 50 | } 51 | 52 | std::vector Experiments::parse_scalars_attrib(pt::ptree& tree, std::string attribute) 53 | { 54 | assert (tree.count(attribute) == 1); 55 | auto sub_tree = tree.get_child(attribute); 56 | return parse_scalars_tree(sub_tree); 57 | } 58 | 59 | std::vector Experiments::parse_scalars_tree(pt::ptree& tree) 60 | { 61 | std::vector values; 62 | 63 | // If sub-tree is a scalar value, return a list with that value only. 64 | try { 65 | double value = tree.get_value(); 66 | values.push_back(value); 67 | return values; 68 | } 69 | catch (boost::exception const&) { } 70 | 71 | // Try parsing it as a {start, end, step_size} or {start, end, step_factor} range. 72 | if (tree.count("start") != 0) { 73 | double start = tree.get("start"); 74 | double end = tree.get("end"); 75 | if (tree.count("step_size") != 0) { 76 | // Parse as {start, end, step_size} 77 | double step_size = tree.get("step_size"); 78 | double value = start; 79 | while (value < end) { 80 | values.push_back(value); 81 | value += step_size; 82 | } 83 | return values; 84 | } else if (tree.count("step_factor") != 0) { 85 | // Parse as {start, end, step_factor} 86 | double step_factor = tree.get("step_factor"); 87 | double value = start; 88 | while (value < end) { 89 | values.push_back(value); 90 | value *= step_factor; 91 | } 92 | return values; 93 | } else { 94 | std::cerr << "expected step_size or step_factor" << std::endl; 95 | exit(1); 96 | } 97 | } 98 | 99 | // Try recursively parsing it as a list of any of the above. 100 | for (auto it = tree.begin(); it != tree.end(); ++it) { 101 | auto more_values = parse_scalars_tree(it->second); 102 | values.insert(values.end(), more_values.begin(), more_values.end()); 103 | } 104 | return values; 105 | } 106 | -------------------------------------------------------------------------------- /study/experiments.h: -------------------------------------------------------------------------------- 1 | #ifndef EXPERIMENTS_H 2 | #define EXPERIMENTS_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace pt = boost::property_tree; 9 | 10 | class Experiment 11 | { 12 | public: 13 | std::string independent_variable; 14 | int runs; 15 | std::vector algorithms; 16 | std::vector key_sizes; 17 | std::vector error_rates; 18 | }; 19 | 20 | class Experiments 21 | { 22 | public: 23 | Experiments(std::string file_name); 24 | std::vector experiments; 25 | private: 26 | std::vector parse_strings_attrib(pt::ptree& tree, std::string attribute); 27 | std::vector parse_scalars_attrib(pt::ptree& tree, std::string attribute); 28 | std::vector parse_scalars_tree(pt::ptree& tree); 29 | }; 30 | 31 | #endif /* ifndef EXPERIMENTS_H */ 32 | -------------------------------------------------------------------------------- /study/experiments_debug.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "independent_variable": "key_size", 4 | "algorithm": "biconf-cascade", 5 | "error_rate": 0.1, 6 | "key_size": 50, 7 | "runs": 1 8 | } 9 | ] 10 | -------------------------------------------------------------------------------- /study/experiments_papers.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "independent_variable": "error_rate", 4 | "algorithm": ["original", "biconf", "yanetal", "option3", "option4", "option7", "option8"], 5 | "error_rate": [ 6 | {"start": 0.0000, "end": 0.0050, "step_size": 0.00005}, 7 | {"start": 0.0050, "end": 0.1100, "step_size": 0.00050} 8 | ], 9 | "key_size": [1000, 2000, 10000], 10 | "runs": 10000 11 | }, 12 | { 13 | "independent_variable": "key_size", 14 | "algorithm": ["original", "biconf", "yanetal", "option3", "option4", "option7", "option8"], 15 | "error_rate": 0.05, 16 | "key_size": { 17 | "start": 1e3, 18 | "end": 1e5, 19 | "step_factor": 1.05 20 | }, 21 | "runs": 10000 22 | }, 23 | { 24 | "independent_variable": "key_size", 25 | "algorithm": "original", 26 | "error_rate": [0.01, 0.02], 27 | "key_size": { 28 | "start": 1e3, 29 | "end": 1e5, 30 | "step_factor": 1.05 31 | }, 32 | "runs": 10000 33 | } 34 | ] 35 | -------------------------------------------------------------------------------- /study/experiments_performance.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "independent_variable": "error_rate", 4 | "algorithm": ["original", "yanetal", "biconf", "option7"], 5 | "error_rate": [0.00, 0.01, 0.02, 0.05, 0.10], 6 | "key_size": 10000, 7 | "runs": 10 8 | }, 9 | { 10 | "independent_variable": "key_size", 11 | "algorithm": ["original", "yanetal", "biconf", "option7"], 12 | "error_rate": 0.02, 13 | "key_size": { 14 | "start": 1e3, 15 | "end": 1e5, 16 | "step_factor": 1.3 17 | }, 18 | "runs": 10 19 | } 20 | ] 21 | -------------------------------------------------------------------------------- /study/experiments_profile.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "independent_variable": "key_size", 4 | "algorithm": ["original", "yanetal", "biconf", "option7"], 5 | "error_rate": 0.02, 6 | "key_size": [1000, 10000], 7 | "runs": 10 8 | } 9 | ] 10 | -------------------------------------------------------------------------------- /study/experiments_zero_handling.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "independent_variable": "error_rate", 4 | "algorithm": ["original", "biconf"], 5 | "error_rate": [ 6 | {"start": 0.000, "end": 0.005, "step_size": 0.00005}, 7 | {"start": 0.005, "end": 0.050, "step_size": 0.00050} 8 | ], 9 | "key_size": 10000, 10 | "runs": 100 11 | } 12 | ] 13 | -------------------------------------------------------------------------------- /study/graphs_andre_reis_thesis.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "graph_name": "andre_reis_thesis_figure_5_1", 4 | "title": "Figure 5.1 from \"Andre Reis Thesis\"", 5 | "x_axis": { 6 | "title": "error rate", 7 | "variable": "requested_bit_error_rate", 8 | "range": [0.00, 0.10] 9 | }, 10 | "y_axis": { 11 | "title": "avg eff", 12 | "variable": "efficiency", 13 | "range": [1.00, 1.50] 14 | }, 15 | "series": [ 16 | { 17 | "data_file": "data__algorithm=yanetal;key_size=10000;error_rate=vary", 18 | "legend": "yanetal", 19 | "line_color": "blue", 20 | "deviation_color": "none" 21 | }, 22 | { 23 | "data_file": "data__algorithm=original;key_size=10000;error_rate=vary", 24 | "legend": "original", 25 | "line_color": "orange", 26 | "deviation_color": "none" 27 | }, 28 | { 29 | "data_file": "data__algorithm=biconf;key_size=10000;error_rate=vary", 30 | "legend": "biconf", 31 | "line_color": "green", 32 | "deviation_color": "none" 33 | }, 34 | { 35 | "data_file": "data__algorithm=option7;key_size=10000;error_rate=vary", 36 | "legend": "option7", 37 | "line_color": "red", 38 | "deviation_color": "none" 39 | }, 40 | { 41 | "data_file": "data__algorithm=option8;key_size=10000;error_rate=vary", 42 | "legend": "option8", 43 | "line_color": "purple", 44 | "deviation_color": "none" 45 | } 46 | ] 47 | }, 48 | { 49 | "graph_name": "andre_reis_thesis_figure_5_2", 50 | "title": "Figure 5.2 from \"Andre Reis Thesis\"", 51 | "x_axis": { 52 | "title": "error rate", 53 | "variable": "requested_bit_error_rate", 54 | "range": [0.0, 0.10] 55 | }, 56 | "y_axis": { 57 | "title": "fer", 58 | "variable": "remaining_frame_error_rate", 59 | "range": [0.00, 0.005] 60 | }, 61 | "series": [ 62 | { 63 | "data_file": "data__algorithm=yanetal;key_size=10000;error_rate=vary", 64 | "legend": "yanetal", 65 | "line_color": "blue", 66 | "deviation_color": "none" 67 | }, 68 | { 69 | "data_file": "data__algorithm=original;key_size=10000;error_rate=vary", 70 | "legend": "original", 71 | "line_color": "orange", 72 | "deviation_color": "none" 73 | }, 74 | { 75 | "data_file": "data__algorithm=biconf;key_size=10000;error_rate=vary", 76 | "legend": "biconf", 77 | "line_color": "green", 78 | "deviation_color": "none" 79 | }, 80 | { 81 | "data_file": "data__algorithm=option7;key_size=10000;error_rate=vary", 82 | "legend": "option7", 83 | "line_color": "red", 84 | "deviation_color": "none" 85 | }, 86 | { 87 | "data_file": "data__algorithm=option8;key_size=10000;error_rate=vary", 88 | "legend": "option8", 89 | "line_color": "purple", 90 | "deviation_color": "none" 91 | } 92 | ] 93 | }, 94 | { 95 | "graph_name": "andre_reis_thesis_figure_5_3", 96 | "title": "Figure 5.3 from \"Andre Reis Thesis\"", 97 | "x_axis": { 98 | "title": "error rate", 99 | "variable": "requested_bit_error_rate", 100 | "range": [0.0, 0.10] 101 | }, 102 | "y_axis": { 103 | "title": "avg cu", 104 | "variable": "ask_parity_messages" 105 | }, 106 | "series": [ 107 | { 108 | "data_file": "data__algorithm=yanetal;key_size=10000;error_rate=vary", 109 | "legend": "yanetal", 110 | "line_color": "blue", 111 | "deviation_color": "none" 112 | }, 113 | { 114 | "data_file": "data__algorithm=original;key_size=10000;error_rate=vary", 115 | "legend": "original", 116 | "line_color": "orange", 117 | "deviation_color": "none" 118 | }, 119 | { 120 | "data_file": "data__algorithm=biconf;key_size=10000;error_rate=vary", 121 | "legend": "biconf", 122 | "line_color": "green", 123 | "deviation_color": "none" 124 | } 125 | ] 126 | }, 127 | { 128 | "graph_name": "andre_reis_thesis_figure_5_5a", 129 | "title": "Figure 5.5a from \"Andre Reis Thesis\"", 130 | "x_axis": { 131 | "title": "key length", 132 | "variable": "key_size", 133 | "range": [0, 100000] 134 | }, 135 | "y_axis": { 136 | "title": "avg eff", 137 | "variable": "efficiency", 138 | "range": [1.00, 1.50] 139 | }, 140 | "series": [ 141 | { 142 | "data_file": "data__algorithm=yanetal;key_size=vary;error_rate=0.05", 143 | "legend": "yanetal", 144 | "mode": "lines+markers", 145 | "marker": { 146 | "symbol": "circle" 147 | }, 148 | "line_color": "blue", 149 | "deviation_color": "none" 150 | }, 151 | { 152 | "data_file": "data__algorithm=original;key_size=vary;error_rate=0.05", 153 | "legend": "original", 154 | "mode": "lines+markers", 155 | "marker": { 156 | "symbol": "square" 157 | }, 158 | "line_color": "orange", 159 | "deviation_color": "none" 160 | }, 161 | { 162 | "data_file": "data__algorithm=biconf;key_size=vary;error_rate=0.05", 163 | "legend": "biconf", 164 | "mode": "lines+markers", 165 | "marker": { 166 | "symbol": "diamond" 167 | }, 168 | "line_color": "green", 169 | "deviation_color": "none" 170 | }, 171 | { 172 | "data_file": "data__algorithm=option7;key_size=vary;error_rate=0.05", 173 | "legend": "option7", 174 | "mode": "lines+markers", 175 | "marker": { 176 | "symbol": "cross" 177 | }, 178 | "line_color": "red", 179 | "deviation_color": "none" 180 | }, 181 | { 182 | "data_file": "data__algorithm=option8;key_size=vary;error_rate=0.05", 183 | "legend": "option8", 184 | "mode": "lines+markers", 185 | "marker": { 186 | "symbol": "triangle-up" 187 | }, 188 | "line_color": "purple", 189 | "deviation_color": "none" 190 | } 191 | ] 192 | }, 193 | { 194 | "graph_name": "andre_reis_thesis_figure_5_5b", 195 | "title": "Figure 5.5b from \"Andre Reis Thesis\"", 196 | "x_axis": { 197 | "title": "key length", 198 | "variable": "key_size", 199 | "range": [0, 100000] 200 | }, 201 | "y_axis": { 202 | "title": "avg cu", 203 | "variable": "ask_parity_messages" 204 | }, 205 | "series": [ 206 | { 207 | "data_file": "data__algorithm=yanetal;key_size=vary;error_rate=0.05", 208 | "legend": "yanetal", 209 | "mode": "lines+markers", 210 | "marker": { 211 | "symbol": "circle" 212 | }, 213 | "line_color": "blue", 214 | "deviation_color": "none" 215 | }, 216 | { 217 | "data_file": "data__algorithm=original;key_size=vary;error_rate=0.05", 218 | "legend": "original", 219 | "mode": "lines+markers", 220 | "marker": { 221 | "symbol": "square" 222 | }, 223 | "line_color": "orange", 224 | "deviation_color": "none" 225 | }, 226 | { 227 | "data_file": "data__algorithm=biconf;key_size=vary;error_rate=0.05", 228 | "legend": "biconf", 229 | "mode": "lines+markers", 230 | "marker": { 231 | "symbol": "diamond" 232 | }, 233 | "line_color": "green", 234 | "deviation_color": "none" 235 | } 236 | ] 237 | } 238 | ] -------------------------------------------------------------------------------- /study/graphs_demystifying.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "graph_name": "demystifying_figure_1", 4 | "title": "Figure 1 from \"Demystifying the Information Reconciliation Protocol Cascade\"", 5 | "x_axis": { 6 | "title": "Quantum Bit Error Rate (QBER)", 7 | "variable": "requested_bit_error_rate" 8 | }, 9 | "y_axis": { 10 | "title": "Reconciliation efficiency", 11 | "variable": "efficiency", 12 | "range": [1.0, 1.3] 13 | }, 14 | "series": [ 15 | { 16 | "data_file": "data__algorithm=original;key_size=10000;error_rate=vary", 17 | "legend": "Cascade orig.", 18 | "line_color": "black", 19 | "deviation_color": "lightgray" 20 | }, 21 | { 22 | "data_file": "data__algorithm=biconf;key_size=10000;error_rate=vary", 23 | "legend": "Cascade mod. (1)", 24 | "line_color": "blue", 25 | "deviation_color": "lightblue" 26 | } 27 | ] 28 | }, 29 | { 30 | "graph_name": "demystifying_figure_2", 31 | "title": "Figure 2 from \"Demystifying the Information Reconciliation Protocol Cascade\"", 32 | "x_axis": { 33 | "title": "Quantum Bit Error Rate (QBER)", 34 | "variable": "requested_bit_error_rate" 35 | }, 36 | "y_axis": { 37 | "title": "Channel uses", 38 | "variable": "ask_parity_messages" 39 | }, 40 | "series": [ 41 | { 42 | "data_file": "data__algorithm=original;key_size=10000;error_rate=vary", 43 | "legend": "Cascade orig.", 44 | "line_color": "black", 45 | "deviation_color": "lightgray" 46 | }, 47 | { 48 | "data_file": "data__algorithm=biconf;key_size=10000;error_rate=vary", 49 | "legend": "Cascade mod. (1)", 50 | "line_color": "blue", 51 | "deviation_color": "lightblue" 52 | } 53 | ] 54 | }, 55 | { 56 | "graph_name": "demystifying_figure_3", 57 | "title": "Figure 3 from \"Demystifying the Information Reconciliation Protocol Cascade\"", 58 | "x_axis": { 59 | "title": "Key Size", 60 | "type": "log", 61 | "variable": "key_size" 62 | }, 63 | "y_axis": { 64 | "title": "Channel uses", 65 | "type": "log", 66 | "variable": "ask_parity_messages" 67 | }, 68 | "series": [ 69 | { 70 | "data_file": "data__algorithm=original;key_size=vary;error_rate=0.01", 71 | "legend": "Q=1%", 72 | "line_color": "red", 73 | "deviation_color": "none" 74 | }, 75 | { 76 | "data_file": "data__algorithm=original;key_size=vary;error_rate=0.02", 77 | "legend": "Q=2%", 78 | "line_color": "green", 79 | "deviation_color": "none" 80 | }, 81 | { 82 | "data_file": "data__algorithm=original;key_size=vary;error_rate=0.05", 83 | "legend": "Q=5%", 84 | "line_color": "blue", 85 | "deviation_color": "none" 86 | } 87 | ] 88 | }, 89 | { 90 | "graph_name": "demystifying_figure_4", 91 | "title": "Figure 4 from \"Demystifying the Information Reconciliation Protocol Cascade\"", 92 | "x_axis": { 93 | "title": "Quantum Bit Error Rate (QBER)", 94 | "variable": "requested_bit_error_rate", 95 | "range": [0.0, 0.11] 96 | }, 97 | "y_axis": { 98 | "title": "Frame error rate", 99 | "type": "log", 100 | "variable": "remaining_frame_error_rate", 101 | "range": [-6.0, 0.0] 102 | }, 103 | "series": [ 104 | { 105 | "data_file": "data__algorithm=original;key_size=1000;error_rate=vary", 106 | "legend": "original key_size=1,000", 107 | "mode": "lines+markers", 108 | "marker": { 109 | "symbol": "square" 110 | }, 111 | "line_color": "black", 112 | "deviation_color": "none", 113 | "filter": { 114 | "variable": "remaining_frame_error_rate", 115 | "min_value": 1e-8 116 | } 117 | }, 118 | { 119 | "data_file": "data__algorithm=original;key_size=10000;error_rate=vary", 120 | "legend": "original key_size=10,000", 121 | "mode": "lines+markers", 122 | "marker": { 123 | "symbol": "circle" 124 | }, 125 | "dash": "dot", 126 | "line_color": "black", 127 | "deviation_color": "none", 128 | "filter": { 129 | "variable": "remaining_frame_error_rate", 130 | "min_value": 1e-8 131 | } 132 | }, 133 | { 134 | "data_file": "data__algorithm=biconf;key_size=1000;error_rate=vary", 135 | "legend": "biconf key_size=1,000", 136 | "mode": "lines+markers", 137 | "marker": { 138 | "symbol": "triangle-up" 139 | }, 140 | "line_color": "blue", 141 | "deviation_color": "none", 142 | "filter": { 143 | "variable": "remaining_frame_error_rate", 144 | "min_value": 1e-8 145 | } 146 | }, 147 | { 148 | "data_file": "data__algorithm=biconf;key_size=10000;error_rate=vary", 149 | "legend": "biconf key_size=10,000", 150 | "mode": "lines+markers", 151 | "marker": { 152 | "symbol": "triangle-down" 153 | }, 154 | "dash": "dot", 155 | "line_color": "blue", 156 | "deviation_color": "none", 157 | "filter": { 158 | "variable": "remaining_frame_error_rate", 159 | "min_value": 1e-8 160 | } 161 | } 162 | ] 163 | }, 164 | { 165 | "graph_name": "demystifying_figure_5", 166 | "title": "Figure 5 from \"Demystifying the Information Reconciliation Protocol Cascade\"", 167 | "x_axis": { 168 | "title": "Quantum Bit Error Rate (QBER)", 169 | "variable": "requested_bit_error_rate", 170 | "range": [0.0, 0.11] 171 | }, 172 | "y_axis": { 173 | "title": "Bit error rate", 174 | "type": "log", 175 | "variable": "remaining_bit_error_rate", 176 | "range": [-10.0, -2.0] 177 | }, 178 | "series": [ 179 | { 180 | "data_file": "data__algorithm=original;key_size=1000;error_rate=vary", 181 | "legend": "original key_size=1,000", 182 | "mode": "lines+markers", 183 | "marker": { 184 | "symbol": "square" 185 | }, 186 | "line_color": "black", 187 | "deviation_color": "none", 188 | "filter": { 189 | "variable": "remaining_bit_error_rate", 190 | "min_value": 1e-11 191 | } 192 | }, 193 | { 194 | "data_file": "data__algorithm=original;key_size=10000;error_rate=vary", 195 | "legend": "original key_size=10,000", 196 | "mode": "lines+markers", 197 | "marker": { 198 | "symbol": "circle" 199 | }, 200 | "dash": "dot", 201 | "line_color": "black", 202 | "deviation_color": "none", 203 | "filter": { 204 | "variable": "remaining_bit_error_rate", 205 | "min_value": 1e-11 206 | } 207 | }, 208 | { 209 | "data_file": "data__algorithm=biconf;key_size=1000;error_rate=vary", 210 | "legend": "biconf key_size=1,000", 211 | "mode": "lines+markers", 212 | "marker": { 213 | "symbol": "triangle-up" 214 | }, 215 | "line_color": "blue", 216 | "deviation_color": "none", 217 | "filter": { 218 | "variable": "remaining_bit_error_rate", 219 | "min_value": 1e-11 220 | } 221 | }, 222 | { 223 | "data_file": "data__algorithm=biconf;key_size=10000;error_rate=vary", 224 | "legend": "biconf key_size=10,000", 225 | "mode": "lines+markers", 226 | "marker": { 227 | "symbol": "triangle-down" 228 | }, 229 | "dash": "dot", 230 | "line_color": "blue", 231 | "deviation_color": "none", 232 | "filter": { 233 | "variable": "remaining_bit_error_rate", 234 | "min_value": 1e-11 235 | } 236 | } 237 | ] 238 | }, 239 | { 240 | "graph_name": "demystifying_figure_8", 241 | "title": "Figure 8 from \"Demystifying the Information Reconciliation Protocol Cascade\"", 242 | "x_axis": { 243 | "title": "Quantum Bit Error Rate (QBER)", 244 | "variable": "requested_bit_error_rate" 245 | }, 246 | "y_axis": { 247 | "title": "Reconciliation efficiency", 248 | "variable": "efficiency", 249 | "range": [1.0, 1.3] 250 | }, 251 | "series": [ 252 | { 253 | "data_file": "data__algorithm=original;key_size=10000;error_rate=vary", 254 | "legend": "Cascade orig.", 255 | "line_color": "black", 256 | "deviation_color": "none" 257 | }, 258 | { 259 | "data_file": "data__algorithm=biconf;key_size=10000;error_rate=vary", 260 | "legend": "Cascade mod. (1)", 261 | "line_color": "blue", 262 | "deviation_color": "none" 263 | }, 264 | { 265 | "data_file": "data__algorithm=yanetal;key_size=10000;error_rate=vary", 266 | "legend": "Cascade opt. (2)", 267 | "line_color": "red", 268 | "deviation_color": "none" 269 | }, 270 | { 271 | "data_file": "data__algorithm=option3;key_size=10000;error_rate=vary", 272 | "legend": "Cascade opt. (3)", 273 | "line_color": "green", 274 | "deviation_color": "none" 275 | } 276 | ] 277 | }, 278 | { 279 | "graph_name": "demystifying_figure_9", 280 | "title": "Figure 9 from \"Demystifying the Information Reconciliation Protocol Cascade\"", 281 | "x_axis": { 282 | "title": "Quantum Bit Error Rate (QBER)", 283 | "variable": "requested_bit_error_rate" 284 | }, 285 | "y_axis": { 286 | "title": "Channel uses", 287 | "variable": "ask_parity_messages" 288 | }, 289 | "series": [ 290 | { 291 | "data_file": "data__algorithm=original;key_size=10000;error_rate=vary", 292 | "legend": "Cascade orig.", 293 | "line_color": "black", 294 | "deviation_color": "none" 295 | }, 296 | { 297 | "data_file": "data__algorithm=biconf;key_size=10000;error_rate=vary", 298 | "legend": "Cascade mod. (1)", 299 | "line_color": "blue", 300 | "deviation_color": "none" 301 | }, 302 | { 303 | "data_file": "data__algorithm=yanetal;key_size=10000;error_rate=vary", 304 | "legend": "Cascade opt. (2)", 305 | "line_color": "red", 306 | "deviation_color": "none" 307 | }, 308 | { 309 | "data_file": "data__algorithm=option3;key_size=10000;error_rate=vary", 310 | "legend": "Cascade opt. (3)", 311 | "line_color": "green", 312 | "deviation_color": "none" 313 | } 314 | ] 315 | }, 316 | { 317 | "graph_name": "demystifying_figure_10", 318 | "title": "Figure 10 from \"Demystifying the Information Reconciliation Protocol Cascade\"", 319 | "x_axis": { 320 | "title": "Quantum Bit Error Rate (QBER)", 321 | "variable": "requested_bit_error_rate", 322 | "range": [0.0, 0.11] 323 | }, 324 | "y_axis": { 325 | "title": "Frame error rate", 326 | "type": "log", 327 | "variable": "remaining_frame_error_rate", 328 | "range": [-6.0, 0.0] 329 | }, 330 | "series": [ 331 | { 332 | "data_file": "data__algorithm=original;key_size=10000;error_rate=vary", 333 | "legend": "Cascade orig.", 334 | "mode": "lines+markers", 335 | "marker": { 336 | "symbol": "square" 337 | }, 338 | "line_color": "black", 339 | "deviation_color": "none", 340 | "filter": { 341 | "variable": "remaining_frame_error_rate", 342 | "min_value": 1e-8 343 | } 344 | }, 345 | { 346 | "data_file": "data__algorithm=biconf;key_size=10000;error_rate=vary", 347 | "legend": "Cascade mod. (1)", 348 | "mode": "lines+markers", 349 | "marker": { 350 | "symbol": "circle" 351 | }, 352 | "line_color": "blue", 353 | "deviation_color": "none", 354 | "filter": { 355 | "variable": "remaining_frame_error_rate", 356 | "min_value": 1e-8 357 | } 358 | }, 359 | { 360 | "data_file": "data__algorithm=yanetal;key_size=10000;error_rate=vary", 361 | "legend": "Cascade opt. (2)", 362 | "mode": "lines+markers", 363 | "marker": { 364 | "symbol": "triangle-up" 365 | }, 366 | "line_color": "red", 367 | "deviation_color": "none", 368 | "filter": { 369 | "variable": "remaining_frame_error_rate", 370 | "min_value": 1e-8 371 | } 372 | }, 373 | { 374 | "data_file": "data__algorithm=option3;key_size=10000;error_rate=vary", 375 | "legend": "Cascade opt. (3)", 376 | "mode": "lines+markers", 377 | "marker": { 378 | "symbol": "triangle-down" 379 | }, 380 | "line_color": "green", 381 | "deviation_color": "none", 382 | "filter": { 383 | "variable": "remaining_frame_error_rate", 384 | "min_value": 1e-8 385 | } 386 | } 387 | ] 388 | }, 389 | { 390 | "graph_name": "demystifying_figure_11", 391 | "title": "Figure 11 from \"Demystifying the Information Reconciliation Protocol Cascade\"", 392 | "x_axis": { 393 | "title": "Quantum Bit Error Rate (QBER)", 394 | "variable": "requested_bit_error_rate" 395 | }, 396 | "y_axis": { 397 | "title": "Reconciliation efficiency", 398 | "variable": "efficiency", 399 | "range": [1.0, 1.3] 400 | }, 401 | "series": [ 402 | { 403 | "data_file": "data__algorithm=original;key_size=10000;error_rate=vary", 404 | "legend": "Cascade orig.", 405 | "line_color": "black", 406 | "deviation_color": "none" 407 | }, 408 | { 409 | "data_file": "data__algorithm=option3;key_size=10000;error_rate=vary", 410 | "legend": "Cascade opt. (3)", 411 | "line_color": "green", 412 | "deviation_color": "none" 413 | }, 414 | { 415 | "data_file": "data__algorithm=option4;key_size=10000;error_rate=vary", 416 | "legend": "Cascade opt. (4)", 417 | "line_color": "brown", 418 | "deviation_color": "none" 419 | } 420 | ] 421 | }, 422 | { 423 | "graph_name": "demystifying_figure_13", 424 | "title": "Figure 13 from \"Demystifying the Information Reconciliation Protocol Cascade\"", 425 | "x_axis": { 426 | "title": "Quantum Bit Error Rate (QBER)", 427 | "variable": "requested_bit_error_rate" 428 | }, 429 | "y_axis": { 430 | "title": "Reconciliation efficiency", 431 | "variable": "efficiency", 432 | "range": [1.0, 1.3] 433 | }, 434 | "series": [ 435 | { 436 | "data_file": "data__algorithm=original;key_size=10000;error_rate=vary", 437 | "legend": "Cascade orig.", 438 | "line_color": "black", 439 | "deviation_color": "none" 440 | }, 441 | { 442 | "data_file": "data__algorithm=option3;key_size=10000;error_rate=vary", 443 | "legend": "Cascade opt. (3)", 444 | "line_color": "green", 445 | "deviation_color": "none" 446 | }, 447 | { 448 | "data_file": "data__algorithm=option4;key_size=10000;error_rate=vary", 449 | "legend": "Cascade opt. (4)", 450 | "line_color": "brown", 451 | "deviation_color": "none" 452 | }, 453 | { 454 | "data_file": "data__algorithm=option7;key_size=10000;error_rate=vary", 455 | "legend": "Cascade opt. (7)", 456 | "line_color": "orange", 457 | "deviation_color": "none" 458 | }, 459 | { 460 | "data_file": "data__algorithm=option8;key_size=10000;error_rate=vary", 461 | "legend": "Cascade opt. (8)", 462 | "line_color": "slateblue", 463 | "deviation_color": "none" 464 | } 465 | ] 466 | } 467 | ] -------------------------------------------------------------------------------- /study/graphs_performance.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "graph_name": "performance_vs_error_rate", 4 | "title": "Reconciliation processing time vs error rate (key size = 10,000)", 5 | "x_axis": { 6 | "title": "Error rate", 7 | "variable": "requested_bit_error_rate", 8 | "range": [0.0, 0.1] 9 | }, 10 | "y_axis": { 11 | "title": "Process time per data point (seconds)", 12 | "variable": "elapsed_process_time" 13 | }, 14 | "series": [ 15 | { 16 | "data_file": "data__algorithm=original;key_size=10000;error_rate=vary", 17 | "legend": "original", 18 | "line_color": "black", 19 | "deviation_color": "lightgray" 20 | }, 21 | { 22 | "data_file": "data__algorithm=yanetal;key_size=10000;error_rate=vary", 23 | "legend": "yanetal", 24 | "line_color": "blue", 25 | "deviation_color": "lightblue" 26 | }, 27 | { 28 | "data_file": "data__algorithm=biconf;key_size=10000;error_rate=vary", 29 | "legend": "biconf", 30 | "line_color": "red", 31 | "deviation_color": "lightsalmon" 32 | }, 33 | { 34 | "data_file": "data__algorithm=option7;key_size=10000;error_rate=vary", 35 | "legend": "option7", 36 | "line_color": "green", 37 | "deviation_color": "lightgreen" 38 | } 39 | ] 40 | }, 41 | { 42 | "graph_name": "performance_vs_key_size", 43 | "title": "Reconciliation processing time vs key size (error rate = 0.02)", 44 | "x_axis": { 45 | "title": "Key size", 46 | "variable": "key_size" 47 | }, 48 | "y_axis": { 49 | "title": "Process time per data point (seconds)", 50 | "variable": "elapsed_process_time" 51 | }, 52 | "series": [ 53 | { 54 | "data_file": "data__algorithm=original;key_size=vary;error_rate=0.02", 55 | "legend": "original", 56 | "line_color": "black", 57 | "deviation_color": "lightgray" 58 | }, 59 | { 60 | "data_file": "data__algorithm=yanetal;key_size=vary;error_rate=0.02", 61 | "legend": "yanetal", 62 | "line_color": "blue", 63 | "deviation_color": "lightblue" 64 | }, 65 | { 66 | "data_file": "data__algorithm=biconf;key_size=vary;error_rate=0.02", 67 | "legend": "biconf", 68 | "line_color": "red", 69 | "deviation_color": "lightsalmon" 70 | }, 71 | { 72 | "data_file": "data__algorithm=option7;key_size=vary;error_rate=0.02", 73 | "legend": "option7", 74 | "line_color": "green", 75 | "deviation_color": "lightgreen" 76 | } 77 | ] 78 | } 79 | ] -------------------------------------------------------------------------------- /study/graphs_zero_handling.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "graph_name": "zero_handling", 4 | "title": "Zero handling", 5 | "x_axis": { 6 | "title": "Error rate", 7 | "variable": "requested_bit_error_rate" 8 | }, 9 | "y_axis": { 10 | "title": "Efficiency", 11 | "variable": "efficiency", 12 | "range": [0.5, 2.0] 13 | }, 14 | "series": [ 15 | { 16 | "data_file": "data__algorithm=original;key_size=10000;error_rate=vary", 17 | "legend": "original", 18 | "line_color": "black", 19 | "deviation_color": "lightgray" 20 | }, 21 | { 22 | "data_file": "data__algorithm=biconf;key_size=10000;error_rate=vary", 23 | "legend": "biconf", 24 | "line_color": "red", 25 | "deviation_color": "lightsalmon" 26 | } 27 | ] 28 | } 29 | ] -------------------------------------------------------------------------------- /study/options.cpp: -------------------------------------------------------------------------------- 1 | #include "options.h" 2 | #include "boost/program_options.hpp" 3 | #include 4 | 5 | Options::Options(): 6 | multi_processing(true), 7 | max_runs(0), // Zero means no limit 8 | output_directory(), 9 | experiments_file() 10 | { 11 | } 12 | 13 | void Options::parse(int argc, char** argv) 14 | { 15 | namespace po = boost::program_options; 16 | po::options_description normal_options("Options"); 17 | normal_options.add_options() 18 | ("help", 19 | "Display help") 20 | ("disable-multi-processing,d", 21 | "Disable multi-processing") 22 | ("max-runs,m", 23 | po::value(), 24 | "Maximum number of reconciliation runs per data point") 25 | ("seed,s", 26 | po::value(), 27 | "Random seed") 28 | ("output-directory,o", 29 | po::value(), 30 | "Output directory where to store data__* files"); 31 | po::options_description hidden_options; 32 | hidden_options.add_options() 33 | ("experiments-file", 34 | po::value(), 35 | "Input experiments file"); 36 | po::options_description options; 37 | options.add(normal_options); 38 | options.add(hidden_options); 39 | po::positional_options_description positional; 40 | positional.add("experiments-file", -1); 41 | try { 42 | po::variables_map vm; 43 | po::store(po::command_line_parser(argc, argv). 44 | options(options). 45 | positional(positional). 46 | run(), 47 | vm); 48 | po::notify(vm); 49 | if (vm.count("help")) { 50 | std::cout << "Usage: run_experiments [options] experiments-file" << std::endl; 51 | std::cout << std::endl; 52 | std::cout << normal_options << std::endl; 53 | exit(0); 54 | } 55 | if (vm.count("disable-multi-processing")) { 56 | multi_processing = false; 57 | } 58 | if (vm.count("max-runs")) { 59 | int command_line_max_runs = vm["max-runs"].as(); 60 | if (command_line_max_runs < 1) { 61 | std::cerr << "Error: --max-runs or -m must be >= 1" << std::endl; 62 | exit(1); 63 | } 64 | max_runs = command_line_max_runs; 65 | } 66 | if (vm.count("seed")) { 67 | int command_line_seed = vm["seed"].as(); 68 | seed_is_set = true; 69 | seed = command_line_seed; 70 | } else { 71 | seed_is_set = false; 72 | seed = 0; 73 | } 74 | 75 | if (vm.count("output-directory")) { 76 | output_directory = vm["output-directory"].as(); 77 | } 78 | if (vm.count("experiments-file") < 1) { 79 | std::cerr << "Error: experiments-file is missing" << std::endl; 80 | exit(1); 81 | } 82 | experiments_file = vm["experiments-file"].as(); 83 | } 84 | catch(po::error& error) { 85 | std::cerr << "Error: " << error.what() << std::endl << std::endl; 86 | exit(1); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /study/options.h: -------------------------------------------------------------------------------- 1 | #ifndef OPTIONS_H 2 | #define OPTIONS_H 3 | 4 | #include 5 | 6 | class Options 7 | { 8 | public: 9 | Options(); 10 | void parse(int argc, char** argv); 11 | bool multi_processing; 12 | int max_runs; 13 | bool seed_is_set; 14 | int seed; 15 | std::string output_directory; 16 | std::string experiments_file; 17 | }; 18 | 19 | #endif /* ifndef OPTIONS_H */ 20 | -------------------------------------------------------------------------------- /study/run_experiments.cpp: -------------------------------------------------------------------------------- 1 | #include "algorithm.h" 2 | #include "data_point.h" 3 | #include "debug.h" 4 | #include "experiments.h" 5 | #include "key.h" 6 | #include "mock_classical_session.h" 7 | #include "options.h" 8 | #include "random.h" 9 | #include "report.h" 10 | #include "reconciliation.h" 11 | #include "series.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | static std::deque series_queue; 22 | static std::mutex series_mutex; 23 | static std::mutex count_mutex; 24 | static int total_nr_data_points = 0; 25 | static int data_points_nr = 0; 26 | 27 | void fatal_perror(const std::string& message) 28 | { 29 | { 30 | // Take mutex to avoid error messages from multiple threads 31 | std::lock_guard guard(series_mutex); 32 | std::perror(message.c_str()); 33 | exit(1); 34 | } 35 | } 36 | 37 | void one_data_point_run(DataPoint& data_point, const std::string& algorithm_name, int key_size, 38 | double error_rate) 39 | { 40 | const Cascade::Algorithm* algorithm = Cascade::Algorithm::get_by_name(algorithm_name); 41 | assert(algorithm); 42 | Cascade::Key correct_key(key_size); 43 | Cascade::MockClassicalSession classical_session(correct_key, algorithm->cache_shuffles); 44 | Cascade::Key noisy_key = correct_key; 45 | noisy_key.apply_noise(error_rate); 46 | int actual_bit_errors = correct_key.nr_bits_different(noisy_key); 47 | data_point.actual_bit_errors.record_value(actual_bit_errors); 48 | double actual_bit_error_rate = double(actual_bit_errors) / double(key_size); 49 | data_point.actual_bit_error_rate.record_value(actual_bit_error_rate); 50 | int remaining_bit_errors = 0; 51 | { 52 | // New scope to make sure reconciliation destructor is run before we reporting bit errors. 53 | Cascade::Reconciliation reconciliation(*algorithm, classical_session, noisy_key, error_rate, 54 | &correct_key); 55 | reconciliation.reconcile(); 56 | data_point.record_reconciliation_stats(reconciliation.get_stats()); 57 | remaining_bit_errors = correct_key.nr_bits_different(reconciliation.get_reconciled_key()); 58 | data_point.remaining_bit_errors.record_value(remaining_bit_errors); 59 | } 60 | double remaining_bit_error_rate = double(remaining_bit_errors) / double(key_size); 61 | data_point.remaining_bit_error_rate.record_value(remaining_bit_error_rate); 62 | if (remaining_bit_errors > 0) 63 | data_point.remaining_frame_error_rate.record_value(1.0); 64 | else 65 | data_point.remaining_frame_error_rate.record_value(0.0); 66 | DEBUG("remaining_bit_errors=" << remaining_bit_errors); 67 | } 68 | 69 | void produce_one_data_point(const std::string& algorithm, int key_size, double error_rate, int runs, 70 | std::ofstream& data_file) 71 | { 72 | { 73 | std::lock_guard guard(count_mutex); 74 | data_points_nr += 1; 75 | REPORT(data_points_nr << "/" << total_nr_data_points 76 | << " algorithm=" << algorithm 77 | << " key_size=" << key_size 78 | << " error_rate=" << error_rate 79 | << " runs=" << runs); 80 | } 81 | 82 | DataPoint data_point(algorithm, key_size, error_rate); 83 | for(int run = 0; run < runs; ++run) { 84 | one_data_point_run(data_point, algorithm, key_size, error_rate); 85 | } 86 | 87 | data_file << data_point.to_json() << std::endl; 88 | if (!data_file.good()) 89 | fatal_perror("Could write data point to file"); 90 | } 91 | 92 | std::string serie_file_name(const Serie& serie) 93 | { 94 | std::stringstream file_name("data__"); 95 | file_name << "algorithm=" << serie.algorithm << ";"; 96 | if (serie.key_sizes.size() == 1) { 97 | file_name << "key_size=" << serie.key_sizes[0] << ";"; 98 | } else { 99 | file_name << "key_size=vary;"; 100 | } 101 | if (serie.error_rates.size() == 1) { 102 | file_name << "error_rate=" << serie.error_rates[0]; 103 | } else { 104 | file_name << "error_rate=vary"; 105 | } 106 | return file_name.str(); 107 | } 108 | 109 | void produce_one_serie(const Serie& serie, const Options& options) 110 | { 111 | boost::filesystem::path data_file_name = "data__" + serie.name; 112 | if (!options.output_directory.empty()) 113 | data_file_name = options.output_directory / data_file_name; 114 | std::ofstream data_file; 115 | data_file.open(data_file_name.string()); 116 | if (!data_file.good()) { 117 | fatal_perror("Could not open file " + data_file_name.string() + " for writing"); 118 | } 119 | for (auto key_size: serie.key_sizes) { 120 | for (auto error_rate: serie.error_rates) { 121 | produce_one_data_point(serie.algorithm, key_size, error_rate, serie.runs, data_file); 122 | } 123 | } 124 | data_file.close(); 125 | } 126 | 127 | void serie_worker(const Options& options) 128 | { 129 | while (true) { 130 | Serie serie; 131 | { 132 | std::lock_guard guard(series_mutex); 133 | if (series_queue.empty()) { 134 | break; 135 | } 136 | serie = series_queue.front(); 137 | series_queue.pop_front(); 138 | } 139 | produce_one_serie(serie, options); 140 | } 141 | } 142 | 143 | void compute_total_nr_data_points(Series& series) 144 | { 145 | total_nr_data_points = 0; 146 | for (Serie& serie: series.series) { 147 | total_nr_data_points += serie.key_sizes.size() * serie.error_rates.size(); 148 | } 149 | } 150 | 151 | void run_all_series_multi_threaded(Series& series, const Options& options) { 152 | // Put all series on the queue. We don't need any locking because we have not started the 153 | // workers yet. 154 | for (Serie& serie: series.series) { 155 | series_queue.push_back(serie); 156 | } 157 | 158 | // Start the workers. 159 | std::vector worker_threads; 160 | int nr_workers = std::thread::hardware_concurrency(); 161 | for (int worker_nr = 0; worker_nr < nr_workers; ++worker_nr) { 162 | std::thread worker_thread = std::thread(serie_worker, options); 163 | worker_threads.push_back(std::move(worker_thread)); 164 | } 165 | 166 | // Wait for all of the workers to complete. 167 | for (auto& worker_thread: worker_threads) { 168 | worker_thread.join(); 169 | } 170 | } 171 | 172 | void run_all_series_single_threaded(Series& series, const Options& options) { 173 | for (Serie& serie: series.series) { 174 | produce_one_serie(serie, options); 175 | } 176 | } 177 | 178 | int main(int argc, char** argv) 179 | { 180 | Options options; 181 | options.parse(argc, argv); 182 | 183 | if (options.seed_is_set) 184 | Cascade::set_random_uint32_seed(options.seed); 185 | Experiments experiments(options.experiments_file); 186 | Series series(experiments, options.max_runs); 187 | compute_total_nr_data_points(series); 188 | if (options.multi_processing) { 189 | run_all_series_multi_threaded(series, options); 190 | } else { 191 | run_all_series_single_threaded(series, options); 192 | } 193 | return 0; 194 | } 195 | -------------------------------------------------------------------------------- /study/series.cpp: -------------------------------------------------------------------------------- 1 | #include "algorithm.h" 2 | #include "series.h" 3 | #include "experiments.h" 4 | #include 5 | 6 | #include 7 | 8 | using namespace Cascade; 9 | 10 | Series::Series(const Experiments& experiments, int max_runs) 11 | { 12 | for (auto it = experiments.experiments.begin(); it != experiments.experiments.end(); ++it) { 13 | std::vector experiment_series; 14 | const Experiment& experiment = (*it); 15 | if (experiment.independent_variable == "error_rate") { 16 | experiment_series = error_rate_series(experiment, max_runs); 17 | } 18 | else if (experiment.independent_variable == "key_size") { 19 | experiment_series = key_size_series(experiment, max_runs); 20 | } else { 21 | assert(false); 22 | } 23 | series.insert(series.begin(), experiment_series.begin(), 24 | experiment_series.end()); 25 | } 26 | } 27 | 28 | static std::vector dvec_to_ivec(const std::vector dvec) 29 | { 30 | std::vector ivec; 31 | for (auto dval: dvec) { 32 | int ival = std::round(dval); 33 | ivec.push_back(ival); 34 | } 35 | return ivec; 36 | } 37 | 38 | static std::string error_rate_to_str(double value) 39 | { 40 | std::string str = std::to_string(value); 41 | while (str.back() == '0') { 42 | str.pop_back(); 43 | } 44 | return str; 45 | } 46 | 47 | std::vector experiment_algorithms(const Experiment& experiment) 48 | { 49 | if (experiment.algorithms.size() == 1 && experiment.algorithms[0] == "all") { 50 | return Algorithm::get_all_algorithm_names(); 51 | } else { 52 | return experiment.algorithms; 53 | } 54 | } 55 | 56 | std::vector Series::error_rate_series(const Experiment& experiment, int max_runs) 57 | { 58 | std::vector series; 59 | for (auto algorithm: experiment_algorithms(experiment)) { 60 | for (auto key_size: experiment.key_sizes) { 61 | Serie serie; 62 | int rounded_key_size = std::round(key_size); 63 | serie.name = "algorithm=" + algorithm + ";" + 64 | "key_size=" + std::to_string(rounded_key_size) + ";" + 65 | "error_rate=vary"; 66 | if (max_runs == 0) { 67 | serie.runs = experiment.runs; 68 | } else { 69 | serie.runs = std::min(experiment.runs, max_runs); 70 | } 71 | serie.algorithm = algorithm; 72 | serie.key_sizes.push_back(rounded_key_size); 73 | serie.error_rates = experiment.error_rates; 74 | series.push_back(serie); 75 | } 76 | } 77 | return series; 78 | } 79 | 80 | std::vector Series::key_size_series(const Experiment& experiment, int max_runs) 81 | { 82 | std::vector series; 83 | for (auto algorithm: experiment_algorithms(experiment)) { 84 | for (auto error_rate: experiment.error_rates) { 85 | Serie serie; 86 | serie.name = "algorithm=" + algorithm + ";" + 87 | "key_size=vary;" + 88 | "error_rate=" + error_rate_to_str(error_rate); 89 | if (max_runs == 0) { 90 | serie.runs = experiment.runs; 91 | } else { 92 | serie.runs = std::min(experiment.runs, max_runs); 93 | } 94 | serie.algorithm = algorithm; 95 | serie.key_sizes = dvec_to_ivec(experiment.key_sizes); 96 | serie.error_rates.push_back(error_rate); 97 | series.push_back(serie); 98 | } 99 | } 100 | return series; 101 | } 102 | 103 | -------------------------------------------------------------------------------- /study/series.h: -------------------------------------------------------------------------------- 1 | #ifndef SERIES_H 2 | #define SERIES_H 3 | 4 | #include 5 | #include 6 | 7 | class Experiment; 8 | class Experiments; 9 | 10 | class Serie 11 | { 12 | public: 13 | std::string name; 14 | std::string algorithm; 15 | std::vector key_sizes; 16 | std::vector error_rates; 17 | int runs; 18 | }; 19 | 20 | class Series 21 | { 22 | public: 23 | Series(const Experiments& experiments, int max_runs); 24 | std::vector series; 25 | private: 26 | std::vector error_rate_series(const Experiment& experiment, int max_runs); 27 | std::vector key_size_series(const Experiment& experiment, int max_runs); 28 | }; 29 | 30 | #endif /* ifndef SERIES_H */ 31 | -------------------------------------------------------------------------------- /tests/test_algorithm.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "algorithm.h" 4 | 5 | using namespace Cascade; 6 | 7 | TEST (Algorithm, get_by_name_does_not_exist) 8 | { 9 | EXPECT_EQ(Algorithm::get_by_name("nonsense"), nullptr); 10 | } 11 | 12 | TEST (Algorithm, original) 13 | { 14 | Algorithm* algorithm = Algorithm::get_by_name("original"); 15 | EXPECT_NE(algorithm, nullptr); 16 | EXPECT_EQ(algorithm->name, "original"); 17 | EXPECT_EQ(algorithm->nr_cascade_iterations, 4); 18 | EXPECT_EQ(algorithm->block_size_function(1, 0.0, 10000), 73000); 19 | EXPECT_EQ(algorithm->block_size_function(1, 0.1, 10000), 8); 20 | EXPECT_EQ(algorithm->block_size_function(1, 0.01, 10000), 73); 21 | EXPECT_EQ(algorithm->block_size_function(2, 0.01, 10000), 146); 22 | EXPECT_EQ(algorithm->block_size_function(3, 0.01, 10000), 292); 23 | EXPECT_EQ(algorithm->block_size_function(1, 0.001, 10000), 730); 24 | EXPECT_EQ(algorithm->nr_biconf_iterations, 0); 25 | EXPECT_FALSE(algorithm->biconf_error_free_streak); 26 | EXPECT_FALSE(algorithm->biconf_correct_complement); 27 | EXPECT_FALSE(algorithm->biconf_cascade); 28 | } 29 | 30 | TEST (Algorithm, biconf) 31 | { 32 | Algorithm* algorithm = Algorithm::get_by_name("biconf"); 33 | EXPECT_NE(algorithm, nullptr); 34 | EXPECT_EQ(algorithm->name, "biconf"); 35 | EXPECT_EQ(algorithm->nr_cascade_iterations, 2); 36 | EXPECT_EQ(algorithm->block_size_function(1, 0.0, 10000), 92000); 37 | EXPECT_EQ(algorithm->block_size_function(1, 0.1, 10000), 10); 38 | EXPECT_EQ(algorithm->block_size_function(1, 0.01, 10000), 92); 39 | EXPECT_EQ(algorithm->block_size_function(2, 0.01, 10000), 276); 40 | EXPECT_EQ(algorithm->block_size_function(3, 0.01, 10000), 828); 41 | EXPECT_EQ(algorithm->block_size_function(1, 0.001, 10000), 920); 42 | EXPECT_EQ(algorithm->nr_biconf_iterations, 10); 43 | EXPECT_TRUE(algorithm->biconf_error_free_streak); 44 | EXPECT_TRUE(algorithm->biconf_correct_complement); 45 | EXPECT_FALSE(algorithm->biconf_cascade); 46 | } 47 | 48 | TEST (Algorithm, biconf_cascade) 49 | { 50 | Algorithm* algorithm = Algorithm::get_by_name("biconf-cascade"); 51 | EXPECT_NE(algorithm, nullptr); 52 | EXPECT_EQ(algorithm->name, "biconf-cascade"); 53 | EXPECT_EQ(algorithm->nr_cascade_iterations, 2); 54 | EXPECT_EQ(algorithm->block_size_function(1, 0.0, 10000), 92000); 55 | EXPECT_EQ(algorithm->block_size_function(1, 0.1, 10000), 10); 56 | EXPECT_EQ(algorithm->block_size_function(1, 0.01, 10000), 92); 57 | EXPECT_EQ(algorithm->block_size_function(2, 0.01, 10000), 276); 58 | EXPECT_EQ(algorithm->block_size_function(3, 0.01, 10000), 828); 59 | EXPECT_EQ(algorithm->block_size_function(1, 0.001, 10000), 920); 60 | EXPECT_EQ(algorithm->nr_biconf_iterations, 10); 61 | EXPECT_TRUE(algorithm->biconf_error_free_streak); 62 | EXPECT_TRUE(algorithm->biconf_correct_complement); 63 | EXPECT_TRUE(algorithm->biconf_cascade); 64 | } 65 | 66 | TEST (Algorithm, biconf_complement) 67 | { 68 | Algorithm* algorithm = Algorithm::get_by_name("biconf-no-complement"); 69 | EXPECT_NE(algorithm, nullptr); 70 | EXPECT_EQ(algorithm->name, "biconf-no-complement"); 71 | EXPECT_EQ(algorithm->nr_cascade_iterations, 2); 72 | EXPECT_EQ(algorithm->block_size_function(1, 0.0, 10000), 92000); 73 | EXPECT_EQ(algorithm->block_size_function(1, 0.1, 10000), 10); 74 | EXPECT_EQ(algorithm->block_size_function(1, 0.01, 10000), 92); 75 | EXPECT_EQ(algorithm->block_size_function(2, 0.01, 10000), 276); 76 | EXPECT_EQ(algorithm->block_size_function(3, 0.01, 10000), 828); 77 | EXPECT_EQ(algorithm->block_size_function(1, 0.001, 10000), 920); 78 | EXPECT_EQ(algorithm->nr_biconf_iterations, 10); 79 | EXPECT_TRUE(algorithm->biconf_error_free_streak); 80 | EXPECT_FALSE(algorithm->biconf_correct_complement); 81 | EXPECT_FALSE(algorithm->biconf_cascade); 82 | } 83 | 84 | TEST (Algorithm, yanetal) 85 | { 86 | Algorithm* algorithm = Algorithm::get_by_name("yanetal"); 87 | EXPECT_NE(algorithm, nullptr); 88 | EXPECT_EQ(algorithm->name, "yanetal"); 89 | EXPECT_EQ(algorithm->nr_cascade_iterations, 10); 90 | EXPECT_EQ(algorithm->block_size_function(1, 0.0, 10000), 80000); 91 | EXPECT_EQ(algorithm->block_size_function(1, 0.1, 10000), 8); 92 | EXPECT_EQ(algorithm->block_size_function(1, 0.01, 10000), 80); 93 | EXPECT_EQ(algorithm->block_size_function(2, 0.01, 10000), 400); 94 | EXPECT_EQ(algorithm->block_size_function(3, 0.01, 10000), 5000); 95 | EXPECT_EQ(algorithm->block_size_function(1, 0.001, 10000), 800); 96 | EXPECT_EQ(algorithm->nr_biconf_iterations, 0); 97 | EXPECT_FALSE(algorithm->biconf_error_free_streak); 98 | EXPECT_FALSE(algorithm->biconf_correct_complement); 99 | EXPECT_FALSE(algorithm->biconf_cascade); 100 | } 101 | 102 | TEST (Algorithm, option3) 103 | { 104 | Algorithm* algorithm = Algorithm::get_by_name("option3"); 105 | EXPECT_NE(algorithm, nullptr); 106 | EXPECT_EQ(algorithm->name, "option3"); 107 | EXPECT_EQ(algorithm->nr_cascade_iterations, 16); 108 | EXPECT_EQ(algorithm->block_size_function(1, 0.0, 10000), 100000); 109 | EXPECT_EQ(algorithm->block_size_function(1, 0.1, 10000), 10); 110 | EXPECT_EQ(algorithm->block_size_function(1, 0.01, 10000), 100); 111 | EXPECT_EQ(algorithm->block_size_function(2, 0.01, 10000), 200); 112 | EXPECT_EQ(algorithm->block_size_function(3, 0.01, 10000), 5000); 113 | EXPECT_EQ(algorithm->block_size_function(1, 0.001, 10000), 1000); 114 | EXPECT_EQ(algorithm->nr_biconf_iterations, 0); 115 | EXPECT_FALSE(algorithm->biconf_error_free_streak); 116 | EXPECT_FALSE(algorithm->biconf_correct_complement); 117 | EXPECT_FALSE(algorithm->biconf_cascade); 118 | } 119 | 120 | TEST (Algorithm, option4) 121 | { 122 | Algorithm* algorithm = Algorithm::get_by_name("option4"); 123 | EXPECT_NE(algorithm, nullptr); 124 | EXPECT_EQ(algorithm->name, "option4"); 125 | EXPECT_EQ(algorithm->nr_cascade_iterations, 16); 126 | EXPECT_EQ(algorithm->block_size_function(1, 0.0, 10000), 100000); 127 | EXPECT_EQ(algorithm->block_size_function(1, 0.1, 10000), 10); 128 | EXPECT_EQ(algorithm->block_size_function(1, 0.01, 10000), 100); 129 | EXPECT_EQ(algorithm->block_size_function(2, 0.01, 10000), 200); 130 | EXPECT_EQ(algorithm->block_size_function(3, 0.01, 10000), 5000); 131 | EXPECT_EQ(algorithm->block_size_function(1, 0.001, 10000), 1000); 132 | EXPECT_EQ(algorithm->nr_biconf_iterations, 0); 133 | EXPECT_FALSE(algorithm->biconf_error_free_streak); 134 | EXPECT_FALSE(algorithm->biconf_correct_complement); 135 | EXPECT_FALSE(algorithm->biconf_cascade); 136 | } 137 | 138 | TEST (Algorithm, option7) 139 | { 140 | Algorithm* algorithm = Algorithm::get_by_name("option7"); 141 | EXPECT_NE(algorithm, nullptr); 142 | EXPECT_EQ(algorithm->name, "option7"); 143 | EXPECT_EQ(algorithm->nr_cascade_iterations, 14); 144 | EXPECT_EQ(algorithm->block_size_function(1, 0.0, 10000), 131072); 145 | EXPECT_EQ(algorithm->block_size_function(1, 0.1, 10000), 16); 146 | EXPECT_EQ(algorithm->block_size_function(1, 0.01, 10000), 128); 147 | EXPECT_EQ(algorithm->block_size_function(2, 0.01, 10000), 512); 148 | EXPECT_EQ(algorithm->block_size_function(3, 0.01, 10000), 5000); 149 | EXPECT_EQ(algorithm->block_size_function(1, 0.001, 10000), 1024); 150 | EXPECT_EQ(algorithm->nr_biconf_iterations, 0); 151 | EXPECT_FALSE(algorithm->biconf_error_free_streak); 152 | EXPECT_FALSE(algorithm->biconf_correct_complement); 153 | EXPECT_FALSE(algorithm->biconf_cascade); 154 | } 155 | 156 | TEST (Algorithm, option8) 157 | { 158 | Algorithm* algorithm = Algorithm::get_by_name("option8"); 159 | EXPECT_NE(algorithm, nullptr); 160 | EXPECT_EQ(algorithm->name, "option8"); 161 | EXPECT_EQ(algorithm->nr_cascade_iterations, 14); 162 | EXPECT_EQ(algorithm->block_size_function(1, 0.0, 10000), 131072); 163 | EXPECT_EQ(algorithm->block_size_function(1, 0.1, 10000), 8); 164 | EXPECT_EQ(algorithm->block_size_function(1, 0.01, 10000), 128); 165 | EXPECT_EQ(algorithm->block_size_function(2, 0.01, 10000), 1024); 166 | EXPECT_EQ(algorithm->block_size_function(3, 0.01, 10000), 4096); 167 | EXPECT_EQ(algorithm->block_size_function(4, 0.01, 10000), 5000); 168 | EXPECT_EQ(algorithm->block_size_function(1, 0.001, 10000), 1024); 169 | EXPECT_EQ(algorithm->nr_biconf_iterations, 0); 170 | EXPECT_FALSE(algorithm->biconf_error_free_streak); 171 | EXPECT_FALSE(algorithm->biconf_correct_complement); 172 | EXPECT_FALSE(algorithm->biconf_cascade); 173 | } 174 | 175 | TEST (Algorithm, get_all_algorithm_names) 176 | { 177 | auto algorithm_names = Algorithm::get_all_algorithm_names(); 178 | EXPECT_EQ(algorithm_names.size(), 9U); 179 | EXPECT_TRUE(std::find(algorithm_names.begin(), algorithm_names.end(), "original") != 180 | algorithm_names.end()); 181 | EXPECT_TRUE(std::find(algorithm_names.begin(), algorithm_names.end(), "biconf") != 182 | algorithm_names.end()); 183 | EXPECT_TRUE(std::find(algorithm_names.begin(), algorithm_names.end(), "biconf-cascade") != 184 | algorithm_names.end()); 185 | EXPECT_TRUE(std::find(algorithm_names.begin(), algorithm_names.end(), "biconf-no-complement") != 186 | algorithm_names.end()); 187 | EXPECT_TRUE(std::find(algorithm_names.begin(), algorithm_names.end(), "yanetal") != 188 | algorithm_names.end()); 189 | EXPECT_TRUE(std::find(algorithm_names.begin(), algorithm_names.end(), "option3") != 190 | algorithm_names.end()); 191 | EXPECT_TRUE(std::find(algorithm_names.begin(), algorithm_names.end(), "option4") != 192 | algorithm_names.end()); 193 | EXPECT_TRUE(std::find(algorithm_names.begin(), algorithm_names.end(), "option7") != 194 | algorithm_names.end()); 195 | EXPECT_TRUE(std::find(algorithm_names.begin(), algorithm_names.end(), "option8") != 196 | algorithm_names.end()); 197 | } 198 | -------------------------------------------------------------------------------- /tests/test_block.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "block.h" 3 | #include "algorithm.h" 4 | #include "key.h" 5 | #include "mock_classical_session.h" 6 | #include "reconciliation.h" 7 | 8 | using namespace Cascade; 9 | 10 | static const int key_size = 100; 11 | 12 | Iteration make_iteration(bool biconf) 13 | { 14 | Key correct_key(key_size); 15 | Key noisy_key = correct_key; 16 | double bit_error_rate = 0.1; 17 | noisy_key.apply_noise(bit_error_rate); 18 | const Algorithm* algorithm = Algorithm::get_by_name("original"); 19 | assert(algorithm); 20 | MockClassicalSession classical_session(correct_key, algorithm->cache_shuffles); 21 | Reconciliation reconciliation(*algorithm, classical_session, noisy_key, bit_error_rate); 22 | int iteration_nr = 1; 23 | Iteration iteration(reconciliation, iteration_nr, biconf); 24 | return iteration; 25 | } 26 | 27 | TEST (Block, constructor_and_destructor) 28 | { 29 | Iteration iteration = make_iteration(false); 30 | } 31 | 32 | TEST (Block, compute_name) 33 | { 34 | Iteration cascade_iteration = make_iteration(false); 35 | Block block_top(cascade_iteration, 0, key_size - 1, NULL, 3); 36 | EXPECT_EQ(block_top.compute_name(), "c:1:3"); /* c = cascade, 1 = iteration, 3 = block nr */ 37 | Block block_l(cascade_iteration, 0, key_size / 2, &block_top, 0); 38 | EXPECT_EQ(block_l.compute_name(), "c:1:3L"); 39 | Block block_lr(cascade_iteration, key_size / 4, key_size / 2, &block_l, 1); 40 | EXPECT_EQ(block_lr.compute_name(), "c:1:3LR"); 41 | Iteration biconf_iteration = make_iteration(true); 42 | Block block_biconf(biconf_iteration, 0, key_size - 1, NULL, 5); 43 | EXPECT_EQ(block_biconf.compute_name(), "b:1:5"); /* b = biconf, 1 = iteration, 5 = block nr */ 44 | } 45 | -------------------------------------------------------------------------------- /tests/test_key.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "key.h" 3 | #include "random.h" 4 | 5 | using namespace Cascade; 6 | 7 | TEST (Key, random_constructor) 8 | { 9 | set_random_uint32_seed(1111); 10 | 11 | Key key_1(1); 12 | EXPECT_EQ(key_1.to_string(), "1"); 13 | 14 | Key key_2(2); 15 | EXPECT_EQ(key_2.to_string(), "10"); 16 | 17 | Key key_63(63); 18 | EXPECT_EQ(key_63.to_string(), 19 | "010001010100010010011001110000100011000110110110001011111110101"); 20 | 21 | Key key_64(64); 22 | EXPECT_EQ(key_64.to_string(), 23 | "0001100100001011100011111101110100101101010101101101111011110010"); 24 | 25 | Key key_65(65); 26 | EXPECT_EQ(key_65.to_string(), 27 | "00101000110000000000101101100100011010011110110111000001000000000"); 28 | 29 | Key key_66(66); 30 | EXPECT_EQ(key_66.to_string(), 31 | "011001111010111111101101010101100001000011010111111110110011110001"); 32 | 33 | Key key_10_000(10000); 34 | 35 | Key key_100_000(100000); 36 | } 37 | 38 | TEST (Key, copy_constructor) 39 | { 40 | set_random_uint32_seed(1111); 41 | 42 | Key key(80); 43 | EXPECT_EQ(key.to_string(), 44 | "11101100100000111010100001110110001110011001011110101110000110001000101010110101"); 45 | 46 | Key key_copy(key); 47 | EXPECT_EQ(key_copy.to_string(), 48 | "11101100100000111010100001110110001110011001011110101110000110001000101010110101"); 49 | 50 | // Make sure that changing a bit in the original key does not affect the copied key, 51 | // and vice versa. 52 | key.set_bit(78, 1); 53 | key_copy.set_bit(77, 0); 54 | EXPECT_EQ(key.to_string(), 55 | "11101100100000111010100001110110001110011001011110101110000110001000101010110111"); 56 | EXPECT_EQ(key_copy.to_string(), 57 | "11101100100000111010100001110110001110011001011110101110000110001000101010110001"); 58 | } 59 | -------------------------------------------------------------------------------- /tests/test_main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char **argv) 4 | { 5 | ::testing::InitGoogleTest(&argc, argv); 6 | return RUN_ALL_TESTS(); 7 | } 8 | -------------------------------------------------------------------------------- /tests/test_reconciliation.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "algorithm.h" 3 | #include "debug.h" 4 | #include "mock_classical_session.h" 5 | #include "random.h" 6 | #include "reconciliation.h" 7 | 8 | using namespace Cascade; 9 | 10 | void run_reconciliation_test(int seed, const char* algorithm_name) 11 | { 12 | const Algorithm* algorithm = Algorithm::get_by_name(algorithm_name); 13 | assert(algorithm); 14 | set_random_uint32_seed(seed); 15 | Key correct_key(10000); 16 | Key noisy_key = correct_key; 17 | double bit_error_rate = 0.1; 18 | noisy_key.apply_noise(bit_error_rate); 19 | MockClassicalSession classical_session(correct_key, algorithm->cache_shuffles); 20 | Reconciliation reconciliation(*algorithm, classical_session, noisy_key, bit_error_rate); 21 | reconciliation.reconcile(); 22 | Key& reconciled_key = reconciliation.get_reconciled_key(); 23 | ASSERT_EQ(correct_key.nr_bits_different(reconciled_key), 0); 24 | } 25 | 26 | TEST (Reconciliation, algorithm_original) 27 | { 28 | run_reconciliation_test(11111, "original"); 29 | } 30 | 31 | TEST (Reconciliation, algorithm_biconf) 32 | { 33 | run_reconciliation_test(222222, "biconf"); 34 | } 35 | 36 | TEST (Reconciliation, algorithm_biconf_cascade) 37 | { 38 | run_reconciliation_test(444444, "biconf-cascade"); 39 | } 40 | 41 | TEST (Reconciliation, algorithm_biconf_no_complement) 42 | { 43 | run_reconciliation_test(666666, "biconf-no-complement"); 44 | } 45 | --------------------------------------------------------------------------------