Skip to content

Commit

Permalink
Merge pull request #3 from itzmeanjan/use-randomshake-as-csprng
Browse files Browse the repository at this point in the history
Use "RandomShake" as CSPRNG
  • Loading branch information
itzmeanjan authored Nov 14, 2024
2 parents aa654db + 6d312bf commit 79db5b8
Show file tree
Hide file tree
Showing 24 changed files with 130 additions and 168 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
- name: Execute Tests on ${{matrix.os}}, compiled with ${{matrix.compiler}}
if: ${{matrix.test_type == 'standard'}}
run: |
CXX=${{matrix.compiler}} make -j
CXX=${{matrix.compiler}} make test -j
make clean
- name: Execute Tests with ${{matrix.test_type}}, in ${{matrix.build_type}} mode, on ${{matrix.os}}, compiled with ${{matrix.compiler}}
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
[submodule "gtest-parallel"]
path = gtest-parallel
url = https://github.com/google/gtest-parallel.git
[submodule "RandomShake"]
path = RandomShake
url = https://github.com/itzmeanjan/RandomShake
26 changes: 20 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
.DEFAULT_GOAL := help

# Collects inspiration from https://github.com/itzmeanjan/sha3/blob/b6ce906994961b711b6f2864fa8ee393c84d23ef/Makefile
.PHONY: help
help:
@for file in $(MAKEFILE_LIST); do \
grep -E '^[a-zA-Z_-]+:.*?## .*$$' $${file} | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}';\
done

CXX ?= clang++
CXX_DEFS +=
CXX_FLAGS := -std=c++20
Expand All @@ -8,7 +17,8 @@ LINK_OPT_FLAGS := -flto

I_FLAGS := -I ./include
SHA3_INC_DIR := ./sha3/include
DEP_IFLAGS := -I $(SHA3_INC_DIR)
RANDOMSHAKE_INC_DIR := ./RandomShake/include
DEP_IFLAGS := -I $(SHA3_INC_DIR) -I $(RANDOMSHAKE_INC_DIR)

SRC_DIR := include
FrodoPIR_SOURCES := $(shell find $(SRC_DIR) -name '*.hpp')
Expand All @@ -18,17 +28,21 @@ all: test

include tests/test.mk
include benches/bench.mk
include examples/example.mk

$(GTEST_PARALLEL):
git submodule update --init gtest-parallel

$(SHA3_INC_DIR): $(GTEST_PARALLEL)
git submodule update --init sha3
$(RANDOMSHAKE_INC_DIR): $(GTEST_PARALLEL)
git submodule update --init --recursive RandomShake

.PHONY: format clean
$(SHA3_INC_DIR): $(RANDOMSHAKE_INC_DIR)
git submodule update --init sha3

clean:
.PHONY: clean
clean: ## Remove build directory
rm -rf $(BUILD_DIR)

format: $(FrodoPIR_SOURCES) $(TEST_SOURCES) $(TEST_HEADERS) $(BENCHMARK_SOURCES) $(BENCHMARK_HEADERS)
.PHONY: format
format: $(FrodoPIR_SOURCES) $(TEST_SOURCES) $(TEST_HEADERS) $(BENCHMARK_SOURCES) $(BENCHMARK_HEADERS) ## Format source code
clang-format -i $^
33 changes: 10 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ g++ (Ubuntu 14-20240412-0ubuntu1) 14.0.1 20240412 (experimental) [master r14-993
For ensuring functional correctness of this implementation of FrodoPIR scheme, issue

```bash
make -j # Run tests without any sort of sanitizers, with default C++ compiler.
CXX=clang++ make -j # Switch to non-default compiler, by setting variable `CXX`.
make test -j # Run tests without any sort of sanitizers, with default C++ compiler.
CXX=clang++ make test -j # Switch to non-default compiler, by setting variable `CXX`.

make debug_asan_test -j # Run tests with AddressSanitizer enabled, with `-O1`.
make release_asan_test -j # Run tests with AddressSanitizer enabled, with `-O3 -march=native`.
Expand All @@ -80,6 +80,9 @@ PASSED TESTS (4/4):
66962 ms: build/test/test.out FrodoPIR.PrivateInformationRetrieval
```

> [!NOTE]
> There is a help menu, which introduces you to all available commands; just run `make` from the root directory of this project.
## Benchmarking

Benchmarking of all 6 algorithms of FrodoPIR scheme can be done, by issuing
Expand All @@ -96,23 +99,13 @@ make perf -j # If you have built google-benchmark library with libPFM supp
### On 12th Gen Intel(R) Core(TM) i7-1260P

Compiled with **gcc version 14.0.1 20240412** on

```bash
$ uname -srm
Linux 6.8.0-45-generic x86_64
```
Compiled with **gcc version 14.0.1 20240412** on `Linux 6.8.0-45-generic x86_64`.

Benchmark result in JSON format @ [bench_result_on_Linux_6.8.0-45-generic_x86_64_with_g++_14.json](./bench_result_on_Linux_6.8.0-45-generic_x86_64_with_g++_14.json).

### On ARM Neoverse-V2 (AWS EC2 Instance `c8g.2xlarge`)

Compiled with **gcc version 13.2.0** on

```bash
$ uname -srm
Linux 6.8.0-1016-aws aarch64
```
Compiled with **gcc version 13.2.0** on `Linux 6.8.0-1016-aws aarch64`.

Benchmark result in JSON format @ [bench_result_on_Linux_6.8.0-1016-aws_aarch64_with_g++_13.json](./bench_result_on_Linux_6.8.0-1016-aws_aarch64_with_g++_13.json).

Expand All @@ -121,7 +114,7 @@ Benchmark result in JSON format @ [bench_result_on_Linux_6.8.0-1016-aws_aarch64_
## Usage

FrodoPIR is a header-only C++20 library implementing all recommended variants (see table 5) in https://ia.cr/2022/98. FrodoPIR header files live `./include` directory, while only additional dependency `sha3` header files live under `sha3/include`.
FrodoPIR is a header-only C++20 library implementing all recommended variants (see table 5) in https://ia.cr/2022/98. FrodoPIR header files live `./include` directory, while additional dependency `sha3` and `RandomShake` header files live under `sha3/include` and `RandomShake/include`, respectively.

- Let's begin by cloning the repository.

Expand All @@ -136,19 +129,13 @@ git clone https://github.com/itzmeanjan/frodoPIR.git --recurse-submodules

```bash
pushd frodoPIR
make -j # Also runs tests
make test -j # Also runs tests
popd
```

- Now that we've all the dependencies to use FrodoPIR header-only library, let's run our [example program](./examples/frodoPIR.cpp).
- Now that we've all the dependencies to use FrodoPIR header-only library, let's run our [example](./examples/frodoPIR.cpp) program, by issuing `make example`.

```bash
FrodoPIR_HEADERS=include
SHA3_HEADERS=sha3/include

g++ -std=c++20 -Wall -Wextra -pedantic -O3 -march=native -I $FrodoPIR_HEADERS -I $SHA3_HEADERS examples/frodoPIR.cpp
./a.out && echo $? # = 0 means success!

Original database row bytes : bf71e04189fff486c062cf1e814bedfc2205422807da319d4ac6f5a956d63e48
PIR decoded database row bytes : bf71e04189fff486c062cf1e814bedfc2205422807da319d4ac6f5a956d63e48
```
1 change: 1 addition & 0 deletions RandomShake
Submodule RandomShake added at a9cd40
4 changes: 2 additions & 2 deletions benches/bench.mk
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ $(BENCHMARK_BUILD_DIR)/%.o: $(BENCHMARK_DIR)/%.cpp $(BENCHMARK_BUILD_DIR) $(SHA3
$(BENCHMARK_BINARY): $(BENCHMARK_OBJECTS)
$(CXX) $(RELEASE_FLAGS) $(LINK_OPT_FLAGS) $^ $(BENCHMARK_LINK_FLAGS) -o $@

benchmark: $(BENCHMARK_BINARY)
benchmark: $(BENCHMARK_BINARY) ## Build and run all benchmarks, without libPFM -based CPU CYCLE counter statistics
# Must *not* build google-benchmark with libPFM
./$< --benchmark_min_warmup_time=.5 --benchmark_enable_random_interleaving=false --benchmark_repetitions=10 --benchmark_min_time=0.1s --benchmark_display_aggregates_only=true --benchmark_report_aggregates_only=true --benchmark_counters_tabular=true --benchmark_out_format=json --benchmark_out=$(BENCHMARK_OUT_FILE)

$(PERF_BINARY): $(BENCHMARK_OBJECTS)
$(CXX) $(RELEASE_FLAGS) $(LINK_OPT_FLAGS) $^ $(PERF_LINK_FLAGS) -o $@

perf: $(PERF_BINARY)
perf: $(PERF_BINARY) ## Build and run all benchmarks, while also collecting libPFM -based CPU CYCLE counter statistics
# Must build google-benchmark with libPFM, follow https://gist.github.com/itzmeanjan/05dc3e946f635d00c5e0b21aae6203a7
./$< --benchmark_min_warmup_time=.5 --benchmark_enable_random_interleaving=false --benchmark_repetitions=10 --benchmark_min_time=0.1s --benchmark_display_aggregates_only=true --benchmark_report_aggregates_only=true --benchmark_counters_tabular=true --benchmark_perf_counters=CYCLES --benchmark_out_format=json --benchmark_out=$(BENCHMARK_OUT_FILE)
12 changes: 6 additions & 6 deletions benches/bench_client_prepare_query.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ bench_client_prepare_query(benchmark::State& state)
auto response_bytes_span = std::span<uint8_t, response_byte_len>(response_bytes);
auto db_row_bytes_span = std::span<uint8_t, db_entry_byte_len>(db_row_bytes);

prng::prng_t prng{};
csprng::csprng_t csprng{};

prng.read(seed_μ_span);
prng.read(db_bytes_span);
csprng.generate(seed_μ_span);
csprng.generate(db_bytes_span);

auto [server, M] = server_t::setup(seed_μ_span, db_bytes_span);

Expand All @@ -45,7 +45,7 @@ bench_client_prepare_query(benchmark::State& state)
size_t buffer = 0;
auto buffer_span = std::span<uint8_t, sizeof(buffer)>(reinterpret_cast<uint8_t*>(&buffer), sizeof(buffer));

prng.read(buffer_span);
csprng.generate(buffer_span);

return buffer % db_entry_count;
}();
Expand All @@ -55,12 +55,12 @@ bench_client_prepare_query(benchmark::State& state)
bool is_response_decoded = true;

for (auto _ : state) {
is_query_preprocessed &= client.prepare_query(rand_db_row_index, prng);
is_query_preprocessed &= client.prepare_query(rand_db_row_index, csprng);

benchmark::DoNotOptimize(is_query_preprocessed);
benchmark::DoNotOptimize(client);
benchmark::DoNotOptimize(rand_db_row_index);
benchmark::DoNotOptimize(prng);
benchmark::DoNotOptimize(&csprng);
benchmark::ClobberMemory();

state.PauseTiming();
Expand Down
12 changes: 6 additions & 6 deletions benches/bench_client_process_response.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ bench_client_process_response(benchmark::State& state)
auto response_bytes_span = std::span<uint8_t, response_byte_len>(response_bytes);
auto db_row_bytes_span = std::span<uint8_t, db_entry_byte_len>(db_row_bytes);

prng::prng_t prng{};
csprng::csprng_t csprng{};

prng.read(seed_μ_span);
prng.read(db_bytes_span);
csprng.generate(seed_μ_span);
csprng.generate(db_bytes_span);

auto [server, M] = server_t::setup(seed_μ_span, db_bytes_span);

Expand All @@ -45,12 +45,12 @@ bench_client_process_response(benchmark::State& state)
size_t buffer = 0;
auto buffer_span = std::span<uint8_t, sizeof(buffer)>(reinterpret_cast<uint8_t*>(&buffer), sizeof(buffer));

prng.read(buffer_span);
csprng.generate(buffer_span);

return buffer % db_entry_count;
}();

auto is_query_preprocessed = client.prepare_query(rand_db_row_index, prng);
auto is_query_preprocessed = client.prepare_query(rand_db_row_index, csprng);
auto is_query_ready = client.query(rand_db_row_index, query_bytes_span);
server.respond(query_bytes_span, response_bytes_span);

Expand All @@ -69,7 +69,7 @@ bench_client_process_response(benchmark::State& state)
rand_db_row_index ^= (rand_db_row_index << 1) ^ 1ul;
rand_db_row_index %= db_entry_count;

is_query_preprocessed &= client.prepare_query(rand_db_row_index, prng);
is_query_preprocessed &= client.prepare_query(rand_db_row_index, csprng);
is_query_ready &= client.query(rand_db_row_index, query_bytes_span);
server.respond(query_bytes_span, response_bytes_span);
state.ResumeTiming();
Expand Down
12 changes: 6 additions & 6 deletions benches/bench_client_query.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ bench_client_query(benchmark::State& state)
auto response_bytes_span = std::span<uint8_t, response_byte_len>(response_bytes);
auto db_row_bytes_span = std::span<uint8_t, db_entry_byte_len>(db_row_bytes);

prng::prng_t prng{};
csprng::csprng_t csprng{};

prng.read(seed_μ_span);
prng.read(db_bytes_span);
csprng.generate(seed_μ_span);
csprng.generate(db_bytes_span);

auto [server, M] = server_t::setup(seed_μ_span, db_bytes_span);

Expand All @@ -45,12 +45,12 @@ bench_client_query(benchmark::State& state)
size_t buffer = 0;
auto buffer_span = std::span<uint8_t, sizeof(buffer)>(reinterpret_cast<uint8_t*>(&buffer), sizeof(buffer));

prng.read(buffer_span);
csprng.generate(buffer_span);

return buffer % db_entry_count;
}();

auto is_query_preprocessed = client.prepare_query(rand_db_row_index, prng);
auto is_query_preprocessed = client.prepare_query(rand_db_row_index, csprng);
bool is_query_ready = true;
bool is_response_decoded = true;

Expand All @@ -70,7 +70,7 @@ bench_client_query(benchmark::State& state)
rand_db_row_index ^= (rand_db_row_index << 1) ^ 1ul;
rand_db_row_index %= db_entry_count;

is_query_preprocessed &= client.prepare_query(rand_db_row_index, prng);
is_query_preprocessed &= client.prepare_query(rand_db_row_index, csprng);
state.ResumeTiming();
}

Expand Down
6 changes: 3 additions & 3 deletions benches/bench_client_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ bench_client_setup(benchmark::State& state)
auto db_bytes_span = std::span<uint8_t, db_byte_len>(db_bytes);
auto pub_matM_bytes_span = std::span<uint8_t, pub_matM_byte_len>(pub_matM_bytes);

prng::prng_t prng{};
csprng::csprng_t csprng{};

prng.read(seed_μ_span);
prng.read(db_bytes_span);
csprng.generate(seed_μ_span);
csprng.generate(db_bytes_span);

auto [server, M] = server_t::setup(seed_μ_span, db_bytes_span);

Expand Down
10 changes: 5 additions & 5 deletions benches/bench_server_respond.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ bench_server_respond(benchmark::State& state)
auto query_bytes_span = std::span<uint8_t, query_byte_len>(query_bytes);
auto response_bytes_span = std::span<uint8_t, response_byte_len>(response_bytes);

prng::prng_t prng{};
csprng::csprng_t csprng{};

prng.read(seed_μ_span);
prng.read(db_bytes_span);
csprng.generate(seed_μ_span);
csprng.generate(db_bytes_span);

auto [server, M] = server_t::setup(seed_μ_span, db_bytes_span);

Expand All @@ -43,12 +43,12 @@ bench_server_respond(benchmark::State& state)
size_t buffer = 0;
auto buffer_span = std::span<uint8_t, sizeof(buffer)>(reinterpret_cast<uint8_t*>(&buffer), sizeof(buffer));

prng.read(buffer_span);
csprng.generate(buffer_span);

return buffer % db_entry_count;
}();

const auto is_query_preprocessed = client.prepare_query(rand_db_row_index, prng);
const auto is_query_preprocessed = client.prepare_query(rand_db_row_index, csprng);
assert(is_query_preprocessed);

const auto is_query_ready = client.query(rand_db_row_index, query_bytes_span);
Expand Down
6 changes: 3 additions & 3 deletions benches/bench_server_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ bench_server_setup(benchmark::State& state)
auto seed_μ_span = std::span(seed_μ);
auto db_bytes_span = std::span<uint8_t, db_byte_len>(db_bytes);

prng::prng_t prng{};
csprng::csprng_t csprng{};

prng.read(seed_μ_span);
prng.read(db_bytes_span);
csprng.generate(seed_μ_span);
csprng.generate(db_bytes_span);

for (auto _ : state) {
auto [server, M] = server_t::setup(seed_μ_span, db_bytes_span);
Expand Down
15 changes: 15 additions & 0 deletions examples/example.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
EXAMPLE_BUILD_DIR := $(BUILD_DIR)/example

EXAMPLE_DIR := examples
EXAMPLE_SOURCES := $(wildcard $(EXAMPLE_DIR)/*.cpp)
EXAMPLE_HEADERS := $(wildcard $(EXAMPLE_DIR)/*.hpp)
EXAMPLE_EXECS := $(addprefix $(EXAMPLE_BUILD_DIR)/, $(notdir $(EXAMPLE_SOURCES:.cpp=.exe)))

$(EXAMPLE_BUILD_DIR):
mkdir -p $@

$(EXAMPLE_BUILD_DIR)/%.exe: $(EXAMPLE_DIR)/%.cpp $(EXAMPLE_BUILD_DIR)
$(CXX) $(CXX_DEFS) $(CXX_FLAGS) $(WARN_FLAGS) $(RELEASE_FLAGS) $(I_FLAGS) $(DEP_IFLAGS) $< -o $@

example: $(EXAMPLE_EXECS) ## Build and run example program, demonstrating usage of FrodoPIR API
$(foreach exec,$^,./$(exec))
11 changes: 6 additions & 5 deletions examples/frodoPIR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "frodoPIR/server.hpp"
#include <algorithm>
#include <cassert>
#include <iomanip>
#include <iostream>
#include <sstream>

Expand All @@ -20,7 +21,7 @@ to_hex(std::span<const uint8_t> bytes)
}

// Compile with
// g++ -std=c++20 -Wall -Wextra -pedantic -O3 -march=native -I include -I sha3/include examples/frodoPIR.cpp
// g++ -std=c++20 -Wall -Wextra -pedantic -O3 -march=native -I include -I sha3/include -I RandomShake/include examples/frodoPIR.cpp
int
main()
{
Expand Down Expand Up @@ -52,12 +53,12 @@ main()
auto response_bytes_span = std::span<uint8_t, response_byte_len>(response_bytes);
auto obtained_db_row_bytes_span = std::span<uint8_t, db_entry_byte_len>(obtained_db_row_bytes);

prng::prng_t prng{};
csprng::csprng_t csprng{};

// Sample pseudo random seed
prng.read(seed_μ);
csprng.generate(seed_μ);
// Fill pseudo random database content
prng.read(db_bytes);
csprng.generate(db_bytes);

// Setup the FrodoPIR server
auto [server, M] = frodoPIR_server::server_t<λ, db_entry_count, db_entry_byte_len, mat_element_bitlen, lwe_dimension>::setup(seed_μ, db_bytes_span);
Expand All @@ -70,7 +71,7 @@ main()
constexpr size_t to_be_queried_db_row_index = 31;

// Client preprocesses a query, keeps cached for now; to be used when enquiring content of specified row of the database
const auto is_query_preprocessed = client.prepare_query(to_be_queried_db_row_index, prng);
const auto is_query_preprocessed = client.prepare_query(to_be_queried_db_row_index, csprng);
assert(is_query_preprocessed);

// Client wants to query content of specific database row, for which we've already a query partially prepared
Expand Down
Loading

0 comments on commit 79db5b8

Please sign in to comment.