From 5411e20443c1f68ed33ee261109c9f6cde2bbbc6 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Fri, 13 Sep 2024 18:23:30 +0400 Subject: [PATCH 01/97] Add clang-format file Following same style-guide as https://github.com/itzmeanjan/raccoon/blob/c66194d50a8e0a54d28d2de1f3bc318158ad1eb1/.clang-format Signed-off-by: Anjan Roy --- .clang-format | 225 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..0b38cb0 --- /dev/null +++ b/.clang-format @@ -0,0 +1,225 @@ +--- +Language: Cpp +# BasedOnStyle: Mozilla +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveAssignments: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: true +AlignConsecutiveBitFields: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveDeclarations: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveMacros: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignEscapedNewlines: Right +AlignOperands: Align +AlignTrailingComments: + Kind: Always + OverEmptyLines: 0 +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortEnumsOnASingleLine: true +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: TopLevel +AlwaysBreakAfterReturnType: TopLevel +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +AttributeMacros: + - __capability +BinPackArguments: false +BinPackParameters: false +BitFieldColonSpacing: Both +BraceWrapping: + AfterCaseLabel: false + AfterClass: true + AfterControlStatement: Never + AfterEnum: true + AfterExternBlock: true + AfterFunction: true + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: true + AfterUnion: true + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: false + SplitEmptyNamespace: true +BreakAfterAttributes: Never +BreakAfterJavaFieldAnnotations: false +BreakArrays: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: Always +BreakBeforeBraces: Mozilla +BreakBeforeInlineASMColon: OnlyMultiline +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeComma +BreakInheritanceList: BeforeComma +BreakStringLiterals: true +ColumnLimit: 160 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerIndentWidth: 2 +ContinuationIndentWidth: 2 +Cpp11BracedListStyle: false +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: false +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: true +IndentExternBlock: AfterExternBlock +IndentGotoLabels: true +IndentPPDirectives: None +IndentRequiresClause: true +IndentWidth: 2 +IndentWrappedFunctionNames: false +InsertBraces: false +InsertNewlineAtEOF: false +InsertTrailingCommas: None +IntegerLiteralSeparator: + Binary: 0 + BinaryMinDigits: 0 + Decimal: 0 + DecimalMinDigits: 0 + Hex: 0 + HexMinDigits: 0 +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +LambdaBodyIndentation: Signature +LineEnding: DeriveLF +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: true +ObjCSpaceBeforeProtocolList: false +PackConstructorInitializers: BinPack +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +PPIndentWidth: -1 +QualifierAlignment: Leave +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +RemoveSemicolon: false +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: LexicographicNumeric +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseTab: Never +WhitespaceSensitiveMacros: + - BOOST_PP_STRINGIZE + - CF_SWIFT_NAME + - NS_SWIFT_NAME + - PP_STRINGIZE + - STRINGIZE +... + From 14947ca275790dcc7832ee6bfc8b3f3ac70e544e Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Fri, 13 Sep 2024 18:27:24 +0400 Subject: [PATCH 02/97] Add sha3 as git submodule based dependency Signed-off-by: Anjan Roy --- .gitmodules | 3 +++ sha3 | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 sha3 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..184e184 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "sha3"] + path = sha3 + url = https://github.com/itzmeanjan/sha3.git diff --git a/sha3 b/sha3 new file mode 160000 index 0000000..f1a79a5 --- /dev/null +++ b/sha3 @@ -0,0 +1 @@ +Subproject commit f1a79a51d3a8dc3cc514ce7908e46c6a7946414e From dd9da56010cc754cf97bd9bb2b8f21b455d1d9a8 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Fri, 13 Sep 2024 18:28:12 +0400 Subject: [PATCH 03/97] Add gtest-parallel as git submodule based dependency Signed-off-by: Anjan Roy --- .gitmodules | 3 +++ gtest-parallel | 1 + 2 files changed, 4 insertions(+) create mode 160000 gtest-parallel diff --git a/.gitmodules b/.gitmodules index 184e184..8e85d6c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "sha3"] path = sha3 url = https://github.com/itzmeanjan/sha3.git +[submodule "gtest-parallel"] + path = gtest-parallel + url = https://github.com/google/gtest-parallel.git diff --git a/gtest-parallel b/gtest-parallel new file mode 160000 index 0000000..96f4f90 --- /dev/null +++ b/gtest-parallel @@ -0,0 +1 @@ +Subproject commit 96f4f904922f9bf66689e749c40f314845baaac8 From b5121db3c2ec2c01db14eaa3b8adc0d5c25e3962 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Fri, 13 Sep 2024 18:33:23 +0400 Subject: [PATCH 04/97] Add force_inline MACRO Signed-off-by: Anjan Roy --- .../internals/utility/force_inline.hpp | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 include/frodoPIR/internals/utility/force_inline.hpp diff --git a/include/frodoPIR/internals/utility/force_inline.hpp b/include/frodoPIR/internals/utility/force_inline.hpp new file mode 100644 index 0000000..f383776 --- /dev/null +++ b/include/frodoPIR/internals/utility/force_inline.hpp @@ -0,0 +1,29 @@ +#pragma once + +// Following content is taken from https://github.com/itzmeanjan/raccoon/blob/c66194d5/include/raccoon/internals/utility/force_inline.hpp + +#ifdef _MSC_VER +// MSVC +#define forceinline __forceinline + +#elif defined(__GNUC__) +// GCC +#if defined(__cplusplus) && __cplusplus >= 201103L +#define forceinline inline __attribute__((__always_inline__)) +#else +#define forceinline inline +#endif + +#elif defined(__CLANG__) +// Clang +#if __has_attribute(__always_inline__) +#define forceinline inline __attribute__((__always_inline__)) +#else +#define forceinline inline +#endif + +#else +// Others +#define forceinline inline + +#endif From eaf6900f180a7a4273237b4f182d31f621ff863c Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Fri, 13 Sep 2024 18:48:18 +0400 Subject: [PATCH 05/97] Add shake128 backed Pseudo Random Number Generator Taken from https://github.com/itzmeanjan/raccoon/blob/c66194d5/include/raccoon/internals/rng/prng.hpp Signed-off-by: Anjan Roy --- include/frodoPIR/internals/rng/prng.hpp | 62 +++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 include/frodoPIR/internals/rng/prng.hpp diff --git a/include/frodoPIR/internals/rng/prng.hpp b/include/frodoPIR/internals/rng/prng.hpp new file mode 100644 index 0000000..865f109 --- /dev/null +++ b/include/frodoPIR/internals/rng/prng.hpp @@ -0,0 +1,62 @@ +#pragma once +#include "frodoPIR/internals/utility/force_inline.hpp" +#include "shake128.hpp" +#include +#include + +// Pseudo Random Number Generator +namespace prng { + +// Pseudo Random Number Generator s.t. N (>0) -many random bytes are read +// from SHAKE128 XOF state, by calling it arbitrary many times, s.t. SHAKE128 +// state is obtained by +// +// - either absorbing 32 -bytes, sampled using std::random_device ( default ) +// - or absorbing M(>0) -bytes, supplied as argument ( explicit ) +// +// Note, std::random_device's behaviour is implementation defined feature, so +// this PRNG implementation doesn't guarantee that it'll generate cryptographic +// secure random bytes if you opt for using default constructor of this struct. +// +// I suggest you read https://en.cppreference.com/w/cpp/numeric/random/random_device/random_device +// before using default constructor. When using explicit constructor, it's +// your responsibility to supply M -many random seed bytes. +// +// This implementation is taken from +// https://github.com/itzmeanjan/raccoon/blob/c66194d5/include/raccoon/internals/rng/prng.hpp +struct prng_t +{ +private: + shake128::shake128_t state; + +public: + forceinline prng_t() + { + std::array seed{}; + auto seed_span = std::span(seed); + + // Read more @ https://en.cppreference.com/w/cpp/numeric/random/random_device/random_device + std::random_device rd{}; + + size_t off = 0; + while (off < sizeof(seed)) { + const uint32_t v = rd(); + std::memcpy(seed_span.subspan(off, sizeof(v)).data(), &v, sizeof(v)); + + off += sizeof(v); + } + + state.absorb(seed_span); + state.finalize(); + } + + forceinline explicit constexpr prng_t(std::span seed) + { + state.absorb(seed); + state.finalize(); + } + + forceinline void constexpr read(std::span bytes) { state.squeeze(bytes); } +}; + +} From 6e4aabf3691bc55daf7dd9eecc95d7a0f0a27dad Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Fri, 13 Sep 2024 18:50:01 +0400 Subject: [PATCH 06/97] Update list of files to be ignored by git Signed-off-by: Anjan Roy --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 259148f..152576f 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,7 @@ *.exe *.out *.app + +.cache +compile_commands.json +build From d546b2d2394305fbcd71398d487f8433575f2f2e Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Fri, 13 Sep 2024 19:10:04 +0400 Subject: [PATCH 07/97] Basic matrix struct, supporting random sampling of matrix, given input seed Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 58 ++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 include/frodoPIR/internals/matrix/matrix.hpp diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp new file mode 100644 index 0000000..d2c60e4 --- /dev/null +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -0,0 +1,58 @@ +#pragma once +#include "frodoPIR/internals/rng/prng.hpp" +#include "frodoPIR/internals/utility/force_inline.hpp" +#include +#include +#include +#include +#include + +namespace frodoPIR_matrix { + +// All arithmetic operations are performed modulo 2^32, for which we have native reduction. +using zq_t = uint32_t; + +// Matrix of dimension `rows x cols`. +template + requires((rows > 0) && (cols > 0)) +struct matrix_t +{ +private: + std::array elements{}; + +public: + // Constructor(s) + forceinline constexpr matrix_t() = default; + // Given a `λ` -bit seed, this routine uniform random samples a matrix of dimension `rows x cols`. + template + forceinline matrix_t generate(std::span::digits> μ) + { + prng::prng_t prng(μ); + + zq_t word{}; + matrix_t mat{}; + + for (size_t r_idx = 0; r_idx < rows; r_idx++) { + for (size_t c_idx = 0; c_idx < cols; c_idx++) { + prng.read(std::span(reinterpret_cast(&word), sizeof(word))); + mat[{ r_idx, c_idx }] = word; + } + } + + return mat; + } + + // Accessor(s) + forceinline constexpr zq_t& operator[](std::pair idx) + { + const auto [r_idx, c_idx] = idx; + return this->elements[r_idx * cols + c_idx]; + } + forceinline constexpr const zq_t& operator[](std::pair idx) const + { + const auto [r_idx, c_idx] = idx; + return this->elements[r_idx * cols + c_idx]; + } +}; + +} From 8e5e016298fcadd8b829e18e1862e4868bcaad9e Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Fri, 13 Sep 2024 19:20:38 +0400 Subject: [PATCH 08/97] Multiply two matrices of valid dimension Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 23 ++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index d2c60e4..b988f66 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -53,6 +53,29 @@ struct matrix_t const auto [r_idx, c_idx] = idx; return this->elements[r_idx * cols + c_idx]; } + + // Given two matrices A ( of dimension rows x cols ) and B ( of dimension rhs_rows x rhs_cols ) s.t. cols == rhs_rows, + // this routine can be used for multiplying them over Zq, resulting into another matrix (C) of dimension rows x rhs_cols. + template + requires((cols == rhs_rows)) + forceinline constexpr matrix_t operator*(const matrix_t& rhs) + { + matrix_t res{}; + + for (size_t r_idx = 0; r_idx < rows; r_idx++) { + for (size_t c_idx = 0; c_idx < rhs_cols; c_idx++) { + zq_t tmp{}; + + for (size_t k = 0; k < cols; k++) { + tmp += (*this)[{ r_idx, k }] * rhs[{ k, c_idx }]; + } + + res[{ r_idx, c_idx }] = tmp; + } + } + + return res; + } }; } From 4d78165d31edd166b923d38e90ba852a6757ca0e Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Fri, 13 Sep 2024 19:22:45 +0400 Subject: [PATCH 09/97] Addition of two equal dimension matrices over Zq Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index b988f66..3beeb41 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -54,11 +54,24 @@ struct matrix_t return this->elements[r_idx * cols + c_idx]; } + // Given two matrices A, B of equal dimension, this routine can be used for performing matrix addition over Zq, + // returning a matrix of same dimension. + inline constexpr matrix_t operator+(const matrix_t& rhs) const + { + matrix_t res{}; + + for (size_t i = 0; i < rows * cols; i++) { + res[i] = (*this)[i] + rhs[i]; + } + + return res; + } + // Given two matrices A ( of dimension rows x cols ) and B ( of dimension rhs_rows x rhs_cols ) s.t. cols == rhs_rows, // this routine can be used for multiplying them over Zq, resulting into another matrix (C) of dimension rows x rhs_cols. template requires((cols == rhs_rows)) - forceinline constexpr matrix_t operator*(const matrix_t& rhs) + forceinline constexpr matrix_t operator*(const matrix_t& rhs) const { matrix_t res{}; From 657b5a9b3cc19966a5cf75cee08d0899bf834059 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Fri, 13 Sep 2024 19:40:21 +0400 Subject: [PATCH 10/97] Serialization and deserialization of matrix data type Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 51 ++++++++++++++++++-- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index 3beeb41..c86d154 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -42,21 +42,25 @@ struct matrix_t return mat; } - // Accessor(s) - forceinline constexpr zq_t& operator[](std::pair idx) + // Accessor, using {row_index, column_index} pair. + forceinline constexpr zq_t& operator[](const std::pair idx) { const auto [r_idx, c_idx] = idx; return this->elements[r_idx * cols + c_idx]; } - forceinline constexpr const zq_t& operator[](std::pair idx) const + forceinline constexpr const zq_t& operator[](const std::pair idx) const { const auto [r_idx, c_idx] = idx; return this->elements[r_idx * cols + c_idx]; } + // Accessor, using linearized index. + forceinline constexpr zq_t& operator[](const size_t lin_idx) { return this->elements[lin_idx]; } + forceinline constexpr const zq_t& operator[](const size_t lin_idx) const { return this->elements[lin_idx]; } + // Given two matrices A, B of equal dimension, this routine can be used for performing matrix addition over Zq, // returning a matrix of same dimension. - inline constexpr matrix_t operator+(const matrix_t& rhs) const + forceinline constexpr matrix_t operator+(const matrix_t& rhs) const { matrix_t res{}; @@ -89,6 +93,45 @@ struct matrix_t return res; } + + // Given a matrix M of dimension `rows x cols`, this routine can be used for serializing each of its elements as + // four little-endian bytes and concatenating them in order to compute a byte array of length m * n * 4. + forceinline constexpr void to_le_bytes(std::span bytes) const + { + for (size_t i = 0; i < rows * cols; i++) { + const size_t boff = i * sizeof(zq_t); + + const auto word = (*this)[i]; + + bytes[boff + 0] = static_cast((word >> 0u) & 0xffu); + bytes[boff + 1] = static_cast((word >> 8u) & 0xffu); + bytes[boff + 2] = static_cast((word >> 16u) & 0xffu); + bytes[boff + 3] = static_cast((word >> 24u) & 0xffu); + } + } + + // Given a byte array of length m * n * 4, this routine can be used for deserializing it as a matrix of dimension m x n + // s.t. each matrix element is computed by interpreting four consecutive bytes in little-endian order. + forceinline static matrix_t from_le_bytes(std::span bytes) + { + constexpr size_t blen = bytes.size(); + matrix_t res{}; + + size_t boff = 0; + size_t lin_idx = 0; + + while (boff < blen) { + const zq_t word = ((static_cast(bytes[boff + 3]) << 24u) | (static_cast(bytes[boff + 2]) << 16u) | + (static_cast(bytes[boff + 1]) << 8u) | (static_cast(bytes[boff + 0]) << 0u)); + + res[lin_idx] = word; + + boff += sizeof(zq_t); + lin_idx += 1; + } + + return res; + } }; } From be301acd457764db778e119676416b78bf9c9464 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sat, 14 Sep 2024 11:27:01 +0400 Subject: [PATCH 11/97] Add utility function for computing logarithm base-2 Signed-off-by: Anjan Roy --- include/frodoPIR/internals/utility/utils.hpp | 26 ++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 include/frodoPIR/internals/utility/utils.hpp diff --git a/include/frodoPIR/internals/utility/utils.hpp b/include/frodoPIR/internals/utility/utils.hpp new file mode 100644 index 0000000..f44afe5 --- /dev/null +++ b/include/frodoPIR/internals/utility/utils.hpp @@ -0,0 +1,26 @@ +#pragma once +#include "frodoPIR/internals/utility/force_inline.hpp" +#include +#include + +namespace frodoPIR_utils { + +// Given an unsigned integer as input, this routine returns TRUTH value only if `v` is power of 2, otherwise it returns FALSE. +template +forceinline constexpr bool +is_power_of_2(const T v) + requires(std::is_unsigned_v) +{ + return ((v) & (v - 1)) == 0; +} + +// Given a power of 2 value `v`, this routine returns logarithm base-2 of v. +template +forceinline constexpr size_t +log2() + requires((v > 0) && is_power_of_2(v)) +{ + return std::countr_zero(v); +} + +} From 723e47de3a6f8ed6233ce8116f411e073fc8fb1d Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sat, 14 Sep 2024 12:07:56 +0400 Subject: [PATCH 12/97] reading from and writing to byte array, in little-endian order Signed-off-by: Anjan Roy --- include/frodoPIR/internals/utility/utils.hpp | 36 ++++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/include/frodoPIR/internals/utility/utils.hpp b/include/frodoPIR/internals/utility/utils.hpp index f44afe5..ce89917 100644 --- a/include/frodoPIR/internals/utility/utils.hpp +++ b/include/frodoPIR/internals/utility/utils.hpp @@ -2,25 +2,39 @@ #include "frodoPIR/internals/utility/force_inline.hpp" #include #include +#include +#include +#include namespace frodoPIR_utils { -// Given an unsigned integer as input, this routine returns TRUTH value only if `v` is power of 2, otherwise it returns FALSE. +// Given a byte array of length n (>=0), this routine copies input bytes into destination word, of unsigned type T, +// while placing bytes following little-endian ordering. template -forceinline constexpr bool -is_power_of_2(const T v) - requires(std::is_unsigned_v) +forceinline constexpr T +from_le_bytes(std::span bytes) + requires(std::is_unsigned_v && (std::endian::native == std::endian::little)) { - return ((v) & (v - 1)) == 0; + T res{}; + + const size_t copyable = std::min(sizeof(res), bytes.size()); + for (size_t i = 0; i < copyable; i++) { + res |= (static_cast(bytes[i]) << (i * std::numeric_limits::digits)); + } + + return res; } -// Given a power of 2 value `v`, this routine returns logarithm base-2 of v. -template -forceinline constexpr size_t -log2() - requires((v > 0) && is_power_of_2(v)) +// Given an unsigned integer as input, this routine copies source bytes, following little-endian order, into destination +// byte array of length n (>=0). +forceinline constexpr void +to_le_bytes(const std::unsigned_integral auto v, std::span bytes) + requires(std::endian::native == std::endian::little) { - return std::countr_zero(v); + const size_t copyable = std::min(sizeof(v), bytes.size()); + for (size_t i = 0; i < copyable; i++) { + bytes[i] = static_cast(v >> (i * std::numeric_limits::digits)); + } } } From cb81fe553772d070e5710d67bd03f705932705c0 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sat, 14 Sep 2024 12:10:57 +0400 Subject: [PATCH 13/97] =?UTF-8?q?Make=20generation=20of=20public=20matrix?= =?UTF-8?q?=20A,=20from=20seed=20=CE=BC,=20`constexpr`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index c86d154..72862bd 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -1,6 +1,7 @@ #pragma once #include "frodoPIR/internals/rng/prng.hpp" #include "frodoPIR/internals/utility/force_inline.hpp" +#include "frodoPIR/internals/utility/utils.hpp" #include #include #include @@ -25,17 +26,19 @@ struct matrix_t forceinline constexpr matrix_t() = default; // Given a `λ` -bit seed, this routine uniform random samples a matrix of dimension `rows x cols`. template - forceinline matrix_t generate(std::span::digits> μ) + static forceinline constexpr matrix_t generate(std::span::digits> μ) { prng::prng_t prng(μ); - zq_t word{}; + std::array buffer{}; + auto buffer_span = std::span(buffer); + matrix_t mat{}; for (size_t r_idx = 0; r_idx < rows; r_idx++) { for (size_t c_idx = 0; c_idx < cols; c_idx++) { - prng.read(std::span(reinterpret_cast(&word), sizeof(word))); - mat[{ r_idx, c_idx }] = word; + prng.read(buffer_span); + mat[{ r_idx, c_idx }] = frodoPIR_utils::from_le_bytes(buffer_span); } } From 750ed5a45079a58c27f82c3e7b3e69bfe16a3a2f Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sat, 14 Sep 2024 12:47:28 +0400 Subject: [PATCH 14/97] Parse byte serialized database into matrix Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 58 ++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index 72862bd..0d67334 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -2,6 +2,7 @@ #include "frodoPIR/internals/rng/prng.hpp" #include "frodoPIR/internals/utility/force_inline.hpp" #include "frodoPIR/internals/utility/utils.hpp" +#include #include #include #include @@ -45,6 +46,63 @@ struct matrix_t return mat; } + // Given a byte serialized database s.t. it has `db_entry_count` -number of rows and each row contains `db_entry_byte_len` -bytes + // entry, this routines parses database into a matrix s.t. each element of matrix has `mat_element_bitlen` significant bits. + // + // Note, 0 < `mat_element_bitlen` < 32. + // Collects inspiration from https://github.com/brave-experiments/frodo-pir/blob/15573960/src/db.rs#L229-L254. + template + requires((rows == db_entry_count) && + (cols == + []() { + const size_t db_entry_bit_len = db_entry_byte_len * std::numeric_limits::digits; + const size_t required_num_cols = (db_entry_bit_len + (mat_element_bitlen - 1)) / mat_element_bitlen; + + return required_num_cols; + }()) && + ((0 < mat_element_bitlen) && (mat_element_bitlen < std::numeric_limits::digits))) + static forceinline matrix_t parse_db_bytes(std::span bytes) + { + constexpr auto mat_element_mask = (1ul << mat_element_bitlen) - 1ul; + + matrix_t mat{}; + size_t mat_lin_idx = 0; + + uint64_t buffer = 0; + auto buffer_span = std::span(reinterpret_cast(&buffer), sizeof(buffer)); + + size_t buf_num_bits = 0; + size_t byte_off = 0; + + while (byte_off < bytes.size()) { + const size_t remaining_num_bytes = bytes.size() - byte_off; + + const size_t fillable_num_bits = std::numeric_limits::digits - buf_num_bits; + const size_t readable_num_bits = fillable_num_bits & (-std::numeric_limits::digits); + const size_t readable_num_bytes = std::min(readable_num_bits / std::numeric_limits::digits, remaining_num_bytes); + + const auto read_word = frodoPIR_utils::from_le_bytes(bytes.subspan(byte_off, readable_num_bytes)); + byte_off += readable_num_bytes; + + buffer |= (read_word << buf_num_bits); + buf_num_bits += readable_num_bits; + + const size_t fillable_mat_elem_count = buf_num_bits / mat_element_bitlen; + + for (size_t elem_idx = 0; elem_idx < fillable_mat_elem_count; elem_idx++) { + const zq_t mat_element = buffer & mat_element_mask; + mat[mat_lin_idx + elem_idx] = mat_element; + + buffer >>= mat_element_bitlen; + buf_num_bits -= mat_element_bitlen; + } + + mat_lin_idx += fillable_mat_elem_count; + } + + return mat; + } + // Accessor, using {row_index, column_index} pair. forceinline constexpr zq_t& operator[](const std::pair idx) { From 3e1ca9ca85e7c1924b6c5a6a0ccc19a27a291da0 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sat, 14 Sep 2024 12:55:46 +0400 Subject: [PATCH 15/97] Implement matrix transpose function Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index 0d67334..8ad68c6 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -119,6 +119,21 @@ struct matrix_t forceinline constexpr zq_t& operator[](const size_t lin_idx) { return this->elements[lin_idx]; } forceinline constexpr const zq_t& operator[](const size_t lin_idx) const { return this->elements[lin_idx]; } + // Given a matrix M of dimension `rows x cols`, this routine is used for computing its transpose M' s.t. + // resulting matrix's dimension becomes `cols x rows`. + forceinline constexpr matrix_t transpose() const + { + matrix_t res{}; + + for (size_t i = 0; i < cols; i++) { + for (size_t j = 0; j < rows; j++) { + res[{ i, j }] = (*this)[{ j, i }]; + } + } + + return res; + } + // Given two matrices A, B of equal dimension, this routine can be used for performing matrix addition over Zq, // returning a matrix of same dimension. forceinline constexpr matrix_t operator+(const matrix_t& rhs) const From c8d30dbcc293624572c31a21a2193a4fbf1e7926 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sat, 14 Sep 2024 12:57:42 +0400 Subject: [PATCH 16/97] Use existing functions for byte (de-)serialization of matrix Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index 8ad68c6..a145bfd 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -171,23 +171,19 @@ struct matrix_t } // Given a matrix M of dimension `rows x cols`, this routine can be used for serializing each of its elements as - // four little-endian bytes and concatenating them in order to compute a byte array of length m * n * 4. + // four little-endian bytes and concatenating them in order to compute a byte array of length `rows * cols * 4`. forceinline constexpr void to_le_bytes(std::span bytes) const { for (size_t i = 0; i < rows * cols; i++) { const size_t boff = i * sizeof(zq_t); const auto word = (*this)[i]; - - bytes[boff + 0] = static_cast((word >> 0u) & 0xffu); - bytes[boff + 1] = static_cast((word >> 8u) & 0xffu); - bytes[boff + 2] = static_cast((word >> 16u) & 0xffu); - bytes[boff + 3] = static_cast((word >> 24u) & 0xffu); + frodoPIR_utils::to_le_bytes(word, bytes.subspan(boff, sizeof(word))); } } - // Given a byte array of length m * n * 4, this routine can be used for deserializing it as a matrix of dimension m x n - // s.t. each matrix element is computed by interpreting four consecutive bytes in little-endian order. + // Given a byte array of length `rows * cols * 4`, this routine can be used for deserializing it as a matrix of dimension + // `rows x cols` s.t. each matrix element is computed by interpreting four consecutive bytes in little-endian order. forceinline static matrix_t from_le_bytes(std::span bytes) { constexpr size_t blen = bytes.size(); @@ -197,12 +193,10 @@ struct matrix_t size_t lin_idx = 0; while (boff < blen) { - const zq_t word = ((static_cast(bytes[boff + 3]) << 24u) | (static_cast(bytes[boff + 2]) << 16u) | - (static_cast(bytes[boff + 1]) << 8u) | (static_cast(bytes[boff + 0]) << 0u)); - + const auto word = frodoPIR_utils::from_le_bytes(bytes.subspan(boff, sizeof(zq_t))); res[lin_idx] = word; - boff += sizeof(zq_t); + boff += sizeof(word); lin_idx += 1; } From 77afcb01b07b28693ee604203070085ecbcbcabf Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sat, 14 Sep 2024 23:07:28 +0400 Subject: [PATCH 17/97] Refactor parsing of database bytes s.t. it encodes all bytes of same database row into same row of matrix Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 50 ++++++++++++-------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index a145bfd..20b05e5 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -66,38 +66,46 @@ struct matrix_t constexpr auto mat_element_mask = (1ul << mat_element_bitlen) - 1ul; matrix_t mat{}; - size_t mat_lin_idx = 0; - uint64_t buffer = 0; - auto buffer_span = std::span(reinterpret_cast(&buffer), sizeof(buffer)); + for (size_t r_idx = 0; r_idx < rows; r_idx++) { + uint64_t buffer = 0; + auto buffer_span = std::span(reinterpret_cast(&buffer), sizeof(buffer)); + + size_t buf_num_bits = 0; + size_t c_idx = 0; - size_t buf_num_bits = 0; - size_t byte_off = 0; + size_t byte_off = r_idx * db_entry_byte_len; + const size_t till_byte_off = byte_off + db_entry_byte_len; - while (byte_off < bytes.size()) { - const size_t remaining_num_bytes = bytes.size() - byte_off; + while (byte_off < till_byte_off) { + const size_t remaining_num_bytes = till_byte_off - byte_off; - const size_t fillable_num_bits = std::numeric_limits::digits - buf_num_bits; - const size_t readable_num_bits = fillable_num_bits & (-std::numeric_limits::digits); - const size_t readable_num_bytes = std::min(readable_num_bits / std::numeric_limits::digits, remaining_num_bytes); + const size_t fillable_num_bits = std::numeric_limits::digits - buf_num_bits; + const size_t readable_num_bits = fillable_num_bits & (-std::numeric_limits::digits); + const size_t readable_num_bytes = std::min(readable_num_bits / std::numeric_limits::digits, remaining_num_bytes); - const auto read_word = frodoPIR_utils::from_le_bytes(bytes.subspan(byte_off, readable_num_bytes)); - byte_off += readable_num_bytes; + const auto read_word = frodoPIR_utils::from_le_bytes(bytes.subspan(byte_off, readable_num_bytes)); + byte_off += readable_num_bytes; - buffer |= (read_word << buf_num_bits); - buf_num_bits += readable_num_bits; + buffer |= (read_word << buf_num_bits); + buf_num_bits += readable_num_bits; - const size_t fillable_mat_elem_count = buf_num_bits / mat_element_bitlen; + const size_t fillable_mat_elem_count = buf_num_bits / mat_element_bitlen; - for (size_t elem_idx = 0; elem_idx < fillable_mat_elem_count; elem_idx++) { - const zq_t mat_element = buffer & mat_element_mask; - mat[mat_lin_idx + elem_idx] = mat_element; + for (size_t elem_idx = 0; elem_idx < fillable_mat_elem_count; elem_idx++) { + const zq_t mat_element = buffer & mat_element_mask; + mat[{ r_idx, c_idx + elem_idx }] = mat_element; - buffer >>= mat_element_bitlen; - buf_num_bits -= mat_element_bitlen; + buffer >>= mat_element_bitlen; + buf_num_bits -= mat_element_bitlen; + } + + c_idx += fillable_mat_elem_count; } - mat_lin_idx += fillable_mat_elem_count; + if ((buf_num_bits > 0) && (c_idx < cols)) { + mat[{ r_idx, c_idx }] = buffer & mat_element_mask; + } } return mat; From c78cb920caa195db6b40d5ec87313e912728ccd5 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sat, 14 Sep 2024 23:47:27 +0400 Subject: [PATCH 18/97] Rejection sampling from uniform ternary distribution Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 61 ++++++++++++++++++-- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index 20b05e5..95d821d 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -14,17 +14,20 @@ namespace frodoPIR_matrix { // All arithmetic operations are performed modulo 2^32, for which we have native reduction. using zq_t = uint32_t; +// Size of interval, used for sampling from uniform ternary distribution χ. +inline constexpr size_t TERNARY_INTERVAL_SIZE = (std::numeric_limits::max() - 2) / 3; +// Uniform sampled value to be rejected, if greater than sampling max, which is < uint32_t_MAX. +inline constexpr size_t TERNARY_REJECTION_SAMPLING_MAX = TERNARY_INTERVAL_SIZE * 3; + // Matrix of dimension `rows x cols`. template requires((rows > 0) && (cols > 0)) struct matrix_t { -private: - std::array elements{}; - public: - // Constructor(s) + // Default constructor forceinline constexpr matrix_t() = default; + // Given a `λ` -bit seed, this routine uniform random samples a matrix of dimension `rows x cols`. template static forceinline constexpr matrix_t generate(std::span::digits> μ) @@ -46,6 +49,20 @@ struct matrix_t return mat; } + // Given a seeded PRNG, this routine samples a column vector of size `rows x 1`, + // by rejection sampling from a uniform ternary distribution. + static forceinline constexpr matrix_t sample_from_uniform_ternary_distribution(prng::prng_t& prng) + requires(cols == 1) + { + matrix_t mat{}; + + for (size_t r_idx = 0; r_idx < rows; r_idx++) { + mat[{ r_idx, 0 }] = sample_random_ternary(prng); + } + + return mat; + } + // Given a byte serialized database s.t. it has `db_entry_count` -number of rows and each row contains `db_entry_byte_len` -bytes // entry, this routines parses database into a matrix s.t. each element of matrix has `mat_element_bitlen` significant bits. // @@ -210,6 +227,42 @@ struct matrix_t return res; } + +private: + std::array elements{}; + + // Given a seeded PRNG, this routine can be used for rejection sampling a value from a uniform ternary distribution χ. + // Returns sampled value ∈ {-1, 0, +1}. + // + // Collects inspiration from https://github.com/brave-experiments/frodo-pir/blob/15573960/src/utils.rs#L102-L125. + static forceinline constexpr zq_t sample_random_ternary(prng::prng_t& prng) + { + const auto val = [&]() { + zq_t val{}; + + std::array buffer{}; + auto buffer_span = std::span(buffer); + + prng.read(buffer_span); + val = frodoPIR_utils::from_le_bytes(buffer_span); + + while (val > TERNARY_REJECTION_SAMPLING_MAX) { + prng.read(buffer_span); + val = frodoPIR_utils::from_le_bytes(buffer_span); + } + + return val; + }(); + + zq_t ternary = 0; + if ((val > TERNARY_INTERVAL_SIZE) && (val < (2 * TERNARY_INTERVAL_SIZE))) { + ternary = 1; + } else { + ternary = std::numeric_limits::max(); + } + + return ternary; + } }; } From 59bd45b9367d614c53a97fae0b87b744f1d80225 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sat, 14 Sep 2024 23:54:45 +0400 Subject: [PATCH 19/97] Add typedef for vector datatype Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/vector.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 include/frodoPIR/internals/matrix/vector.hpp diff --git a/include/frodoPIR/internals/matrix/vector.hpp b/include/frodoPIR/internals/matrix/vector.hpp new file mode 100644 index 0000000..22cee43 --- /dev/null +++ b/include/frodoPIR/internals/matrix/vector.hpp @@ -0,0 +1,9 @@ +#pragma once +#include "frodoPIR/internals/matrix/matrix.hpp" + +namespace frodoPIR_vector { + +template +using vector_t = frodoPIR_matrix::matrix_t; + +} From ad907cf3670af561d82c46b348d17a80acd3c045 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sun, 15 Sep 2024 10:12:50 +0400 Subject: [PATCH 20/97] Instead of using std::array as backing data structure for matrix data type, prefer std::vector, due to "very" large size requirements Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index 95d821d..223ba91 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace frodoPIR_matrix { @@ -26,7 +27,7 @@ struct matrix_t { public: // Default constructor - forceinline constexpr matrix_t() = default; + forceinline constexpr matrix_t() { this->elements = std::vector(rows * cols, zq_t{}); }; // Given a `λ` -bit seed, this routine uniform random samples a matrix of dimension `rows x cols`. template @@ -229,7 +230,7 @@ struct matrix_t } private: - std::array elements{}; + std::vector elements; // Given a seeded PRNG, this routine can be used for rejection sampling a value from a uniform ternary distribution χ. // Returns sampled value ∈ {-1, 0, +1}. From 28c60c33599d9c9a939e7de5a882458f35ee5e73 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sun, 15 Sep 2024 23:53:42 +0400 Subject: [PATCH 21/97] Implement FrodoPIR server setup phase Signed-off-by: Anjan Roy --- include/frodoPIR/server.hpp | 70 +++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 include/frodoPIR/server.hpp diff --git a/include/frodoPIR/server.hpp b/include/frodoPIR/server.hpp new file mode 100644 index 0000000..541b3df --- /dev/null +++ b/include/frodoPIR/server.hpp @@ -0,0 +1,70 @@ +#pragma once +#include "frodoPIR/internals/matrix/matrix.hpp" +#include "frodoPIR/internals/utility/force_inline.hpp" +#include +#include +#include +#include + +namespace frodoPIR_server { + +// Frodo *P*rivate *I*nformation *R*etrieval Server +template +struct server_t +{ +public: + // Constructor(s) + explicit constexpr server_t(frodoPIR_matrix::matrix_t::digits; + const size_t required_num_cols = (db_entry_bit_len + (mat_element_bitlen - 1)) / mat_element_bitlen; + + return required_num_cols; + }()> db) + : D(std::move(db)) + { + } + + server_t(const server_t&) = default; + server_t(server_t&&) = default; + server_t& operator=(const server_t&) = default; + server_t& operator=(server_t&&) = default; + + // Given a `λ` -bit seed and a byte serialized database which has `db_entry_count` -many entries s.t. + // each entry is of `db_entry_byte_len` -bytes, this routine can be used for setting up FrodoPIR server, + // returning initialized server (ready to respond to client queries) handle and public matrix M, which will + // be used by clients for preprocessing queries. + static forceinline constexpr std::pair::digits; + return (db_entry_bit_len + (mat_element_bitlen - 1)) / mat_element_bitlen; + }()>> + setup(std::span::digits> seed_μ, std::span db_bytes) + { + constexpr auto cols = []() { + const size_t db_entry_bit_len = db_entry_byte_len * std::numeric_limits::digits; + const size_t required_num_cols = (db_entry_bit_len + (mat_element_bitlen - 1)) / mat_element_bitlen; + + return required_num_cols; + }(); + + const auto A = frodoPIR_matrix::matrix_t::template generate<λ>(seed_μ); + const auto D = frodoPIR_matrix::matrix_t::template parse_db_bytes(db_bytes); + const auto M = A * D; + + return { server_t(D), M }; + }; + +private: + frodoPIR_matrix::matrix_t::digits; + const size_t required_num_cols = (db_entry_bit_len + (mat_element_bitlen - 1)) / mat_element_bitlen; + + return required_num_cols; + }()> + D{}; +}; + +} From aa38e5a4e340d1a7d4cc8e503390d7a22acb0dc9 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Mon, 16 Sep 2024 00:08:57 +0400 Subject: [PATCH 22/97] Create lambda for computing row width of parsed database matrix Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 17 ++++++----- include/frodoPIR/server.hpp | 32 +++++--------------- 2 files changed, 17 insertions(+), 32 deletions(-) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index 223ba91..267dcde 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -20,6 +20,14 @@ inline constexpr size_t TERNARY_INTERVAL_SIZE = (std::numeric_limits::max( // Uniform sampled value to be rejected, if greater than sampling max, which is < uint32_t_MAX. inline constexpr size_t TERNARY_REJECTION_SAMPLING_MAX = TERNARY_INTERVAL_SIZE * 3; +// Lambda for computing row width (i.e. number of columns) of parsed database matrix. +constexpr auto get_required_num_columns = [](const size_t db_entry_byte_len, const size_t mat_element_bitlen) { + const size_t db_entry_bit_len = db_entry_byte_len * std::numeric_limits::digits; + const size_t required_num_cols = (db_entry_bit_len + (mat_element_bitlen - 1)) / mat_element_bitlen; + + return required_num_cols; +}; + // Matrix of dimension `rows x cols`. template requires((rows > 0) && (cols > 0)) @@ -70,14 +78,7 @@ struct matrix_t // Note, 0 < `mat_element_bitlen` < 32. // Collects inspiration from https://github.com/brave-experiments/frodo-pir/blob/15573960/src/db.rs#L229-L254. template - requires((rows == db_entry_count) && - (cols == - []() { - const size_t db_entry_bit_len = db_entry_byte_len * std::numeric_limits::digits; - const size_t required_num_cols = (db_entry_bit_len + (mat_element_bitlen - 1)) / mat_element_bitlen; - - return required_num_cols; - }()) && + requires((rows == db_entry_count) && (cols == get_required_num_columns(db_entry_byte_len, mat_element_bitlen)) && ((0 < mat_element_bitlen) && (mat_element_bitlen < std::numeric_limits::digits))) static forceinline matrix_t parse_db_bytes(std::span bytes) { diff --git a/include/frodoPIR/server.hpp b/include/frodoPIR/server.hpp index 541b3df..82b0efa 100644 --- a/include/frodoPIR/server.hpp +++ b/include/frodoPIR/server.hpp @@ -14,13 +14,7 @@ struct server_t { public: // Constructor(s) - explicit constexpr server_t(frodoPIR_matrix::matrix_t::digits; - const size_t required_num_cols = (db_entry_bit_len + (mat_element_bitlen - 1)) / mat_element_bitlen; - - return required_num_cols; - }()> db) + explicit constexpr server_t(frodoPIR_matrix::matrix_t db) : D(std::move(db)) { } @@ -34,27 +28,18 @@ struct server_t // each entry is of `db_entry_byte_len` -bytes, this routine can be used for setting up FrodoPIR server, // returning initialized server (ready to respond to client queries) handle and public matrix M, which will // be used by clients for preprocessing queries. - static forceinline constexpr std::pair::digits; - return (db_entry_bit_len + (mat_element_bitlen - 1)) / mat_element_bitlen; - }()>> - setup(std::span::digits> seed_μ, std::span db_bytes) + static forceinline constexpr std:: + pair> + setup(std::span::digits> seed_μ, std::span db_bytes) { - constexpr auto cols = []() { - const size_t db_entry_bit_len = db_entry_byte_len * std::numeric_limits::digits; - const size_t required_num_cols = (db_entry_bit_len + (mat_element_bitlen - 1)) / mat_element_bitlen; - - return required_num_cols; - }(); + constexpr auto cols = frodoPIR_matrix::get_required_num_columns(db_entry_byte_len, mat_element_bitlen); const auto A = frodoPIR_matrix::matrix_t::template generate<λ>(seed_μ); const auto D = frodoPIR_matrix::matrix_t::template parse_db_bytes(db_bytes); const auto M = A * D; return { server_t(D), M }; - }; + } private: frodoPIR_matrix::matrix_t::digits; const size_t required_num_cols = (db_entry_bit_len + (mat_element_bitlen - 1)) / mat_element_bitlen; - return required_num_cols; - }()> - D{}; +private: + frodoPIR_matrix::matrix_t D{}; }; } From c82d56c9c36eb27d5badd9664e29ba7e92993e33 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Mon, 16 Sep 2024 00:20:09 +0400 Subject: [PATCH 23/97] Implement function for responding to client query Signed-off-by: Anjan Roy --- include/frodoPIR/server.hpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/include/frodoPIR/server.hpp b/include/frodoPIR/server.hpp index 82b0efa..4d0cc31 100644 --- a/include/frodoPIR/server.hpp +++ b/include/frodoPIR/server.hpp @@ -1,5 +1,6 @@ #pragma once #include "frodoPIR/internals/matrix/matrix.hpp" +#include "frodoPIR/internals/matrix/vector.hpp" #include "frodoPIR/internals/utility/force_inline.hpp" #include #include @@ -41,11 +42,16 @@ struct server_t return { server_t(D), M }; } -private: - frodoPIR_matrix::matrix_t::digits; - const size_t required_num_cols = (db_entry_bit_len + (mat_element_bitlen - 1)) / mat_element_bitlen; + // Given byte serialized client query, this routine can be used for responding back to it, producing byte serialized server response. + constexpr void respond(std::span query_bytes, + std::span response_bytes) const + { + const auto b_tilda = frodoPIR_vector::vector_t::from_le_bytes(query_bytes); + const auto b_tilda_transposed = b_tilda.transpose(); + const auto c_tilda = b_tilda_transposed * this->D; + + c_tilda.to_le_bytes(response_bytes); + } private: frodoPIR_matrix::matrix_t D{}; From 2ede3fdfd296238cb43fc48f2dab6018c198127a Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Mon, 16 Sep 2024 22:53:29 +0400 Subject: [PATCH 24/97] Implement FrodoPIR client setup function Signed-off-by: Anjan Roy --- include/frodoPIR/client.hpp | 46 +++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 include/frodoPIR/client.hpp diff --git a/include/frodoPIR/client.hpp b/include/frodoPIR/client.hpp new file mode 100644 index 0000000..a49065c --- /dev/null +++ b/include/frodoPIR/client.hpp @@ -0,0 +1,46 @@ +#pragma once +#include "frodoPIR/internals/matrix/matrix.hpp" +#include "frodoPIR/internals/utility/force_inline.hpp" +#include +#include +#include + +namespace frodoPIR_client { + +// Frodo *P*rivate *I*nformation *R*etrieval Client +template +struct client_t +{ +public: + // Constructor(s) + explicit constexpr client_t( + frodoPIR_matrix::matrix_t pub_matA, + frodoPIR_matrix::matrix_t pub_matM) + : A(std::move(pub_matA)) + , M(std::move(pub_matM)) + { + } + + client_t(const client_t&) = default; + client_t(client_t&&) = default; + client_t& operator=(const client_t&) = default; + client_t& operator=(client_t&&) = default; + + // Given a `λ` -bit seed and a byte serialized public matrix M, computed by frodoPIR server, this routine can be used + // for setting up FrodoPIR client, ready to generate queries and process server response. + static forceinline constexpr client_t setup( + std::span::digits> seed_μ, + std::span pub_matM_bytes) + { + constexpr auto cols = frodoPIR_matrix::get_required_num_columns(db_entry_byte_len, mat_element_bitlen); + + return client_t(frodoPIR_matrix::matrix_t::template generate<λ>(seed_μ), + frodoPIR_matrix::matrix_t::from_le_bytes(pub_matM_bytes)); + } + +private: + frodoPIR_matrix::matrix_t A{}; + frodoPIR_matrix::matrix_t M{}; +}; + +} From 35cde71049ca0a203f824d60b4470856f8f17d18 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Wed, 18 Sep 2024 19:47:10 +0400 Subject: [PATCH 25/97] Implement function for FrodoPIR client query preparation Signed-off-by: Anjan Roy --- include/frodoPIR/client.hpp | 42 +++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/include/frodoPIR/client.hpp b/include/frodoPIR/client.hpp index a49065c..ee346ba 100644 --- a/include/frodoPIR/client.hpp +++ b/include/frodoPIR/client.hpp @@ -1,12 +1,33 @@ #pragma once #include "frodoPIR/internals/matrix/matrix.hpp" +#include "frodoPIR/internals/matrix/vector.hpp" +#include "frodoPIR/internals/rng/prng.hpp" #include "frodoPIR/internals/utility/force_inline.hpp" #include #include +#include #include namespace frodoPIR_client { +// FrodoPIR query status +enum class query_status_t : uint32_t +{ + prepared, + sent, + responded +}; + +// FrodoPIR client query data type +template +struct client_query_t +{ + query_status_t status; + size_t db_index; + frodoPIR_vector::vector_t b; + frodoPIR_vector::vector_t c; +}; + // Frodo *P*rivate *I*nformation *R*etrieval Client template struct client_t @@ -38,9 +59,30 @@ struct client_t frodoPIR_matrix::matrix_t::from_le_bytes(pub_matM_bytes)); } + // Given a set of database row indices, this routine prepares those many queries, for enquiring their values, using FrodoPIR scheme. + constexpr void prepare_query(std::span db_indices, prng::prng_t& prng) + { + for (const auto db_index : db_indices) { + const auto s = frodoPIR_vector::vector_t::sample_from_uniform_ternary_distribution(prng); // secret vector + const auto e = frodoPIR_vector::vector_t::sample_from_uniform_ternary_distribution(prng); // error vector + + const auto s_transposed = s.transpose(); + const auto b = s_transposed * this->A + e.transpose(); + const auto c = s_transposed * this->M; + + this->queries[db_index] = client_query_t{ + .status = query_status_t::prepared, + .db_index = db_index, + .b = b, + .c = c, + }; + } + } + private: frodoPIR_matrix::matrix_t A{}; frodoPIR_matrix::matrix_t M{}; + std::unordered_map> queries{}; }; } From 12cf8decd678071074c2a9092f844eebd2820cc2 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Wed, 18 Sep 2024 20:07:46 +0400 Subject: [PATCH 26/97] Finalize client query, make it ready for sending to server Signed-off-by: Anjan Roy --- include/frodoPIR/client.hpp | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/include/frodoPIR/client.hpp b/include/frodoPIR/client.hpp index ee346ba..a90ac35 100644 --- a/include/frodoPIR/client.hpp +++ b/include/frodoPIR/client.hpp @@ -5,6 +5,7 @@ #include "frodoPIR/internals/utility/force_inline.hpp" #include #include +#include #include #include @@ -59,10 +60,11 @@ struct client_t frodoPIR_matrix::matrix_t::from_le_bytes(pub_matM_bytes)); } - // Given a set of database row indices, this routine prepares those many queries, for enquiring their values, using FrodoPIR scheme. - constexpr void prepare_query(std::span db_indices, prng::prng_t& prng) + // Given a set of database row indices, this routine prepares those many queries, for enquiring their values, + // using FrodoPIR scheme. + constexpr void prepare_query(std::span db_row_indices, prng::prng_t& prng) { - for (const auto db_index : db_indices) { + for (const auto db_row_index : db_row_indices) { const auto s = frodoPIR_vector::vector_t::sample_from_uniform_ternary_distribution(prng); // secret vector const auto e = frodoPIR_vector::vector_t::sample_from_uniform_ternary_distribution(prng); // error vector @@ -70,15 +72,37 @@ struct client_t const auto b = s_transposed * this->A + e.transpose(); const auto c = s_transposed * this->M; - this->queries[db_index] = client_query_t{ + this->queries[db_row_index] = client_query_t{ .status = query_status_t::prepared, - .db_index = db_index, + .db_index = db_row_index, .b = b, .c = c, }; } } + // Given a database row index, for which query has already been prepared, this routine finalizes the query, + // making it ready for processing at the server's end. + constexpr bool query(const size_t db_row_index, std::span query_bytes) + { + if (!this->queries.contains(db_row_index)) { + return false; + } + if (this->queries[db_row_index].status != query_status_t::prepared) { + return false; + } + + constexpr auto q = static_cast(std::numeric_limits::max()) + 1; + constexpr auto ρ = 1ul << mat_element_bitlen; + constexpr auto query_indicator_value = static_cast(q / ρ); + + this->queries[db_row_index].status = query_status_t::sent; + this->queries[db_row_index].b[db_row_index] += query_indicator_value; + this->queries[db_row_index].b.to_le_bytes(query_bytes); + + return true; + } + private: frodoPIR_matrix::matrix_t A{}; frodoPIR_matrix::matrix_t M{}; From 8d49a0d6c7487ded69ada6d6f74413afa6073f02 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Wed, 18 Sep 2024 23:25:09 +0400 Subject: [PATCH 27/97] Add new function for serializing a row of parsed database matrix Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 36 ++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index 267dcde..97e0a9f 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -130,6 +130,42 @@ struct matrix_t return mat; } + // Given a row of parsed database s.t. each coefficient of input vector has at max `mat_element_bitlen` -many significant bits, + // this function can be used for serializing them as little-endian bytes, producing a byte array of length `db_entry_byte_len`. + template + requires((rows == get_required_num_columns(db_entry_byte_len, mat_element_bitlen)) && (cols == 1)) + constexpr void serialize_db_row(std::span row_bytes) const + { + constexpr auto element_mask = static_cast((1u << mat_element_bitlen) - 1u); + constexpr size_t total_num_writable_bits = row_bytes * std::numeric_limits::digits; + + uint64_t buffer = 0; + auto buffer_span = std::span(reinterpret_cast(&buffer), sizeof(buffer)); + + size_t buf_num_bits = 0; + size_t byte_off = 0; + size_t coeff_idx = 0; + + while (coeff_idx < rows) { + const size_t remaining_num_bits = total_num_writable_bits - ((byte_off * std::numeric_limits::digits) + buf_num_bits); + const auto selected_bits = static_cast((*this)[coeff_idx] & element_mask); + + buffer |= (selected_bits << buf_num_bits); + buf_num_bits += std::min(mat_element_bitlen, remaining_num_bits); + + const size_t writable_num_bits = buf_num_bits & (-std::numeric_limits::digits); + const size_t writable_num_bytes = writable_num_bits / std::numeric_limits::digits; + + std::copy_n(buffer_span.begin(), writable_num_bytes, row_bytes.subspan(byte_off).begin()); + + buffer >>= writable_num_bits; + buf_num_bits -= writable_num_bits; + + coeff_idx++; + byte_off += writable_num_bytes; + } + } + // Accessor, using {row_index, column_index} pair. forceinline constexpr zq_t& operator[](const std::pair idx) { From 95598cfd07a251f3b90a4e532fd333db920ef3e7 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Wed, 18 Sep 2024 23:26:31 +0400 Subject: [PATCH 28/97] Correctly mention byte length of serialized response vector Signed-off-by: Anjan Roy --- include/frodoPIR/server.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/frodoPIR/server.hpp b/include/frodoPIR/server.hpp index 4d0cc31..2a3c6e9 100644 --- a/include/frodoPIR/server.hpp +++ b/include/frodoPIR/server.hpp @@ -43,8 +43,9 @@ struct server_t } // Given byte serialized client query, this routine can be used for responding back to it, producing byte serialized server response. - constexpr void respond(std::span query_bytes, - std::span response_bytes) const + constexpr void respond( + std::span query_bytes, + std::span response_bytes) const { const auto b_tilda = frodoPIR_vector::vector_t::from_le_bytes(query_bytes); const auto b_tilda_transposed = b_tilda.transpose(); From 87098f2c5bc172be179413e716cc911947b5969a Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Wed, 18 Sep 2024 23:43:56 +0400 Subject: [PATCH 29/97] Add functionality of processing server response at client side Signed-off-by: Anjan Roy --- include/frodoPIR/client.hpp | 47 +++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/include/frodoPIR/client.hpp b/include/frodoPIR/client.hpp index a90ac35..ac93e96 100644 --- a/include/frodoPIR/client.hpp +++ b/include/frodoPIR/client.hpp @@ -16,7 +16,6 @@ enum class query_status_t : uint32_t { prepared, sent, - responded }; // FrodoPIR client query data type @@ -96,9 +95,53 @@ struct client_t constexpr auto ρ = 1ul << mat_element_bitlen; constexpr auto query_indicator_value = static_cast(q / ρ); - this->queries[db_row_index].status = query_status_t::sent; this->queries[db_row_index].b[db_row_index] += query_indicator_value; this->queries[db_row_index].b.to_le_bytes(query_bytes); + this->queries[db_row_index].status = query_status_t::sent; + + return true; + } + + // Given a database row index, for which query has already been sent to server and we are awaiting response, + // this routine can be used for processing server response, returning byte serialized content of queried row. + constexpr bool process_response( + const size_t db_row_index, + std::span response_bytes, + std::span db_row_bytes) + { + if (!this->queries.contains(db_row_index)) { + return false; + } + if (this->queries[db_row_index].status != query_status_t::sent) { + return false; + } + + constexpr auto q = static_cast(std::numeric_limits::max()) + 1; + constexpr auto rho = 1ul << mat_element_bitlen; + constexpr auto rounding_factor = static_cast(q / rho); + constexpr auto rounding_floor = rounding_factor / 2; + + constexpr size_t db_matrix_row_width = frodoPIR_matrix::get_required_num_columns(db_entry_byte_len, mat_element_bitlen); + + frodoPIR_vector::vector_t db_matrix_row{}; + auto c_tilda = frodoPIR_vector::vector_t::from_le_bytes(response_bytes); + + for (size_t idx = 0; idx < db_matrix_row_width; idx++) { + const auto unscaled_res = c_tilda[idx] - this->queries[db_row_index].c[idx]; + + const auto scaled_res = unscaled_res / rounding_factor; + const auto scaled_rem = unscaled_res % rounding_factor; + + auto rounded_res = scaled_res; + + rounded_res += ((scaled_rem > rounding_floor) ? 1 : 0); + rounded_res %= static_cast(rho); + + db_matrix_row[idx] = rounded_res; + } + + db_matrix_row.serialize_db_row(db_row_bytes); + this->queries.erase(db_row_index); return true; } From 48ba3f4d17305c61a60e4037873209cfb3dfd07c Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Thu, 19 Sep 2024 21:45:15 +0400 Subject: [PATCH 30/97] Address compilation issues Signed-off-by: Anjan Roy --- include/frodoPIR/client.hpp | 9 +++++---- include/frodoPIR/internals/matrix/matrix.hpp | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/include/frodoPIR/client.hpp b/include/frodoPIR/client.hpp index ac93e96..8f42157 100644 --- a/include/frodoPIR/client.hpp +++ b/include/frodoPIR/client.hpp @@ -51,7 +51,8 @@ struct client_t // for setting up FrodoPIR client, ready to generate queries and process server response. static forceinline constexpr client_t setup( std::span::digits> seed_μ, - std::span pub_matM_bytes) + std::span + pub_matM_bytes) { constexpr auto cols = frodoPIR_matrix::get_required_num_columns(db_entry_byte_len, mat_element_bitlen); @@ -74,8 +75,8 @@ struct client_t this->queries[db_row_index] = client_query_t{ .status = query_status_t::prepared, .db_index = db_row_index, - .b = b, - .c = c, + .b = b.transpose(), + .c = c.transpose(), }; } } @@ -140,7 +141,7 @@ struct client_t db_matrix_row[idx] = rounded_res; } - db_matrix_row.serialize_db_row(db_row_bytes); + db_matrix_row.template serialize_db_row(db_row_bytes); this->queries.erase(db_row_index); return true; diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index 97e0a9f..7153756 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -137,7 +137,7 @@ struct matrix_t constexpr void serialize_db_row(std::span row_bytes) const { constexpr auto element_mask = static_cast((1u << mat_element_bitlen) - 1u); - constexpr size_t total_num_writable_bits = row_bytes * std::numeric_limits::digits; + constexpr size_t total_num_writable_bits = row_bytes.size() * std::numeric_limits::digits; uint64_t buffer = 0; auto buffer_span = std::span(reinterpret_cast(&buffer), sizeof(buffer)); From f8d8f0b365fafb6473a9263eb10750e163f26f00 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sat, 21 Sep 2024 18:39:40 +0400 Subject: [PATCH 31/97] Move functions for parsing database matrix from bytes and vice-versa Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 99 +------------- .../internals/matrix/serialization.hpp | 127 ++++++++++++++++++ 2 files changed, 129 insertions(+), 97 deletions(-) create mode 100644 include/frodoPIR/internals/matrix/serialization.hpp diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index 7153756..cd64aa3 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -2,7 +2,6 @@ #include "frodoPIR/internals/rng/prng.hpp" #include "frodoPIR/internals/utility/force_inline.hpp" #include "frodoPIR/internals/utility/utils.hpp" -#include #include #include #include @@ -14,6 +13,7 @@ namespace frodoPIR_matrix { // All arithmetic operations are performed modulo 2^32, for which we have native reduction. using zq_t = uint32_t; +constexpr auto Q = static_cast(std::numeric_limits::max()) + 1; // Size of interval, used for sampling from uniform ternary distribution χ. inline constexpr size_t TERNARY_INTERVAL_SIZE = (std::numeric_limits::max() - 2) / 3; @@ -58,8 +58,7 @@ struct matrix_t return mat; } - // Given a seeded PRNG, this routine samples a column vector of size `rows x 1`, - // by rejection sampling from a uniform ternary distribution. + // Given a seeded PRNG, this routine samples a column vector of size `rows x 1`, by rejection sampling from a uniform ternary distribution. static forceinline constexpr matrix_t sample_from_uniform_ternary_distribution(prng::prng_t& prng) requires(cols == 1) { @@ -72,100 +71,6 @@ struct matrix_t return mat; } - // Given a byte serialized database s.t. it has `db_entry_count` -number of rows and each row contains `db_entry_byte_len` -bytes - // entry, this routines parses database into a matrix s.t. each element of matrix has `mat_element_bitlen` significant bits. - // - // Note, 0 < `mat_element_bitlen` < 32. - // Collects inspiration from https://github.com/brave-experiments/frodo-pir/blob/15573960/src/db.rs#L229-L254. - template - requires((rows == db_entry_count) && (cols == get_required_num_columns(db_entry_byte_len, mat_element_bitlen)) && - ((0 < mat_element_bitlen) && (mat_element_bitlen < std::numeric_limits::digits))) - static forceinline matrix_t parse_db_bytes(std::span bytes) - { - constexpr auto mat_element_mask = (1ul << mat_element_bitlen) - 1ul; - - matrix_t mat{}; - - for (size_t r_idx = 0; r_idx < rows; r_idx++) { - uint64_t buffer = 0; - auto buffer_span = std::span(reinterpret_cast(&buffer), sizeof(buffer)); - - size_t buf_num_bits = 0; - size_t c_idx = 0; - - size_t byte_off = r_idx * db_entry_byte_len; - const size_t till_byte_off = byte_off + db_entry_byte_len; - - while (byte_off < till_byte_off) { - const size_t remaining_num_bytes = till_byte_off - byte_off; - - const size_t fillable_num_bits = std::numeric_limits::digits - buf_num_bits; - const size_t readable_num_bits = fillable_num_bits & (-std::numeric_limits::digits); - const size_t readable_num_bytes = std::min(readable_num_bits / std::numeric_limits::digits, remaining_num_bytes); - - const auto read_word = frodoPIR_utils::from_le_bytes(bytes.subspan(byte_off, readable_num_bytes)); - byte_off += readable_num_bytes; - - buffer |= (read_word << buf_num_bits); - buf_num_bits += readable_num_bits; - - const size_t fillable_mat_elem_count = buf_num_bits / mat_element_bitlen; - - for (size_t elem_idx = 0; elem_idx < fillable_mat_elem_count; elem_idx++) { - const zq_t mat_element = buffer & mat_element_mask; - mat[{ r_idx, c_idx + elem_idx }] = mat_element; - - buffer >>= mat_element_bitlen; - buf_num_bits -= mat_element_bitlen; - } - - c_idx += fillable_mat_elem_count; - } - - if ((buf_num_bits > 0) && (c_idx < cols)) { - mat[{ r_idx, c_idx }] = buffer & mat_element_mask; - } - } - - return mat; - } - - // Given a row of parsed database s.t. each coefficient of input vector has at max `mat_element_bitlen` -many significant bits, - // this function can be used for serializing them as little-endian bytes, producing a byte array of length `db_entry_byte_len`. - template - requires((rows == get_required_num_columns(db_entry_byte_len, mat_element_bitlen)) && (cols == 1)) - constexpr void serialize_db_row(std::span row_bytes) const - { - constexpr auto element_mask = static_cast((1u << mat_element_bitlen) - 1u); - constexpr size_t total_num_writable_bits = row_bytes.size() * std::numeric_limits::digits; - - uint64_t buffer = 0; - auto buffer_span = std::span(reinterpret_cast(&buffer), sizeof(buffer)); - - size_t buf_num_bits = 0; - size_t byte_off = 0; - size_t coeff_idx = 0; - - while (coeff_idx < rows) { - const size_t remaining_num_bits = total_num_writable_bits - ((byte_off * std::numeric_limits::digits) + buf_num_bits); - const auto selected_bits = static_cast((*this)[coeff_idx] & element_mask); - - buffer |= (selected_bits << buf_num_bits); - buf_num_bits += std::min(mat_element_bitlen, remaining_num_bits); - - const size_t writable_num_bits = buf_num_bits & (-std::numeric_limits::digits); - const size_t writable_num_bytes = writable_num_bits / std::numeric_limits::digits; - - std::copy_n(buffer_span.begin(), writable_num_bytes, row_bytes.subspan(byte_off).begin()); - - buffer >>= writable_num_bits; - buf_num_bits -= writable_num_bits; - - coeff_idx++; - byte_off += writable_num_bytes; - } - } - // Accessor, using {row_index, column_index} pair. forceinline constexpr zq_t& operator[](const std::pair idx) { diff --git a/include/frodoPIR/internals/matrix/serialization.hpp b/include/frodoPIR/internals/matrix/serialization.hpp new file mode 100644 index 0000000..75904e6 --- /dev/null +++ b/include/frodoPIR/internals/matrix/serialization.hpp @@ -0,0 +1,127 @@ +#pragma once +#include "frodoPIR/internals/matrix/matrix.hpp" +#include "frodoPIR/internals/matrix/vector.hpp" + +namespace frodoPIR_serialization { + +// Given a byte serialized database s.t. it has `db_entry_count` -number of rows and each row contains `db_entry_byte_len` -bytes +// entry, this routines parses database into a matrix s.t. each element of matrix has at max `mat_element_bitlen` significant bits. +// +// Note, 0 < `mat_element_bitlen` < 32. +// Collects inspiration from https://github.com/brave-experiments/frodo-pir/blob/15573960/src/db.rs#L229-L254. +template + requires(((0 < mat_element_bitlen) && (mat_element_bitlen < std::numeric_limits::digits))) +constexpr frodoPIR_matrix::matrix_t +parse_db_bytes(std::span bytes) +{ + constexpr auto mat_element_mask = (1ul << mat_element_bitlen) - 1ul; + constexpr size_t rows = db_entry_count; + constexpr size_t cols = frodoPIR_matrix::get_required_num_columns(db_entry_byte_len, mat_element_bitlen); + + frodoPIR_matrix::matrix_t mat{}; + + for (size_t r_idx = 0; r_idx < rows; r_idx++) { + uint64_t buffer = 0; + auto buffer_span = std::span(reinterpret_cast(&buffer), sizeof(buffer)); + + size_t buf_num_bits = 0; + size_t c_idx = 0; + + size_t byte_off = r_idx * db_entry_byte_len; + const size_t till_byte_off = byte_off + db_entry_byte_len; + + while (byte_off < till_byte_off) { + const size_t remaining_num_bytes = till_byte_off - byte_off; + + const size_t fillable_num_bits = std::numeric_limits::digits - buf_num_bits; + const size_t readable_num_bits = fillable_num_bits & (-std::numeric_limits::digits); + const size_t readable_num_bytes = std::min(readable_num_bits / std::numeric_limits::digits, remaining_num_bytes); + + const auto read_word = frodoPIR_utils::from_le_bytes(bytes.subspan(byte_off, readable_num_bytes)); + byte_off += readable_num_bytes; + + buffer |= (read_word << buf_num_bits); + buf_num_bits += readable_num_bits; + + const size_t fillable_mat_elem_count = buf_num_bits / mat_element_bitlen; + + for (size_t elem_idx = 0; elem_idx < fillable_mat_elem_count; elem_idx++) { + const auto mat_element = static_cast(buffer & mat_element_mask); + mat[{ r_idx, c_idx + elem_idx }] = mat_element; + + buffer >>= mat_element_bitlen; + buf_num_bits -= mat_element_bitlen; + } + + c_idx += fillable_mat_elem_count; + } + + if ((buf_num_bits > 0) && (c_idx < cols)) { + mat[{ r_idx, c_idx }] = buffer & mat_element_mask; + } + } + + return mat; +} + +// Given a parsed database matrix as input s.t. each element of matrix has at max `mat_element_bitlen` significant bits, this routine serializes it +// into little-endian bytes of length `db_entry_count x db_entry_byte_len`, which can be interpretted as a database having `db_entry_count` -many +// entries s.t. each of those entries are `db_entry_byte_len` -bytes. +// +// M = parse_db_bytes(orig_database_bytes) +// comp_database_bytes = serialize_parsed_db_matrix(M) +// assert(orig_database_bytes == comp_database_bytes) +template + requires(((0 < mat_element_bitlen) && (mat_element_bitlen < std::numeric_limits::digits))) +constexpr void +serialize_parsed_db_matrix( + frodoPIR_matrix::matrix_t const& db_matrix, + std::span bytes) +{ + constexpr auto mat_element_mask = (1ul << mat_element_bitlen) - 1ul; + constexpr size_t rows = db_entry_count; + constexpr size_t cols = frodoPIR_matrix::get_required_num_columns(db_entry_byte_len, mat_element_bitlen); + constexpr size_t total_num_writable_bits_per_row = db_entry_byte_len * std::numeric_limits::digits; + + for (size_t r_idx = 0; r_idx < rows; r_idx++) { + uint64_t buffer = 0; + auto buffer_span = std::span(reinterpret_cast(&buffer), sizeof(buffer)); + + size_t buf_num_bits = 0; + size_t c_idx = 0; + + size_t byte_off = 0; + const size_t row_begins_at_offset = r_idx * db_entry_byte_len; + + while (c_idx < cols) { + const size_t remaining_num_bits = total_num_writable_bits_per_row - ((byte_off * std::numeric_limits::digits) + buf_num_bits); + const auto selected_bits = static_cast(db_matrix[{ r_idx, c_idx }] & mat_element_mask); + + buffer |= (selected_bits << buf_num_bits); + buf_num_bits += std::min(mat_element_bitlen, remaining_num_bits); + + const size_t writable_num_bits = buf_num_bits & (-std::numeric_limits::digits); + const size_t writable_num_bytes = writable_num_bits / std::numeric_limits::digits; + + std::copy_n(buffer_span.begin(), writable_num_bytes, bytes.subspan(row_begins_at_offset + byte_off).begin()); + + buffer >>= writable_num_bits; + buf_num_bits -= writable_num_bits; + + c_idx++; + byte_off += writable_num_bytes; + } + } +} + +// Given a row of parsed database s.t. each coefficient of input vector has at max `mat_element_bitlen` -many significant bits, +// this function can be used for serializing them as little-endian bytes, producing a byte array of length `db_entry_byte_len`. +template +constexpr void +serialize_db_row(frodoPIR_vector::row_vector_t const& db_row, + std::span bytes) +{ + serialize_parsed_db_matrix<1, db_entry_byte_len, mat_element_bitlen>(db_row, bytes); +} + +} From 66ddda448522676dda4d88966241c53bda3a6e24 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sat, 21 Sep 2024 18:45:48 +0400 Subject: [PATCH 32/97] Test functional correctness of database parsing and matrix serialization functions Signed-off-by: Anjan Roy --- tests/test_serialization.cpp | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 tests/test_serialization.cpp diff --git a/tests/test_serialization.cpp b/tests/test_serialization.cpp new file mode 100644 index 0000000..497d05b --- /dev/null +++ b/tests/test_serialization.cpp @@ -0,0 +1,35 @@ +#include "frodoPIR/internals/matrix/serialization.hpp" +#include "frodoPIR/internals/rng/prng.hpp" +#include +#include + +template +static void +test_db_parsing_and_serialization() +{ + prng::prng_t prng; + + constexpr size_t db_byte_len = db_entry_count * db_entry_byte_len; + + std::vector orig_db_bytes(db_byte_len, 0); + std::vector comp_db_bytes(db_byte_len, 0); + + auto orig_db_bytes_span = std::span(orig_db_bytes); + auto comp_db_bytes_span = std::span(comp_db_bytes); + + prng.read(orig_db_bytes_span); + + auto D = frodoPIR_serialization::parse_db_bytes(orig_db_bytes_span); + frodoPIR_serialization::serialize_parsed_db_matrix(D, comp_db_bytes_span); + + EXPECT_EQ(orig_db_bytes, comp_db_bytes); +} + +TEST(FrodoPIR, ParsingDatabaseAndSerializingDatabaseMatrix) +{ + test_db_parsing_and_serialization<1ul << 16u, 1024, 10>(); + test_db_parsing_and_serialization<1ul << 17u, 1024, 10>(); + test_db_parsing_and_serialization<1ul << 18u, 1024, 10>(); + test_db_parsing_and_serialization<1ul << 19u, 1024, 9>(); + test_db_parsing_and_serialization<1ul << 20u, 1024, 9>(); +} From 8fc89441194d7d7b211b2845bb858a53a919050a Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sat, 21 Sep 2024 18:47:08 +0400 Subject: [PATCH 33/97] Add new column and row vector type Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/vector.hpp | 5 ++++- include/frodoPIR/server.hpp | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/frodoPIR/internals/matrix/vector.hpp b/include/frodoPIR/internals/matrix/vector.hpp index 22cee43..69116e2 100644 --- a/include/frodoPIR/internals/matrix/vector.hpp +++ b/include/frodoPIR/internals/matrix/vector.hpp @@ -4,6 +4,9 @@ namespace frodoPIR_vector { template -using vector_t = frodoPIR_matrix::matrix_t; +using column_vector_t = frodoPIR_matrix::matrix_t; + +template +using row_vector_t = frodoPIR_matrix::matrix_t<1, element_count>; } diff --git a/include/frodoPIR/server.hpp b/include/frodoPIR/server.hpp index 2a3c6e9..ff2c31c 100644 --- a/include/frodoPIR/server.hpp +++ b/include/frodoPIR/server.hpp @@ -47,7 +47,7 @@ struct server_t std::span query_bytes, std::span response_bytes) const { - const auto b_tilda = frodoPIR_vector::vector_t::from_le_bytes(query_bytes); + const auto b_tilda = frodoPIR_vector::column_vector_t::from_le_bytes(query_bytes); const auto b_tilda_transposed = b_tilda.transpose(); const auto c_tilda = b_tilda_transposed * this->D; From 3d562492ad7138add10159206aa1c4c3b850cf95 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sun, 22 Sep 2024 11:48:49 +0400 Subject: [PATCH 34/97] Use correct function for parsing database bytes Signed-off-by: Anjan Roy --- include/frodoPIR/server.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/frodoPIR/server.hpp b/include/frodoPIR/server.hpp index ff2c31c..fcb9fd0 100644 --- a/include/frodoPIR/server.hpp +++ b/include/frodoPIR/server.hpp @@ -1,5 +1,6 @@ #pragma once #include "frodoPIR/internals/matrix/matrix.hpp" +#include "frodoPIR/internals/matrix/serialization.hpp" #include "frodoPIR/internals/matrix/vector.hpp" #include "frodoPIR/internals/utility/force_inline.hpp" #include @@ -33,10 +34,8 @@ struct server_t pair> setup(std::span::digits> seed_μ, std::span db_bytes) { - constexpr auto cols = frodoPIR_matrix::get_required_num_columns(db_entry_byte_len, mat_element_bitlen); - const auto A = frodoPIR_matrix::matrix_t::template generate<λ>(seed_μ); - const auto D = frodoPIR_matrix::matrix_t::template parse_db_bytes(db_bytes); + const auto D = frodoPIR_serialization::parse_db_bytes(db_bytes); const auto M = A * D; return { server_t(D), M }; From 29eb7fff0908f94257ac755749f35e6d8d5d7b77 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sun, 22 Sep 2024 11:49:54 +0400 Subject: [PATCH 35/97] Refactor client operations implementation Signed-off-by: Anjan Roy --- include/frodoPIR/client.hpp | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/include/frodoPIR/client.hpp b/include/frodoPIR/client.hpp index 8f42157..5827e6c 100644 --- a/include/frodoPIR/client.hpp +++ b/include/frodoPIR/client.hpp @@ -1,5 +1,6 @@ #pragma once #include "frodoPIR/internals/matrix/matrix.hpp" +#include "frodoPIR/internals/matrix/serialization.hpp" #include "frodoPIR/internals/matrix/vector.hpp" #include "frodoPIR/internals/rng/prng.hpp" #include "frodoPIR/internals/utility/force_inline.hpp" @@ -24,8 +25,8 @@ struct client_query_t { query_status_t status; size_t db_index; - frodoPIR_vector::vector_t b; - frodoPIR_vector::vector_t c; + frodoPIR_vector::row_vector_t b; + frodoPIR_vector::row_vector_t c; }; // Frodo *P*rivate *I*nformation *R*etrieval Client @@ -65,8 +66,8 @@ struct client_t constexpr void prepare_query(std::span db_row_indices, prng::prng_t& prng) { for (const auto db_row_index : db_row_indices) { - const auto s = frodoPIR_vector::vector_t::sample_from_uniform_ternary_distribution(prng); // secret vector - const auto e = frodoPIR_vector::vector_t::sample_from_uniform_ternary_distribution(prng); // error vector + const auto s = frodoPIR_vector::column_vector_t::sample_from_uniform_ternary_distribution(prng); // secret vector + const auto e = frodoPIR_vector::column_vector_t::sample_from_uniform_ternary_distribution(prng); // error vector const auto s_transposed = s.transpose(); const auto b = s_transposed * this->A + e.transpose(); @@ -75,8 +76,8 @@ struct client_t this->queries[db_row_index] = client_query_t{ .status = query_status_t::prepared, .db_index = db_row_index, - .b = b.transpose(), - .c = c.transpose(), + .b = b, + .c = c, }; } } @@ -92,9 +93,8 @@ struct client_t return false; } - constexpr auto q = static_cast(std::numeric_limits::max()) + 1; - constexpr auto ρ = 1ul << mat_element_bitlen; - constexpr auto query_indicator_value = static_cast(q / ρ); + constexpr auto rho = 1ul << mat_element_bitlen; + constexpr auto query_indicator_value = static_cast(frodoPIR_matrix::Q / rho); this->queries[db_row_index].b[db_row_index] += query_indicator_value; this->queries[db_row_index].b.to_le_bytes(query_bytes); @@ -117,15 +117,14 @@ struct client_t return false; } - constexpr auto q = static_cast(std::numeric_limits::max()) + 1; constexpr auto rho = 1ul << mat_element_bitlen; - constexpr auto rounding_factor = static_cast(q / rho); + constexpr auto rounding_factor = static_cast(frodoPIR_matrix::Q / rho); constexpr auto rounding_floor = rounding_factor / 2; constexpr size_t db_matrix_row_width = frodoPIR_matrix::get_required_num_columns(db_entry_byte_len, mat_element_bitlen); - frodoPIR_vector::vector_t db_matrix_row{}; - auto c_tilda = frodoPIR_vector::vector_t::from_le_bytes(response_bytes); + frodoPIR_vector::row_vector_t db_matrix_row{}; + auto c_tilda = frodoPIR_vector::row_vector_t::from_le_bytes(response_bytes); for (size_t idx = 0; idx < db_matrix_row_width; idx++) { const auto unscaled_res = c_tilda[idx] - this->queries[db_row_index].c[idx]; @@ -141,7 +140,7 @@ struct client_t db_matrix_row[idx] = rounded_res; } - db_matrix_row.template serialize_db_row(db_row_bytes); + frodoPIR_serialization::serialize_db_row(db_matrix_row, db_row_bytes); this->queries.erase(db_row_index); return true; From 1ee444acca1931e4e06e3ca02b4b0748517f0d75 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sun, 22 Sep 2024 12:05:23 +0400 Subject: [PATCH 36/97] Fix how uniform rejection sampling is performed from ternary distribution Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index cd64aa3..6c8c085 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -198,9 +198,9 @@ struct matrix_t }(); zq_t ternary = 0; - if ((val > TERNARY_INTERVAL_SIZE) && (val < (2 * TERNARY_INTERVAL_SIZE))) { + if ((val > TERNARY_INTERVAL_SIZE) && (val <= (2 * TERNARY_INTERVAL_SIZE))) { ternary = 1; - } else { + } else if (val > (2 * TERNARY_INTERVAL_SIZE)) { ternary = std::numeric_limits::max(); } From 34c39547e39e2517a8ddae5ff89b4d53ead7337f Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sun, 22 Sep 2024 12:34:14 +0400 Subject: [PATCH 37/97] Add overload for equality operator on matrix type Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index 6c8c085..595ec01 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -87,6 +87,20 @@ struct matrix_t forceinline constexpr zq_t& operator[](const size_t lin_idx) { return this->elements[lin_idx]; } forceinline constexpr const zq_t& operator[](const size_t lin_idx) const { return this->elements[lin_idx]; } + // Check equality of two equal dimension matrices, returning boolean result. + forceinline constexpr bool operator==(const matrix_t& rhs) const + { + zq_t result = 0; + + for (size_t r_idx = 0; r_idx < rows; r_idx++) { + for (size_t c_idx = 0; c_idx < cols; c_idx++) { + result ^= ((*this)[{ r_idx, c_idx }] ^ rhs[{ r_idx, c_idx }]); + } + } + + return (result == 0); + } + // Given a matrix M of dimension `rows x cols`, this routine is used for computing its transpose M' s.t. // resulting matrix's dimension becomes `cols x rows`. forceinline constexpr matrix_t transpose() const @@ -104,7 +118,7 @@ struct matrix_t // Given two matrices A, B of equal dimension, this routine can be used for performing matrix addition over Zq, // returning a matrix of same dimension. - forceinline constexpr matrix_t operator+(const matrix_t& rhs) const + forceinline constexpr matrix_t operator+(const matrix_t& rhs) const { matrix_t res{}; From fa7c4b1e3fc4983ff4e7be3ff992b5d8cb7e9f18 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sun, 22 Sep 2024 12:51:51 +0400 Subject: [PATCH 38/97] Add tests for ensuring functional correctness of matrix operations Signed-off-by: Anjan Roy --- tests/test_matrix_operations.cpp | 39 ++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 tests/test_matrix_operations.cpp diff --git a/tests/test_matrix_operations.cpp b/tests/test_matrix_operations.cpp new file mode 100644 index 0000000..5d040ea --- /dev/null +++ b/tests/test_matrix_operations.cpp @@ -0,0 +1,39 @@ +#include "frodoPIR/internals/matrix/matrix.hpp" +#include "frodoPIR/internals/rng/prng.hpp" +#include +#include +#include +#include +#include + +template +static void +test_matrix_operations() +{ + constexpr size_t λ = 128; + constexpr size_t mat_byte_len = rows * cols * sizeof(frodoPIR_matrix::zq_t); + + std::array::digits> μ{}; + std::vector matA_bytes(mat_byte_len, 0); + + auto μ_span = std::span(μ); + auto matA_bytes_span = std::span(matA_bytes); + + prng::prng_t prng; + prng.read(μ_span); + + auto A = frodoPIR_matrix::matrix_t::template generate<λ>(μ_span); + auto A_transposed = A.transpose(); + A_transposed.to_le_bytes(matA_bytes_span); + + auto A_prime = frodoPIR_matrix::matrix_t::from_le_bytes(matA_bytes_span); + auto A_prime_transposed = A_prime.transpose(); + + EXPECT_EQ(A, A_prime_transposed); +} + +TEST(FrodoPIR, MatrixOperations) +{ + test_matrix_operations<1774, 1ul << 16>(); + test_matrix_operations<1774, 1ul << 20>(); +} From 66976d4a9d3f1f5830d2206fc8ef5cec5696d69f Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sun, 22 Sep 2024 20:50:40 +0400 Subject: [PATCH 39/97] Add function for returning identity matrix Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index 595ec01..45190fa 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -71,6 +71,19 @@ struct matrix_t return mat; } + // Returns an identity matrix of dimension `rows x rows`. + static forceinline constexpr matrix_t identity() + requires(rows == cols) + { + matrix_t mat{}; + + for (size_t idx = 0; idx < rows; idx++) { + mat[{ idx, idx }] = zq_t(1); + } + + return mat; + } + // Accessor, using {row_index, column_index} pair. forceinline constexpr zq_t& operator[](const std::pair idx) { From ab3553f97bbf1eac53d4cea7a3c7243355d8e7d0 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sun, 22 Sep 2024 20:55:48 +0400 Subject: [PATCH 40/97] Add function for ease of getting byte length of serialized matrix Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index 45190fa..ce58d86 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -100,6 +100,9 @@ struct matrix_t forceinline constexpr zq_t& operator[](const size_t lin_idx) { return this->elements[lin_idx]; } forceinline constexpr const zq_t& operator[](const size_t lin_idx) const { return this->elements[lin_idx]; } + // Get byte length of serialized matrix. + static forceinline constexpr size_t get_byte_len() { return rows * cols * sizeof(zq_t); } + // Check equality of two equal dimension matrices, returning boolean result. forceinline constexpr bool operator==(const matrix_t& rhs) const { @@ -167,9 +170,10 @@ struct matrix_t // Given a matrix M of dimension `rows x cols`, this routine can be used for serializing each of its elements as // four little-endian bytes and concatenating them in order to compute a byte array of length `rows * cols * 4`. - forceinline constexpr void to_le_bytes(std::span bytes) const + forceinline constexpr void to_le_bytes(std::span bytes) const { - for (size_t i = 0; i < rows * cols; i++) { + constexpr size_t num_elements = rows * cols; + for (size_t i = 0; i < num_elements; i++) { const size_t boff = i * sizeof(zq_t); const auto word = (*this)[i]; @@ -179,7 +183,7 @@ struct matrix_t // Given a byte array of length `rows * cols * 4`, this routine can be used for deserializing it as a matrix of dimension // `rows x cols` s.t. each matrix element is computed by interpreting four consecutive bytes in little-endian order. - forceinline static matrix_t from_le_bytes(std::span bytes) + forceinline static matrix_t from_le_bytes(std::span bytes) { constexpr size_t blen = bytes.size(); matrix_t res{}; From 6d092752818bc574c2a28369e41231a42cad8454 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sun, 22 Sep 2024 20:57:26 +0400 Subject: [PATCH 41/97] Add more tests for ensuring that matrix multiplication works correctly Signed-off-by: Anjan Roy --- tests/test_matrix_operations.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/test_matrix_operations.cpp b/tests/test_matrix_operations.cpp index 5d040ea..63484e1 100644 --- a/tests/test_matrix_operations.cpp +++ b/tests/test_matrix_operations.cpp @@ -11,7 +11,7 @@ static void test_matrix_operations() { constexpr size_t λ = 128; - constexpr size_t mat_byte_len = rows * cols * sizeof(frodoPIR_matrix::zq_t); + constexpr size_t mat_byte_len = frodoPIR_matrix::matrix_t::get_byte_len(); std::array::digits> μ{}; std::vector matA_bytes(mat_byte_len, 0); @@ -30,6 +30,16 @@ test_matrix_operations() auto A_prime_transposed = A_prime.transpose(); EXPECT_EQ(A, A_prime_transposed); + + auto I = frodoPIR_matrix::matrix_t::identity(); + auto AI = A * I; + + EXPECT_EQ(A, AI); + + auto I_prime = frodoPIR_matrix::matrix_t::identity(); + auto IA = I_prime * A; + + EXPECT_EQ(A, IA); } TEST(FrodoPIR, MatrixOperations) From 575ca01d2421e72513a2be5402f1b6d287e12cd9 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sun, 22 Sep 2024 21:14:05 +0400 Subject: [PATCH 42/97] Add check if query for specific row index has already been prepared Signed-off-by: Anjan Roy --- include/frodoPIR/client.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/frodoPIR/client.hpp b/include/frodoPIR/client.hpp index 5827e6c..8bb7a81 100644 --- a/include/frodoPIR/client.hpp +++ b/include/frodoPIR/client.hpp @@ -66,6 +66,10 @@ struct client_t constexpr void prepare_query(std::span db_row_indices, prng::prng_t& prng) { for (const auto db_row_index : db_row_indices) { + if (this->queries.contains(db_row_index)) { + continue; + } + const auto s = frodoPIR_vector::column_vector_t::sample_from_uniform_ternary_distribution(prng); // secret vector const auto e = frodoPIR_vector::column_vector_t::sample_from_uniform_ternary_distribution(prng); // error vector From 730b786cc6db7e6d6159c780be5b3f50a8d53454 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sun, 22 Sep 2024 21:14:41 +0400 Subject: [PATCH 43/97] Add preparing query for single database row index Signed-off-by: Anjan Roy --- include/frodoPIR/client.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/frodoPIR/client.hpp b/include/frodoPIR/client.hpp index 8bb7a81..1e08408 100644 --- a/include/frodoPIR/client.hpp +++ b/include/frodoPIR/client.hpp @@ -4,6 +4,7 @@ #include "frodoPIR/internals/matrix/vector.hpp" #include "frodoPIR/internals/rng/prng.hpp" #include "frodoPIR/internals/utility/force_inline.hpp" +#include #include #include #include @@ -86,6 +87,13 @@ struct client_t } } + // Given a database row index, this routine prepares a query, so that value at that index can be enquired, using FrodoPIR scheme. + constexpr void prepare_query(const size_t db_row_index, prng::prng_t& prng) + { + const std::array db_row_indices{ db_row_index }; + this->prepare_query(db_row_indices, prng); + } + // Given a database row index, for which query has already been prepared, this routine finalizes the query, // making it ready for processing at the server's end. constexpr bool query(const size_t db_row_index, std::span query_bytes) From 3612f49938ae4419072634f3e77e6c95f23eb2e1 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sun, 22 Sep 2024 21:16:51 +0400 Subject: [PATCH 44/97] Rewrite query preparation function - make the dependency pattern more logical Signed-off-by: Anjan Roy --- include/frodoPIR/client.hpp | 38 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/include/frodoPIR/client.hpp b/include/frodoPIR/client.hpp index 1e08408..7e92ba1 100644 --- a/include/frodoPIR/client.hpp +++ b/include/frodoPIR/client.hpp @@ -4,7 +4,6 @@ #include "frodoPIR/internals/matrix/vector.hpp" #include "frodoPIR/internals/rng/prng.hpp" #include "frodoPIR/internals/utility/force_inline.hpp" -#include #include #include #include @@ -67,31 +66,30 @@ struct client_t constexpr void prepare_query(std::span db_row_indices, prng::prng_t& prng) { for (const auto db_row_index : db_row_indices) { - if (this->queries.contains(db_row_index)) { - continue; - } - - const auto s = frodoPIR_vector::column_vector_t::sample_from_uniform_ternary_distribution(prng); // secret vector - const auto e = frodoPIR_vector::column_vector_t::sample_from_uniform_ternary_distribution(prng); // error vector - - const auto s_transposed = s.transpose(); - const auto b = s_transposed * this->A + e.transpose(); - const auto c = s_transposed * this->M; - - this->queries[db_row_index] = client_query_t{ - .status = query_status_t::prepared, - .db_index = db_row_index, - .b = b, - .c = c, - }; + this->prepare_query(db_row_index, prng); } } // Given a database row index, this routine prepares a query, so that value at that index can be enquired, using FrodoPIR scheme. constexpr void prepare_query(const size_t db_row_index, prng::prng_t& prng) { - const std::array db_row_indices{ db_row_index }; - this->prepare_query(db_row_indices, prng); + if (this->queries.contains(db_row_index)) { + return; + } + + const auto s = frodoPIR_vector::column_vector_t::sample_from_uniform_ternary_distribution(prng); // secret vector + const auto e = frodoPIR_vector::column_vector_t::sample_from_uniform_ternary_distribution(prng); // error vector + + const auto s_transposed = s.transpose(); + const auto b = s_transposed * this->A + e.transpose(); + const auto c = s_transposed * this->M; + + this->queries[db_row_index] = client_query_t{ + .status = query_status_t::prepared, + .db_index = db_row_index, + .b = b, + .c = c, + }; } // Given a database row index, for which query has already been prepared, this routine finalizes the query, From 997bd37e51e2c7563d3edf11fa181af110d06ec4 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Mon, 23 Sep 2024 08:11:04 +0400 Subject: [PATCH 45/97] Add tests ensuring functional correctness of FrodoPIR scheme Signed-off-by: Anjan Roy --- tests/test_frodoPIR.cpp | 78 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 tests/test_frodoPIR.cpp diff --git a/tests/test_frodoPIR.cpp b/tests/test_frodoPIR.cpp new file mode 100644 index 0000000..a4d559b --- /dev/null +++ b/tests/test_frodoPIR.cpp @@ -0,0 +1,78 @@ +#include "frodoPIR/client.hpp" +#include "frodoPIR/internals/matrix/matrix.hpp" +#include "frodoPIR/internals/rng/prng.hpp" +#include "frodoPIR/server.hpp" +#include "gtest/gtest.h" +#include +#include +#include +#include +#include + +template +static void +test_private_information_retrieval(const size_t num_queries) +{ + constexpr size_t λ = 128; + constexpr size_t parsed_db_column_count = frodoPIR_matrix::get_required_num_columns(db_entry_byte_len, mat_element_bitlen); + constexpr size_t db_byte_len = db_entry_count * db_entry_byte_len; + constexpr size_t pub_matM_byte_len = frodoPIR_matrix::matrix_t::get_byte_len(); + constexpr size_t query_byte_len = frodoPIR_vector::row_vector_t::get_byte_len(); + constexpr size_t response_byte_len = frodoPIR_vector::row_vector_t::get_byte_len(); + + std::array::digits> seed_μ{}; + std::vector db_bytes(db_byte_len, 0); + std::vector pub_matM_bytes(pub_matM_byte_len, 0); + std::vector query_bytes(query_byte_len, 0); + std::vector response_bytes(response_byte_len, 0); + std::vector db_row_bytes(db_entry_byte_len, 0); + + auto db_bytes_span = std::span(db_bytes); + auto pub_matM_bytes_span = std::span(pub_matM_bytes); + auto query_bytes_span = std::span(query_bytes); + auto response_bytes_span = std::span(response_bytes); + auto db_row_bytes_span = std::span(db_row_bytes); + + prng::prng_t prng{}; + + prng.read(seed_μ); + prng.read(db_bytes); + + auto [server, M] = frodoPIR_server::server_t<λ, db_entry_count, db_entry_byte_len, mat_element_bitlen, lwe_dimension>::setup(seed_μ, db_bytes_span); + + M.to_le_bytes(pub_matM_bytes_span); + auto client = frodoPIR_client::client_t<λ, db_entry_count, db_entry_byte_len, mat_element_bitlen, lwe_dimension>::setup(seed_μ, pub_matM_bytes_span); + + for (size_t cur_query_count = 0; cur_query_count < num_queries; cur_query_count++) { + const size_t db_row_index = [&]() { + size_t buffer = 0; + auto buffer_span = std::span(reinterpret_cast(&buffer), sizeof(buffer)); + + prng.read(buffer_span); + + return buffer % db_entry_count; + }(); + + client.prepare_query(db_row_index, prng); + + const auto is_query_ready = client.query(db_row_index, query_bytes_span); + EXPECT_TRUE(is_query_ready); + + server.respond(query_bytes_span, response_bytes_span); + + const auto is_response_decoded = client.process_response(db_row_index, response_bytes_span, db_row_bytes_span); + EXPECT_TRUE(is_response_decoded); + + const size_t db_row_begin_at = db_row_index * db_entry_byte_len; + EXPECT_TRUE(std::ranges::equal(db_row_bytes_span, db_bytes_span.subspan(db_row_begin_at, db_entry_byte_len))); + } +} + +TEST(FrodoPIR, PrivateInformationRetrieval) +{ + test_private_information_retrieval<1ul << 16, 32, 10, 1774>(128); + test_private_information_retrieval<1ul << 17, 32, 10, 1774>(128); + test_private_information_retrieval<1ul << 18, 32, 10, 1774>(128); + test_private_information_retrieval<1ul << 19, 32, 9, 1774>(128); + test_private_information_retrieval<1ul << 20, 32, 9, 1774>(128); +} From 88db0e0c273f82a7529d3fcda12bf279bfedb7ac Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Mon, 23 Sep 2024 08:11:48 +0400 Subject: [PATCH 46/97] Add makefile for ease of building and running tests Signed-off-by: Anjan Roy --- Makefile | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3f2e3b8 --- /dev/null +++ b/Makefile @@ -0,0 +1,120 @@ +CXX ?= clang++ +CXX_DEFS += +CXX_FLAGS := -std=c++20 +WARN_FLAGS := -Wall -Wextra -Wpedantic +DEBUG_FLAGS := -O1 -g +RELEASE_FLAGS := -O3 -march=native +LINK_OPT_FLAGS := -flto +ASAN_FLAGS := -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address # From https://clang.llvm.org/docs/AddressSanitizer.html +DEBUG_ASAN_FLAGS := $(DEBUG_FLAGS) $(ASAN_FLAGS) +RELEASE_ASAN_FLAGS := -g $(RELEASE_FLAGS) $(ASAN_FLAGS) +UBSAN_FLAGS := -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=undefined # From https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html +DEBUG_UBSAN_FLAGS := $(DEBUG_FLAGS) $(UBSAN_FLAGS) +RELEASE_UBSAN_FLAGS := -g $(RELEASE_FLAGS) $(UBSAN_FLAGS) + +I_FLAGS := -I ./include +SHA3_INC_DIR := ./sha3/include +DEP_IFLAGS := -I $(SHA3_INC_DIR) + +SRC_DIR := include +FrodoPIR_SOURCES := $(shell find $(SRC_DIR) -name '*.hpp') +BUILD_DIR := build +TEST_BUILD_DIR := $(BUILD_DIR)/test +ASAN_BUILD_DIR := $(BUILD_DIR)/asan +DEBUG_ASAN_BUILD_DIR := $(ASAN_BUILD_DIR)/debug +RELEASE_ASAN_BUILD_DIR := $(ASAN_BUILD_DIR)/release +UBSAN_BUILD_DIR := $(BUILD_DIR)/ubsan +DEBUG_UBSAN_BUILD_DIR := $(UBSAN_BUILD_DIR)/debug +RELEASE_UBSAN_BUILD_DIR := $(UBSAN_BUILD_DIR)/release + +TEST_DIR := tests +TEST_SOURCES := $(wildcard $(TEST_DIR)/*.cpp) +TEST_HEADERS := $(wildcard $(TEST_DIR)/*.hpp) +TEST_OBJECTS := $(addprefix $(TEST_BUILD_DIR)/, $(notdir $(patsubst %.cpp,%.o,$(TEST_SOURCES)))) +TEST_BINARY := $(TEST_BUILD_DIR)/test.out +TEST_LINK_FLAGS := -lgtest -lgtest_main +GTEST_PARALLEL := ./gtest-parallel/gtest-parallel +DEBUG_ASAN_TEST_OBJECTS := $(addprefix $(DEBUG_ASAN_BUILD_DIR)/, $(notdir $(patsubst %.cpp,%.o,$(TEST_SOURCES)))) +RELEASE_ASAN_TEST_OBJECTS := $(addprefix $(RELEASE_ASAN_BUILD_DIR)/, $(notdir $(patsubst %.cpp,%.o,$(TEST_SOURCES)))) +DEBUG_ASAN_TEST_BINARY := $(DEBUG_ASAN_BUILD_DIR)/test.out +RELEASE_ASAN_TEST_BINARY := $(RELEASE_ASAN_BUILD_DIR)/test.out +DEBUG_UBSAN_TEST_OBJECTS := $(addprefix $(DEBUG_UBSAN_BUILD_DIR)/, $(notdir $(patsubst %.cpp,%.o,$(TEST_SOURCES)))) +RELEASE_UBSAN_TEST_OBJECTS := $(addprefix $(RELEASE_UBSAN_BUILD_DIR)/, $(notdir $(patsubst %.cpp,%.o,$(TEST_SOURCES)))) +DEBUG_UBSAN_TEST_BINARY := $(DEBUG_UBSAN_BUILD_DIR)/test.out +RELEASE_UBSAN_TEST_BINARY := $(RELEASE_UBSAN_BUILD_DIR)/test.out + +all: test + +$(DEBUG_ASAN_BUILD_DIR): + mkdir -p $@ + +$(RELEASE_ASAN_BUILD_DIR): + mkdir -p $@ + +$(DEBUG_UBSAN_BUILD_DIR): + mkdir -p $@ + +$(RELEASE_UBSAN_BUILD_DIR): + mkdir -p $@ + +$(TEST_BUILD_DIR): + mkdir -p $@ + +$(GTEST_PARALLEL): + git submodule update --init gtest-parallel + +$(SHA3_INC_DIR): $(GTEST_PARALLEL) + git submodule update --init sha3 + +$(TEST_BUILD_DIR)/%.o: $(TEST_DIR)/%.cpp $(TEST_BUILD_DIR) $(SHA3_INC_DIR) + $(CXX) $(CXX_DEFS) $(CXX_FLAGS) $(WARN_FLAGS) $(RELEASE_FLAGS) $(I_FLAGS) $(DEP_IFLAGS) -c $< -o $@ + +$(DEBUG_ASAN_BUILD_DIR)/%.o: $(TEST_DIR)/%.cpp $(DEBUG_ASAN_BUILD_DIR) $(SHA3_INC_DIR) + $(CXX) $(CXX_DEFS) $(CXX_FLAGS) $(WARN_FLAGS) $(DEBUG_ASAN_FLAGS) $(I_FLAGS) $(DEP_IFLAGS) -c $< -o $@ + +$(RELEASE_ASAN_BUILD_DIR)/%.o: $(TEST_DIR)/%.cpp $(RELEASE_ASAN_BUILD_DIR) $(SHA3_INC_DIR) + $(CXX) $(CXX_DEFS) $(CXX_FLAGS) $(WARN_FLAGS) $(RELEASE_ASAN_FLAGS) $(I_FLAGS) $(DEP_IFLAGS) -c $< -o $@ + +$(DEBUG_UBSAN_BUILD_DIR)/%.o: $(TEST_DIR)/%.cpp $(DEBUG_UBSAN_BUILD_DIR) $(SHA3_INC_DIR) + $(CXX) $(CXX_DEFS) $(CXX_FLAGS) $(WARN_FLAGS) $(DEBUG_UBSAN_FLAGS) $(I_FLAGS) $(DEP_IFLAGS) -c $< -o $@ + +$(RELEASE_UBSAN_BUILD_DIR)/%.o: $(TEST_DIR)/%.cpp $(RELEASE_UBSAN_BUILD_DIR) $(SHA3_INC_DIR) + $(CXX) $(CXX_DEFS) $(CXX_FLAGS) $(WARN_FLAGS) $(RELEASE_UBSAN_FLAGS) $(I_FLAGS) $(DEP_IFLAGS) -c $< -o $@ + +$(TEST_BINARY): $(TEST_OBJECTS) + $(CXX) $(RELEASE_FLAGS) $(LINK_OPT_FLAGS) $^ $(TEST_LINK_FLAGS) -o $@ + +$(DEBUG_ASAN_TEST_BINARY): $(DEBUG_ASAN_TEST_OBJECTS) + $(CXX) $(DEBUG_ASAN_FLAGS) $^ $(TEST_LINK_FLAGS) -o $@ + +$(RELEASE_ASAN_TEST_BINARY): $(RELEASE_ASAN_TEST_OBJECTS) + $(CXX) $(RELEASE_ASAN_FLAGS) $^ $(TEST_LINK_FLAGS) -o $@ + +$(DEBUG_UBSAN_TEST_BINARY): $(DEBUG_UBSAN_TEST_OBJECTS) + $(CXX) $(DEBUG_UBSAN_FLAGS) $^ $(TEST_LINK_FLAGS) -o $@ + +$(RELEASE_UBSAN_TEST_BINARY): $(RELEASE_UBSAN_TEST_OBJECTS) + $(CXX) $(RELEASE_UBSAN_FLAGS) $^ $(TEST_LINK_FLAGS) -o $@ + +test: $(TEST_BINARY) $(GTEST_PARALLEL) + $(GTEST_PARALLEL) $< --print_test_times --serialize_test_cases + +debug_asan_test: $(DEBUG_ASAN_TEST_BINARY) $(GTEST_PARALLEL) + $(GTEST_PARALLEL) $< --print_test_times --serialize_test_cases + +release_asan_test: $(RELEASE_ASAN_TEST_BINARY) $(GTEST_PARALLEL) + $(GTEST_PARALLEL) $< --print_test_times --serialize_test_cases + +debug_ubsan_test: $(DEBUG_UBSAN_TEST_BINARY) $(GTEST_PARALLEL) + $(GTEST_PARALLEL) $< --print_test_times --serialize_test_cases + +release_ubsan_test: $(RELEASE_UBSAN_TEST_BINARY) $(GTEST_PARALLEL) + $(GTEST_PARALLEL) $< --print_test_times --serialize_test_cases + +.PHONY: format clean + +clean: + rm -rf $(BUILD_DIR) + +format: $(FrodoPIR_SOURCES) $(TEST_SOURCES) $(TEST_HEADERS) + clang-format -i $^ From 480c15749de35769285e06a9c00c79a3f54c46cc Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Mon, 23 Sep 2024 08:19:06 +0400 Subject: [PATCH 47/97] Add yaml script for running tests on Github Actions CI Signed-off-by: Anjan Roy --- .github/workflows/test_ci.yml | 44 +++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .github/workflows/test_ci.yml diff --git a/.github/workflows/test_ci.yml b/.github/workflows/test_ci.yml new file mode 100644 index 0000000..6da056d --- /dev/null +++ b/.github/workflows/test_ci.yml @@ -0,0 +1,44 @@ +name: Test Frodo Private Information Retrieval Scheme + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + runs-on: ${{matrix.os}} + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + compiler: [g++, clang++] + build_type: [debug, release] + test_type: ['standard', asan, ubsan] + + steps: + - uses: actions/checkout@v4 + - name: Setup Google-Test + run: | + pushd ~ + git clone https://github.com/google/googletest.git -b v1.15.2 + pushd googletest + mkdir build + pushd build + cmake .. -DBUILD_GMOCK=OFF + make + sudo make install + popd + popd + popd + - name: Execute Tests on ${{matrix.os}}, compiled with ${{matrix.compiler}} + if: ${{matrix.test_type == 'standard'}} + run: | + CXX=${{matrix.compiler}} make -j + make clean + + - name: Execute Tests with ${{matrix.test_type}}, in ${{matrix.build_type}} mode, on ${{matrix.os}}, compiled with ${{matrix.compiler}} + if: ${{matrix.test_type != 'standard'}} + run: | + CXX=${{matrix.compiler}} make ${{matrix.build_type}}_${{matrix.test_type}}_test -j + make clean From f6d9ec99380caf7299c07388e4db2decb8ce01fe Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Mon, 23 Sep 2024 19:05:13 +0400 Subject: [PATCH 48/97] Reduce number of tests run - it was taking way too long ! Signed-off-by: Anjan Roy --- tests/test_frodoPIR.cpp | 7 ++----- tests/test_serialization.cpp | 3 --- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/tests/test_frodoPIR.cpp b/tests/test_frodoPIR.cpp index a4d559b..67defa5 100644 --- a/tests/test_frodoPIR.cpp +++ b/tests/test_frodoPIR.cpp @@ -70,9 +70,6 @@ test_private_information_retrieval(const size_t num_queries) TEST(FrodoPIR, PrivateInformationRetrieval) { - test_private_information_retrieval<1ul << 16, 32, 10, 1774>(128); - test_private_information_retrieval<1ul << 17, 32, 10, 1774>(128); - test_private_information_retrieval<1ul << 18, 32, 10, 1774>(128); - test_private_information_retrieval<1ul << 19, 32, 9, 1774>(128); - test_private_information_retrieval<1ul << 20, 32, 9, 1774>(128); + test_private_information_retrieval<1ul << 16, 32, 10, 1774>(32); + test_private_information_retrieval<1ul << 20, 32, 9, 1774>(32); } diff --git a/tests/test_serialization.cpp b/tests/test_serialization.cpp index 497d05b..7b1372d 100644 --- a/tests/test_serialization.cpp +++ b/tests/test_serialization.cpp @@ -28,8 +28,5 @@ test_db_parsing_and_serialization() TEST(FrodoPIR, ParsingDatabaseAndSerializingDatabaseMatrix) { test_db_parsing_and_serialization<1ul << 16u, 1024, 10>(); - test_db_parsing_and_serialization<1ul << 17u, 1024, 10>(); - test_db_parsing_and_serialization<1ul << 18u, 1024, 10>(); - test_db_parsing_and_serialization<1ul << 19u, 1024, 9>(); test_db_parsing_and_serialization<1ul << 20u, 1024, 9>(); } From 981185cd0b2ff3a3cdc0bcab19ffd3083d5c1521 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Mon, 23 Sep 2024 19:07:11 +0400 Subject: [PATCH 49/97] Common function used for benchmarking Signed-off-by: Anjan Roy --- benches/bench_common.hpp | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 benches/bench_common.hpp diff --git a/benches/bench_common.hpp b/benches/bench_common.hpp new file mode 100644 index 0000000..58e62ec --- /dev/null +++ b/benches/bench_common.hpp @@ -0,0 +1,6 @@ +#pragma once +#include +#include + +const auto compute_min = [](const std::vector& v) -> double { return *std::min_element(v.begin(), v.end()); }; +const auto compute_max = [](const std::vector& v) -> double { return *std::max_element(v.begin(), v.end()); }; From e0d77cccb3e1b878255086c6ec27712f175469d8 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Mon, 23 Sep 2024 20:15:52 +0400 Subject: [PATCH 50/97] Address buffer overflow issue - all thanks to ASAN Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/serialization.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/frodoPIR/internals/matrix/serialization.hpp b/include/frodoPIR/internals/matrix/serialization.hpp index 75904e6..c22bf1a 100644 --- a/include/frodoPIR/internals/matrix/serialization.hpp +++ b/include/frodoPIR/internals/matrix/serialization.hpp @@ -1,6 +1,8 @@ #pragma once #include "frodoPIR/internals/matrix/matrix.hpp" #include "frodoPIR/internals/matrix/vector.hpp" +#include +#include namespace frodoPIR_serialization { @@ -36,12 +38,13 @@ parse_db_bytes(std::span byte const size_t fillable_num_bits = std::numeric_limits::digits - buf_num_bits; const size_t readable_num_bits = fillable_num_bits & (-std::numeric_limits::digits); const size_t readable_num_bytes = std::min(readable_num_bits / std::numeric_limits::digits, remaining_num_bytes); + const size_t read_num_bits = readable_num_bytes * std::numeric_limits::digits; const auto read_word = frodoPIR_utils::from_le_bytes(bytes.subspan(byte_off, readable_num_bytes)); byte_off += readable_num_bytes; buffer |= (read_word << buf_num_bits); - buf_num_bits += readable_num_bits; + buf_num_bits += read_num_bits; const size_t fillable_mat_elem_count = buf_num_bits / mat_element_bitlen; From e3ba7b0fb27b8acfb713131fcb01463fa0de7444 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Mon, 23 Sep 2024 20:17:55 +0400 Subject: [PATCH 51/97] Parallelize building of `google-test` on Github Actions CI Signed-off-by: Anjan Roy --- .github/workflows/test_ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test_ci.yml b/.github/workflows/test_ci.yml index 6da056d..48cad7d 100644 --- a/.github/workflows/test_ci.yml +++ b/.github/workflows/test_ci.yml @@ -26,8 +26,8 @@ jobs: mkdir build pushd build cmake .. -DBUILD_GMOCK=OFF - make - sudo make install + make -j + sudo make -j install popd popd popd From 39a5a40e5181ef9c663ae761f677388a1568f4aa Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Mon, 23 Sep 2024 20:28:26 +0400 Subject: [PATCH 52/97] Benchmark FrodoPIR server-setup step Signed-off-by: Anjan Roy --- benches/bench_server_setup.cpp | 58 ++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 benches/bench_server_setup.cpp diff --git a/benches/bench_server_setup.cpp b/benches/bench_server_setup.cpp new file mode 100644 index 0000000..7493fb9 --- /dev/null +++ b/benches/bench_server_setup.cpp @@ -0,0 +1,58 @@ +#include "bench_common.hpp" +#include "frodoPIR/server.hpp" +#include + +template +static void +bench_server_setup(benchmark::State& state) +{ + constexpr size_t db_byte_len = db_entry_count * db_entry_byte_len; + + std::array::digits> seed_μ{}; + std::vector db_bytes(db_byte_len, 0); + + auto seed_μ_span = std::span(seed_μ); + auto db_bytes_span = std::span(db_bytes); + + prng::prng_t prng{}; + + prng.read(seed_μ_span); + prng.read(db_bytes_span); + + for (auto _ : state) { + auto [server, M] = frodoPIR_server::server_t<λ, db_entry_count, db_entry_byte_len, mat_element_bitlen, lwe_dimension>::setup(seed_μ_span, db_bytes_span); + + benchmark::DoNotOptimize(seed_μ_span); + benchmark::DoNotOptimize(db_bytes_span); + benchmark::DoNotOptimize(server); + benchmark::DoNotOptimize(M); + benchmark::ClobberMemory(); + } + + state.SetItemsProcessed(state.iterations()); +} + +BENCHMARK(bench_server_setup<128, 1ul << 16, 256, 10, 1774>) + ->Name("frodoPIR/server_setup/2^16/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); + +BENCHMARK(bench_server_setup<128, 1ul << 17, 256, 10, 1774>) + ->Name("frodoPIR/server_setup/2^17/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); + +BENCHMARK(bench_server_setup<128, 1ul << 18, 256, 10, 1774>) + ->Name("frodoPIR/server_setup/2^18/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); + +BENCHMARK(bench_server_setup<128, 1ul << 19, 256, 9, 1774>) + ->Name("frodoPIR/server_setup/2^19/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); + +BENCHMARK(bench_server_setup<128, 1ul << 20, 256, 9, 1774>) + ->Name("frodoPIR/server_setup/2^20/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); From a64b489ff1f415813579b206125ce650665a9ada Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Mon, 23 Sep 2024 20:30:02 +0400 Subject: [PATCH 53/97] Add new recipes for benchmarking frodoPIR Signed-off-by: Anjan Roy --- Makefile | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3f2e3b8..c83b69d 100644 --- a/Makefile +++ b/Makefile @@ -26,6 +26,7 @@ RELEASE_ASAN_BUILD_DIR := $(ASAN_BUILD_DIR)/release UBSAN_BUILD_DIR := $(BUILD_DIR)/ubsan DEBUG_UBSAN_BUILD_DIR := $(UBSAN_BUILD_DIR)/debug RELEASE_UBSAN_BUILD_DIR := $(UBSAN_BUILD_DIR)/release +BENCHMARK_BUILD_DIR := $(BUILD_DIR)/benchmark TEST_DIR := tests TEST_SOURCES := $(wildcard $(TEST_DIR)/*.cpp) @@ -43,6 +44,16 @@ RELEASE_UBSAN_TEST_OBJECTS := $(addprefix $(RELEASE_UBSAN_BUILD_DIR)/, $(notdir DEBUG_UBSAN_TEST_BINARY := $(DEBUG_UBSAN_BUILD_DIR)/test.out RELEASE_UBSAN_TEST_BINARY := $(RELEASE_UBSAN_BUILD_DIR)/test.out +BENCHMARK_DIR := benches +BENCHMARK_SOURCES := $(wildcard $(BENCHMARK_DIR)/*.cpp) +BENCHMARK_HEADERS := $(wildcard $(BENCHMARK_DIR)/*.hpp) +BENCHMARK_OBJECTS := $(addprefix $(BENCHMARK_BUILD_DIR)/, $(notdir $(patsubst %.cpp,%.o,$(BENCHMARK_SOURCES)))) +BENCHMARK_LINK_FLAGS := -lbenchmark -lbenchmark_main -lpthread +BENCHMARK_BINARY := $(BENCHMARK_BUILD_DIR)/bench.out +PERF_LINK_FLAGS := -lbenchmark -lbenchmark_main -lpfm -lpthread +PERF_BINARY := $(BENCHMARK_BUILD_DIR)/perf.out +BENCHMARK_OUT_FILE := bench_result_on_$(shell uname -s)_$(shell uname -r)_$(shell uname -m)_with_$(CXX)_$(shell $(CXX) -dumpversion).json + all: test $(DEBUG_ASAN_BUILD_DIR): @@ -60,6 +71,9 @@ $(RELEASE_UBSAN_BUILD_DIR): $(TEST_BUILD_DIR): mkdir -p $@ +$(BENCHMARK_BUILD_DIR): + mkdir -p $@ + $(GTEST_PARALLEL): git submodule update --init gtest-parallel @@ -111,10 +125,27 @@ debug_ubsan_test: $(DEBUG_UBSAN_TEST_BINARY) $(GTEST_PARALLEL) release_ubsan_test: $(RELEASE_UBSAN_TEST_BINARY) $(GTEST_PARALLEL) $(GTEST_PARALLEL) $< --print_test_times --serialize_test_cases +$(BENCHMARK_BUILD_DIR)/%.o: $(BENCHMARK_DIR)/%.cpp $(BENCHMARK_BUILD_DIR) $(SHA3_INC_DIR) + $(CXX) $(CXX_DEFS) $(CXX_FLAGS) $(WARN_FLAGS) $(RELEASE_FLAGS) $(I_FLAGS) $(DEP_IFLAGS) -c $< -o $@ + +$(BENCHMARK_BINARY): $(BENCHMARK_OBJECTS) + $(CXX) $(RELEASE_FLAGS) $(LINK_OPT_FLAGS) $^ $(BENCHMARK_LINK_FLAGS) -o $@ + +benchmark: $(BENCHMARK_BINARY) + # Must *not* build google-benchmark with libPFM + ./$< --benchmark_time_unit=s --benchmark_min_warmup_time=10 --benchmark_enable_random_interleaving=true --benchmark_repetitions=16 --benchmark_min_time=60s --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) + # Must build google-benchmark with libPFM, follow https://gist.github.com/itzmeanjan/05dc3e946f635d00c5e0b21aae6203a7 + ./$< --benchmark_time_unit=s --benchmark_min_warmup_time=10 --benchmark_enable_random_interleaving=true --benchmark_repetitions=16 --benchmark_min_time=60s --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) + .PHONY: format clean clean: rm -rf $(BUILD_DIR) -format: $(FrodoPIR_SOURCES) $(TEST_SOURCES) $(TEST_HEADERS) +format: $(FrodoPIR_SOURCES) $(TEST_SOURCES) $(TEST_HEADERS) $(BENCHMARK_SOURCES) $(BENCHMARK_HEADERS) clang-format -i $^ From 5bc9934c4fa0effbc0484d8d4f71617c5303b59f Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Tue, 24 Sep 2024 08:44:09 +0400 Subject: [PATCH 54/97] Refactor matrix operations functional correctness test to run on lesser memory Signed-off-by: Anjan Roy --- tests/test_matrix_operations.cpp | 42 +++++++++++++++++--------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/tests/test_matrix_operations.cpp b/tests/test_matrix_operations.cpp index 63484e1..b867362 100644 --- a/tests/test_matrix_operations.cpp +++ b/tests/test_matrix_operations.cpp @@ -6,11 +6,12 @@ #include #include -template -static void -test_matrix_operations() +TEST(FrodoPIR, MatrixOperations) { constexpr size_t λ = 128; + constexpr size_t rows = 1024; + constexpr size_t cols = rows + 1; + constexpr size_t mat_byte_len = frodoPIR_matrix::matrix_t::get_byte_len(); std::array::digits> μ{}; @@ -23,27 +24,30 @@ test_matrix_operations() prng.read(μ_span); auto A = frodoPIR_matrix::matrix_t::template generate<λ>(μ_span); - auto A_transposed = A.transpose(); - A_transposed.to_le_bytes(matA_bytes_span); - auto A_prime = frodoPIR_matrix::matrix_t::from_le_bytes(matA_bytes_span); - auto A_prime_transposed = A_prime.transpose(); + { + auto A_transposed = A.transpose(); + A_transposed.to_le_bytes(matA_bytes_span); + } - EXPECT_EQ(A, A_prime_transposed); + { + auto A_prime = frodoPIR_matrix::matrix_t::from_le_bytes(matA_bytes_span); + auto A_prime_transposed = A_prime.transpose(); - auto I = frodoPIR_matrix::matrix_t::identity(); - auto AI = A * I; + EXPECT_EQ(A, A_prime_transposed); + } - EXPECT_EQ(A, AI); + { + auto I = frodoPIR_matrix::matrix_t::identity(); + auto AI = A * I; - auto I_prime = frodoPIR_matrix::matrix_t::identity(); - auto IA = I_prime * A; + EXPECT_EQ(A, AI); + } - EXPECT_EQ(A, IA); -} + { + auto I_prime = frodoPIR_matrix::matrix_t::identity(); + auto IA = I_prime * A; -TEST(FrodoPIR, MatrixOperations) -{ - test_matrix_operations<1774, 1ul << 16>(); - test_matrix_operations<1774, 1ul << 20>(); + EXPECT_EQ(A, IA); + } } From b9d9dc87733a28b1533751d469043376465dd36b Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Tue, 24 Sep 2024 09:15:36 +0400 Subject: [PATCH 55/97] Make github actions workflow name shorter Signed-off-by: Anjan Roy --- .github/workflows/test_ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_ci.yml b/.github/workflows/test_ci.yml index 48cad7d..092f1c1 100644 --- a/.github/workflows/test_ci.yml +++ b/.github/workflows/test_ci.yml @@ -1,4 +1,4 @@ -name: Test Frodo Private Information Retrieval Scheme +name: Test FrodoPIR Scheme on: push: From 4971285472dcb55f5ecec795ada91fbb38889a35 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Tue, 24 Sep 2024 20:51:51 +0400 Subject: [PATCH 56/97] Benchmark server `respond` function Signed-off-by: Anjan Roy --- benches/bench_server_respond.cpp | 88 ++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 benches/bench_server_respond.cpp diff --git a/benches/bench_server_respond.cpp b/benches/bench_server_respond.cpp new file mode 100644 index 0000000..037d3a6 --- /dev/null +++ b/benches/bench_server_respond.cpp @@ -0,0 +1,88 @@ +#include "bench_common.hpp" +#include "frodoPIR/client.hpp" +#include "frodoPIR/server.hpp" +#include +#include + +template +static void +bench_server_respond(benchmark::State& state) +{ + constexpr size_t db_byte_len = db_entry_count * db_entry_byte_len; + constexpr size_t parsed_db_column_count = frodoPIR_matrix::get_required_num_columns(db_entry_byte_len, mat_element_bitlen); + constexpr size_t pub_matM_byte_len = frodoPIR_matrix::matrix_t::get_byte_len(); + constexpr size_t query_byte_len = frodoPIR_vector::row_vector_t::get_byte_len(); + constexpr size_t response_byte_len = frodoPIR_vector::row_vector_t::get_byte_len(); + + std::array::digits> seed_μ{}; + std::vector db_bytes(db_byte_len, 0); + std::vector pub_matM_bytes(pub_matM_byte_len, 0); + std::vector query_bytes(query_byte_len, 0); + std::vector response_bytes(response_byte_len, 0); + + auto seed_μ_span = std::span(seed_μ); + auto db_bytes_span = std::span(db_bytes); + auto pub_matM_bytes_span = std::span(pub_matM_bytes); + auto query_bytes_span = std::span(query_bytes); + auto response_bytes_span = std::span(response_bytes); + + prng::prng_t prng{}; + + prng.read(seed_μ_span); + prng.read(db_bytes_span); + + auto [server, M] = frodoPIR_server::server_t<λ, db_entry_count, db_entry_byte_len, mat_element_bitlen, lwe_dimension>::setup(seed_μ_span, db_bytes_span); + + M.to_le_bytes(pub_matM_bytes_span); + auto client = frodoPIR_client::client_t<λ, db_entry_count, db_entry_byte_len, mat_element_bitlen, lwe_dimension>::setup(seed_μ, pub_matM_bytes_span); + + const size_t rand_db_row_index = [&]() { + size_t buffer = 0; + auto buffer_span = std::span(reinterpret_cast(&buffer), sizeof(buffer)); + + prng.read(buffer_span); + + return buffer % db_entry_count; + }(); + + client.prepare_query(rand_db_row_index, prng); + + const auto is_query_ready = client.query(rand_db_row_index, query_bytes_span); + assert(is_query_ready); + + for (auto _ : state) { + server.respond(query_bytes_span, response_bytes_span); + + benchmark::DoNotOptimize(server); + benchmark::DoNotOptimize(query_bytes_span); + benchmark::DoNotOptimize(response_bytes_span); + benchmark::ClobberMemory(); + } + + state.SetItemsProcessed(state.iterations()); +} + +BENCHMARK(bench_server_respond<128, 1ul << 16, 256, 10, 1774>) + ->Name("frodoPIR/server_respond/2^16/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); + +BENCHMARK(bench_server_respond<128, 1ul << 17, 256, 10, 1774>) + ->Name("frodoPIR/server_respond/2^17/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); + +BENCHMARK(bench_server_respond<128, 1ul << 18, 256, 10, 1774>) + ->Name("frodoPIR/server_respond/2^18/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); + +BENCHMARK(bench_server_respond<128, 1ul << 19, 256, 9, 1774>) + ->Name("frodoPIR/server_respond/2^19/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); + +BENCHMARK(bench_server_respond<128, 1ul << 20, 256, 9, 1774>) + ->Name("frodoPIR/server_respond/2^20/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); From 0a231bb51978123ef118eae8d8d5e10b36acf9b3 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Tue, 24 Sep 2024 21:15:08 +0400 Subject: [PATCH 57/97] Benchmark client query preparation function Signed-off-by: Anjan Roy --- benches/bench_client_prepare_query.cpp | 80 ++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 benches/bench_client_prepare_query.cpp diff --git a/benches/bench_client_prepare_query.cpp b/benches/bench_client_prepare_query.cpp new file mode 100644 index 0000000..7e68487 --- /dev/null +++ b/benches/bench_client_prepare_query.cpp @@ -0,0 +1,80 @@ +#include "bench_common.hpp" +#include "frodoPIR/client.hpp" +#include "frodoPIR/server.hpp" +#include +#include + +template +static void +bench_client_prepare_query(benchmark::State& state) +{ + constexpr size_t db_byte_len = db_entry_count * db_entry_byte_len; + constexpr size_t parsed_db_column_count = frodoPIR_matrix::get_required_num_columns(db_entry_byte_len, mat_element_bitlen); + constexpr size_t pub_matM_byte_len = frodoPIR_matrix::matrix_t::get_byte_len(); + + std::array::digits> seed_μ{}; + std::vector db_bytes(db_byte_len, 0); + std::vector pub_matM_bytes(pub_matM_byte_len, 0); + + auto seed_μ_span = std::span(seed_μ); + auto db_bytes_span = std::span(db_bytes); + auto pub_matM_bytes_span = std::span(pub_matM_bytes); + + prng::prng_t prng{}; + + prng.read(seed_μ_span); + prng.read(db_bytes_span); + + auto [server, M] = frodoPIR_server::server_t<λ, db_entry_count, db_entry_byte_len, mat_element_bitlen, lwe_dimension>::setup(seed_μ_span, db_bytes_span); + + M.to_le_bytes(pub_matM_bytes_span); + auto client = frodoPIR_client::client_t<λ, db_entry_count, db_entry_byte_len, mat_element_bitlen, lwe_dimension>::setup(seed_μ, pub_matM_bytes_span); + + size_t rand_db_row_index = [&]() { + size_t buffer = 0; + auto buffer_span = std::span(reinterpret_cast(&buffer), sizeof(buffer)); + + prng.read(buffer_span); + + return buffer % db_entry_count; + }(); + + for (auto _ : state) { + client.prepare_query(rand_db_row_index, prng); + + benchmark::DoNotOptimize(client); + benchmark::DoNotOptimize(rand_db_row_index); + benchmark::DoNotOptimize(prng); + benchmark::ClobberMemory(); + + rand_db_row_index ^= (rand_db_row_index << 1) ^ 1ul; + rand_db_row_index %= db_entry_count; + } + + state.SetItemsProcessed(state.iterations()); +} + +BENCHMARK(bench_client_prepare_query<128, 1ul << 16, 256, 10, 1774>) + ->Name("frodoPIR/client_prepare_query/2^16/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); + +BENCHMARK(bench_client_prepare_query<128, 1ul << 17, 256, 10, 1774>) + ->Name("frodoPIR/client_prepare_query/2^17/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); + +BENCHMARK(bench_client_prepare_query<128, 1ul << 18, 256, 10, 1774>) + ->Name("frodoPIR/client_prepare_query/2^18/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); + +BENCHMARK(bench_client_prepare_query<128, 1ul << 19, 256, 9, 1774>) + ->Name("frodoPIR/client_prepare_query/2^19/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); + +BENCHMARK(bench_client_prepare_query<128, 1ul << 20, 256, 9, 1774>) + ->Name("frodoPIR/client_prepare_query/2^20/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); From ab4004d778277029580861e2aae75e5e30f767a2 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Tue, 24 Sep 2024 21:29:55 +0400 Subject: [PATCH 58/97] Benchmark client query function Signed-off-by: Anjan Roy --- benches/bench_client_query.cpp | 95 ++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 benches/bench_client_query.cpp diff --git a/benches/bench_client_query.cpp b/benches/bench_client_query.cpp new file mode 100644 index 0000000..9ce296b --- /dev/null +++ b/benches/bench_client_query.cpp @@ -0,0 +1,95 @@ +#include "bench_common.hpp" +#include "frodoPIR/client.hpp" +#include "frodoPIR/server.hpp" +#include +#include + +template +static void +bench_client_query(benchmark::State& state) +{ + constexpr size_t db_byte_len = db_entry_count * db_entry_byte_len; + constexpr size_t parsed_db_column_count = frodoPIR_matrix::get_required_num_columns(db_entry_byte_len, mat_element_bitlen); + constexpr size_t pub_matM_byte_len = frodoPIR_matrix::matrix_t::get_byte_len(); + constexpr size_t query_byte_len = frodoPIR_vector::row_vector_t::get_byte_len(); + constexpr size_t response_byte_len = frodoPIR_vector::row_vector_t::get_byte_len(); + + std::array::digits> seed_μ{}; + std::vector db_bytes(db_byte_len, 0); + std::vector pub_matM_bytes(pub_matM_byte_len, 0); + std::vector query_bytes(query_byte_len, 0); + std::vector response_bytes(response_byte_len, 0); + + auto seed_μ_span = std::span(seed_μ); + auto db_bytes_span = std::span(db_bytes); + auto pub_matM_bytes_span = std::span(pub_matM_bytes); + auto query_bytes_span = std::span(query_bytes); + auto response_bytes_span = std::span(response_bytes); + + prng::prng_t prng{}; + + prng.read(seed_μ_span); + prng.read(db_bytes_span); + + auto [server, M] = frodoPIR_server::server_t<λ, db_entry_count, db_entry_byte_len, mat_element_bitlen, lwe_dimension>::setup(seed_μ_span, db_bytes_span); + + M.to_le_bytes(pub_matM_bytes_span); + auto client = frodoPIR_client::client_t<λ, db_entry_count, db_entry_byte_len, mat_element_bitlen, lwe_dimension>::setup(seed_μ, pub_matM_bytes_span); + + size_t rand_db_row_index = [&]() { + size_t buffer = 0; + auto buffer_span = std::span(reinterpret_cast(&buffer), sizeof(buffer)); + + prng.read(buffer_span); + + return buffer % db_entry_count; + }(); + + client.prepare_query(rand_db_row_index, prng); + + bool is_query_ready = true; + for (auto _ : state) { + is_query_ready &= client.query(rand_db_row_index, query_bytes_span); + + benchmark::DoNotOptimize(client); + benchmark::DoNotOptimize(query_bytes_span); + benchmark::DoNotOptimize(is_query_ready); + benchmark::ClobberMemory(); + + state.PauseTiming(); + server.respond(query_bytes_span, response_bytes_span); + + rand_db_row_index ^= (rand_db_row_index << 1) ^ 1ul; + rand_db_row_index %= db_entry_count; + + client.prepare_query(rand_db_row_index, prng); + state.ResumeTiming(); + } + + state.SetItemsProcessed(state.iterations()); +} + +BENCHMARK(bench_client_query<128, 1ul << 16, 256, 10, 1774>) + ->Name("frodoPIR/client_query/2^16/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); + +BENCHMARK(bench_client_query<128, 1ul << 17, 256, 10, 1774>) + ->Name("frodoPIR/client_query/2^17/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); + +BENCHMARK(bench_client_query<128, 1ul << 18, 256, 10, 1774>) + ->Name("frodoPIR/client_query/2^18/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); + +BENCHMARK(bench_client_query<128, 1ul << 19, 256, 9, 1774>) + ->Name("frodoPIR/client_query/2^19/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); + +BENCHMARK(bench_client_query<128, 1ul << 20, 256, 9, 1774>) + ->Name("frodoPIR/client_query/2^20/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); From f8024db18924bccda7e65ce69429ad986badb5eb Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Tue, 24 Sep 2024 22:26:48 +0400 Subject: [PATCH 59/97] Add comments and `nodiscard` attribute Signed-off-by: Anjan Roy --- include/frodoPIR/client.hpp | 43 ++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/include/frodoPIR/client.hpp b/include/frodoPIR/client.hpp index 7e92ba1..84ec32e 100644 --- a/include/frodoPIR/client.hpp +++ b/include/frodoPIR/client.hpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace frodoPIR_client { @@ -61,20 +62,30 @@ struct client_t frodoPIR_matrix::matrix_t::from_le_bytes(pub_matM_bytes)); } - // Given a set of database row indices, this routine prepares those many queries, for enquiring their values, - // using FrodoPIR scheme. - constexpr void prepare_query(std::span db_row_indices, prng::prng_t& prng) + // Given `n` -many database row indices, this routine prepares `n` -many queries, for enquiring their values, + // using FrodoPIR scheme. This function returns a boolean vector of length `n` s.t. each boolean value denotes + // status of query preparation, for corresponding database row index, as appearing in `db_row_indices`, in order. + [[nodiscard("Must use status of query preparation for DB row indices")]] constexpr std::vector prepare_query(std::span db_row_indices, + prng::prng_t& prng) { + std::vector query_prep_status; + query_prep_status.reserve(db_row_indices.size()); + for (const auto db_row_index : db_row_indices) { - this->prepare_query(db_row_index, prng); + query_prep_status.push_back(this->prepare_query(db_row_index, prng)); } + + return query_prep_status; } // Given a database row index, this routine prepares a query, so that value at that index can be enquired, using FrodoPIR scheme. - constexpr void prepare_query(const size_t db_row_index, prng::prng_t& prng) + // This routine returns boolean truth value if query for requested database row index is prepared - ready to be used, while also + // placing an entry of query for corresponding database row index in the internal cache. But in case, query for corresponding database + // row index has already been prepared, it returns false, denoting that no change has been done to the internal cache. + [[nodiscard("Must use status of query preparation")]] constexpr bool prepare_query(const size_t db_row_index, prng::prng_t& prng) { if (this->queries.contains(db_row_index)) { - return; + return false; } const auto s = frodoPIR_vector::column_vector_t::sample_from_uniform_ternary_distribution(prng); // secret vector @@ -90,11 +101,18 @@ struct client_t .b = b, .c = c, }; + + return true; } - // Given a database row index, for which query has already been prepared, this routine finalizes the query, - // making it ready for processing at the server's end. - constexpr bool query(const size_t db_row_index, std::span query_bytes) + // Given a database row index, for which query has already been prepared, this routine finalizes the query, making it ready + // for processing at the server's end. This routine returns boolean truth value if byte serialized query is ready to be sent to server. + // Or else it returns false, denoting either of + // + // (a) Query is not yet prepared for requested database row index. + // (b) Query is already sent to server for requested database row index. + [[nodiscard("Must use status of query finalization")]] constexpr bool query(const size_t db_row_index, + std::span query_bytes) { if (!this->queries.contains(db_row_index)) { return false; @@ -115,7 +133,12 @@ struct client_t // Given a database row index, for which query has already been sent to server and we are awaiting response, // this routine can be used for processing server response, returning byte serialized content of queried row. - constexpr bool process_response( + // This function returns boolean truth value, if response is successfully decoded, while also removing entry + // of corresponding client query from internal cache. Or it may return false, denoting either of + // + // (a) Query is not yet prepared for requested database row index. + // (b) Query has not yet been sent to server, so can't process response for it. + [[nodiscard("Must use status of response decoding")]] constexpr bool process_response( const size_t db_row_index, std::span response_bytes, std::span db_row_bytes) From cce865e65e001f6fd2a6603f572add33b833bbe2 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Tue, 24 Sep 2024 22:35:16 +0400 Subject: [PATCH 60/97] Use return value of client query function in benchmarking Signed-off-by: Anjan Roy --- benches/bench_client_query.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/benches/bench_client_query.cpp b/benches/bench_client_query.cpp index 9ce296b..f253004 100644 --- a/benches/bench_client_query.cpp +++ b/benches/bench_client_query.cpp @@ -45,15 +45,15 @@ bench_client_query(benchmark::State& state) return buffer % db_entry_count; }(); - client.prepare_query(rand_db_row_index, prng); - + auto is_query_preprocessed = client.prepare_query(rand_db_row_index, prng); bool is_query_ready = true; + for (auto _ : state) { is_query_ready &= client.query(rand_db_row_index, query_bytes_span); + benchmark::DoNotOptimize(is_query_ready); benchmark::DoNotOptimize(client); benchmark::DoNotOptimize(query_bytes_span); - benchmark::DoNotOptimize(is_query_ready); benchmark::ClobberMemory(); state.PauseTiming(); @@ -62,10 +62,13 @@ bench_client_query(benchmark::State& state) rand_db_row_index ^= (rand_db_row_index << 1) ^ 1ul; rand_db_row_index %= db_entry_count; - client.prepare_query(rand_db_row_index, prng); + is_query_preprocessed &= client.prepare_query(rand_db_row_index, prng); state.ResumeTiming(); } + assert(is_query_preprocessed); + assert(is_query_ready); + state.SetItemsProcessed(state.iterations()); } From 7ce16cbb6e14cc978a5b12f9585d8b0eff68eb9d Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Tue, 24 Sep 2024 22:35:58 +0400 Subject: [PATCH 61/97] Use return value of client operations Signed-off-by: Anjan Roy --- benches/bench_server_respond.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/benches/bench_server_respond.cpp b/benches/bench_server_respond.cpp index 037d3a6..161e4c1 100644 --- a/benches/bench_server_respond.cpp +++ b/benches/bench_server_respond.cpp @@ -45,7 +45,8 @@ bench_server_respond(benchmark::State& state) return buffer % db_entry_count; }(); - client.prepare_query(rand_db_row_index, prng); + const auto is_query_preprocessed = client.prepare_query(rand_db_row_index, prng); + assert(is_query_preprocessed); const auto is_query_ready = client.query(rand_db_row_index, query_bytes_span); assert(is_query_ready); From 711049d8e116f03b6e0f3e17703ddef10f9921bc Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Tue, 24 Sep 2024 22:42:32 +0400 Subject: [PATCH 62/97] Refactor client-prepare-query by using return value of functions Signed-off-by: Anjan Roy --- benches/bench_client_prepare_query.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/benches/bench_client_prepare_query.cpp b/benches/bench_client_prepare_query.cpp index 7e68487..e2902d7 100644 --- a/benches/bench_client_prepare_query.cpp +++ b/benches/bench_client_prepare_query.cpp @@ -11,14 +11,20 @@ bench_client_prepare_query(benchmark::State& state) constexpr size_t db_byte_len = db_entry_count * db_entry_byte_len; constexpr size_t parsed_db_column_count = frodoPIR_matrix::get_required_num_columns(db_entry_byte_len, mat_element_bitlen); constexpr size_t pub_matM_byte_len = frodoPIR_matrix::matrix_t::get_byte_len(); + constexpr size_t query_byte_len = frodoPIR_vector::row_vector_t::get_byte_len(); + constexpr size_t response_byte_len = frodoPIR_vector::row_vector_t::get_byte_len(); std::array::digits> seed_μ{}; std::vector db_bytes(db_byte_len, 0); std::vector pub_matM_bytes(pub_matM_byte_len, 0); + std::vector query_bytes(query_byte_len, 0); + std::vector response_bytes(response_byte_len, 0); auto seed_μ_span = std::span(seed_μ); auto db_bytes_span = std::span(db_bytes); auto pub_matM_bytes_span = std::span(pub_matM_bytes); + auto query_bytes_span = std::span(query_bytes); + auto response_bytes_span = std::span(response_bytes); prng::prng_t prng{}; @@ -39,18 +45,31 @@ bench_client_prepare_query(benchmark::State& state) return buffer % db_entry_count; }(); + bool is_query_preprocessed = true; + bool is_query_ready = true; + for (auto _ : state) { - client.prepare_query(rand_db_row_index, prng); + is_query_preprocessed &= client.prepare_query(rand_db_row_index, prng); + benchmark::DoNotOptimize(is_query_preprocessed); benchmark::DoNotOptimize(client); benchmark::DoNotOptimize(rand_db_row_index); benchmark::DoNotOptimize(prng); benchmark::ClobberMemory(); + state.PauseTiming(); + is_query_ready &= client.query(rand_db_row_index, query_bytes_span); + server.respond(query_bytes_span, response_bytes_span); + rand_db_row_index ^= (rand_db_row_index << 1) ^ 1ul; rand_db_row_index %= db_entry_count; + + state.ResumeTiming(); } + assert(is_query_preprocessed); + assert(is_query_ready); + state.SetItemsProcessed(state.iterations()); } From 66b5714ebdf066ea9797780e561e4fe8d787336f Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Tue, 24 Sep 2024 22:51:35 +0400 Subject: [PATCH 63/97] Add benchmarking for processing of server response at client's end Signed-off-by: Anjan Roy --- benches/bench_client_process_response.cpp | 104 ++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 benches/bench_client_process_response.cpp diff --git a/benches/bench_client_process_response.cpp b/benches/bench_client_process_response.cpp new file mode 100644 index 0000000..785e770 --- /dev/null +++ b/benches/bench_client_process_response.cpp @@ -0,0 +1,104 @@ +#include "bench_common.hpp" +#include "frodoPIR/client.hpp" +#include "frodoPIR/server.hpp" +#include +#include + +template +static void +bench_client_process_response(benchmark::State& state) +{ + constexpr size_t db_byte_len = db_entry_count * db_entry_byte_len; + constexpr size_t parsed_db_column_count = frodoPIR_matrix::get_required_num_columns(db_entry_byte_len, mat_element_bitlen); + constexpr size_t pub_matM_byte_len = frodoPIR_matrix::matrix_t::get_byte_len(); + constexpr size_t query_byte_len = frodoPIR_vector::row_vector_t::get_byte_len(); + constexpr size_t response_byte_len = frodoPIR_vector::row_vector_t::get_byte_len(); + + std::array::digits> seed_μ{}; + std::vector db_bytes(db_byte_len, 0); + std::vector pub_matM_bytes(pub_matM_byte_len, 0); + std::vector query_bytes(query_byte_len, 0); + std::vector response_bytes(response_byte_len, 0); + std::vector db_row_bytes(db_entry_byte_len, 0); + + auto seed_μ_span = std::span(seed_μ); + auto db_bytes_span = std::span(db_bytes); + auto pub_matM_bytes_span = std::span(pub_matM_bytes); + auto query_bytes_span = std::span(query_bytes); + auto response_bytes_span = std::span(response_bytes); + auto db_row_bytes_span = std::span(db_row_bytes); + + prng::prng_t prng{}; + + prng.read(seed_μ_span); + prng.read(db_bytes_span); + + auto [server, M] = frodoPIR_server::server_t<λ, db_entry_count, db_entry_byte_len, mat_element_bitlen, lwe_dimension>::setup(seed_μ_span, db_bytes_span); + + M.to_le_bytes(pub_matM_bytes_span); + auto client = frodoPIR_client::client_t<λ, db_entry_count, db_entry_byte_len, mat_element_bitlen, lwe_dimension>::setup(seed_μ, pub_matM_bytes_span); + + size_t rand_db_row_index = [&]() { + size_t buffer = 0; + auto buffer_span = std::span(reinterpret_cast(&buffer), sizeof(buffer)); + + prng.read(buffer_span); + + return buffer % db_entry_count; + }(); + + auto is_query_preprocessed = client.prepare_query(rand_db_row_index, prng); + auto is_query_ready = client.query(rand_db_row_index, query_bytes_span); + server.respond(query_bytes_span, response_bytes_span); + + bool is_response_decoded = true; + for (auto _ : state) { + is_response_decoded &= client.process_response(rand_db_row_index, response_bytes_span, db_row_bytes_span); + + benchmark::DoNotOptimize(client); + benchmark::DoNotOptimize(rand_db_row_index); + benchmark::DoNotOptimize(response_bytes_span); + benchmark::DoNotOptimize(db_row_bytes_span); + benchmark::ClobberMemory(); + + state.PauseTiming(); + 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_ready &= client.query(rand_db_row_index, query_bytes_span); + server.respond(query_bytes_span, response_bytes_span); + state.ResumeTiming(); + } + + assert(is_query_preprocessed); + assert(is_query_ready); + assert(is_response_decoded); + + state.SetItemsProcessed(state.iterations()); +} + +BENCHMARK(bench_client_process_response<128, 1ul << 16, 256, 10, 1774>) + ->Name("frodoPIR/client_process_response/2^16/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); + +BENCHMARK(bench_client_process_response<128, 1ul << 17, 256, 10, 1774>) + ->Name("frodoPIR/client_process_response/2^17/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); + +BENCHMARK(bench_client_process_response<128, 1ul << 18, 256, 10, 1774>) + ->Name("frodoPIR/client_process_response/2^18/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); + +BENCHMARK(bench_client_process_response<128, 1ul << 19, 256, 9, 1774>) + ->Name("frodoPIR/client_process_response/2^19/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); + +BENCHMARK(bench_client_process_response<128, 1ul << 20, 256, 9, 1774>) + ->Name("frodoPIR/client_process_response/2^20/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max); From 7afa82a81a8c764fd0dacf58471b269719b58e94 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Tue, 24 Sep 2024 22:53:32 +0400 Subject: [PATCH 64/97] Slightly modify test to use return value of client operation step Signed-off-by: Anjan Roy --- tests/test_frodoPIR.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_frodoPIR.cpp b/tests/test_frodoPIR.cpp index 67defa5..f572a1c 100644 --- a/tests/test_frodoPIR.cpp +++ b/tests/test_frodoPIR.cpp @@ -53,7 +53,8 @@ test_private_information_retrieval(const size_t num_queries) return buffer % db_entry_count; }(); - client.prepare_query(db_row_index, prng); + const auto is_query_preprocessed = client.prepare_query(db_row_index, prng); + EXPECT_TRUE(is_query_preprocessed); const auto is_query_ready = client.query(db_row_index, query_bytes_span); EXPECT_TRUE(is_query_ready); From 8399aca90276208bd5e1e16f0017cc534f2ee8f8 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Wed, 25 Sep 2024 09:40:00 +0400 Subject: [PATCH 65/97] Implement setup phase of client operation benchmarking correctly Signed-off-by: Anjan Roy --- benches/bench_client_prepare_query.cpp | 6 +++++- benches/bench_client_query.cpp | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/benches/bench_client_prepare_query.cpp b/benches/bench_client_prepare_query.cpp index e2902d7..8ebc1bd 100644 --- a/benches/bench_client_prepare_query.cpp +++ b/benches/bench_client_prepare_query.cpp @@ -19,12 +19,14 @@ bench_client_prepare_query(benchmark::State& state) std::vector pub_matM_bytes(pub_matM_byte_len, 0); std::vector query_bytes(query_byte_len, 0); std::vector response_bytes(response_byte_len, 0); + std::vector db_row_bytes(db_entry_byte_len, 0); auto seed_μ_span = std::span(seed_μ); auto db_bytes_span = std::span(db_bytes); auto pub_matM_bytes_span = std::span(pub_matM_bytes); auto query_bytes_span = std::span(query_bytes); auto response_bytes_span = std::span(response_bytes); + auto db_row_bytes_span = std::span(db_row_bytes); prng::prng_t prng{}; @@ -47,6 +49,7 @@ bench_client_prepare_query(benchmark::State& state) bool is_query_preprocessed = true; bool is_query_ready = true; + bool is_response_decoded = true; for (auto _ : state) { is_query_preprocessed &= client.prepare_query(rand_db_row_index, prng); @@ -60,15 +63,16 @@ bench_client_prepare_query(benchmark::State& state) state.PauseTiming(); is_query_ready &= client.query(rand_db_row_index, query_bytes_span); server.respond(query_bytes_span, response_bytes_span); + is_response_decoded &= client.process_response(rand_db_row_index, response_bytes_span, db_row_bytes_span); rand_db_row_index ^= (rand_db_row_index << 1) ^ 1ul; rand_db_row_index %= db_entry_count; - state.ResumeTiming(); } assert(is_query_preprocessed); assert(is_query_ready); + assert(is_response_decoded); state.SetItemsProcessed(state.iterations()); } diff --git a/benches/bench_client_query.cpp b/benches/bench_client_query.cpp index f253004..ae41407 100644 --- a/benches/bench_client_query.cpp +++ b/benches/bench_client_query.cpp @@ -19,12 +19,14 @@ bench_client_query(benchmark::State& state) std::vector pub_matM_bytes(pub_matM_byte_len, 0); std::vector query_bytes(query_byte_len, 0); std::vector response_bytes(response_byte_len, 0); + std::vector db_row_bytes(db_entry_byte_len, 0); auto seed_μ_span = std::span(seed_μ); auto db_bytes_span = std::span(db_bytes); auto pub_matM_bytes_span = std::span(pub_matM_bytes); auto query_bytes_span = std::span(query_bytes); auto response_bytes_span = std::span(response_bytes); + auto db_row_bytes_span = std::span(db_row_bytes); prng::prng_t prng{}; @@ -47,6 +49,7 @@ bench_client_query(benchmark::State& state) auto is_query_preprocessed = client.prepare_query(rand_db_row_index, prng); bool is_query_ready = true; + bool is_response_decoded = true; for (auto _ : state) { is_query_ready &= client.query(rand_db_row_index, query_bytes_span); @@ -58,6 +61,7 @@ bench_client_query(benchmark::State& state) state.PauseTiming(); server.respond(query_bytes_span, response_bytes_span); + is_response_decoded &= client.process_response(rand_db_row_index, response_bytes_span, db_row_bytes_span); rand_db_row_index ^= (rand_db_row_index << 1) ^ 1ul; rand_db_row_index %= db_entry_count; @@ -68,6 +72,7 @@ bench_client_query(benchmark::State& state) assert(is_query_preprocessed); assert(is_query_ready); + assert(is_response_decoded); state.SetItemsProcessed(state.iterations()); } From 86b5a9443f9a4fe0a0026c1faf4716328cd7eb51 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Wed, 25 Sep 2024 20:48:06 +0400 Subject: [PATCH 66/97] Reduce benchmark minimum running time and minimum warmup time Signed-off-by: Anjan Roy --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index c83b69d..8ef5447 100644 --- a/Makefile +++ b/Makefile @@ -133,14 +133,14 @@ $(BENCHMARK_BINARY): $(BENCHMARK_OBJECTS) benchmark: $(BENCHMARK_BINARY) # Must *not* build google-benchmark with libPFM - ./$< --benchmark_time_unit=s --benchmark_min_warmup_time=10 --benchmark_enable_random_interleaving=true --benchmark_repetitions=16 --benchmark_min_time=60s --benchmark_display_aggregates_only=true --benchmark_report_aggregates_only=true --benchmark_counters_tabular=true --benchmark_out_format=json --benchmark_out=$(BENCHMARK_OUT_FILE) + ./$< --benchmark_time_unit=s --benchmark_min_warmup_time=1 --benchmark_enable_random_interleaving=true --benchmark_repetitions=16 --benchmark_min_time=5s --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) # Must build google-benchmark with libPFM, follow https://gist.github.com/itzmeanjan/05dc3e946f635d00c5e0b21aae6203a7 - ./$< --benchmark_time_unit=s --benchmark_min_warmup_time=10 --benchmark_enable_random_interleaving=true --benchmark_repetitions=16 --benchmark_min_time=60s --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) + ./$< --benchmark_time_unit=s --benchmark_min_warmup_time=1 --benchmark_enable_random_interleaving=true --benchmark_repetitions=16 --benchmark_min_time=5s --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) .PHONY: format clean From 285982174cedb66ce670cd84cdb330da9e81e4d2 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Wed, 25 Sep 2024 21:15:38 +0400 Subject: [PATCH 67/97] Add copy/ move constructors for matrix struct type Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index ce58d86..102040c 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -34,8 +34,16 @@ template struct matrix_t { public: - // Default constructor + // Constructor(s) forceinline constexpr matrix_t() { this->elements = std::vector(rows * cols, zq_t{}); }; + explicit matrix_t(std::vector elements) + : elements(std::move(elements)) + { + } + matrix_t(const matrix_t&) = default; + matrix_t(matrix_t&&) = default; + matrix_t& operator=(const matrix_t&) = default; + matrix_t& operator=(matrix_t&&) = default; // Given a `λ` -bit seed, this routine uniform random samples a matrix of dimension `rows x cols`. template From ded644a77851e943f5c62b1e28d6476ffd57dc2b Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Wed, 25 Sep 2024 21:20:29 +0400 Subject: [PATCH 68/97] Do lesser number of squeezing from shake128 -backed PRNG Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index 102040c..5bdbdfd 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -49,17 +49,20 @@ struct matrix_t template static forceinline constexpr matrix_t generate(std::span::digits> μ) { - prng::prng_t prng(μ); + constexpr size_t row_byte_len = cols * sizeof(zq_t); - std::array buffer{}; - auto buffer_span = std::span(buffer); + std::vector buffer(row_byte_len, 0); + auto buffer_span = std::span(buffer); + prng::prng_t prng(μ); matrix_t mat{}; for (size_t r_idx = 0; r_idx < rows; r_idx++) { + prng.read(buffer_span); + for (size_t c_idx = 0; c_idx < cols; c_idx++) { - prng.read(buffer_span); - mat[{ r_idx, c_idx }] = frodoPIR_utils::from_le_bytes(buffer_span); + const size_t buffer_offset = c_idx * sizeof(zq_t); + mat[{ r_idx, c_idx }] = frodoPIR_utils::from_le_bytes(buffer_span.subspan(buffer_offset, sizeof(zq_t))); } } From 26207b19682196ea65ea5a51ee7c06ea47072c54 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Wed, 25 Sep 2024 22:21:14 +0400 Subject: [PATCH 69/97] Improve matrix multiplication algorithm Following https://lemire.me/blog/2024/06/13/rolling-your-own-fast-matrix-multiplication-loop-order-and-vectorization/ Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index 5bdbdfd..0d76e61 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -158,6 +158,9 @@ struct matrix_t // Given two matrices A ( of dimension rows x cols ) and B ( of dimension rhs_rows x rhs_cols ) s.t. cols == rhs_rows, // this routine can be used for multiplying them over Zq, resulting into another matrix (C) of dimension rows x rhs_cols. + // + // Following homebrewed matrix multiplication technique from + // https://lemire.me/blog/2024/06/13/rolling-your-own-fast-matrix-multiplication-loop-order-and-vectorization. template requires((cols == rhs_rows)) forceinline constexpr matrix_t operator*(const matrix_t& rhs) const @@ -165,14 +168,10 @@ struct matrix_t matrix_t res{}; for (size_t r_idx = 0; r_idx < rows; r_idx++) { - for (size_t c_idx = 0; c_idx < rhs_cols; c_idx++) { - zq_t tmp{}; - - for (size_t k = 0; k < cols; k++) { - tmp += (*this)[{ r_idx, k }] * rhs[{ k, c_idx }]; + for (size_t k = 0; k < cols; k++) { + for (size_t c_idx = 0; c_idx < rhs_cols; c_idx++) { + res[{ r_idx, c_idx }] += (*this)[{ r_idx, k }] * rhs[{ k, c_idx }]; } - - res[{ r_idx, c_idx }] = tmp; } } From 0036d01e00fabbd625509437167e00576381914b Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Thu, 26 Sep 2024 22:48:57 +0400 Subject: [PATCH 70/97] Improve implementation of uniform rejection sampling from ternary distribution Cache random bytes, sampled from Shake128 backed PRNG Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 75 ++++++++++---------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index 0d76e61..c062fbd 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -2,6 +2,8 @@ #include "frodoPIR/internals/rng/prng.hpp" #include "frodoPIR/internals/utility/force_inline.hpp" #include "frodoPIR/internals/utility/utils.hpp" +#include "shake128.hpp" +#include #include #include #include @@ -69,14 +71,48 @@ struct matrix_t return mat; } - // Given a seeded PRNG, this routine samples a column vector of size `rows x 1`, by rejection sampling from a uniform ternary distribution. + // Given a seeded PRNG, this routine can be used for sampling a column vector of size `rows x 1`, s.t. each value is rejection sampled from + // a uniform ternary distribution χ. Returns sampled value ∈ {-1, 0, +1}. + // + // Collects inspiration from https://github.com/brave-experiments/frodo-pir/blob/15573960/src/utils.rs#L102-L125. static forceinline constexpr matrix_t sample_from_uniform_ternary_distribution(prng::prng_t& prng) requires(cols == 1) { matrix_t mat{}; - for (size_t r_idx = 0; r_idx < rows; r_idx++) { - mat[{ r_idx, 0 }] = sample_random_ternary(prng); + constexpr size_t buffer_byte_len = (8 * shake128::RATE) / std::numeric_limits::digits; + + std::array buffer{}; + auto buffer_span = std::span(buffer); + + size_t buffer_offset = 0; + size_t r_idx = 0; + + while (r_idx < rows) { + zq_t val = std::numeric_limits::max(); + + while (val > TERNARY_REJECTION_SAMPLING_MAX) { + if ((buffer_offset + sizeof(zq_t)) > buffer_span.size()) { + const size_t remaining_num_random_bytes = buffer_span.size() - buffer_offset; + + std::copy_n(buffer_span.last(remaining_num_random_bytes).begin(), remaining_num_random_bytes, buffer_span.begin()); + prng.read(buffer_span.subspan(remaining_num_random_bytes)); + buffer_offset = 0; + } + + val = frodoPIR_utils::from_le_bytes(buffer_span.subspan(buffer_offset, sizeof(zq_t))); + buffer_offset += sizeof(zq_t); + } + + zq_t ternary = 0; + if ((val > TERNARY_INTERVAL_SIZE) && (val <= (2 * TERNARY_INTERVAL_SIZE))) { + ternary = 1; + } else if (val > (2 * TERNARY_INTERVAL_SIZE)) { + ternary = std::numeric_limits::max(); + } + + mat[{ r_idx, 0 }] = ternary; + r_idx++; } return mat; @@ -214,39 +250,6 @@ struct matrix_t private: std::vector elements; - - // Given a seeded PRNG, this routine can be used for rejection sampling a value from a uniform ternary distribution χ. - // Returns sampled value ∈ {-1, 0, +1}. - // - // Collects inspiration from https://github.com/brave-experiments/frodo-pir/blob/15573960/src/utils.rs#L102-L125. - static forceinline constexpr zq_t sample_random_ternary(prng::prng_t& prng) - { - const auto val = [&]() { - zq_t val{}; - - std::array buffer{}; - auto buffer_span = std::span(buffer); - - prng.read(buffer_span); - val = frodoPIR_utils::from_le_bytes(buffer_span); - - while (val > TERNARY_REJECTION_SAMPLING_MAX) { - prng.read(buffer_span); - val = frodoPIR_utils::from_le_bytes(buffer_span); - } - - return val; - }(); - - zq_t ternary = 0; - if ((val > TERNARY_INTERVAL_SIZE) && (val <= (2 * TERNARY_INTERVAL_SIZE))) { - ternary = 1; - } else if (val > (2 * TERNARY_INTERVAL_SIZE)) { - ternary = std::numeric_limits::max(); - } - - return ternary; - } }; } From 7810525c49c350cc23ab358ad497d605b34fe0f5 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Thu, 26 Sep 2024 23:16:08 +0400 Subject: [PATCH 71/97] Improve uniform random sampling -based matrix generation algorithm Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index c062fbd..bd10afc 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -49,23 +50,20 @@ struct matrix_t // Given a `λ` -bit seed, this routine uniform random samples a matrix of dimension `rows x cols`. template - static forceinline constexpr matrix_t generate(std::span::digits> μ) + static forceinline matrix_t generate(std::span::digits> μ) { constexpr size_t row_byte_len = cols * sizeof(zq_t); - std::vector buffer(row_byte_len, 0); - auto buffer_span = std::span(buffer); - prng::prng_t prng(μ); matrix_t mat{}; for (size_t r_idx = 0; r_idx < rows; r_idx++) { - prng.read(buffer_span); + const size_t row_begins_at = r_idx * row_byte_len; - for (size_t c_idx = 0; c_idx < cols; c_idx++) { - const size_t buffer_offset = c_idx * sizeof(zq_t); - mat[{ r_idx, c_idx }] = frodoPIR_utils::from_le_bytes(buffer_span.subspan(buffer_offset, sizeof(zq_t))); - } + auto row_begin_ptr = reinterpret_cast(mat.elements.data()) + row_begins_at; + auto row_span = std::span(row_begin_ptr, row_byte_len); + + prng.read(row_span); } return mat; From fc9c9e04c0f317236b405eca28169fce3e3f896a Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Thu, 26 Sep 2024 23:25:06 +0400 Subject: [PATCH 72/97] Get rid of redundant vector transpose operation in server respond step Signed-off-by: Anjan Roy --- include/frodoPIR/server.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/frodoPIR/server.hpp b/include/frodoPIR/server.hpp index fcb9fd0..606ffec 100644 --- a/include/frodoPIR/server.hpp +++ b/include/frodoPIR/server.hpp @@ -46,9 +46,8 @@ struct server_t std::span query_bytes, std::span response_bytes) const { - const auto b_tilda = frodoPIR_vector::column_vector_t::from_le_bytes(query_bytes); - const auto b_tilda_transposed = b_tilda.transpose(); - const auto c_tilda = b_tilda_transposed * this->D; + const auto b_tilda = frodoPIR_vector::row_vector_t::from_le_bytes(query_bytes); + const auto c_tilda = b_tilda * this->D; c_tilda.to_le_bytes(response_bytes); } From ea88c37fbb1f2ac817c781e78c61a5b972b1f091 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Thu, 26 Sep 2024 23:47:51 +0400 Subject: [PATCH 73/97] Improve serialization to(/from) little-endian bytes from(/to) a matrix Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 28 +++++++------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index bd10afc..aee08d1 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -5,6 +5,7 @@ #include "shake128.hpp" #include #include +#include #include #include #include @@ -50,6 +51,7 @@ struct matrix_t // Given a `λ` -bit seed, this routine uniform random samples a matrix of dimension `rows x cols`. template + requires(std::endian::native == std::endian::little) static forceinline matrix_t generate(std::span::digits> μ) { constexpr size_t row_byte_len = cols * sizeof(zq_t); @@ -214,34 +216,22 @@ struct matrix_t // Given a matrix M of dimension `rows x cols`, this routine can be used for serializing each of its elements as // four little-endian bytes and concatenating them in order to compute a byte array of length `rows * cols * 4`. - forceinline constexpr void to_le_bytes(std::span bytes) const + forceinline void to_le_bytes(std::span bytes) const + requires(std::endian::native == std::endian::little) { - constexpr size_t num_elements = rows * cols; - for (size_t i = 0; i < num_elements; i++) { - const size_t boff = i * sizeof(zq_t); - - const auto word = (*this)[i]; - frodoPIR_utils::to_le_bytes(word, bytes.subspan(boff, sizeof(word))); - } + auto elements_ptr = reinterpret_cast(this->elements.data()); + memcpy(bytes.data(), elements_ptr, bytes.size()); } // Given a byte array of length `rows * cols * 4`, this routine can be used for deserializing it as a matrix of dimension // `rows x cols` s.t. each matrix element is computed by interpreting four consecutive bytes in little-endian order. forceinline static matrix_t from_le_bytes(std::span bytes) + requires(std::endian::native == std::endian::little) { - constexpr size_t blen = bytes.size(); matrix_t res{}; - size_t boff = 0; - size_t lin_idx = 0; - - while (boff < blen) { - const auto word = frodoPIR_utils::from_le_bytes(bytes.subspan(boff, sizeof(zq_t))); - res[lin_idx] = word; - - boff += sizeof(word); - lin_idx += 1; - } + auto elements_ptr = reinterpret_cast(res.elements.data()); + memcpy(elements_ptr, bytes.data(), bytes.size()); return res; } From 226a3b489223181016d07cc45663ce72eb133637 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Fri, 27 Sep 2024 00:23:55 +0400 Subject: [PATCH 74/97] Parallelize outer-loop of large matrix multiplication, using std::thread Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 23 +++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index aee08d1..cfca181 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include namespace frodoPIR_matrix { @@ -199,16 +201,27 @@ struct matrix_t // https://lemire.me/blog/2024/06/13/rolling-your-own-fast-matrix-multiplication-loop-order-and-vectorization. template requires((cols == rhs_rows)) - forceinline constexpr matrix_t operator*(const matrix_t& rhs) const + forceinline matrix_t operator*(const matrix_t& rhs) const { matrix_t res{}; + std::vector threads; + threads.reserve(rows); + for (size_t r_idx = 0; r_idx < rows; r_idx++) { - for (size_t k = 0; k < cols; k++) { - for (size_t c_idx = 0; c_idx < rhs_cols; c_idx++) { - res[{ r_idx, c_idx }] += (*this)[{ r_idx, k }] * rhs[{ k, c_idx }]; + auto thread = std::thread([=, this, &rhs, &res]() { + for (size_t k = 0; k < cols; k++) { + for (size_t c_idx = 0; c_idx < rhs_cols; c_idx++) { + res[{ r_idx, c_idx }] += (*this)[{ r_idx, k }] * rhs[{ k, c_idx }]; + } } - } + }); + + threads.push_back(std::move(thread)); + } + + for (size_t r_idx = 0; r_idx < rows; r_idx++) { + threads[r_idx].join(); } return res; From 8e11fe4058c9d52d328537a1b15fe35feb146a51 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sat, 28 Sep 2024 09:14:41 +0400 Subject: [PATCH 75/97] Optimize matrix multiplication multi-threading by using h/w hinted many threads Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 46 ++++++++++++++++---- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index cfca181..7a0fb4b 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -197,22 +197,37 @@ struct matrix_t // Given two matrices A ( of dimension rows x cols ) and B ( of dimension rhs_rows x rhs_cols ) s.t. cols == rhs_rows, // this routine can be used for multiplying them over Zq, resulting into another matrix (C) of dimension rows x rhs_cols. // - // Following homebrewed matrix multiplication technique from - // https://lemire.me/blog/2024/06/13/rolling-your-own-fast-matrix-multiplication-loop-order-and-vectorization. + // Following home-brewed matrix multiplication technique from + // https://lemire.me/blog/2024/06/13/rolling-your-own-fast-matrix-multiplication-loop-order-and-vectorization, while also + // parallelizing the outer loop using std::thread API. template requires((cols == rhs_rows)) forceinline matrix_t operator*(const matrix_t& rhs) const { matrix_t res{}; + constexpr size_t min_num_threads = 1; + const size_t hw_hinted_max_num_threads = std::thread::hardware_concurrency(); + const size_t spawnable_num_threads = std::max(min_num_threads, hw_hinted_max_num_threads); + + const size_t num_rows_per_thread = rows / spawnable_num_threads; + const size_t num_rows_distributed = num_rows_per_thread * spawnable_num_threads; + const size_t remaining_num_rows = rows - num_rows_distributed; + std::vector threads; - threads.reserve(rows); + threads.reserve(spawnable_num_threads); + + // Let's first spawn N -number of threads s.t. each of them will have equal many rows to work on. + for (size_t t_idx = 0; t_idx < spawnable_num_threads; t_idx++) { + const size_t r_idx_begin = t_idx * num_rows_per_thread; + const size_t r_idx_end = r_idx_begin + num_rows_per_thread; - for (size_t r_idx = 0; r_idx < rows; r_idx++) { auto thread = std::thread([=, this, &rhs, &res]() { - for (size_t k = 0; k < cols; k++) { - for (size_t c_idx = 0; c_idx < rhs_cols; c_idx++) { - res[{ r_idx, c_idx }] += (*this)[{ r_idx, k }] * rhs[{ k, c_idx }]; + for (size_t r_idx = r_idx_begin; r_idx < r_idx_end; r_idx++) { + for (size_t k = 0; k < cols; k++) { + for (size_t c_idx = 0; c_idx < rhs_cols; c_idx++) { + res[{ r_idx, c_idx }] += (*this)[{ r_idx, k }] * rhs[{ k, c_idx }]; + } } } }); @@ -220,10 +235,23 @@ struct matrix_t threads.push_back(std::move(thread)); } - for (size_t r_idx = 0; r_idx < rows; r_idx++) { - threads[r_idx].join(); + // Finally, remaining rows, if any, are processed by "this" parent thread. + if (remaining_num_rows > 0) { + const size_t final_thread_r_idx_begin = num_rows_distributed; + const size_t final_thread_r_idx_end = final_thread_r_idx_begin + remaining_num_rows; + + for (size_t r_idx = final_thread_r_idx_begin; r_idx < final_thread_r_idx_end; r_idx++) { + for (size_t k = 0; k < cols; k++) { + for (size_t c_idx = 0; c_idx < rhs_cols; c_idx++) { + res[{ r_idx, c_idx }] += (*this)[{ r_idx, k }] * rhs[{ k, c_idx }]; + } + } + } } + // Now we wait until all of spawned threads finish their job. + std::ranges::for_each(threads, [](auto& handle) { handle.join(); }); + return res; } From 1027a95576dfa16d19e45430a3ba4060dec9373e Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sat, 28 Sep 2024 09:34:57 +0400 Subject: [PATCH 76/97] Make parsing of byte-serialized database multi-threaded Signed-off-by: Anjan Roy --- .../internals/matrix/serialization.hpp | 45 +++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/include/frodoPIR/internals/matrix/serialization.hpp b/include/frodoPIR/internals/matrix/serialization.hpp index c22bf1a..2813423 100644 --- a/include/frodoPIR/internals/matrix/serialization.hpp +++ b/include/frodoPIR/internals/matrix/serialization.hpp @@ -3,6 +3,7 @@ #include "frodoPIR/internals/matrix/vector.hpp" #include #include +#include namespace frodoPIR_serialization { @@ -10,10 +11,10 @@ namespace frodoPIR_serialization { // entry, this routines parses database into a matrix s.t. each element of matrix has at max `mat_element_bitlen` significant bits. // // Note, 0 < `mat_element_bitlen` < 32. -// Collects inspiration from https://github.com/brave-experiments/frodo-pir/blob/15573960/src/db.rs#L229-L254. +// Collects inspiration from https://github.com/brave-experiments/frodo-pir/blob/15573960/src/db.rs#L229-L254, while also making it multi-threaded. template requires(((0 < mat_element_bitlen) && (mat_element_bitlen < std::numeric_limits::digits))) -constexpr frodoPIR_matrix::matrix_t +frodoPIR_matrix::matrix_t parse_db_bytes(std::span bytes) { constexpr auto mat_element_mask = (1ul << mat_element_bitlen) - 1ul; @@ -22,7 +23,7 @@ parse_db_bytes(std::span byte frodoPIR_matrix::matrix_t mat{}; - for (size_t r_idx = 0; r_idx < rows; r_idx++) { + auto parse_db_row = [=, &bytes, &mat](const size_t r_idx) { uint64_t buffer = 0; auto buffer_span = std::span(reinterpret_cast(&buffer), sizeof(buffer)); @@ -62,8 +63,46 @@ parse_db_bytes(std::span byte if ((buf_num_bits > 0) && (c_idx < cols)) { mat[{ r_idx, c_idx }] = buffer & mat_element_mask; } + }; + + constexpr size_t min_num_threads = 1; + const size_t hw_hinted_max_num_threads = std::thread::hardware_concurrency(); + const size_t spawnable_num_threads = std::max(min_num_threads, hw_hinted_max_num_threads); + + const size_t num_rows_per_thread = rows / spawnable_num_threads; + const size_t num_rows_distributed = num_rows_per_thread * spawnable_num_threads; + const size_t remaining_num_rows = rows - num_rows_distributed; + + std::vector threads; + threads.reserve(spawnable_num_threads); + + // Let's first spawn N -number of threads s.t. each of them will have equal many database rows to parse. + for (size_t t_idx = 0; t_idx < spawnable_num_threads; t_idx++) { + const size_t r_idx_begin = t_idx * num_rows_per_thread; + const size_t r_idx_end = r_idx_begin + num_rows_per_thread; + + auto thread = std::thread([=, &bytes]() { + for (size_t r_idx = r_idx_begin; r_idx < r_idx_end; r_idx++) { + parse_db_row(r_idx); + } + }); + + threads.push_back(std::move(thread)); + } + + // Finally, remaining rows, if any, are parsed by "this" parent thread. + if (remaining_num_rows > 0) { + const size_t final_thread_r_idx_begin = num_rows_distributed; + const size_t final_thread_r_idx_end = final_thread_r_idx_begin + remaining_num_rows; + + for (size_t r_idx = final_thread_r_idx_begin; r_idx < final_thread_r_idx_end; r_idx++) { + parse_db_row(r_idx); + } } + // Now we wait until all of spawned threads finish their job. + std::ranges::for_each(threads, [](auto& handle) { handle.join(); }); + return mat; } From 5c61cf0250d4d3d487846f645843e8ae0bba7d4e Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sat, 28 Sep 2024 09:47:29 +0400 Subject: [PATCH 77/97] Make serialization of parsed database matrix multi-threaded Signed-off-by: Anjan Roy --- .../internals/matrix/serialization.hpp | 44 +++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/include/frodoPIR/internals/matrix/serialization.hpp b/include/frodoPIR/internals/matrix/serialization.hpp index 2813423..b7be05d 100644 --- a/include/frodoPIR/internals/matrix/serialization.hpp +++ b/include/frodoPIR/internals/matrix/serialization.hpp @@ -108,14 +108,14 @@ parse_db_bytes(std::span byte // Given a parsed database matrix as input s.t. each element of matrix has at max `mat_element_bitlen` significant bits, this routine serializes it // into little-endian bytes of length `db_entry_count x db_entry_byte_len`, which can be interpretted as a database having `db_entry_count` -many -// entries s.t. each of those entries are `db_entry_byte_len` -bytes. +// entries s.t. each of those entries are `db_entry_byte_len` -bytes, using multiple threads. // // M = parse_db_bytes(orig_database_bytes) // comp_database_bytes = serialize_parsed_db_matrix(M) // assert(orig_database_bytes == comp_database_bytes) template requires(((0 < mat_element_bitlen) && (mat_element_bitlen < std::numeric_limits::digits))) -constexpr void +void serialize_parsed_db_matrix( frodoPIR_matrix::matrix_t const& db_matrix, std::span bytes) @@ -125,7 +125,7 @@ serialize_parsed_db_matrix( constexpr size_t cols = frodoPIR_matrix::get_required_num_columns(db_entry_byte_len, mat_element_bitlen); constexpr size_t total_num_writable_bits_per_row = db_entry_byte_len * std::numeric_limits::digits; - for (size_t r_idx = 0; r_idx < rows; r_idx++) { + auto serialize_parsed_db_row = [=, &db_matrix, &bytes](const size_t r_idx) { uint64_t buffer = 0; auto buffer_span = std::span(reinterpret_cast(&buffer), sizeof(buffer)); @@ -153,7 +153,45 @@ serialize_parsed_db_matrix( c_idx++; byte_off += writable_num_bytes; } + }; + + constexpr size_t min_num_threads = 1; + const size_t hw_hinted_max_num_threads = std::thread::hardware_concurrency(); + const size_t spawnable_num_threads = std::max(min_num_threads, hw_hinted_max_num_threads); + + const size_t num_rows_per_thread = rows / spawnable_num_threads; + const size_t num_rows_distributed = num_rows_per_thread * spawnable_num_threads; + const size_t remaining_num_rows = rows - num_rows_distributed; + + std::vector threads; + threads.reserve(spawnable_num_threads); + + // Let's first spawn N -number of threads s.t. each of them will have equal many database rows to serialize. + for (size_t t_idx = 0; t_idx < spawnable_num_threads; t_idx++) { + const size_t r_idx_begin = t_idx * num_rows_per_thread; + const size_t r_idx_end = r_idx_begin + num_rows_per_thread; + + auto thread = std::thread([=, &bytes]() { + for (size_t r_idx = r_idx_begin; r_idx < r_idx_end; r_idx++) { + serialize_parsed_db_row(r_idx); + } + }); + + threads.push_back(std::move(thread)); } + + // Finally, remaining rows, if any, are serialized by "this" parent thread. + if (remaining_num_rows > 0) { + const size_t final_thread_r_idx_begin = num_rows_distributed; + const size_t final_thread_r_idx_end = final_thread_r_idx_begin + remaining_num_rows; + + for (size_t r_idx = final_thread_r_idx_begin; r_idx < final_thread_r_idx_end; r_idx++) { + serialize_parsed_db_row(r_idx); + } + } + + // Now we wait until all of spawned threads finish their job. + std::ranges::for_each(threads, [](auto& handle) { handle.join(); }); } // Given a row of parsed database s.t. each coefficient of input vector has at max `mat_element_bitlen` -many significant bits, From 73244355716873606a9829eac0b08f43e5dd6944 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sat, 28 Sep 2024 09:56:03 +0400 Subject: [PATCH 78/97] Make addition of two matrices multi-threaded Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 43 ++++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index 7a0fb4b..c347dec 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -182,15 +182,50 @@ struct matrix_t } // Given two matrices A, B of equal dimension, this routine can be used for performing matrix addition over Zq, - // returning a matrix of same dimension. - forceinline constexpr matrix_t operator+(const matrix_t& rhs) const + // returning a matrix of same dimension, using multiple threads. + forceinline matrix_t operator+(const matrix_t& rhs) const { matrix_t res{}; - for (size_t i = 0; i < rows * cols; i++) { - res[i] = (*this)[i] + rhs[i]; + constexpr size_t min_num_threads = 1; + const size_t hw_hinted_max_num_threads = std::thread::hardware_concurrency(); + const size_t spawnable_num_threads = std::max(min_num_threads, hw_hinted_max_num_threads); + + const size_t total_num_elements = rows * cols; + const size_t num_elements_per_thread = total_num_elements / spawnable_num_threads; + const size_t num_elements_distributed = num_elements_per_thread * spawnable_num_threads; + const size_t remaining_num_elements = total_num_elements - num_elements_distributed; + + std::vector threads; + threads.reserve(spawnable_num_threads); + + // Let's first spawn N -number of threads s.t. each of them will have equal many rows to work on. + for (size_t t_idx = 0; t_idx < spawnable_num_threads; t_idx++) { + const size_t e_idx_begin = t_idx * num_elements_per_thread; + const size_t e_idx_end = e_idx_begin + num_elements_per_thread; + + auto thread = std::thread([=, this, &rhs, &res]() { + for (size_t e_idx = e_idx_begin; e_idx < e_idx_end; e_idx++) { + res[e_idx] = (*this)[e_idx] + rhs[e_idx]; + } + }); + + threads.push_back(std::move(thread)); + } + + // Finally, remaining rows, if any, are processed by "this" parent thread. + if (remaining_num_elements > 0) { + const size_t final_thread_e_idx_begin = num_elements_distributed; + const size_t final_thread_e_idx_end = final_thread_e_idx_begin + remaining_num_elements; + + for (size_t e_idx = final_thread_e_idx_begin; e_idx < final_thread_e_idx_end; e_idx++) { + res[e_idx] = (*this)[e_idx] + rhs[e_idx]; + } } + // Now we wait until all of spawned threads finish their job. + std::ranges::for_each(threads, [](auto& handle) { handle.join(); }); + return res; } From 6105616fab29eb0fa922a6832896fe0c4f77869a Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sat, 28 Sep 2024 20:27:18 +0400 Subject: [PATCH 79/97] Run address santinizer with leak sanitizer check Signed-off-by: Anjan Roy --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 8ef5447..15922fa 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ WARN_FLAGS := -Wall -Wextra -Wpedantic DEBUG_FLAGS := -O1 -g RELEASE_FLAGS := -O3 -march=native LINK_OPT_FLAGS := -flto -ASAN_FLAGS := -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address # From https://clang.llvm.org/docs/AddressSanitizer.html +ASAN_FLAGS := -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address # From https://clang.llvm.org/docs/AddressSanitizer.html and https://clang.llvm.org/docs/LeakSanitizer.html DEBUG_ASAN_FLAGS := $(DEBUG_FLAGS) $(ASAN_FLAGS) RELEASE_ASAN_FLAGS := -g $(RELEASE_FLAGS) $(ASAN_FLAGS) UBSAN_FLAGS := -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=undefined # From https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html @@ -114,10 +114,10 @@ test: $(TEST_BINARY) $(GTEST_PARALLEL) $(GTEST_PARALLEL) $< --print_test_times --serialize_test_cases debug_asan_test: $(DEBUG_ASAN_TEST_BINARY) $(GTEST_PARALLEL) - $(GTEST_PARALLEL) $< --print_test_times --serialize_test_cases + ASAN_OPTIONS=detect_leaks=1 $(GTEST_PARALLEL) $< --print_test_times --serialize_test_cases release_asan_test: $(RELEASE_ASAN_TEST_BINARY) $(GTEST_PARALLEL) - $(GTEST_PARALLEL) $< --print_test_times --serialize_test_cases + ASAN_OPTIONS=detect_leaks=1 $(GTEST_PARALLEL) $< --print_test_times --serialize_test_cases debug_ubsan_test: $(DEBUG_UBSAN_TEST_BINARY) $(GTEST_PARALLEL) $(GTEST_PARALLEL) $< --print_test_times --serialize_test_cases From 62d13f39dcdd5386131c61a82f853061ec069d7f Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sat, 28 Sep 2024 20:59:43 +0400 Subject: [PATCH 80/97] Refactor sampling from uniform ternary distribution such that it can produce either row or column vector Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index c347dec..2e3d6f2 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -73,24 +73,25 @@ struct matrix_t return mat; } - // Given a seeded PRNG, this routine can be used for sampling a column vector of size `rows x 1`, s.t. each value is rejection sampled from + // Given a seeded PRNG, this routine can be used for sampling a row/ column vector, s.t. each value is rejection sampled from // a uniform ternary distribution χ. Returns sampled value ∈ {-1, 0, +1}. // // Collects inspiration from https://github.com/brave-experiments/frodo-pir/blob/15573960/src/utils.rs#L102-L125. static forceinline constexpr matrix_t sample_from_uniform_ternary_distribution(prng::prng_t& prng) - requires(cols == 1) + requires((rows == 1) || (cols == 1)) { matrix_t mat{}; constexpr size_t buffer_byte_len = (8 * shake128::RATE) / std::numeric_limits::digits; + constexpr size_t total_num_elements = rows * cols; std::array buffer{}; auto buffer_span = std::span(buffer); size_t buffer_offset = 0; - size_t r_idx = 0; + size_t e_idx = 0; - while (r_idx < rows) { + while (e_idx < total_num_elements) { zq_t val = std::numeric_limits::max(); while (val > TERNARY_REJECTION_SAMPLING_MAX) { @@ -113,8 +114,8 @@ struct matrix_t ternary = std::numeric_limits::max(); } - mat[{ r_idx, 0 }] = ternary; - r_idx++; + mat[e_idx] = ternary; + e_idx++; } return mat; From 20c7314a9a5210651d8206ca9b004af7f4bf8b61 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sat, 28 Sep 2024 21:01:14 +0400 Subject: [PATCH 81/97] Update prepare query step of client, to get rid of redundant matrix transpose operations Signed-off-by: Anjan Roy --- include/frodoPIR/client.hpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/include/frodoPIR/client.hpp b/include/frodoPIR/client.hpp index 84ec32e..05a20e6 100644 --- a/include/frodoPIR/client.hpp +++ b/include/frodoPIR/client.hpp @@ -88,12 +88,11 @@ struct client_t return false; } - const auto s = frodoPIR_vector::column_vector_t::sample_from_uniform_ternary_distribution(prng); // secret vector - const auto e = frodoPIR_vector::column_vector_t::sample_from_uniform_ternary_distribution(prng); // error vector + const auto s = frodoPIR_vector::row_vector_t::sample_from_uniform_ternary_distribution(prng); // secret vector + const auto e = frodoPIR_vector::row_vector_t::sample_from_uniform_ternary_distribution(prng); // error vector - const auto s_transposed = s.transpose(); - const auto b = s_transposed * this->A + e.transpose(); - const auto c = s_transposed * this->M; + const auto b = s * this->A + e; + const auto c = s * this->M; this->queries[db_row_index] = client_query_t{ .status = query_status_t::prepared, From a94f41c4bde881b4ec018f7876a5220eab956c6b Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sat, 28 Sep 2024 21:52:38 +0400 Subject: [PATCH 82/97] Update benchmark running configuration Running running time and repetition count Signed-off-by: Anjan Roy --- Makefile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 15922fa..2d993fd 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ LINK_OPT_FLAGS := -flto ASAN_FLAGS := -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address # From https://clang.llvm.org/docs/AddressSanitizer.html and https://clang.llvm.org/docs/LeakSanitizer.html DEBUG_ASAN_FLAGS := $(DEBUG_FLAGS) $(ASAN_FLAGS) RELEASE_ASAN_FLAGS := -g $(RELEASE_FLAGS) $(ASAN_FLAGS) +ASAN_RUNTIME_FLAGS := ASAN_OPTIONS=detect_leaks=1 UBSAN_FLAGS := -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=undefined # From https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html DEBUG_UBSAN_FLAGS := $(DEBUG_FLAGS) $(UBSAN_FLAGS) RELEASE_UBSAN_FLAGS := -g $(RELEASE_FLAGS) $(UBSAN_FLAGS) @@ -114,10 +115,10 @@ test: $(TEST_BINARY) $(GTEST_PARALLEL) $(GTEST_PARALLEL) $< --print_test_times --serialize_test_cases debug_asan_test: $(DEBUG_ASAN_TEST_BINARY) $(GTEST_PARALLEL) - ASAN_OPTIONS=detect_leaks=1 $(GTEST_PARALLEL) $< --print_test_times --serialize_test_cases + $(ASAN_RUNTIME_FLAGS) $(GTEST_PARALLEL) $< --print_test_times --serialize_test_cases release_asan_test: $(RELEASE_ASAN_TEST_BINARY) $(GTEST_PARALLEL) - ASAN_OPTIONS=detect_leaks=1 $(GTEST_PARALLEL) $< --print_test_times --serialize_test_cases + $(ASAN_RUNTIME_FLAGS) $(GTEST_PARALLEL) $< --print_test_times --serialize_test_cases debug_ubsan_test: $(DEBUG_UBSAN_TEST_BINARY) $(GTEST_PARALLEL) $(GTEST_PARALLEL) $< --print_test_times --serialize_test_cases @@ -133,14 +134,14 @@ $(BENCHMARK_BINARY): $(BENCHMARK_OBJECTS) benchmark: $(BENCHMARK_BINARY) # Must *not* build google-benchmark with libPFM - ./$< --benchmark_time_unit=s --benchmark_min_warmup_time=1 --benchmark_enable_random_interleaving=true --benchmark_repetitions=16 --benchmark_min_time=5s --benchmark_display_aggregates_only=true --benchmark_report_aggregates_only=true --benchmark_counters_tabular=true --benchmark_out_format=json --benchmark_out=$(BENCHMARK_OUT_FILE) + ./$< --benchmark_time_unit=ms --benchmark_min_warmup_time=.5 --benchmark_enable_random_interleaving=true --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) # Must build google-benchmark with libPFM, follow https://gist.github.com/itzmeanjan/05dc3e946f635d00c5e0b21aae6203a7 - ./$< --benchmark_time_unit=s --benchmark_min_warmup_time=1 --benchmark_enable_random_interleaving=true --benchmark_repetitions=16 --benchmark_min_time=5s --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) + ./$< --benchmark_time_unit=ms --benchmark_min_warmup_time=.5 --benchmark_enable_random_interleaving=true --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) .PHONY: format clean From 1aad837b43a356381b7ff2f62a54b60415056d7b Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sat, 28 Sep 2024 21:57:35 +0400 Subject: [PATCH 83/97] Make matrix multiplication use multiple-threads in more flexible way Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 76 ++++++++++++++------ 1 file changed, 56 insertions(+), 20 deletions(-) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index 2e3d6f2..3f0ee01 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -246,40 +246,76 @@ struct matrix_t const size_t hw_hinted_max_num_threads = std::thread::hardware_concurrency(); const size_t spawnable_num_threads = std::max(min_num_threads, hw_hinted_max_num_threads); - const size_t num_rows_per_thread = rows / spawnable_num_threads; - const size_t num_rows_distributed = num_rows_per_thread * spawnable_num_threads; - const size_t remaining_num_rows = rows - num_rows_distributed; + // Distribute work either row-wise or column-wise, based on which one has more work. + constexpr size_t distributable_work_count = std::max(rows, rhs_cols); + constexpr bool if_distribute_across_row = rows >= rhs_cols; + + const size_t num_work_per_thread = distributable_work_count / spawnable_num_threads; + const size_t num_work_distributed = num_work_per_thread * spawnable_num_threads; + const size_t remaining_num_work = distributable_work_count - num_work_distributed; std::vector threads; threads.reserve(spawnable_num_threads); // Let's first spawn N -number of threads s.t. each of them will have equal many rows to work on. for (size_t t_idx = 0; t_idx < spawnable_num_threads; t_idx++) { - const size_t r_idx_begin = t_idx * num_rows_per_thread; - const size_t r_idx_end = r_idx_begin + num_rows_per_thread; + if constexpr (if_distribute_across_row) { + // If there are more (or equal many) rows than columns, it's better to distribute computation of rows. + const size_t r_idx_begin = t_idx * num_work_per_thread; + const size_t r_idx_end = r_idx_begin + num_work_per_thread; + + auto thread = std::thread([=, this, &rhs, &res]() { + for (size_t r_idx = r_idx_begin; r_idx < r_idx_end; r_idx++) { + for (size_t k = 0; k < cols; k++) { + for (size_t c_idx = 0; c_idx < rhs_cols; c_idx++) { + res[{ r_idx, c_idx }] += (*this)[{ r_idx, k }] * rhs[{ k, c_idx }]; + } + } + } + }); + + threads.push_back(std::move(thread)); + } else { + // If there are more columns, it's better to distribute computation of columns across threads. + const size_t c_idx_begin = t_idx * num_work_per_thread; + const size_t c_idx_end = c_idx_begin + num_work_per_thread; + + auto thread = std::thread([=, this, &rhs, &res]() { + for (size_t r_idx = 0; r_idx < rows; r_idx++) { + for (size_t k = 0; k < cols; k++) { + for (size_t c_idx = c_idx_begin; c_idx < c_idx_end; c_idx++) { + res[{ r_idx, c_idx }] += (*this)[{ r_idx, k }] * rhs[{ k, c_idx }]; + } + } + } + }); - auto thread = std::thread([=, this, &rhs, &res]() { - for (size_t r_idx = r_idx_begin; r_idx < r_idx_end; r_idx++) { + threads.push_back(std::move(thread)); + } + } + + // Finally, remaining rows, if any, are processed by "this" parent thread. + if (remaining_num_work > 0) { + if constexpr (if_distribute_across_row) { + const size_t final_thread_r_idx_begin = num_work_distributed; + const size_t final_thread_r_idx_end = final_thread_r_idx_begin + remaining_num_work; + + for (size_t r_idx = final_thread_r_idx_begin; r_idx < final_thread_r_idx_end; r_idx++) { for (size_t k = 0; k < cols; k++) { for (size_t c_idx = 0; c_idx < rhs_cols; c_idx++) { res[{ r_idx, c_idx }] += (*this)[{ r_idx, k }] * rhs[{ k, c_idx }]; } } } - }); - - threads.push_back(std::move(thread)); - } + } else { + const size_t final_thread_c_idx_begin = num_work_distributed; + const size_t final_thread_c_idx_end = final_thread_c_idx_begin + remaining_num_work; - // Finally, remaining rows, if any, are processed by "this" parent thread. - if (remaining_num_rows > 0) { - const size_t final_thread_r_idx_begin = num_rows_distributed; - const size_t final_thread_r_idx_end = final_thread_r_idx_begin + remaining_num_rows; - - for (size_t r_idx = final_thread_r_idx_begin; r_idx < final_thread_r_idx_end; r_idx++) { - for (size_t k = 0; k < cols; k++) { - for (size_t c_idx = 0; c_idx < rhs_cols; c_idx++) { - res[{ r_idx, c_idx }] += (*this)[{ r_idx, k }] * rhs[{ k, c_idx }]; + for (size_t r_idx = 0; r_idx < rows; r_idx++) { + for (size_t k = 0; k < cols; k++) { + for (size_t c_idx = final_thread_c_idx_begin; c_idx < final_thread_c_idx_end; c_idx++) { + res[{ r_idx, c_idx }] += (*this)[{ r_idx, k }] * rhs[{ k, c_idx }]; + } } } } From 7020cc34fd4b7079e1d2565e8634a73509832422 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sat, 28 Sep 2024 22:21:26 +0400 Subject: [PATCH 84/97] Don't run ASAN with leak sanitizer It's not supported on macos target available on github actions CI Signed-off-by: Anjan Roy --- Makefile | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 2d993fd..7e096ec 100644 --- a/Makefile +++ b/Makefile @@ -5,10 +5,9 @@ WARN_FLAGS := -Wall -Wextra -Wpedantic DEBUG_FLAGS := -O1 -g RELEASE_FLAGS := -O3 -march=native LINK_OPT_FLAGS := -flto -ASAN_FLAGS := -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address # From https://clang.llvm.org/docs/AddressSanitizer.html and https://clang.llvm.org/docs/LeakSanitizer.html +ASAN_FLAGS := -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address # From https://clang.llvm.org/docs/AddressSanitizer.html DEBUG_ASAN_FLAGS := $(DEBUG_FLAGS) $(ASAN_FLAGS) RELEASE_ASAN_FLAGS := -g $(RELEASE_FLAGS) $(ASAN_FLAGS) -ASAN_RUNTIME_FLAGS := ASAN_OPTIONS=detect_leaks=1 UBSAN_FLAGS := -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=undefined # From https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html DEBUG_UBSAN_FLAGS := $(DEBUG_FLAGS) $(UBSAN_FLAGS) RELEASE_UBSAN_FLAGS := -g $(RELEASE_FLAGS) $(UBSAN_FLAGS) @@ -115,10 +114,10 @@ test: $(TEST_BINARY) $(GTEST_PARALLEL) $(GTEST_PARALLEL) $< --print_test_times --serialize_test_cases debug_asan_test: $(DEBUG_ASAN_TEST_BINARY) $(GTEST_PARALLEL) - $(ASAN_RUNTIME_FLAGS) $(GTEST_PARALLEL) $< --print_test_times --serialize_test_cases + $(GTEST_PARALLEL) $< --print_test_times --serialize_test_cases release_asan_test: $(RELEASE_ASAN_TEST_BINARY) $(GTEST_PARALLEL) - $(ASAN_RUNTIME_FLAGS) $(GTEST_PARALLEL) $< --print_test_times --serialize_test_cases + $(GTEST_PARALLEL) $< --print_test_times --serialize_test_cases debug_ubsan_test: $(DEBUG_UBSAN_TEST_BINARY) $(GTEST_PARALLEL) $(GTEST_PARALLEL) $< --print_test_times --serialize_test_cases From c3d7d360ecc4d186ed4ec4c007acba465fb92607 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sat, 28 Sep 2024 23:40:50 +0400 Subject: [PATCH 85/97] Correctly use "DoNotOptimize" trap Signed-off-by: Anjan Roy --- benches/bench_client_process_response.cpp | 1 + benches/bench_client_query.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/benches/bench_client_process_response.cpp b/benches/bench_client_process_response.cpp index 785e770..375bd42 100644 --- a/benches/bench_client_process_response.cpp +++ b/benches/bench_client_process_response.cpp @@ -55,6 +55,7 @@ bench_client_process_response(benchmark::State& state) for (auto _ : state) { is_response_decoded &= client.process_response(rand_db_row_index, response_bytes_span, db_row_bytes_span); + benchmark::DoNotOptimize(is_response_decoded); benchmark::DoNotOptimize(client); benchmark::DoNotOptimize(rand_db_row_index); benchmark::DoNotOptimize(response_bytes_span); diff --git a/benches/bench_client_query.cpp b/benches/bench_client_query.cpp index ae41407..81ec3ba 100644 --- a/benches/bench_client_query.cpp +++ b/benches/bench_client_query.cpp @@ -56,6 +56,7 @@ bench_client_query(benchmark::State& state) benchmark::DoNotOptimize(is_query_ready); benchmark::DoNotOptimize(client); + benchmark::DoNotOptimize(rand_db_row_index); benchmark::DoNotOptimize(query_bytes_span); benchmark::ClobberMemory(); From 8958741cc77cf8cfc2c5d309846328f999a0a534 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sun, 29 Sep 2024 00:19:18 +0400 Subject: [PATCH 86/97] Add new test ensuring functional correctness of client cache state transition Signed-off-by: Anjan Roy --- tests/test_frodoPIR.cpp | 86 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/tests/test_frodoPIR.cpp b/tests/test_frodoPIR.cpp index f572a1c..71a551f 100644 --- a/tests/test_frodoPIR.cpp +++ b/tests/test_frodoPIR.cpp @@ -74,3 +74,89 @@ TEST(FrodoPIR, PrivateInformationRetrieval) test_private_information_retrieval<1ul << 16, 32, 10, 1774>(32); test_private_information_retrieval<1ul << 20, 32, 9, 1774>(32); } + +TEST(FrodoPIR, ClientQueryCacheStateTransition) +{ + constexpr size_t λ = 128; + constexpr size_t db_entry_count = 1ul << 16; + constexpr size_t db_entry_byte_len = 32; + constexpr size_t mat_element_bitlen = 10; + constexpr size_t lwe_dimension = 1774; + constexpr size_t parsed_db_column_count = frodoPIR_matrix::get_required_num_columns(db_entry_byte_len, mat_element_bitlen); + constexpr size_t db_byte_len = db_entry_count * db_entry_byte_len; + constexpr size_t pub_matM_byte_len = frodoPIR_matrix::matrix_t::get_byte_len(); + constexpr size_t query_byte_len = frodoPIR_vector::row_vector_t::get_byte_len(); + constexpr size_t response_byte_len = frodoPIR_vector::row_vector_t::get_byte_len(); + + std::array::digits> seed_μ{}; + std::vector db_bytes(db_byte_len, 0); + std::vector pub_matM_bytes(pub_matM_byte_len, 0); + std::vector query_bytes(query_byte_len, 0); + std::vector response_bytes(response_byte_len, 0); + std::vector db_row_bytes(db_entry_byte_len, 0); + + auto db_bytes_span = std::span(db_bytes); + auto pub_matM_bytes_span = std::span(pub_matM_bytes); + auto query_bytes_span = std::span(query_bytes); + auto response_bytes_span = std::span(response_bytes); + auto db_row_bytes_span = std::span(db_row_bytes); + + prng::prng_t prng{}; + + prng.read(seed_μ); + prng.read(db_bytes); + + auto [server, M] = frodoPIR_server::server_t<λ, db_entry_count, db_entry_byte_len, mat_element_bitlen, lwe_dimension>::setup(seed_μ, db_bytes_span); + + M.to_le_bytes(pub_matM_bytes_span); + auto client = frodoPIR_client::client_t<λ, db_entry_count, db_entry_byte_len, mat_element_bitlen, lwe_dimension>::setup(seed_μ, pub_matM_bytes_span); + + constexpr size_t db_first_row_index = 0; + constexpr size_t db_second_row_index = db_first_row_index + 1; + + // Before query for specific database row is prepared, attempt to use the query or decode response for the query. + EXPECT_FALSE(client.query(db_first_row_index, query_bytes_span)); + EXPECT_FALSE(client.query(db_second_row_index, query_bytes_span)); + EXPECT_FALSE(client.process_response(db_first_row_index, response_bytes_span, db_row_bytes_span)); + EXPECT_FALSE(client.process_response(db_second_row_index, response_bytes_span, db_row_bytes_span)); + + // Prepare query for a specific database row. + EXPECT_TRUE(client.prepare_query(db_first_row_index, prng)); + // Retry preparing query for the same database row. + EXPECT_FALSE(client.prepare_query(db_first_row_index, prng)); + + // Prepare query for a different database row. + EXPECT_TRUE(client.prepare_query(db_second_row_index, prng)); + // Retry preparing query for same database row. + EXPECT_FALSE(client.prepare_query(db_second_row_index, prng)); + + // Attempt processing response for specific database row even though query for that row is not yet sent. + EXPECT_FALSE(client.process_response(db_first_row_index, response_bytes_span, db_row_bytes_span)); + EXPECT_FALSE(client.process_response(db_second_row_index, response_bytes_span, db_row_bytes_span)); + + // Finalize query for specific database row. + EXPECT_TRUE(client.query(db_first_row_index, query_bytes_span)); + // Retry finalizing query for same database row. + EXPECT_FALSE(client.query(db_first_row_index, query_bytes_span)); + + // Finalize query for different database row. + EXPECT_TRUE(client.query(db_second_row_index, query_bytes_span)); + // Retry finalizing query for same database row. + EXPECT_FALSE(client.query(db_second_row_index, query_bytes_span)); + + // Ask server to respond for finalized query. + server.respond(query_bytes_span, response_bytes_span); + + // Process response obtained from server, decoding database row. + EXPECT_TRUE(client.process_response(db_first_row_index, response_bytes_span, db_row_bytes_span)); + // Retry processing response obtained from server, attempting to decode same database row. + EXPECT_FALSE(client.process_response(db_first_row_index, response_bytes_span, db_row_bytes_span)); + + // Process response obtained from server, decoding database row. + EXPECT_TRUE(client.process_response(db_second_row_index, response_bytes_span, db_row_bytes_span)); + // Retry processing response obtained from server, attempting to decode same database row. + EXPECT_FALSE(client.process_response(db_second_row_index, response_bytes_span, db_row_bytes_span)); + + constexpr size_t db_second_row_bytes_begin_at = db_second_row_index * db_entry_byte_len; + EXPECT_TRUE(std::ranges::equal(db_row_bytes_span, db_bytes_span.subspan(db_second_row_bytes_begin_at, db_entry_byte_len))); +} From a5b602d1d3346c640c18c08a2c5c5022830337da Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sun, 29 Sep 2024 06:58:42 +0400 Subject: [PATCH 87/97] Use a combination of total time spent by all process threads and wallclock time for benchmark measurements Signed-off-by: Anjan Roy --- benches/bench_client_prepare_query.cpp | 20 +++++++++++++++----- benches/bench_client_process_response.cpp | 20 +++++++++++++++----- benches/bench_client_query.cpp | 20 +++++++++++++++----- benches/bench_server_respond.cpp | 20 +++++++++++++++----- benches/bench_server_setup.cpp | 20 +++++++++++++++----- 5 files changed, 75 insertions(+), 25 deletions(-) diff --git a/benches/bench_client_prepare_query.cpp b/benches/bench_client_prepare_query.cpp index 8ebc1bd..9b8e5d1 100644 --- a/benches/bench_client_prepare_query.cpp +++ b/benches/bench_client_prepare_query.cpp @@ -80,24 +80,34 @@ bench_client_prepare_query(benchmark::State& state) BENCHMARK(bench_client_prepare_query<128, 1ul << 16, 256, 10, 1774>) ->Name("frodoPIR/client_prepare_query/2^16/256B") ->ComputeStatistics("min", compute_min) - ->ComputeStatistics("max", compute_max); + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime(); BENCHMARK(bench_client_prepare_query<128, 1ul << 17, 256, 10, 1774>) ->Name("frodoPIR/client_prepare_query/2^17/256B") ->ComputeStatistics("min", compute_min) - ->ComputeStatistics("max", compute_max); + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime(); BENCHMARK(bench_client_prepare_query<128, 1ul << 18, 256, 10, 1774>) ->Name("frodoPIR/client_prepare_query/2^18/256B") ->ComputeStatistics("min", compute_min) - ->ComputeStatistics("max", compute_max); + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime(); BENCHMARK(bench_client_prepare_query<128, 1ul << 19, 256, 9, 1774>) ->Name("frodoPIR/client_prepare_query/2^19/256B") ->ComputeStatistics("min", compute_min) - ->ComputeStatistics("max", compute_max); + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime(); BENCHMARK(bench_client_prepare_query<128, 1ul << 20, 256, 9, 1774>) ->Name("frodoPIR/client_prepare_query/2^20/256B") ->ComputeStatistics("min", compute_min) - ->ComputeStatistics("max", compute_max); + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime(); diff --git a/benches/bench_client_process_response.cpp b/benches/bench_client_process_response.cpp index 375bd42..d243867 100644 --- a/benches/bench_client_process_response.cpp +++ b/benches/bench_client_process_response.cpp @@ -82,24 +82,34 @@ bench_client_process_response(benchmark::State& state) BENCHMARK(bench_client_process_response<128, 1ul << 16, 256, 10, 1774>) ->Name("frodoPIR/client_process_response/2^16/256B") ->ComputeStatistics("min", compute_min) - ->ComputeStatistics("max", compute_max); + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime(); BENCHMARK(bench_client_process_response<128, 1ul << 17, 256, 10, 1774>) ->Name("frodoPIR/client_process_response/2^17/256B") ->ComputeStatistics("min", compute_min) - ->ComputeStatistics("max", compute_max); + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime(); BENCHMARK(bench_client_process_response<128, 1ul << 18, 256, 10, 1774>) ->Name("frodoPIR/client_process_response/2^18/256B") ->ComputeStatistics("min", compute_min) - ->ComputeStatistics("max", compute_max); + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime(); BENCHMARK(bench_client_process_response<128, 1ul << 19, 256, 9, 1774>) ->Name("frodoPIR/client_process_response/2^19/256B") ->ComputeStatistics("min", compute_min) - ->ComputeStatistics("max", compute_max); + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime(); BENCHMARK(bench_client_process_response<128, 1ul << 20, 256, 9, 1774>) ->Name("frodoPIR/client_process_response/2^20/256B") ->ComputeStatistics("min", compute_min) - ->ComputeStatistics("max", compute_max); + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime(); diff --git a/benches/bench_client_query.cpp b/benches/bench_client_query.cpp index 81ec3ba..64ddb93 100644 --- a/benches/bench_client_query.cpp +++ b/benches/bench_client_query.cpp @@ -81,24 +81,34 @@ bench_client_query(benchmark::State& state) BENCHMARK(bench_client_query<128, 1ul << 16, 256, 10, 1774>) ->Name("frodoPIR/client_query/2^16/256B") ->ComputeStatistics("min", compute_min) - ->ComputeStatistics("max", compute_max); + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime(); BENCHMARK(bench_client_query<128, 1ul << 17, 256, 10, 1774>) ->Name("frodoPIR/client_query/2^17/256B") ->ComputeStatistics("min", compute_min) - ->ComputeStatistics("max", compute_max); + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime(); BENCHMARK(bench_client_query<128, 1ul << 18, 256, 10, 1774>) ->Name("frodoPIR/client_query/2^18/256B") ->ComputeStatistics("min", compute_min) - ->ComputeStatistics("max", compute_max); + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime(); BENCHMARK(bench_client_query<128, 1ul << 19, 256, 9, 1774>) ->Name("frodoPIR/client_query/2^19/256B") ->ComputeStatistics("min", compute_min) - ->ComputeStatistics("max", compute_max); + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime(); BENCHMARK(bench_client_query<128, 1ul << 20, 256, 9, 1774>) ->Name("frodoPIR/client_query/2^20/256B") ->ComputeStatistics("min", compute_min) - ->ComputeStatistics("max", compute_max); + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime(); diff --git a/benches/bench_server_respond.cpp b/benches/bench_server_respond.cpp index 161e4c1..d0d052f 100644 --- a/benches/bench_server_respond.cpp +++ b/benches/bench_server_respond.cpp @@ -66,24 +66,34 @@ bench_server_respond(benchmark::State& state) BENCHMARK(bench_server_respond<128, 1ul << 16, 256, 10, 1774>) ->Name("frodoPIR/server_respond/2^16/256B") ->ComputeStatistics("min", compute_min) - ->ComputeStatistics("max", compute_max); + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime(); BENCHMARK(bench_server_respond<128, 1ul << 17, 256, 10, 1774>) ->Name("frodoPIR/server_respond/2^17/256B") ->ComputeStatistics("min", compute_min) - ->ComputeStatistics("max", compute_max); + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime(); BENCHMARK(bench_server_respond<128, 1ul << 18, 256, 10, 1774>) ->Name("frodoPIR/server_respond/2^18/256B") ->ComputeStatistics("min", compute_min) - ->ComputeStatistics("max", compute_max); + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime(); BENCHMARK(bench_server_respond<128, 1ul << 19, 256, 9, 1774>) ->Name("frodoPIR/server_respond/2^19/256B") ->ComputeStatistics("min", compute_min) - ->ComputeStatistics("max", compute_max); + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime(); BENCHMARK(bench_server_respond<128, 1ul << 20, 256, 9, 1774>) ->Name("frodoPIR/server_respond/2^20/256B") ->ComputeStatistics("min", compute_min) - ->ComputeStatistics("max", compute_max); + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime(); diff --git a/benches/bench_server_setup.cpp b/benches/bench_server_setup.cpp index 7493fb9..87cfd2a 100644 --- a/benches/bench_server_setup.cpp +++ b/benches/bench_server_setup.cpp @@ -35,24 +35,34 @@ bench_server_setup(benchmark::State& state) BENCHMARK(bench_server_setup<128, 1ul << 16, 256, 10, 1774>) ->Name("frodoPIR/server_setup/2^16/256B") ->ComputeStatistics("min", compute_min) - ->ComputeStatistics("max", compute_max); + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime(); BENCHMARK(bench_server_setup<128, 1ul << 17, 256, 10, 1774>) ->Name("frodoPIR/server_setup/2^17/256B") ->ComputeStatistics("min", compute_min) - ->ComputeStatistics("max", compute_max); + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime(); BENCHMARK(bench_server_setup<128, 1ul << 18, 256, 10, 1774>) ->Name("frodoPIR/server_setup/2^18/256B") ->ComputeStatistics("min", compute_min) - ->ComputeStatistics("max", compute_max); + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime(); BENCHMARK(bench_server_setup<128, 1ul << 19, 256, 9, 1774>) ->Name("frodoPIR/server_setup/2^19/256B") ->ComputeStatistics("min", compute_min) - ->ComputeStatistics("max", compute_max); + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime(); BENCHMARK(bench_server_setup<128, 1ul << 20, 256, 9, 1774>) ->Name("frodoPIR/server_setup/2^20/256B") ->ComputeStatistics("min", compute_min) - ->ComputeStatistics("max", compute_max); + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime(); From 334c2d9c67da7aade6c4756d9c751c5727bbe904 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sun, 29 Sep 2024 12:17:02 +0400 Subject: [PATCH 88/97] Hardcode which time unit to use for reporting benchmark results Signed-off-by: Anjan Roy --- Makefile | 4 ++-- benches/bench_client_prepare_query.cpp | 15 ++++++++++----- benches/bench_client_process_response.cpp | 15 ++++++++++----- benches/bench_client_query.cpp | 15 ++++++++++----- benches/bench_server_respond.cpp | 15 ++++++++++----- benches/bench_server_setup.cpp | 15 ++++++++++----- 6 files changed, 52 insertions(+), 27 deletions(-) diff --git a/Makefile b/Makefile index 7e096ec..3f6d0d5 100644 --- a/Makefile +++ b/Makefile @@ -133,14 +133,14 @@ $(BENCHMARK_BINARY): $(BENCHMARK_OBJECTS) benchmark: $(BENCHMARK_BINARY) # Must *not* build google-benchmark with libPFM - ./$< --benchmark_time_unit=ms --benchmark_min_warmup_time=.5 --benchmark_enable_random_interleaving=true --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) + ./$< --benchmark_min_warmup_time=.5 --benchmark_enable_random_interleaving=true --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) # Must build google-benchmark with libPFM, follow https://gist.github.com/itzmeanjan/05dc3e946f635d00c5e0b21aae6203a7 - ./$< --benchmark_time_unit=ms --benchmark_min_warmup_time=.5 --benchmark_enable_random_interleaving=true --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) + ./$< --benchmark_min_warmup_time=.5 --benchmark_enable_random_interleaving=true --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) .PHONY: format clean diff --git a/benches/bench_client_prepare_query.cpp b/benches/bench_client_prepare_query.cpp index 9b8e5d1..56a33bd 100644 --- a/benches/bench_client_prepare_query.cpp +++ b/benches/bench_client_prepare_query.cpp @@ -82,32 +82,37 @@ BENCHMARK(bench_client_prepare_query<128, 1ul << 16, 256, 10, 1774>) ->ComputeStatistics("min", compute_min) ->ComputeStatistics("max", compute_max) ->MeasureProcessCPUTime() - ->UseRealTime(); + ->UseRealTime() + ->Unit(benchmark::kMillisecond); BENCHMARK(bench_client_prepare_query<128, 1ul << 17, 256, 10, 1774>) ->Name("frodoPIR/client_prepare_query/2^17/256B") ->ComputeStatistics("min", compute_min) ->ComputeStatistics("max", compute_max) ->MeasureProcessCPUTime() - ->UseRealTime(); + ->UseRealTime() + ->Unit(benchmark::kMillisecond); BENCHMARK(bench_client_prepare_query<128, 1ul << 18, 256, 10, 1774>) ->Name("frodoPIR/client_prepare_query/2^18/256B") ->ComputeStatistics("min", compute_min) ->ComputeStatistics("max", compute_max) ->MeasureProcessCPUTime() - ->UseRealTime(); + ->UseRealTime() + ->Unit(benchmark::kMillisecond); BENCHMARK(bench_client_prepare_query<128, 1ul << 19, 256, 9, 1774>) ->Name("frodoPIR/client_prepare_query/2^19/256B") ->ComputeStatistics("min", compute_min) ->ComputeStatistics("max", compute_max) ->MeasureProcessCPUTime() - ->UseRealTime(); + ->UseRealTime() + ->Unit(benchmark::kMillisecond); BENCHMARK(bench_client_prepare_query<128, 1ul << 20, 256, 9, 1774>) ->Name("frodoPIR/client_prepare_query/2^20/256B") ->ComputeStatistics("min", compute_min) ->ComputeStatistics("max", compute_max) ->MeasureProcessCPUTime() - ->UseRealTime(); + ->UseRealTime() + ->Unit(benchmark::kMillisecond); diff --git a/benches/bench_client_process_response.cpp b/benches/bench_client_process_response.cpp index d243867..bce4444 100644 --- a/benches/bench_client_process_response.cpp +++ b/benches/bench_client_process_response.cpp @@ -84,32 +84,37 @@ BENCHMARK(bench_client_process_response<128, 1ul << 16, 256, 10, 1774>) ->ComputeStatistics("min", compute_min) ->ComputeStatistics("max", compute_max) ->MeasureProcessCPUTime() - ->UseRealTime(); + ->UseRealTime() + ->Unit(benchmark::kMicrosecond); BENCHMARK(bench_client_process_response<128, 1ul << 17, 256, 10, 1774>) ->Name("frodoPIR/client_process_response/2^17/256B") ->ComputeStatistics("min", compute_min) ->ComputeStatistics("max", compute_max) ->MeasureProcessCPUTime() - ->UseRealTime(); + ->UseRealTime() + ->Unit(benchmark::kMicrosecond); BENCHMARK(bench_client_process_response<128, 1ul << 18, 256, 10, 1774>) ->Name("frodoPIR/client_process_response/2^18/256B") ->ComputeStatistics("min", compute_min) ->ComputeStatistics("max", compute_max) ->MeasureProcessCPUTime() - ->UseRealTime(); + ->UseRealTime() + ->Unit(benchmark::kMicrosecond); BENCHMARK(bench_client_process_response<128, 1ul << 19, 256, 9, 1774>) ->Name("frodoPIR/client_process_response/2^19/256B") ->ComputeStatistics("min", compute_min) ->ComputeStatistics("max", compute_max) ->MeasureProcessCPUTime() - ->UseRealTime(); + ->UseRealTime() + ->Unit(benchmark::kMicrosecond); BENCHMARK(bench_client_process_response<128, 1ul << 20, 256, 9, 1774>) ->Name("frodoPIR/client_process_response/2^20/256B") ->ComputeStatistics("min", compute_min) ->ComputeStatistics("max", compute_max) ->MeasureProcessCPUTime() - ->UseRealTime(); + ->UseRealTime() + ->Unit(benchmark::kMicrosecond); diff --git a/benches/bench_client_query.cpp b/benches/bench_client_query.cpp index 64ddb93..bc15b23 100644 --- a/benches/bench_client_query.cpp +++ b/benches/bench_client_query.cpp @@ -83,32 +83,37 @@ BENCHMARK(bench_client_query<128, 1ul << 16, 256, 10, 1774>) ->ComputeStatistics("min", compute_min) ->ComputeStatistics("max", compute_max) ->MeasureProcessCPUTime() - ->UseRealTime(); + ->UseRealTime() + ->Unit(benchmark::kMicrosecond); BENCHMARK(bench_client_query<128, 1ul << 17, 256, 10, 1774>) ->Name("frodoPIR/client_query/2^17/256B") ->ComputeStatistics("min", compute_min) ->ComputeStatistics("max", compute_max) ->MeasureProcessCPUTime() - ->UseRealTime(); + ->UseRealTime() + ->Unit(benchmark::kMicrosecond); BENCHMARK(bench_client_query<128, 1ul << 18, 256, 10, 1774>) ->Name("frodoPIR/client_query/2^18/256B") ->ComputeStatistics("min", compute_min) ->ComputeStatistics("max", compute_max) ->MeasureProcessCPUTime() - ->UseRealTime(); + ->UseRealTime() + ->Unit(benchmark::kMicrosecond); BENCHMARK(bench_client_query<128, 1ul << 19, 256, 9, 1774>) ->Name("frodoPIR/client_query/2^19/256B") ->ComputeStatistics("min", compute_min) ->ComputeStatistics("max", compute_max) ->MeasureProcessCPUTime() - ->UseRealTime(); + ->UseRealTime() + ->Unit(benchmark::kMicrosecond); BENCHMARK(bench_client_query<128, 1ul << 20, 256, 9, 1774>) ->Name("frodoPIR/client_query/2^20/256B") ->ComputeStatistics("min", compute_min) ->ComputeStatistics("max", compute_max) ->MeasureProcessCPUTime() - ->UseRealTime(); + ->UseRealTime() + ->Unit(benchmark::kMicrosecond); diff --git a/benches/bench_server_respond.cpp b/benches/bench_server_respond.cpp index d0d052f..6bd20d0 100644 --- a/benches/bench_server_respond.cpp +++ b/benches/bench_server_respond.cpp @@ -68,32 +68,37 @@ BENCHMARK(bench_server_respond<128, 1ul << 16, 256, 10, 1774>) ->ComputeStatistics("min", compute_min) ->ComputeStatistics("max", compute_max) ->MeasureProcessCPUTime() - ->UseRealTime(); + ->UseRealTime() + ->Unit(benchmark::kMillisecond); BENCHMARK(bench_server_respond<128, 1ul << 17, 256, 10, 1774>) ->Name("frodoPIR/server_respond/2^17/256B") ->ComputeStatistics("min", compute_min) ->ComputeStatistics("max", compute_max) ->MeasureProcessCPUTime() - ->UseRealTime(); + ->UseRealTime() + ->Unit(benchmark::kMillisecond); BENCHMARK(bench_server_respond<128, 1ul << 18, 256, 10, 1774>) ->Name("frodoPIR/server_respond/2^18/256B") ->ComputeStatistics("min", compute_min) ->ComputeStatistics("max", compute_max) ->MeasureProcessCPUTime() - ->UseRealTime(); + ->UseRealTime() + ->Unit(benchmark::kMillisecond); BENCHMARK(bench_server_respond<128, 1ul << 19, 256, 9, 1774>) ->Name("frodoPIR/server_respond/2^19/256B") ->ComputeStatistics("min", compute_min) ->ComputeStatistics("max", compute_max) ->MeasureProcessCPUTime() - ->UseRealTime(); + ->UseRealTime() + ->Unit(benchmark::kMillisecond); BENCHMARK(bench_server_respond<128, 1ul << 20, 256, 9, 1774>) ->Name("frodoPIR/server_respond/2^20/256B") ->ComputeStatistics("min", compute_min) ->ComputeStatistics("max", compute_max) ->MeasureProcessCPUTime() - ->UseRealTime(); + ->UseRealTime() + ->Unit(benchmark::kMillisecond); diff --git a/benches/bench_server_setup.cpp b/benches/bench_server_setup.cpp index 87cfd2a..0946430 100644 --- a/benches/bench_server_setup.cpp +++ b/benches/bench_server_setup.cpp @@ -37,32 +37,37 @@ BENCHMARK(bench_server_setup<128, 1ul << 16, 256, 10, 1774>) ->ComputeStatistics("min", compute_min) ->ComputeStatistics("max", compute_max) ->MeasureProcessCPUTime() - ->UseRealTime(); + ->UseRealTime() + ->Unit(benchmark::kSecond); BENCHMARK(bench_server_setup<128, 1ul << 17, 256, 10, 1774>) ->Name("frodoPIR/server_setup/2^17/256B") ->ComputeStatistics("min", compute_min) ->ComputeStatistics("max", compute_max) ->MeasureProcessCPUTime() - ->UseRealTime(); + ->UseRealTime() + ->Unit(benchmark::kSecond); BENCHMARK(bench_server_setup<128, 1ul << 18, 256, 10, 1774>) ->Name("frodoPIR/server_setup/2^18/256B") ->ComputeStatistics("min", compute_min) ->ComputeStatistics("max", compute_max) ->MeasureProcessCPUTime() - ->UseRealTime(); + ->UseRealTime() + ->Unit(benchmark::kSecond); BENCHMARK(bench_server_setup<128, 1ul << 19, 256, 9, 1774>) ->Name("frodoPIR/server_setup/2^19/256B") ->ComputeStatistics("min", compute_min) ->ComputeStatistics("max", compute_max) ->MeasureProcessCPUTime() - ->UseRealTime(); + ->UseRealTime() + ->Unit(benchmark::kSecond); BENCHMARK(bench_server_setup<128, 1ul << 20, 256, 9, 1774>) ->Name("frodoPIR/server_setup/2^20/256B") ->ComputeStatistics("min", compute_min) ->ComputeStatistics("max", compute_max) ->MeasureProcessCPUTime() - ->UseRealTime(); + ->UseRealTime() + ->Unit(benchmark::kSecond); From a83fd949515839cc90ee5483bb4acec1130ac3ef Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sun, 29 Sep 2024 14:01:47 +0400 Subject: [PATCH 89/97] Add benchmark for client setup stage Signed-off-by: Anjan Roy --- benches/bench_client_setup.cpp | 82 ++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 benches/bench_client_setup.cpp diff --git a/benches/bench_client_setup.cpp b/benches/bench_client_setup.cpp new file mode 100644 index 0000000..5b2cb1a --- /dev/null +++ b/benches/bench_client_setup.cpp @@ -0,0 +1,82 @@ +#include "bench_common.hpp" +#include "frodoPIR/client.hpp" +#include "frodoPIR/server.hpp" +#include +#include + +template +static void +bench_client_setup(benchmark::State& state) +{ + constexpr size_t db_byte_len = db_entry_count * db_entry_byte_len; + constexpr size_t parsed_db_column_count = frodoPIR_matrix::get_required_num_columns(db_entry_byte_len, mat_element_bitlen); + constexpr size_t pub_matM_byte_len = frodoPIR_matrix::matrix_t::get_byte_len(); + + std::array::digits> seed_μ{}; + std::vector db_bytes(db_byte_len, 0); + std::vector pub_matM_bytes(pub_matM_byte_len, 0); + + auto seed_μ_span = std::span(seed_μ); + auto db_bytes_span = std::span(db_bytes); + auto pub_matM_bytes_span = std::span(pub_matM_bytes); + + prng::prng_t prng{}; + + prng.read(seed_μ_span); + prng.read(db_bytes_span); + + auto [server, M] = frodoPIR_server::server_t<λ, db_entry_count, db_entry_byte_len, mat_element_bitlen, lwe_dimension>::setup(seed_μ_span, db_bytes_span); + + M.to_le_bytes(pub_matM_bytes_span); + + for (auto _ : state) { + auto client = frodoPIR_client::client_t<λ, db_entry_count, db_entry_byte_len, mat_element_bitlen, lwe_dimension>::setup(seed_μ, pub_matM_bytes_span); + + benchmark::DoNotOptimize(client); + benchmark::DoNotOptimize(seed_μ); + benchmark::DoNotOptimize(pub_matM_bytes_span); + benchmark::ClobberMemory(); + } + + state.SetItemsProcessed(state.iterations()); +} + +BENCHMARK(bench_client_setup<128, 1ul << 16, 256, 10, 1774>) + ->Name("frodoPIR/client_setup/2^16/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime() + ->Unit(benchmark::kMillisecond); + +BENCHMARK(bench_client_setup<128, 1ul << 17, 256, 10, 1774>) + ->Name("frodoPIR/client_setup/2^17/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime() + ->Unit(benchmark::kMillisecond); + +BENCHMARK(bench_client_setup<128, 1ul << 18, 256, 10, 1774>) + ->Name("frodoPIR/client_setup/2^18/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime() + ->Unit(benchmark::kMillisecond); + +BENCHMARK(bench_client_setup<128, 1ul << 19, 256, 9, 1774>) + ->Name("frodoPIR/client_setup/2^19/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime() + ->Unit(benchmark::kMillisecond); + +BENCHMARK(bench_client_setup<128, 1ul << 20, 256, 9, 1774>) + ->Name("frodoPIR/client_setup/2^20/256B") + ->ComputeStatistics("min", compute_min) + ->ComputeStatistics("max", compute_max) + ->MeasureProcessCPUTime() + ->UseRealTime() + ->Unit(benchmark::kMillisecond); From 36ac642360a2f5b40192875c3452b0a714764138 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sun, 29 Sep 2024 14:24:16 +0400 Subject: [PATCH 90/97] Add compile-time check function for ensuring that FrodoPIR can only be instantiated with recommended parameters in paper Signed-off-by: Anjan Roy --- include/frodoPIR/internals/utility/params.hpp | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 include/frodoPIR/internals/utility/params.hpp diff --git a/include/frodoPIR/internals/utility/params.hpp b/include/frodoPIR/internals/utility/params.hpp new file mode 100644 index 0000000..8667664 --- /dev/null +++ b/include/frodoPIR/internals/utility/params.hpp @@ -0,0 +1,31 @@ +#pragma once +#include "frodoPIR/internals/matrix/matrix.hpp" +#include +#include + +namespace frodoPIR_params { + +// Compile-time check, if chosen parameters for instantiating FrodoPIR, is correct, following Eq. 8 in section 5.1 of https://ia.cr/2022/981. +consteval bool +check_frodoPIR_param_correctness(const size_t db_entry_count, const size_t mat_element_bitlen) +{ + const auto ρ = 1ul << mat_element_bitlen; + return frodoPIR_matrix::Q >= ((8 * ρ * ρ) * std::sqrt(db_entry_count)); +} + +// Compile-time check, if instantiated FrodoPIR uses one of recommended parameters in table 5 of https://ia.cr/2022/981. +consteval bool +check_frodoPIR_params(const size_t λ, const size_t db_entry_count, const size_t mat_element_bitlen, const size_t lwe_dimension) +{ + return check_frodoPIR_param_correctness(db_entry_count, mat_element_bitlen) && // First check if Eq. 8 of https://ia.cr/2022/981 holds + (λ == 128) && // Only 128 -bit security level is supported + (lwe_dimension == 1774) && // LWE dimension is also fixed for all variants + (((db_entry_count == (1ul << 16)) && (mat_element_bitlen == 10)) || // Database has 2^16 rows s.t. each row can be of arbitrary byte length + ((db_entry_count == (1ul << 17)) && (mat_element_bitlen == 10)) || // Database has 2^17 rows s.t. each row can be of arbitrary byte length + ((db_entry_count == (1ul << 18)) && (mat_element_bitlen == 10)) || // Database has 2^18 rows s.t. each row can be of arbitrary byte length + ((db_entry_count == (1ul << 19)) && (mat_element_bitlen == 9)) || // Database has 2^19 rows s.t. each row can be of arbitrary byte length + ((db_entry_count == (1ul << 20)) && (mat_element_bitlen == 9)) // Database has 2^20 rows s.t. each row can be of arbitrary byte length + ); +} + +} From a4357851434b483477267e2ff40a6e0ec672b1eb Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sun, 29 Sep 2024 14:25:10 +0400 Subject: [PATCH 91/97] Activate compile-time checks, ensuring FrodoPIR client and server can only instantiated with recommended parameters in paper Signed-off-by: Anjan Roy --- include/frodoPIR/client.hpp | 2 ++ include/frodoPIR/server.hpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/include/frodoPIR/client.hpp b/include/frodoPIR/client.hpp index 05a20e6..478fc28 100644 --- a/include/frodoPIR/client.hpp +++ b/include/frodoPIR/client.hpp @@ -4,6 +4,7 @@ #include "frodoPIR/internals/matrix/vector.hpp" #include "frodoPIR/internals/rng/prng.hpp" #include "frodoPIR/internals/utility/force_inline.hpp" +#include "frodoPIR/internals/utility/params.hpp" #include #include #include @@ -32,6 +33,7 @@ struct client_query_t // Frodo *P*rivate *I*nformation *R*etrieval Client template + requires(frodoPIR_params::check_frodoPIR_params(λ, db_entry_count, mat_element_bitlen, lwe_dimension)) struct client_t { public: diff --git a/include/frodoPIR/server.hpp b/include/frodoPIR/server.hpp index 606ffec..f4be5ae 100644 --- a/include/frodoPIR/server.hpp +++ b/include/frodoPIR/server.hpp @@ -3,6 +3,7 @@ #include "frodoPIR/internals/matrix/serialization.hpp" #include "frodoPIR/internals/matrix/vector.hpp" #include "frodoPIR/internals/utility/force_inline.hpp" +#include "frodoPIR/internals/utility/params.hpp" #include #include #include @@ -12,6 +13,7 @@ namespace frodoPIR_server { // Frodo *P*rivate *I*nformation *R*etrieval Server template + requires(frodoPIR_params::check_frodoPIR_params(λ, db_entry_count, mat_element_bitlen, lwe_dimension)) struct server_t { public: From 7e320d665ce83e3ab34be9193c4b2ef22217cd70 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sun, 29 Sep 2024 17:56:57 +0400 Subject: [PATCH 92/97] Don't rely on non-constexpr `std::sqrt` function for evaluating compile-time check Signed-off-by: Anjan Roy --- include/frodoPIR/internals/utility/params.hpp | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/include/frodoPIR/internals/utility/params.hpp b/include/frodoPIR/internals/utility/params.hpp index 8667664..d68ecca 100644 --- a/include/frodoPIR/internals/utility/params.hpp +++ b/include/frodoPIR/internals/utility/params.hpp @@ -1,16 +1,35 @@ #pragma once #include "frodoPIR/internals/matrix/matrix.hpp" -#include #include namespace frodoPIR_params { +// Compile-time executable recursive integer square-root function. +constexpr size_t +ct_sqrt_helper(const size_t x, const size_t lo, const size_t hi) +{ + if (lo == hi) { + return lo; + } + + const auto mid = (lo + hi + 1ul) / 2ul; + return ((x / mid) < mid) ? ct_sqrt_helper(x, lo, mid - 1ul) : ct_sqrt_helper(x, mid, hi); +} + +// Homebrewed compile-time executable square-root implementation for integer values. +// Taken from https://stackoverflow.com/a/27709195. +constexpr size_t +ct_sqrt(const size_t x) +{ + return ct_sqrt_helper(x, 0, (x / 2ul) + 1ul); +} + // Compile-time check, if chosen parameters for instantiating FrodoPIR, is correct, following Eq. 8 in section 5.1 of https://ia.cr/2022/981. consteval bool check_frodoPIR_param_correctness(const size_t db_entry_count, const size_t mat_element_bitlen) { const auto ρ = 1ul << mat_element_bitlen; - return frodoPIR_matrix::Q >= ((8 * ρ * ρ) * std::sqrt(db_entry_count)); + return frodoPIR_matrix::Q >= ((8 * ρ * ρ) * ct_sqrt(db_entry_count)); } // Compile-time check, if instantiated FrodoPIR uses one of recommended parameters in table 5 of https://ia.cr/2022/981. From 9ff03d20e44a5469b858e399550d644217e843f4 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sun, 29 Sep 2024 17:57:43 +0400 Subject: [PATCH 93/97] Don't capture variable, which is not at all used Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/serialization.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/frodoPIR/internals/matrix/serialization.hpp b/include/frodoPIR/internals/matrix/serialization.hpp index b7be05d..bf3b8aa 100644 --- a/include/frodoPIR/internals/matrix/serialization.hpp +++ b/include/frodoPIR/internals/matrix/serialization.hpp @@ -81,7 +81,7 @@ parse_db_bytes(std::span byte const size_t r_idx_begin = t_idx * num_rows_per_thread; const size_t r_idx_end = r_idx_begin + num_rows_per_thread; - auto thread = std::thread([=, &bytes]() { + auto thread = std::thread([=]() { for (size_t r_idx = r_idx_begin; r_idx < r_idx_end; r_idx++) { parse_db_row(r_idx); } @@ -171,7 +171,7 @@ serialize_parsed_db_matrix( const size_t r_idx_begin = t_idx * num_rows_per_thread; const size_t r_idx_end = r_idx_begin + num_rows_per_thread; - auto thread = std::thread([=, &bytes]() { + auto thread = std::thread([=]() { for (size_t r_idx = r_idx_begin; r_idx < r_idx_end; r_idx++) { serialize_parsed_db_row(r_idx); } From 5d5cd4c804275e4c273b302ad18e6255610fb725 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Sun, 29 Sep 2024 22:27:23 +0400 Subject: [PATCH 94/97] Remove redundant function for computing transpose of matrix Signed-off-by: Anjan Roy --- include/frodoPIR/internals/matrix/matrix.hpp | 15 --------------- tests/test_matrix_operations.cpp | 12 +++--------- 2 files changed, 3 insertions(+), 24 deletions(-) diff --git a/include/frodoPIR/internals/matrix/matrix.hpp b/include/frodoPIR/internals/matrix/matrix.hpp index 3f0ee01..d0a9835 100644 --- a/include/frodoPIR/internals/matrix/matrix.hpp +++ b/include/frodoPIR/internals/matrix/matrix.hpp @@ -167,21 +167,6 @@ struct matrix_t return (result == 0); } - // Given a matrix M of dimension `rows x cols`, this routine is used for computing its transpose M' s.t. - // resulting matrix's dimension becomes `cols x rows`. - forceinline constexpr matrix_t transpose() const - { - matrix_t res{}; - - for (size_t i = 0; i < cols; i++) { - for (size_t j = 0; j < rows; j++) { - res[{ i, j }] = (*this)[{ j, i }]; - } - } - - return res; - } - // Given two matrices A, B of equal dimension, this routine can be used for performing matrix addition over Zq, // returning a matrix of same dimension, using multiple threads. forceinline matrix_t operator+(const matrix_t& rhs) const diff --git a/tests/test_matrix_operations.cpp b/tests/test_matrix_operations.cpp index b867362..b240f3d 100644 --- a/tests/test_matrix_operations.cpp +++ b/tests/test_matrix_operations.cpp @@ -24,17 +24,11 @@ TEST(FrodoPIR, MatrixOperations) prng.read(μ_span); auto A = frodoPIR_matrix::matrix_t::template generate<λ>(μ_span); + A.to_le_bytes(matA_bytes_span); { - auto A_transposed = A.transpose(); - A_transposed.to_le_bytes(matA_bytes_span); - } - - { - auto A_prime = frodoPIR_matrix::matrix_t::from_le_bytes(matA_bytes_span); - auto A_prime_transposed = A_prime.transpose(); - - EXPECT_EQ(A, A_prime_transposed); + auto A_prime = frodoPIR_matrix::matrix_t::from_le_bytes(matA_bytes_span); + EXPECT_EQ(A, A_prime); } { From 1fac362a03a7b8732b3d60781089db4b47aadbb4 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Mon, 30 Sep 2024 21:28:16 +0400 Subject: [PATCH 95/97] Add example program demonstrating usage of frodoPIR API Signed-off-by: Anjan Roy --- examples/frodoPIR.cpp | 97 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 examples/frodoPIR.cpp diff --git a/examples/frodoPIR.cpp b/examples/frodoPIR.cpp new file mode 100644 index 0000000..153d28f --- /dev/null +++ b/examples/frodoPIR.cpp @@ -0,0 +1,97 @@ +#include "frodoPIR/client.hpp" +#include "frodoPIR/server.hpp" +#include +#include +#include +#include + +// Given a bytearray of length N, this function converts it to human readable hex string of length N << 1 | N >= 0 +static inline const std::string +to_hex(std::span bytes) +{ + std::stringstream ss; + ss << std::hex; + + for (size_t i = 0; i < bytes.size(); i++) { + ss << std::setw(2) << std::setfill('0') << static_cast(bytes[i]); + } + + return ss.str(); +} + +// Compile with +// g++ -std=c++20 -Wall -Wextra -pedantic -O3 -march=native -I include -I sha3/include examples/frodoPIR.cpp +int +main() +{ + // Parameter setup for instantiating FrodoPIR + constexpr size_t λ = 128; + constexpr size_t db_entry_count = 1ul << 16; + constexpr size_t db_entry_byte_len = 32; + constexpr size_t mat_element_bitlen = 10; + constexpr size_t lwe_dimension = 1774; + + // Database, query and response byte length + constexpr size_t parsed_db_column_count = frodoPIR_matrix::get_required_num_columns(db_entry_byte_len, mat_element_bitlen); + constexpr size_t db_byte_len = db_entry_count * db_entry_byte_len; + constexpr size_t pub_matM_byte_len = frodoPIR_matrix::matrix_t::get_byte_len(); + constexpr size_t query_byte_len = frodoPIR_vector::row_vector_t::get_byte_len(); + constexpr size_t response_byte_len = frodoPIR_vector::row_vector_t::get_byte_len(); + + // Database, query and response memory allocation + std::array::digits> seed_μ{}; + std::vector db_bytes(db_byte_len, 0); + std::vector pub_matM_bytes(pub_matM_byte_len, 0); + std::vector query_bytes(query_byte_len, 0); + std::vector response_bytes(response_byte_len, 0); + std::vector obtained_db_row_bytes(db_entry_byte_len, 0); + + auto db_bytes_span = std::span(db_bytes); + auto pub_matM_bytes_span = std::span(pub_matM_bytes); + auto query_bytes_span = std::span(query_bytes); + auto response_bytes_span = std::span(response_bytes); + auto obtained_db_row_bytes_span = std::span(obtained_db_row_bytes); + + prng::prng_t prng{}; + + // Sample pseudo random seed + prng.read(seed_μ); + // Fill pseudo random database content + prng.read(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); + M.to_le_bytes(pub_matM_bytes_span); + + // Setup a FrodoPIR client + auto client = frodoPIR_client::client_t<λ, db_entry_count, db_entry_byte_len, mat_element_bitlen, lwe_dimension>::setup(seed_μ, pub_matM_bytes_span); + + // We will enquire server about the content of this database row + 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); + assert(is_query_preprocessed); + + // Client wants to query content of specific database row, for which we've already a query partially prepared + const auto is_query_ready = client.query(to_be_queried_db_row_index, query_bytes_span); + assert(is_query_ready); + + // Query reaches FrodoPIR server, it responds back + server.respond(query_bytes_span, response_bytes_span); + + // Response reaches FrodoPIR client, decodes it, obtains database row content + const auto is_response_decoded = client.process_response(to_be_queried_db_row_index, response_bytes_span, obtained_db_row_bytes_span); + assert(is_response_decoded); + + // Original database row content, which server has access to + const auto orig_db_row_bytes = db_bytes_span.subspan(to_be_queried_db_row_index * db_entry_byte_len, db_entry_byte_len); + + std::cout << "Original database row bytes : " << to_hex(orig_db_row_bytes) << "\n"; + std::cout << "PIR decoded database row bytes : " << to_hex(obtained_db_row_bytes_span) << "\n"; + + // Original database row content and FrodoPIR client decoded row content must match ! + assert(std::ranges::equal(orig_db_row_bytes, obtained_db_row_bytes_span)); + + return 0; +} From fa9eca9a6944ee1ec1200962199f4523e3b61417 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Mon, 30 Sep 2024 06:38:44 +0400 Subject: [PATCH 96/97] Benchmark result dumped into JSON file Signed-off-by: Anjan Roy --- ...x_6.8.0-45-generic_x86_64_with_g++_14.json | 3102 +++++++++++++++++ 1 file changed, 3102 insertions(+) create mode 100644 bench_result_on_Linux_6.8.0-45-generic_x86_64_with_g++_14.json diff --git a/bench_result_on_Linux_6.8.0-45-generic_x86_64_with_g++_14.json b/bench_result_on_Linux_6.8.0-45-generic_x86_64_with_g++_14.json new file mode 100644 index 0000000..ea47d50 --- /dev/null +++ b/bench_result_on_Linux_6.8.0-45-generic_x86_64_with_g++_14.json @@ -0,0 +1,3102 @@ +{ + "context": { + "date": "2024-09-29T23:13:04+04:00", + "host_name": "linux", + "executable": "./build/benchmark/perf.out", + "num_cpus": 16, + "mhz_per_cpu": 503, + "cpu_scaling_enabled": false, + "caches": [ + { + "type": "Data", + "level": 1, + "size": 49152, + "num_sharing": 2 + }, + { + "type": "Instruction", + "level": 1, + "size": 32768, + "num_sharing": 2 + }, + { + "type": "Unified", + "level": 2, + "size": 1310720, + "num_sharing": 2 + }, + { + "type": "Unified", + "level": 3, + "size": 18874368, + "num_sharing": 16 + } + ], + "load_avg": [1.28955,0.628418,0.577637], + "library_version": "v1.9.0-8-g3fd1e6a7", + "library_build_type": "release", + "json_schema_version": 1 + }, + "benchmarks": [ + { + "name": "frodoPIR/client_setup/2^17/256B/process_time/real_time_mean", + "family_index": 16, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.9303630694994354e+03, + "cpu_time": 1.9302617517983890e+03, + "time_unit": "ms", + "CYCLES": 6.1731687173000002e+09, + "items_per_second": 5.1912996706515524e-01 + }, + { + "name": "frodoPIR/client_setup/2^17/256B/process_time/real_time_median", + "family_index": 16, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.9582316965006612e+03, + "cpu_time": 1.9581133449974004e+03, + "time_unit": "ms", + "CYCLES": 6.1729738855000000e+09, + "items_per_second": 5.1068416098468528e-01 + }, + { + "name": "frodoPIR/client_setup/2^17/256B/process_time/real_time_stddev", + "family_index": 16, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 9.1962950160234357e+01, + "cpu_time": 9.1963120959194626e+01, + "time_unit": "ms", + "CYCLES": 5.2239258023793222e+06, + "items_per_second": 2.5501641018147891e-02 + }, + { + "name": "frodoPIR/client_setup/2^17/256B/process_time/real_time_cv", + "family_index": 16, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 4.7640234945067285e-02, + "cpu_time": 4.7642824022966983e-02, + "time_unit": "ms", + "CYCLES": 8.4623084863038461e-04, + "items_per_second": 4.9123808364056970e-02 + }, + { + "name": "frodoPIR/client_setup/2^17/256B/process_time/real_time_min", + "family_index": 16, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.7702972589977435e+03, + "cpu_time": 1.7702106590004405e+03, + "time_unit": "ms", + "CYCLES": 6.1659000060000000e+09, + "items_per_second": 4.9040564487030569e-01 + }, + { + "name": "frodoPIR/client_setup/2^17/256B/process_time/real_time_max", + "family_index": 16, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 2.0391282409982523e+03, + "cpu_time": 2.0390684979938669e+03, + "time_unit": "ms", + "CYCLES": 6.1823898030000000e+09, + "items_per_second": 5.6487688432966987e-01 + }, + { + "name": "frodoPIR/client_process_response/2^16/256B/process_time/real_time_mean", + "family_index": 5, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 5.5263232988560105e+02, + "cpu_time": 6.0126526840955262e+02, + "time_unit": "us", + "CYCLES": 7.6526624452554737e+04, + "items_per_second": 1.8199276744205986e+03 + }, + { + "name": "frodoPIR/client_process_response/2^16/256B/process_time/real_time_median", + "family_index": 5, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 5.7099113866676623e+02, + "cpu_time": 6.1643615336721189e+02, + "time_unit": "us", + "CYCLES": 7.6616525547445257e+04, + "items_per_second": 1.7513419562510821e+03 + }, + { + "name": "frodoPIR/client_process_response/2^16/256B/process_time/real_time_stddev", + "family_index": 5, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 4.2817779358819649e+01, + "cpu_time": 4.6960844548413213e+01, + "time_unit": "us", + "CYCLES": 7.2079066277301436e+03, + "items_per_second": 1.4943148585581159e+02 + }, + { + "name": "frodoPIR/client_process_response/2^16/256B/process_time/real_time_cv", + "family_index": 5, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 7.7479685938177459e-02, + "cpu_time": 7.8103371366572569e-02, + "time_unit": "us", + "CYCLES": 9.4188221149084247e-02, + "items_per_second": 8.2108474944415227e-02 + }, + { + "name": "frodoPIR/client_process_response/2^16/256B/process_time/real_time_min", + "family_index": 5, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 4.7790026257683883e+02, + "cpu_time": 5.2066377045868819e+02, + "time_unit": "us", + "CYCLES": 6.4853405109489053e+04, + "items_per_second": 1.6709827928430486e+03 + }, + { + "name": "frodoPIR/client_process_response/2^16/256B/process_time/real_time_max", + "family_index": 5, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 5.9845020803510306e+02, + "cpu_time": 6.5309308804095770e+02, + "time_unit": "us", + "CYCLES": 9.1606864963503656e+04, + "items_per_second": 2.0924868185005771e+03 + }, + { + "name": "frodoPIR/server_respond/2^16/256B/process_time/real_time_mean", + "family_index": 20, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 4.9963995538536654e+00, + "cpu_time": 4.3376249123048190e+01, + "time_unit": "ms", + "CYCLES": 7.5289536834615394e+07, + "items_per_second": 2.0021870649235768e+02 + }, + { + "name": "frodoPIR/server_respond/2^16/256B/process_time/real_time_median", + "family_index": 20, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 4.9926683461587977e+00, + "cpu_time": 4.3236368230841791e+01, + "time_unit": "ms", + "CYCLES": 7.5628787442307681e+07, + "items_per_second": 2.0029466754299290e+02 + }, + { + "name": "frodoPIR/server_respond/2^16/256B/process_time/real_time_stddev", + "family_index": 20, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.0252730495029003e-01, + "cpu_time": 6.3674607124627314e-01, + "time_unit": "ms", + "CYCLES": 1.3572387641404720e+06, + "items_per_second": 4.0396107036359652e+00 + }, + { + "name": "frodoPIR/server_respond/2^16/256B/process_time/real_time_cv", + "family_index": 20, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 2.0520237391985982e-02, + "cpu_time": 1.4679601950827393e-02, + "time_unit": "ms", + "CYCLES": 1.8026924074746903e-02, + "items_per_second": 2.0175990417709330e-02 + }, + { + "name": "frodoPIR/server_respond/2^16/256B/process_time/real_time_min", + "family_index": 20, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 4.8824681154935838e+00, + "cpu_time": 4.2487922038442498e+01, + "time_unit": "ms", + "CYCLES": 7.3224985807692304e+07, + "items_per_second": 1.9154732734476420e+02 + }, + { + "name": "frodoPIR/server_respond/2^16/256B/process_time/real_time_max", + "family_index": 20, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 5.2206418844994360e+00, + "cpu_time": 4.4743087153899701e+01, + "time_unit": "ms", + "CYCLES": 7.6921613884615391e+07, + "items_per_second": 2.0481444555197203e+02 + }, + { + "name": "frodoPIR/client_query/2^18/256B/process_time/real_time_mean", + "family_index": 12, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.1046277850562987e+02, + "cpu_time": 1.0893512268872912e+02, + "time_unit": "us", + "CYCLES": 2.5264480706401766e+05, + "items_per_second": 9.0530844446772408e+03 + }, + { + "name": "frodoPIR/client_query/2^18/256B/process_time/real_time_median", + "family_index": 12, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.1066766706600012e+02, + "cpu_time": 1.0912830485890204e+02, + "time_unit": "us", + "CYCLES": 2.5303858940397351e+05, + "items_per_second": 9.0360630051956668e+03 + }, + { + "name": "frodoPIR/client_query/2^18/256B/process_time/real_time_stddev", + "family_index": 12, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 6.2264351281989982e-01, + "cpu_time": 6.1968060126185653e-01, + "time_unit": "us", + "CYCLES": 2.9667776924574496e+03, + "items_per_second": 5.1504806373100848e+01 + }, + { + "name": "frodoPIR/client_query/2^18/256B/process_time/real_time_cv", + "family_index": 12, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 5.6366816156825711e-03, + "cpu_time": 5.6885289699680226e-03, + "time_unit": "us", + "CYCLES": 1.1742880160231031e-02, + "items_per_second": 5.6891998177906198e-03 + }, + { + "name": "frodoPIR/client_query/2^18/256B/process_time/real_time_min", + "family_index": 12, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.0891301543812058e+02, + "cpu_time": 1.0741190939701031e+02, + "time_unit": "us", + "CYCLES": 2.4768236791758647e+05, + "items_per_second": 9.0094617860590988e+03 + }, + { + "name": "frodoPIR/client_query/2^18/256B/process_time/real_time_max", + "family_index": 12, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.1099442161432576e+02, + "cpu_time": 1.0948197571219376e+02, + "time_unit": "us", + "CYCLES": 2.5592987858719646e+05, + "items_per_second": 9.1816390904001237e+03 + }, + { + "name": "frodoPIR/client_query/2^19/256B/process_time/real_time_mean", + "family_index": 13, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 2.1603535149737209e+02, + "cpu_time": 2.1432607792410062e+02, + "time_unit": "us", + "CYCLES": 5.0734047784431139e+05, + "items_per_second": 4.6289422885367594e+03 + }, + { + "name": "frodoPIR/client_query/2^19/256B/process_time/real_time_median", + "family_index": 13, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 2.1573995732586681e+02, + "cpu_time": 2.1397064874636379e+02, + "time_unit": "us", + "CYCLES": 5.1025575224550895e+05, + "items_per_second": 4.6352099810486052e+03 + }, + { + "name": "frodoPIR/client_query/2^19/256B/process_time/real_time_stddev", + "family_index": 13, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 8.8877394887543093e-01, + "cpu_time": 8.4177359471190738e-01, + "time_unit": "us", + "CYCLES": 8.1770140882049354e+03, + "items_per_second": 1.8970571823631875e+01 + }, + { + "name": "frodoPIR/client_query/2^19/256B/process_time/real_time_cv", + "family_index": 13, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 4.1140208892443339e-03, + "cpu_time": 3.9275369701395136e-03, + "time_unit": "us", + "CYCLES": 1.6117409206040587e-02, + "items_per_second": 4.0982519636529333e-03 + }, + { + "name": "frodoPIR/client_query/2^19/256B/process_time/real_time_min", + "family_index": 13, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 2.1512691466864317e+02, + "cpu_time": 2.1346541264332819e+02, + "time_unit": "us", + "CYCLES": 4.9201673952095810e+05, + "items_per_second": 4.5879906779411904e+03 + }, + { + "name": "frodoPIR/client_query/2^19/256B/process_time/real_time_max", + "family_index": 13, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 2.1796033823868598e+02, + "cpu_time": 2.1609651920954488e+02, + "time_unit": "us", + "CYCLES": 5.1743235628742515e+05, + "items_per_second": 4.6484188254188712e+03 + }, + { + "name": "frodoPIR/client_process_response/2^19/256B/process_time/real_time_mean", + "family_index": 8, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 5.7055962211157998e+02, + "cpu_time": 8.5535724277622990e+02, + "time_unit": "us", + "CYCLES": 1.3306945581395351e+05, + "items_per_second": 1.7532090758064890e+03 + }, + { + "name": "frodoPIR/client_process_response/2^19/256B/process_time/real_time_median", + "family_index": 8, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 5.6927442828471032e+02, + "cpu_time": 8.5824066396286457e+02, + "time_unit": "us", + "CYCLES": 1.3328104457364342e+05, + "items_per_second": 1.7566221264498251e+03 + }, + { + "name": "frodoPIR/client_process_response/2^19/256B/process_time/real_time_stddev", + "family_index": 8, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.0646152827165945e+01, + "cpu_time": 2.0706023818120080e+01, + "time_unit": "us", + "CYCLES": 2.5159889209244288e+03, + "items_per_second": 3.2392314003361257e+01 + }, + { + "name": "frodoPIR/client_process_response/2^19/256B/process_time/real_time_cv", + "family_index": 8, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 1.8659141682276208e-02, + "cpu_time": 2.4207457168322573e-02, + "time_unit": "us", + "CYCLES": 1.8907336063973032e-02, + "items_per_second": 1.8476013186539408e-02 + }, + { + "name": "frodoPIR/client_process_response/2^19/256B/process_time/real_time_min", + "family_index": 8, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 5.5713740307122532e+02, + "cpu_time": 8.1918156180574101e+02, + "time_unit": "us", + "CYCLES": 1.2904673643410853e+05, + "items_per_second": 1.6903475288196673e+03 + }, + { + "name": "frodoPIR/client_process_response/2^19/256B/process_time/real_time_max", + "family_index": 8, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 5.9159432184828768e+02, + "cpu_time": 8.8789314313614818e+02, + "time_unit": "us", + "CYCLES": 1.3681745348837209e+05, + "items_per_second": 1.7948893656887694e+03 + }, + { + "name": "frodoPIR/client_process_response/2^17/256B/process_time/real_time_mean", + "family_index": 6, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 5.7752883936722446e+02, + "cpu_time": 6.4877717359560495e+02, + "time_unit": "us", + "CYCLES": 7.3878794779116477e+04, + "items_per_second": 1.7352267195515492e+03 + }, + { + "name": "frodoPIR/client_process_response/2^17/256B/process_time/real_time_median", + "family_index": 6, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 5.7358876304544583e+02, + "cpu_time": 6.5056430090575975e+02, + "time_unit": "us", + "CYCLES": 7.3304012048192773e+04, + "items_per_second": 1.7437049489368769e+03 + }, + { + "name": "frodoPIR/client_process_response/2^17/256B/process_time/real_time_stddev", + "family_index": 6, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 2.8102536973565073e+01, + "cpu_time": 3.3125077168914700e+01, + "time_unit": "us", + "CYCLES": 3.5018283278624808e+03, + "items_per_second": 8.4848641711819468e+01 + }, + { + "name": "frodoPIR/client_process_response/2^17/256B/process_time/real_time_cv", + "family_index": 6, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 4.8659971689649140e-02, + "cpu_time": 5.1057710593193875e-02, + "time_unit": "us", + "CYCLES": 4.7399640699774280e-02, + "items_per_second": 4.8897726594336728e-02 + }, + { + "name": "frodoPIR/client_process_response/2^17/256B/process_time/real_time_min", + "family_index": 6, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 5.3020217276216169e+02, + "cpu_time": 5.9179805631068598e+02, + "time_unit": "us", + "CYCLES": 6.8712831325301202e+04, + "items_per_second": 1.6113043316611145e+03 + }, + { + "name": "frodoPIR/client_process_response/2^17/256B/process_time/real_time_max", + "family_index": 6, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 6.2061522479064342e+02, + "cpu_time": 6.9578781564547921e+02, + "time_unit": "us", + "CYCLES": 7.8961851405622496e+04, + "items_per_second": 1.8860729951187514e+03 + }, + { + "name": "frodoPIR/client_setup/2^16/256B/process_time/real_time_mean", + "family_index": 15, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 9.7904755879972072e+02, + "cpu_time": 9.7896439579799335e+02, + "time_unit": "ms", + "CYCLES": 3.0495237393000002e+09, + "items_per_second": 1.0232777176433110e+00 + }, + { + "name": "frodoPIR/client_setup/2^16/256B/process_time/real_time_median", + "family_index": 15, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 9.8886466849944554e+02, + "cpu_time": 9.8869968850249279e+02, + "time_unit": "ms", + "CYCLES": 3.0497205210000000e+09, + "items_per_second": 1.0112861235846904e+00 + }, + { + "name": "frodoPIR/client_setup/2^16/256B/process_time/real_time_stddev", + "family_index": 15, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 4.3411367444416193e+01, + "cpu_time": 4.3401282274011272e+01, + "time_unit": "ms", + "CYCLES": 1.6096655361078379e+06, + "items_per_second": 4.7061678776021285e-02 + }, + { + "name": "frodoPIR/client_setup/2^16/256B/process_time/real_time_cv", + "family_index": 15, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 4.4340407219478760e-02, + "cpu_time": 4.4333872059395103e-02, + "time_unit": "ms", + "CYCLES": 5.2784161518851691e-04, + "items_per_second": 4.5991110687339139e-02 + }, + { + "name": "frodoPIR/client_setup/2^16/256B/process_time/real_time_min", + "family_index": 15, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 9.0315754400216974e+02, + "cpu_time": 9.0311731999099720e+02, + "time_unit": "ms", + "CYCLES": 3.0474821320000000e+09, + "items_per_second": 9.7496635724951486e-01 + }, + { + "name": "frodoPIR/client_setup/2^16/256B/process_time/real_time_max", + "family_index": 15, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.0256764170007955e+03, + "cpu_time": 1.0256788039987441e+03, + "time_unit": "ms", + "CYCLES": 3.0523225780000000e+09, + "items_per_second": 1.1072265372093240e+00 + }, + { + "name": "frodoPIR/client_process_response/2^20/256B/process_time/real_time_mean", + "family_index": 9, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 5.9131988778733751e+02, + "cpu_time": 9.6280517982897254e+02, + "time_unit": "us", + "CYCLES": 1.4044303811475410e+05, + "items_per_second": 1.6914429288394476e+03 + }, + { + "name": "frodoPIR/client_process_response/2^20/256B/process_time/real_time_median", + "family_index": 9, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 5.8910263939398021e+02, + "cpu_time": 9.4947903073530210e+02, + "time_unit": "us", + "CYCLES": 1.4059400409836066e+05, + "items_per_second": 1.6975000812737285e+03 + }, + { + "name": "frodoPIR/client_process_response/2^20/256B/process_time/real_time_stddev", + "family_index": 9, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 8.4874609956731124e+00, + "cpu_time": 3.0606483492159260e+01, + "time_unit": "us", + "CYCLES": 2.4715805406550694e+03, + "items_per_second": 2.4069385243997655e+01 + }, + { + "name": "frodoPIR/client_process_response/2^20/256B/process_time/real_time_cv", + "family_index": 9, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 1.4353417111391908e-02, + "cpu_time": 3.1788864594180961e-02, + "time_unit": "us", + "CYCLES": 1.7598455386842134e-02, + "items_per_second": 1.4230090080847375e-02 + }, + { + "name": "frodoPIR/client_process_response/2^20/256B/process_time/real_time_min", + "family_index": 9, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 5.8111112692310348e+02, + "cpu_time": 9.4108817193344169e+02, + "time_unit": "us", + "CYCLES": 1.3507422540983607e+05, + "items_per_second": 1.6464594913865812e+03 + }, + { + "name": "frodoPIR/client_process_response/2^20/256B/process_time/real_time_max", + "family_index": 9, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 6.0736386484543300e+02, + "cpu_time": 1.0416430893395150e+03, + "time_unit": "us", + "CYCLES": 1.4428640573770492e+05, + "items_per_second": 1.7208412533672354e+03 + }, + { + "name": "frodoPIR/client_prepare_query/2^16/256B/process_time/real_time_mean", + "family_index": 0, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 9.9726010715520346e+00, + "cpu_time": 1.1826224600653018e+02, + "time_unit": "ms", + "CYCLES": 2.1581577781428576e+08, + "items_per_second": 1.0029258446475916e+02 + }, + { + "name": "frodoPIR/client_prepare_query/2^16/256B/process_time/real_time_median", + "family_index": 0, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.0007216999968348e+01, + "cpu_time": 1.1877965171203998e+02, + "time_unit": "ms", + "CYCLES": 2.1641503725000000e+08, + "items_per_second": 9.9928429765421214e+01 + }, + { + "name": "frodoPIR/client_prepare_query/2^16/256B/process_time/real_time_stddev", + "family_index": 0, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.3904870542010628e-01, + "cpu_time": 1.8208909703332530e+00, + "time_unit": "ms", + "CYCLES": 3.5277758993362631e+06, + "items_per_second": 1.4220042112954094e+00 + }, + { + "name": "frodoPIR/client_prepare_query/2^16/256B/process_time/real_time_cv", + "family_index": 0, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 1.3943073068144513e-02, + "cpu_time": 1.5397060615885036e-02, + "time_unit": "ms", + "CYCLES": 1.6346237217058301e-02, + "items_per_second": 1.4178557855342474e-02 + }, + { + "name": "frodoPIR/client_prepare_query/2^16/256B/process_time/real_time_min", + "family_index": 0, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 9.6524902861087227e+00, + "cpu_time": 1.1454675635676332e+02, + "time_unit": "ms", + "CYCLES": 2.1031424892857143e+08, + "items_per_second": 9.9056345381980790e+01 + }, + { + "name": "frodoPIR/client_prepare_query/2^16/256B/process_time/real_time_max", + "family_index": 0, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.0095264428985372e+01, + "cpu_time": 1.2011301685976962e+02, + "time_unit": "ms", + "CYCLES": 2.2008992835714287e+08, + "items_per_second": 1.0360020785922357e+02 + }, + { + "name": "frodoPIR/server_setup/2^18/256B/process_time/real_time_mean", + "family_index": 27, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 6.6953876573010351e+00, + "cpu_time": 4.5032110746200821e+01, + "time_unit": "s", + "CYCLES": 7.3052390791600006e+10, + "items_per_second": 1.4991502004806964e-01 + }, + { + "name": "frodoPIR/server_setup/2^18/256B/process_time/real_time_median", + "family_index": 27, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 6.6843278309988818e+00, + "cpu_time": 4.4816003255502437e+01, + "time_unit": "s", + "CYCLES": 7.2379777102500000e+10, + "items_per_second": 1.4960375250262581e-01 + }, + { + "name": "frodoPIR/server_setup/2^18/256B/process_time/real_time_stddev", + "family_index": 27, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 4.4200621786951666e-01, + "cpu_time": 1.2255356656628116e+00, + "time_unit": "s", + "CYCLES": 3.7089811187230949e+09, + "items_per_second": 9.4385097162827496e-03 + }, + { + "name": "frodoPIR/server_setup/2^18/256B/process_time/real_time_cv", + "family_index": 27, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 6.6016523686649828e-02, + "cpu_time": 2.7214706247501514e-02, + "time_unit": "s", + "CYCLES": 5.0771522718590825e-02, + "items_per_second": 6.2959066498182309e-02 + }, + { + "name": "frodoPIR/server_setup/2^18/256B/process_time/real_time_min", + "family_index": 27, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 6.0568969600026321e+00, + "cpu_time": 4.3488345366989961e+01, + "time_unit": "s", + "CYCLES": 7.0097049994000000e+10, + "items_per_second": 1.2964585350451530e-01 + }, + { + "name": "frodoPIR/server_setup/2^18/256B/process_time/real_time_max", + "family_index": 27, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 7.7133203490011510e+00, + "cpu_time": 4.7975228871000581e+01, + "time_unit": "s", + "CYCLES": 8.3064550193000000e+10, + "items_per_second": 1.6510104210185630e-01 + }, + { + "name": "frodoPIR/client_setup/2^19/256B/process_time/real_time_mean", + "family_index": 18, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 7.5739208281982428e+03, + "cpu_time": 7.5735056151985191e+03, + "time_unit": "ms", + "CYCLES": 2.4381041459600002e+10, + "items_per_second": 1.3204007035505214e-01 + }, + { + "name": "frodoPIR/client_setup/2^19/256B/process_time/real_time_median", + "family_index": 18, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 7.5615645545003645e+03, + "cpu_time": 7.5612071534997085e+03, + "time_unit": "ms", + "CYCLES": 2.4414211170500000e+10, + "items_per_second": 1.3224784435993453e-01 + }, + { + "name": "frodoPIR/client_setup/2^19/256B/process_time/real_time_stddev", + "family_index": 18, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 6.2617416246620039e+01, + "cpu_time": 6.2815014941188238e+01, + "time_unit": "ms", + "CYCLES": 6.0975089157975033e+07, + "items_per_second": 1.0831310648780443e-03 + }, + { + "name": "frodoPIR/client_setup/2^19/256B/process_time/real_time_cv", + "family_index": 18, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 8.2675034063586939e-03, + "cpu_time": 8.2940474507777456e-03, + "time_unit": "ms", + "CYCLES": 2.5009222538344921e-03, + "items_per_second": 8.2030482259327388e-03 + }, + { + "name": "frodoPIR/client_setup/2^19/256B/process_time/real_time_min", + "family_index": 18, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 7.5113229009948554e+03, + "cpu_time": 7.5106534159858711e+03, + "time_unit": "ms", + "CYCLES": 2.4236685054000000e+10, + "items_per_second": 1.2983193884425981e-01 + }, + { + "name": "frodoPIR/client_setup/2^19/256B/process_time/real_time_max", + "family_index": 18, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 7.7022650119979517e+03, + "cpu_time": 7.7023325390036916e+03, + "time_unit": "ms", + "CYCLES": 2.4417969159000000e+10, + "items_per_second": 1.3313234075818423e-01 + }, + { + "name": "frodoPIR/server_setup/2^19/256B/process_time/real_time_mean", + "family_index": 28, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.4177798043599978e+01, + "cpu_time": 1.0365879490240005e+02, + "time_unit": "s", + "CYCLES": 1.6031954788380002e+11, + "items_per_second": 7.0574357348983388e-02 + }, + { + "name": "frodoPIR/server_setup/2^19/256B/process_time/real_time_median", + "family_index": 28, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.4125514323000971e+01, + "cpu_time": 1.0344201871600671e+02, + "time_unit": "s", + "CYCLES": 1.6102227325800000e+11, + "items_per_second": 7.0802710970220978e-02 + }, + { + "name": "frodoPIR/server_setup/2^19/256B/process_time/real_time_stddev", + "family_index": 28, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 3.6386459336909327e-01, + "cpu_time": 2.6419688931708594e+00, + "time_unit": "s", + "CYCLES": 7.7105038200968676e+09, + "items_per_second": 1.7988873732714193e-03 + }, + { + "name": "frodoPIR/server_setup/2^19/256B/process_time/real_time_cv", + "family_index": 28, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 2.5664393881907915e-02, + "cpu_time": 2.5487165808346562e-02, + "time_unit": "s", + "CYCLES": 4.8094595586593465e-02, + "items_per_second": 2.5489249082015650e-02 + }, + { + "name": "frodoPIR/server_setup/2^19/256B/process_time/real_time_min", + "family_index": 28, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.3737517675002891e+01, + "cpu_time": 1.0048534050799208e+02, + "time_unit": "s", + "CYCLES": 1.4598025152500000e+11, + "items_per_second": 6.7556819172655477e-02 + }, + { + "name": "frodoPIR/server_setup/2^19/256B/process_time/real_time_max", + "family_index": 28, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.4802354702998855e+01, + "cpu_time": 1.0740523553099774e+02, + "time_unit": "s", + "CYCLES": 1.7393567681900000e+11, + "items_per_second": 7.2793354931919282e-02 + }, + { + "name": "frodoPIR/server_setup/2^17/256B/process_time/real_time_mean", + "family_index": 26, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 3.3935977132005064e+00, + "cpu_time": 2.2218088060501032e+01, + "time_unit": "s", + "CYCLES": 3.5674169701099998e+10, + "items_per_second": 2.9492839506398616e-01 + }, + { + "name": "frodoPIR/server_setup/2^17/256B/process_time/real_time_median", + "family_index": 26, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 3.3722993129995302e+00, + "cpu_time": 2.2592620591494779e+01, + "time_unit": "s", + "CYCLES": 3.6117868318000000e+10, + "items_per_second": 2.9653763254530718e-01 + }, + { + "name": "frodoPIR/server_setup/2^17/256B/process_time/real_time_stddev", + "family_index": 26, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.0529061056977884e-01, + "cpu_time": 8.8214276224531307e-01, + "time_unit": "s", + "CYCLES": 1.8643142531520638e+09, + "items_per_second": 9.1659947033347570e-03 + }, + { + "name": "frodoPIR/server_setup/2^17/256B/process_time/real_time_cv", + "family_index": 26, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 3.1026249858731526e-02, + "cpu_time": 3.9703810689884364e-02, + "time_unit": "s", + "CYCLES": 5.2259499485830460e-02, + "items_per_second": 3.1078712178073425e-02 + }, + { + "name": "frodoPIR/server_setup/2^17/256B/process_time/real_time_min", + "family_index": 26, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 3.2250516610001796e+00, + "cpu_time": 2.0670847209003114e+01, + "time_unit": "s", + "CYCLES": 3.2735787523000000e+10, + "items_per_second": 2.8390610605651384e-01 + }, + { + "name": "frodoPIR/server_setup/2^17/256B/process_time/real_time_max", + "family_index": 26, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 3.5222912740064203e+00, + "cpu_time": 2.3415086480003083e+01, + "time_unit": "s", + "CYCLES": 3.8223364836000000e+10, + "items_per_second": 3.1007255235405184e-01 + }, + { + "name": "frodoPIR/client_query/2^20/256B/process_time/real_time_mean", + "family_index": 14, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 4.4614832999014016e+02, + "cpu_time": 4.4462098879886491e+02, + "time_unit": "us", + "CYCLES": 1.0387364076452599e+06, + "items_per_second": 2.2417185513039194e+03 + }, + { + "name": "frodoPIR/client_query/2^20/256B/process_time/real_time_median", + "family_index": 14, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 4.4765854587123215e+02, + "cpu_time": 4.4614401905311826e+02, + "time_unit": "us", + "CYCLES": 1.0373700229357798e+06, + "items_per_second": 2.2338455037456115e+03 + }, + { + "name": "frodoPIR/client_query/2^20/256B/process_time/real_time_stddev", + "family_index": 14, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 5.4853870497653148e+00, + "cpu_time": 5.4117392558714927e+00, + "time_unit": "us", + "CYCLES": 3.1563530673394023e+04, + "items_per_second": 2.8155949528335682e+01 + }, + { + "name": "frodoPIR/client_query/2^20/256B/process_time/real_time_cv", + "family_index": 14, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 1.2294985055500579e-02, + "cpu_time": 1.2171578472917355e-02, + "time_unit": "us", + "CYCLES": 3.0386468059732556e-02, + "items_per_second": 1.2559984174622847e-02 + }, + { + "name": "frodoPIR/client_query/2^20/256B/process_time/real_time_min", + "family_index": 14, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 4.3203365442420306e+02, + "cpu_time": 4.3071196323970190e+02, + "time_unit": "us", + "CYCLES": 9.9244489602446486e+05, + "items_per_second": 2.2121106588226376e+03 + }, + { + "name": "frodoPIR/client_query/2^20/256B/process_time/real_time_max", + "family_index": 14, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 4.5205695113472984e+02, + "cpu_time": 4.5050218945585584e+02, + "time_unit": "us", + "CYCLES": 1.0969591284403671e+06, + "items_per_second": 2.3146344960851702e+03 + }, + { + "name": "frodoPIR/client_process_response/2^18/256B/process_time/real_time_mean", + "family_index": 7, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 5.9770448701872772e+02, + "cpu_time": 7.7935868426792172e+02, + "time_unit": "us", + "CYCLES": 9.4559038431372552e+04, + "items_per_second": 1.6742429179312167e+03 + }, + { + "name": "frodoPIR/client_process_response/2^18/256B/process_time/real_time_median", + "family_index": 7, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 5.9703969005461067e+02, + "cpu_time": 7.8152528799632012e+02, + "time_unit": "us", + "CYCLES": 9.3835764705882350e+04, + "items_per_second": 1.6749894768772233e+03 + }, + { + "name": "frodoPIR/client_process_response/2^18/256B/process_time/real_time_stddev", + "family_index": 7, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.6710127196565956e+01, + "cpu_time": 2.2399934167343261e+01, + "time_unit": "us", + "CYCLES": 4.3256816576106376e+03, + "items_per_second": 4.6728543118753677e+01 + }, + { + "name": "frodoPIR/client_process_response/2^18/256B/process_time/real_time_cv", + "family_index": 7, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 2.7957172079992074e-02, + "cpu_time": 2.8741495564887795e-02, + "time_unit": "us", + "CYCLES": 4.5745829582965324e-02, + "items_per_second": 2.7910252818326951e-02 + }, + { + "name": "frodoPIR/client_process_response/2^18/256B/process_time/real_time_min", + "family_index": 7, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 5.7389307437594709e+02, + "cpu_time": 7.5151142327562343e+02, + "time_unit": "us", + "CYCLES": 8.8641556862745099e+04, + "items_per_second": 1.6074698960344936e+03 + }, + { + "name": "frodoPIR/client_process_response/2^18/256B/process_time/real_time_max", + "family_index": 7, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_process_response/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 6.2209563144350273e+02, + "cpu_time": 8.1703085480851360e+02, + "time_unit": "us", + "CYCLES": 1.0096329803921569e+05, + "items_per_second": 1.7424848715719436e+03 + }, + { + "name": "frodoPIR/client_prepare_query/2^17/256B/process_time/real_time_mean", + "family_index": 1, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.8463361474914564e+01, + "cpu_time": 2.4046430266223524e+02, + "time_unit": "ms", + "CYCLES": 4.3155175896250004e+08, + "items_per_second": 5.4169817932771551e+01 + }, + { + "name": "frodoPIR/client_prepare_query/2^17/256B/process_time/real_time_median", + "family_index": 1, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.8450404625127703e+01, + "cpu_time": 2.4146060487419163e+02, + "time_unit": "ms", + "CYCLES": 4.3449306756250000e+08, + "items_per_second": 5.4200419013943780e+01 + }, + { + "name": "frodoPIR/client_prepare_query/2^17/256B/process_time/real_time_stddev", + "family_index": 1, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 2.4375233163806137e-01, + "cpu_time": 5.2632846323842220e+00, + "time_unit": "ms", + "CYCLES": 1.0593356282975771e+07, + "items_per_second": 7.1538142574899066e-01 + }, + { + "name": "frodoPIR/client_prepare_query/2^17/256B/process_time/real_time_cv", + "family_index": 1, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 1.3201947650173995e-02, + "cpu_time": 2.1888008216243305e-02, + "time_unit": "ms", + "CYCLES": 2.4547128039620125e-02, + "items_per_second": 1.3206273401856879e-02 + }, + { + "name": "frodoPIR/client_prepare_query/2^17/256B/process_time/real_time_min", + "family_index": 1, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.8084738624565944e+01, + "cpu_time": 2.2938320912362542e+02, + "time_unit": "ms", + "CYCLES": 4.0694117750000000e+08, + "items_per_second": 5.3249372208212641e+01 + }, + { + "name": "frodoPIR/client_prepare_query/2^17/256B/process_time/real_time_max", + "family_index": 1, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.8779564124997705e+01, + "cpu_time": 2.4607893900065392e+02, + "time_unit": "ms", + "CYCLES": 4.4588623975000000e+08, + "items_per_second": 5.5295242069001773e+01 + }, + { + "name": "frodoPIR/server_setup/2^20/256B/process_time/real_time_mean", + "family_index": 29, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 2.8485062221799307e+01, + "cpu_time": 2.1336153385680373e+02, + "time_unit": "s", + "CYCLES": 3.0509052506500000e+11, + "items_per_second": 3.5120933758718088e-02 + }, + { + "name": "frodoPIR/server_setup/2^20/256B/process_time/real_time_median", + "family_index": 29, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 2.8650050181498955e+01, + "cpu_time": 2.1343651316500473e+02, + "time_unit": "s", + "CYCLES": 3.0276175407150000e+11, + "items_per_second": 3.4904319018897893e-02 + }, + { + "name": "frodoPIR/server_setup/2^20/256B/process_time/real_time_stddev", + "family_index": 29, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 6.0915889162822923e-01, + "cpu_time": 5.9287587728647448e+00, + "time_unit": "s", + "CYCLES": 1.1025933562233030e+10, + "items_per_second": 7.6993012114469350e-04 + }, + { + "name": "frodoPIR/server_setup/2^20/256B/process_time/real_time_cv", + "family_index": 29, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 2.1385204879842128e-02, + "cpu_time": 2.7787383534858698e-02, + "time_unit": "s", + "CYCLES": 3.6139875402174282e-02, + "items_per_second": 2.1922256578772576e-02 + }, + { + "name": "frodoPIR/server_setup/2^20/256B/process_time/real_time_min", + "family_index": 29, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 2.7087251325996476e+01, + "cpu_time": 2.0609326159099874e+02, + "time_unit": "s", + "CYCLES": 2.9098113703300000e+11, + "items_per_second": 3.4280063631722604e-02 + }, + { + "name": "frodoPIR/server_setup/2^20/256B/process_time/real_time_max", + "family_index": 29, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 2.9171474438997393e+01, + "cpu_time": 2.2224652409400733e+02, + "time_unit": "s", + "CYCLES": 3.2911213194400000e+11, + "items_per_second": 3.6917736242963455e-02 + }, + { + "name": "frodoPIR/client_prepare_query/2^18/256B/process_time/real_time_mean", + "family_index": 2, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 3.5438512475593598e+01, + "cpu_time": 4.8617289200046798e+02, + "time_unit": "ms", + "CYCLES": 8.6590119990000010e+08, + "items_per_second": 2.8225655991268582e+01 + }, + { + "name": "frodoPIR/client_prepare_query/2^18/256B/process_time/real_time_median", + "family_index": 2, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 3.5468733999550750e+01, + "cpu_time": 4.8760428700006742e+02, + "time_unit": "ms", + "CYCLES": 8.7254717075000000e+08, + "items_per_second": 2.8194871575798793e+01 + }, + { + "name": "frodoPIR/client_prepare_query/2^18/256B/process_time/real_time_stddev", + "family_index": 2, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 6.1925455297139709e-01, + "cpu_time": 7.1714231242868420e+00, + "time_unit": "ms", + "CYCLES": 1.8131560930317428e+07, + "items_per_second": 4.9397430403134523e-01 + }, + { + "name": "frodoPIR/client_prepare_query/2^18/256B/process_time/real_time_cv", + "family_index": 2, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 1.7474056039961494e-02, + "cpu_time": 1.4750767149477227e-02, + "time_unit": "ms", + "CYCLES": 2.0939526278992773e-02, + "items_per_second": 1.7500897204449486e-02 + }, + { + "name": "frodoPIR/client_prepare_query/2^18/256B/process_time/real_time_min", + "family_index": 2, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 3.4509457750573347e+01, + "cpu_time": 4.7528948950093763e+02, + "time_unit": "ms", + "CYCLES": 8.2453913175000000e+08, + "items_per_second": 2.7414627441367184e+01 + }, + { + "name": "frodoPIR/client_prepare_query/2^18/256B/process_time/real_time_max", + "family_index": 2, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 3.6476877248787787e+01, + "cpu_time": 4.9340463624685071e+02, + "time_unit": "ms", + "CYCLES": 8.8194557475000000e+08, + "items_per_second": 2.8977563403858056e+01 + }, + { + "name": "frodoPIR/client_setup/2^18/256B/process_time/real_time_mean", + "family_index": 17, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 3.7712566806003451e+03, + "cpu_time": 3.7708353435024037e+03, + "time_unit": "ms", + "CYCLES": 1.2366928862400002e+10, + "items_per_second": 2.6589549207247881e-01 + }, + { + "name": "frodoPIR/client_setup/2^18/256B/process_time/real_time_median", + "family_index": 17, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 3.8333885624997492e+03, + "cpu_time": 3.8331456810010422e+03, + "time_unit": "ms", + "CYCLES": 1.2369701332000000e+10, + "items_per_second": 2.6086904147080714e-01 + }, + { + "name": "frodoPIR/client_setup/2^18/256B/process_time/real_time_stddev", + "family_index": 17, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 2.0803574633449830e+02, + "cpu_time": 2.0798729853868394e+02, + "time_unit": "ms", + "CYCLES": 1.3942834329194970e+07, + "items_per_second": 1.4750201183876054e-02 + }, + { + "name": "frodoPIR/client_setup/2^18/256B/process_time/real_time_cv", + "family_index": 17, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 5.5163507539715162e-02, + "cpu_time": 5.5156823247949745e-02, + "time_unit": "ms", + "CYCLES": 1.1274290071794865e-03, + "items_per_second": 5.5473679034225176e-02 + }, + { + "name": "frodoPIR/client_setup/2^18/256B/process_time/real_time_min", + "family_index": 17, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 3.5207733499992173e+03, + "cpu_time": 3.5206432280101581e+03, + "time_unit": "ms", + "CYCLES": 1.2348132135000000e+10, + "items_per_second": 2.4664207628379439e-01 + }, + { + "name": "frodoPIR/client_setup/2^18/256B/process_time/real_time_max", + "family_index": 17, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 4.0544582460024685e+03, + "cpu_time": 4.0542361780026113e+03, + "time_unit": "ms", + "CYCLES": 1.2385266100000000e+10, + "items_per_second": 2.8402850754372538e-01 + }, + { + "name": "frodoPIR/client_prepare_query/2^20/256B/process_time/real_time_mean", + "family_index": 4, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.3834875560023650e+02, + "cpu_time": 1.9645069176011020e+03, + "time_unit": "ms", + "CYCLES": 3.4664217314000001e+09, + "items_per_second": 7.2287942061247383e+00 + }, + { + "name": "frodoPIR/client_prepare_query/2^20/256B/process_time/real_time_median", + "family_index": 4, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.3899626050078950e+02, + "cpu_time": 1.9762574825035699e+03, + "time_unit": "ms", + "CYCLES": 3.4696032380000000e+09, + "items_per_second": 7.1944556351130249e+00 + }, + { + "name": "frodoPIR/client_prepare_query/2^20/256B/process_time/real_time_stddev", + "family_index": 4, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.4156951144296084e+00, + "cpu_time": 2.1104332453316115e+01, + "time_unit": "ms", + "CYCLES": 3.5245440807878308e+07, + "items_per_second": 7.4313251363943317e-02 + }, + { + "name": "frodoPIR/client_prepare_query/2^20/256B/process_time/real_time_cv", + "family_index": 4, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 1.0232799769593218e-02, + "cpu_time": 1.0742814018230606e-02, + "time_unit": "ms", + "CYCLES": 1.0167672470032538e-02, + "items_per_second": 1.0280172494187199e-02 + }, + { + "name": "frodoPIR/client_prepare_query/2^20/256B/process_time/real_time_min", + "family_index": 4, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.3616252000065288e+02, + "cpu_time": 1.9289290190208703e+03, + "time_unit": "ms", + "CYCLES": 3.3975880380000000e+09, + "items_per_second": 7.1496081090837782e+00 + }, + { + "name": "frodoPIR/client_prepare_query/2^20/256B/process_time/real_time_max", + "family_index": 4, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.3986780600316706e+02, + "cpu_time": 1.9820629470050335e+03, + "time_unit": "ms", + "CYCLES": 3.5103291460000000e+09, + "items_per_second": 7.3441648993805719e+00 + }, + { + "name": "frodoPIR/server_respond/2^20/256B/process_time/real_time_mean", + "family_index": 24, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 9.9546000299960738e+01, + "cpu_time": 1.1732740358511364e+03, + "time_unit": "ms", + "CYCLES": 1.9787832042000000e+09, + "items_per_second": 1.0056504295202640e+01 + }, + { + "name": "frodoPIR/server_respond/2^20/256B/process_time/real_time_median", + "family_index": 24, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 9.9583197000356449e+01, + "cpu_time": 1.1712973662579316e+03, + "time_unit": "ms", + "CYCLES": 1.9779057582500000e+09, + "items_per_second": 1.0042164516504959e+01 + }, + { + "name": "frodoPIR/server_respond/2^20/256B/process_time/real_time_stddev", + "family_index": 24, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 3.4524809076831930e+00, + "cpu_time": 3.1152096472182116e+01, + "time_unit": "ms", + "CYCLES": 7.9324378255252436e+07, + "items_per_second": 3.4920618033990491e-01 + }, + { + "name": "frodoPIR/server_respond/2^20/256B/process_time/real_time_cv", + "family_index": 24, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 3.4682266462538670e-02, + "cpu_time": 2.6551424066572165e-02, + "time_unit": "ms", + "CYCLES": 4.0087452777487265e-02, + "items_per_second": 3.4724410201514101e-02 + }, + { + "name": "frodoPIR/server_respond/2^20/256B/process_time/real_time_min", + "family_index": 24, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 9.4800969498464838e+01, + "cpu_time": 1.1114197394999792e+03, + "time_unit": "ms", + "CYCLES": 1.8385129920000000e+09, + "items_per_second": 9.5904767179693859e+00 + }, + { + "name": "frodoPIR/server_respond/2^20/256B/process_time/real_time_max", + "family_index": 24, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.0427010350031196e+02, + "cpu_time": 1.2162013344968727e+03, + "time_unit": "ms", + "CYCLES": 2.0727546990000000e+09, + "items_per_second": 1.0548415330459184e+01 + }, + { + "name": "frodoPIR/server_respond/2^17/256B/process_time/real_time_mean", + "family_index": 21, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.0226222038377625e+01, + "cpu_time": 1.0296949509994681e+02, + "time_unit": "ms", + "CYCLES": 1.6963182595384616e+08, + "items_per_second": 9.7903458140478918e+01 + }, + { + "name": "frodoPIR/server_respond/2^17/256B/process_time/real_time_median", + "family_index": 21, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.0154559961497750e+01, + "cpu_time": 1.0391115746125043e+02, + "time_unit": "ms", + "CYCLES": 1.7105264338461536e+08, + "items_per_second": 9.8486312231152098e+01 + }, + { + "name": "frodoPIR/server_respond/2^17/256B/process_time/real_time_stddev", + "family_index": 21, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 3.7430585164799351e-01, + "cpu_time": 3.2183832976759974e+00, + "time_unit": "ms", + "CYCLES": 5.7074443067484731e+06, + "items_per_second": 3.5123876094732149e+00 + }, + { + "name": "frodoPIR/server_respond/2^17/256B/process_time/real_time_cv", + "family_index": 21, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 3.6602554711141072e-02, + "cpu_time": 3.1255696597833074e-02, + "time_unit": "ms", + "CYCLES": 3.3646070097137132e-02, + "items_per_second": 3.5876032125784454e-02 + }, + { + "name": "frodoPIR/server_respond/2^17/256B/process_time/real_time_min", + "family_index": 21, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 9.7321661537884783e+00, + "cpu_time": 9.6471812692470849e+01, + "time_unit": "ms", + "CYCLES": 1.5711807038461539e+08, + "items_per_second": 9.1474659541396804e+01 + }, + { + "name": "frodoPIR/server_respond/2^17/256B/process_time/real_time_max", + "family_index": 21, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.0931989307349657e+01, + "cpu_time": 1.0601175407646224e+02, + "time_unit": "ms", + "CYCLES": 1.7633267076923078e+08, + "items_per_second": 1.0275204761179774e+02 + }, + { + "name": "frodoPIR/server_respond/2^18/256B/process_time/real_time_mean", + "family_index": 22, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 2.0064326028659707e+01, + "cpu_time": 2.2675649368622027e+02, + "time_unit": "ms", + "CYCLES": 3.7278863710000002e+08, + "items_per_second": 4.9850930587628447e+01 + }, + { + "name": "frodoPIR/server_respond/2^18/256B/process_time/real_time_median", + "family_index": 22, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 2.0081433285927883e+01, + "cpu_time": 2.2644882921511976e+02, + "time_unit": "ms", + "CYCLES": 3.7404163750000000e+08, + "items_per_second": 4.9797432301701448e+01 + }, + { + "name": "frodoPIR/server_respond/2^18/256B/process_time/real_time_stddev", + "family_index": 22, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 3.1871637920692364e-01, + "cpu_time": 5.8540065837569468e+00, + "time_unit": "ms", + "CYCLES": 9.9586279880303908e+06, + "items_per_second": 7.8566169052180934e-01 + }, + { + "name": "frodoPIR/server_respond/2^18/256B/process_time/real_time_cv", + "family_index": 22, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 1.5884728884073752e-02, + "cpu_time": 2.5816268758581045e-02, + "time_unit": "ms", + "CYCLES": 2.6713872143476848e-02, + "items_per_second": 1.5760221148545375e-02 + }, + { + "name": "frodoPIR/server_respond/2^18/256B/process_time/real_time_min", + "family_index": 22, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.9611815285835682e+01, + "cpu_time": 2.1783294514274789e+02, + "time_unit": "ms", + "CYCLES": 3.5738698642857140e+08, + "items_per_second": 4.8273490009502638e+01 + }, + { + "name": "frodoPIR/server_respond/2^18/256B/process_time/real_time_max", + "family_index": 22, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^18/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 2.0715303571445734e+01, + "cpu_time": 2.3544942942680791e+02, + "time_unit": "ms", + "CYCLES": 3.8625175300000000e+08, + "items_per_second": 5.0989670534080233e+01 + }, + { + "name": "frodoPIR/client_prepare_query/2^19/256B/process_time/real_time_mean", + "family_index": 3, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 6.9319429749702977e+01, + "cpu_time": 9.5747442710016912e+02, + "time_unit": "ms", + "CYCLES": 1.6853161189000001e+09, + "items_per_second": 1.4432595715616131e+01 + }, + { + "name": "frodoPIR/client_prepare_query/2^19/256B/process_time/real_time_median", + "family_index": 3, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 6.8819328998870333e+01, + "cpu_time": 9.5303603049978847e+02, + "time_unit": "ms", + "CYCLES": 1.6915861252500000e+09, + "items_per_second": 1.4530924310684195e+01 + }, + { + "name": "frodoPIR/client_prepare_query/2^19/256B/process_time/real_time_stddev", + "family_index": 3, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.5791088449609041e+00, + "cpu_time": 2.4381559707259008e+01, + "time_unit": "ms", + "CYCLES": 6.5427505009686090e+07, + "items_per_second": 3.2325383027145249e-01 + }, + { + "name": "frodoPIR/client_prepare_query/2^19/256B/process_time/real_time_cv", + "family_index": 3, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 2.2780176505529753e-02, + "cpu_time": 2.5464450033513279e-02, + "time_unit": "ms", + "CYCLES": 3.8822096505188829e-02, + "items_per_second": 2.2397483906632987e-02 + }, + { + "name": "frodoPIR/client_prepare_query/2^19/256B/process_time/real_time_min", + "family_index": 3, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 6.7342775500947027e+01, + "cpu_time": 9.0529490300104953e+02, + "time_unit": "ms", + "CYCLES": 1.5164779230000000e+09, + "items_per_second": 1.3795626049874905e+01 + }, + { + "name": "frodoPIR/client_prepare_query/2^19/256B/process_time/real_time_max", + "family_index": 3, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_prepare_query/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 7.2486742999899434e+01, + "cpu_time": 9.9224911849887576e+02, + "time_unit": "ms", + "CYCLES": 1.7479777250000000e+09, + "items_per_second": 1.4849402813608970e+01 + }, + { + "name": "frodoPIR/server_setup/2^16/256B/process_time/real_time_mean", + "family_index": 25, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.7240043763995345e+00, + "cpu_time": 1.1308576625100978e+01, + "time_unit": "s", + "CYCLES": 1.8694712613000000e+10, + "items_per_second": 5.8037411453617505e-01 + }, + { + "name": "frodoPIR/server_setup/2^16/256B/process_time/real_time_median", + "family_index": 25, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.7335794399987208e+00, + "cpu_time": 1.1412752398005978e+01, + "time_unit": "s", + "CYCLES": 1.8867256801500000e+10, + "items_per_second": 5.7684117539585711e-01 + }, + { + "name": "frodoPIR/server_setup/2^16/256B/process_time/real_time_stddev", + "family_index": 25, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 4.2792627526659348e-02, + "cpu_time": 3.0594967894855085e-01, + "time_unit": "s", + "CYCLES": 4.8409205410763425e+08, + "items_per_second": 1.4739502174297033e-02 + }, + { + "name": "frodoPIR/server_setup/2^16/256B/process_time/real_time_cv", + "family_index": 25, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 2.4821646692120836e-02, + "cpu_time": 2.7054658520812645e-02, + "time_unit": "s", + "CYCLES": 2.5894597265485882e-02, + "items_per_second": 2.5396553369849358e-02 + }, + { + "name": "frodoPIR/server_setup/2^16/256B/process_time/real_time_min", + "family_index": 25, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.6393869099993026e+00, + "cpu_time": 1.0537715104001109e+01, + "time_unit": "s", + "CYCLES": 1.7467902828000000e+10, + "items_per_second": 5.6296458736974386e-01 + }, + { + "name": "frodoPIR/server_setup/2^16/256B/process_time/real_time_max", + "family_index": 25, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_setup/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.7763106640013575e+00, + "cpu_time": 1.1512138252001023e+01, + "time_unit": "s", + "CYCLES": 1.9072573364000000e+10, + "items_per_second": 6.0998413120208783e-01 + }, + { + "name": "frodoPIR/server_respond/2^19/256B/process_time/real_time_mean", + "family_index": 23, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 4.8253633700248130e+01, + "cpu_time": 5.5408527119919506e+02, + "time_unit": "ms", + "CYCLES": 9.2053334360000002e+08, + "items_per_second": 2.0752846650270385e+01 + }, + { + "name": "frodoPIR/server_respond/2^19/256B/process_time/real_time_median", + "family_index": 23, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 4.8059337166099191e+01, + "cpu_time": 5.5195918816510436e+02, + "time_unit": "ms", + "CYCLES": 9.1652231116666675e+08, + "items_per_second": 2.0810581859634965e+01 + }, + { + "name": "frodoPIR/server_respond/2^19/256B/process_time/real_time_stddev", + "family_index": 23, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.9078129900866703e+00, + "cpu_time": 1.4985713449024640e+01, + "time_unit": "ms", + "CYCLES": 2.1216028411976956e+07, + "items_per_second": 8.1601243561999626e-01 + }, + { + "name": "frodoPIR/server_respond/2^19/256B/process_time/real_time_cv", + "family_index": 23, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 3.9537188057960908e-02, + "cpu_time": 2.7045861400703499e-02, + "time_unit": "ms", + "CYCLES": 2.3047539298257046e-02, + "items_per_second": 3.9320506211583485e-02 + }, + { + "name": "frodoPIR/server_respond/2^19/256B/process_time/real_time_min", + "family_index": 23, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 4.5723660332441796e+01, + "cpu_time": 5.3454960733264068e+02, + "time_unit": "ms", + "CYCLES": 8.9852621533333337e+08, + "items_per_second": 1.9405150380294536e+01 + }, + { + "name": "frodoPIR/server_respond/2^19/256B/process_time/real_time_max", + "family_index": 23, + "per_family_instance_index": 0, + "run_name": "frodoPIR/server_respond/2^19/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 5.1532710667136904e+01, + "cpu_time": 5.7723068466778693e+02, + "time_unit": "ms", + "CYCLES": 9.6582786433333337e+08, + "items_per_second": 2.1870515018468048e+01 + }, + { + "name": "frodoPIR/client_query/2^16/256B/process_time/real_time_mean", + "family_index": 10, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 3.1549750652385370e+01, + "cpu_time": 2.9817645678835781e+01, + "time_unit": "us", + "CYCLES": 4.4546428542234338e+04, + "items_per_second": 3.1701900536574245e+04 + }, + { + "name": "frodoPIR/client_query/2^16/256B/process_time/real_time_median", + "family_index": 10, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 3.1331213862066285e+01, + "cpu_time": 2.9572663238803081e+01, + "time_unit": "us", + "CYCLES": 4.4152198228882829e+04, + "items_per_second": 3.1917140681773613e+04 + }, + { + "name": "frodoPIR/client_query/2^16/256B/process_time/real_time_stddev", + "family_index": 10, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 4.5632211353807384e-01, + "cpu_time": 4.6281805446797258e-01, + "time_unit": "us", + "CYCLES": 1.2567652447286018e+03, + "items_per_second": 4.5548343541466284e+02 + }, + { + "name": "frodoPIR/client_query/2^16/256B/process_time/real_time_cv", + "family_index": 10, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 1.4463572741535211e-02, + "cpu_time": 1.5521616275575890e-02, + "time_unit": "us", + "CYCLES": 2.8212480458159880e-02, + "items_per_second": 1.4367701232586199e-02 + }, + { + "name": "frodoPIR/client_query/2^16/256B/process_time/real_time_min", + "family_index": 10, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 3.1049363541446535e+01, + "cpu_time": 2.9311819778345900e+01, + "time_unit": "us", + "CYCLES": 4.2985038601271568e+04, + "items_per_second": 3.1053747401912715e+04 + }, + { + "name": "frodoPIR/client_query/2^16/256B/process_time/real_time_max", + "family_index": 10, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^16/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 3.2202232698601982e+01, + "cpu_time": 3.0489729598790937e+01, + "time_unit": "us", + "CYCLES": 4.6431719118982743e+04, + "items_per_second": 3.2206779332695194e+04 + }, + { + "name": "frodoPIR/client_setup/2^20/256B/process_time/real_time_mean", + "family_index": 19, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.4626545454400184e+04, + "cpu_time": 1.4625866297905304e+04, + "time_unit": "ms", + "CYCLES": 4.8732424190800003e+10, + "items_per_second": 6.8425612784389300e-02 + }, + { + "name": "frodoPIR/client_setup/2^20/256B/process_time/real_time_median", + "family_index": 19, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.4770910181501677e+04, + "cpu_time": 1.4769835088511172e+04, + "time_unit": "ms", + "CYCLES": 4.8735385480000000e+10, + "items_per_second": 6.7701127114830256e-02 + }, + { + "name": "frodoPIR/client_setup/2^20/256B/process_time/real_time_stddev", + "family_index": 19, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 4.3878843092272410e+02, + "cpu_time": 4.3861576085045516e+02, + "time_unit": "ms", + "CYCLES": 4.8772069652347542e+07, + "items_per_second": 2.1030359447048457e-03 + }, + { + "name": "frodoPIR/client_setup/2^20/256B/process_time/real_time_cv", + "family_index": 19, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 2.9999457649839040e-02, + "cpu_time": 2.9989044882303695e-02, + "time_unit": "ms", + "CYCLES": 1.0008135335396473e-03, + "items_per_second": 3.0734630778266624e-02 + }, + { + "name": "frodoPIR/client_setup/2^20/256B/process_time/real_time_min", + "family_index": 19, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.3862490396000794e+04, + "cpu_time": 1.3862446214014199e+04, + "time_unit": "ms", + "CYCLES": 4.8632218443000000e+10, + "items_per_second": 6.6229178406376488e-02 + }, + { + "name": "frodoPIR/client_setup/2^20/256B/process_time/real_time_max", + "family_index": 19, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_setup/2^20/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 1.5099085087000276e+04, + "cpu_time": 1.5097990868001943e+04, + "time_unit": "ms", + "CYCLES": 4.8794284478000000e+10, + "items_per_second": 7.2137110391686271e-02 + }, + { + "name": "frodoPIR/client_query/2^17/256B/process_time/real_time_mean", + "family_index": 11, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "mean", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 5.7421580714538813e+01, + "cpu_time": 5.5816838749405029e+01, + "time_unit": "us", + "CYCLES": 1.2074560191680261e+05, + "items_per_second": 1.7415255823192849e+04 + }, + { + "name": "frodoPIR/client_query/2^17/256B/process_time/real_time_median", + "family_index": 11, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "median", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 5.7408505520635188e+01, + "cpu_time": 5.5832817247280801e+01, + "time_unit": "us", + "CYCLES": 1.2089376835236541e+05, + "items_per_second": 1.7419022040515971e+04 + }, + { + "name": "frodoPIR/client_query/2^17/256B/process_time/real_time_stddev", + "family_index": 11, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "stddev", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 2.0515201819778400e-01, + "cpu_time": 1.7868938394318429e-01, + "time_unit": "us", + "CYCLES": 1.0294054051623225e+03, + "items_per_second": 6.2382007544052442e+01 + }, + { + "name": "frodoPIR/client_query/2^17/256B/process_time/real_time_cv", + "family_index": 11, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "cv", + "aggregate_unit": "percentage", + "iterations": 10, + "real_time": 3.5727337291124187e-03, + "cpu_time": 3.2013526374259052e-03, + "time_unit": "us", + "CYCLES": 8.5254070444041024e-03, + "items_per_second": 3.5820322237801933e-03 + }, + { + "name": "frodoPIR/client_query/2^17/256B/process_time/real_time_min", + "family_index": 11, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "min", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 5.6986077089940594e+01, + "cpu_time": 5.5424630722459426e+01, + "time_unit": "us", + "CYCLES": 1.1904875652528548e+05, + "items_per_second": 1.7336664414045255e+04 + }, + { + "name": "frodoPIR/client_query/2^17/256B/process_time/real_time_max", + "family_index": 11, + "per_family_instance_index": 0, + "run_name": "frodoPIR/client_query/2^17/256B/process_time/real_time", + "run_type": "aggregate", + "repetitions": 10, + "threads": 1, + "aggregate_name": "max", + "aggregate_unit": "time", + "iterations": 10, + "real_time": 5.7681222645681046e+01, + "cpu_time": 5.6009845115021427e+01, + "time_unit": "us", + "CYCLES": 1.2208443270799347e+05, + "items_per_second": 1.7548145986987478e+04 + } + ] +} From 6bc2827d4a15bd641de4aa2142260570dde81307 Mon Sep 17 00:00:00 2001 From: Anjan Roy Date: Mon, 30 Sep 2024 21:28:34 +0400 Subject: [PATCH 97/97] Add project documentation Signed-off-by: Anjan Roy --- README.md | 327 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 327 insertions(+) diff --git a/README.md b/README.md index 7f11627..9d2ef27 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,329 @@ +> [!CAUTION] +> Following implementation of FrodoPIR private information retrieval scheme is designed from scratch, having zero third-party dependencies. It's not yet audited, avoid using it in production! + # frodoPIR FrodoPIR: Simple, Scalable, Single-Server Private Information Retrieval + +## Introduction + +FrodoPIR is a very simple, stateful, single-server index-based *P*rivate *I*nformation *R*etrieval (PIR) scheme, built on top of *L*earning *W*ith *E*rror (LWE) problem, proposed in https://ia.cr/2022/981. + +FrodoPIR protocol can be split into offline and online phases s.t. offline phase can solely be performed by the server, doesn't require any input from clients. As soon as public parameters become available from server, client can begin preprocessing queries, making them ready for quick future use. A simplified description of the protocol is given below. See figure 1 of https://ia.cr/2022/981 for more details. + +- **Offline Phase** + 1) `server_setup`: Server samples pseudo-random matrix $A$, from seed $\mu$ and sets up database as matrix $D$, which has blowup factor of <3.5x, over the original database size. Server prepares public parameter $(\mu, M)$. + 2) `client_setup`: Client downloads public parameter $(\mu, M)$, setups up internal state. + 3) `client_prepare_query`: Client preprocesses a query by storing $(b, c)$ s.t. $b$ is a randomly distributed LWE sample vector. +- **Online Phase** + 1) `client_query`: When client is ready to make a query, it pops a pair of $(b, c)$ from it's internal cache and sends slightly mutated vector $b$, as query to the server. + 2) `server_respond`: Server responds to client's query, returning back response vector $\tilde{c}$. + 3) `client_process_response`: Client decodes server response, obtaining content of queried database row. + +To present a more practical picture, imagine, we have a database with $2^{20}$ entries s.t. each entry is 256 -bytes, meaning database is of size 256 MB. We are setting up both server and client(s), on a `12th Gen Intel(R) Core(TM) i7-1260P` machine, running GNU/Linux kernel `Linux 6.8.0-45-generic x86_64` and this implementation of FrodoPIR is compiled with `GCC 14.0.1`, while also passing `-O3 -march=native -flto` compiler optimization flags. + +| Step | Time Taken +:-- | --: +`server_setup` | 29.43 seconds +`client_setup` | 14.77 seconds +`client_preprocess_query` | 136.54 milliseconds +`client_query` | 449.73 microseconds +`server_respond` | 99.49 milliseconds +`client_process_response` | 628.83 microseconds + +Here I'm maintaining a zero-dependency, header-only C++20 library implementation of FrodoPIR scheme, supporting all parameter sets, as suggested in table 5 of https://ia.cr/2022/981. Using this library is very easy, follow [here](#usage). + +## Prerequisites + +- A C++ compiler with support for compiling C++20 code. + +```bash +$ g++ --version +g++ (Ubuntu 14-20240412-0ubuntu1) 14.0.1 20240412 (experimental) [master r14-9935-g67e1433a94f] +``` + +- System development utility programs such as `make` and `cmake`. +- For testing functional correctness of this PIR scheme, you need to globally install `google-test` library and its headers. Follow guide @ https://github.com/google/googletest/tree/main/googletest#standalone-cmake-project, if you don't have it installed. +- For benchmarking this PIR scheme, you must have `google-benchmark` header and library globally installed. I found guide @ https://github.com/google/benchmark#installation helpful. + +> [!NOTE] +> If you are on a machine running GNU/Linux kernel and you want to obtain CPU cycle count for digital signature scheme routines, you should consider building `google-benchmark` library with libPFM support, following https://gist.github.com/itzmeanjan/05dc3e946f635d00c5e0b21aae6203a7, a step-by-step guide. Find more about libPFM @ https://perfmon2.sourceforge.net. + +> [!TIP] +> Git submodule based dependencies will generally be imported automatically, but in case that doesn't work, you can manually initialize and update them by issuing `$ git submodule update --init` from inside the root of this repository. + +## Testing + +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 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`. +make debug_ubsan_test -j # Run tests with UndefinedBehaviourSanitizer enabled, with `-O1`. +make release_ubsan_test -j # Run tests with UndefinedBehaviourSanitizer enabled, with `-O3 -march=native`. +``` + +```bash +PASSED TESTS (4/4): + 162 ms: build/test/test.out FrodoPIR.MatrixOperations + 3256 ms: build/test/test.out FrodoPIR.ClientQueryCacheStateTransition + 7399 ms: build/test/test.out FrodoPIR.ParsingDatabaseAndSerializingDatabaseMatrix + 66962 ms: build/test/test.out FrodoPIR.PrivateInformationRetrieval +``` + +## Benchmarking + +Benchmarking of all 6 algorithms of FrodoPIR scheme can be done, by issuing + +```bash +# For switching to non-default compiler, set `CXX` variable, right before invoking following command. + +make benchmark -j # If you haven't built google-benchmark library with libPFM support. +make perf -j # If you have built google-benchmark library with libPFM support. +``` + +> [!CAUTION] +> You must put all the CPU cores on **performance** mode before running benchmark program, follow guide @ https://github.com/google/benchmark/blob/main/docs/reducing_variance.md. + +## On 12th Gen Intel(R) Core(TM) i7-1260P + +Compiled with **gcc version 14.0.1 20240412**. + +```bash +$ uname -srm +Linux 6.8.0-45-generic x86_64 +``` + +> [!NOTE] +> I maintain following benchmark result table as JSON [here](./bench_result_on_Linux_6.8.0-45-generic_x86_64_with_g++_14.json) for ease of benchmark comparison with future iterations. + +```bash +2024-09-29T23:13:04+04:00 +Running ./build/benchmark/perf.out +Run on (16 X 503.267 MHz CPU s) +CPU Caches: + L1 Data 48 KiB (x8) + L1 Instruction 32 KiB (x8) + L2 Unified 1280 KiB (x8) + L3 Unified 18432 KiB (x1) +Load Average: 1.29, 0.63, 0.58 +----------------------------------------------------------------------------------------------------------------------------------------------- +Benchmark Time CPU Iterations CYCLES items_per_second +----------------------------------------------------------------------------------------------------------------------------------------------- +frodoPIR/client_setup/2^17/256B/process_time/real_time_mean 1930 ms 1930 ms 10 6.17317G 0.51913/s +frodoPIR/client_setup/2^17/256B/process_time/real_time_median 1958 ms 1958 ms 10 6.17297G 0.510684/s +frodoPIR/client_setup/2^17/256B/process_time/real_time_stddev 92.0 ms 92.0 ms 10 5.22393M 0.0255016/s +frodoPIR/client_setup/2^17/256B/process_time/real_time_cv 4.76 % 4.76 % 10 0.08% 4.91% +frodoPIR/client_setup/2^17/256B/process_time/real_time_min 1770 ms 1770 ms 10 6.1659G 0.490406/s +frodoPIR/client_setup/2^17/256B/process_time/real_time_max 2039 ms 2039 ms 10 6.18239G 0.564877/s +frodoPIR/client_process_response/2^16/256B/process_time/real_time_mean 553 us 601 us 10 76.5266k 1.81993k/s +frodoPIR/client_process_response/2^16/256B/process_time/real_time_median 571 us 616 us 10 76.6165k 1.75134k/s +frodoPIR/client_process_response/2^16/256B/process_time/real_time_stddev 42.8 us 47.0 us 10 7.20791k 149.431/s +frodoPIR/client_process_response/2^16/256B/process_time/real_time_cv 7.75 % 7.81 % 10 9.42% 8.21% +frodoPIR/client_process_response/2^16/256B/process_time/real_time_min 478 us 521 us 10 64.8534k 1.67098k/s +frodoPIR/client_process_response/2^16/256B/process_time/real_time_max 598 us 653 us 10 91.6069k 2.09249k/s +frodoPIR/server_respond/2^16/256B/process_time/real_time_mean 5.00 ms 43.4 ms 10 75.2895M 200.219/s +frodoPIR/server_respond/2^16/256B/process_time/real_time_median 4.99 ms 43.2 ms 10 75.6288M 200.295/s +frodoPIR/server_respond/2^16/256B/process_time/real_time_stddev 0.103 ms 0.637 ms 10 1.35724M 4.03961/s +frodoPIR/server_respond/2^16/256B/process_time/real_time_cv 2.05 % 1.47 % 10 1.80% 2.02% +frodoPIR/server_respond/2^16/256B/process_time/real_time_min 4.88 ms 42.5 ms 10 73.225M 191.547/s +frodoPIR/server_respond/2^16/256B/process_time/real_time_max 5.22 ms 44.7 ms 10 76.9216M 204.814/s +frodoPIR/client_query/2^18/256B/process_time/real_time_mean 110 us 109 us 10 252.645k 9.05308k/s +frodoPIR/client_query/2^18/256B/process_time/real_time_median 111 us 109 us 10 253.039k 9.03606k/s +frodoPIR/client_query/2^18/256B/process_time/real_time_stddev 0.623 us 0.620 us 10 2.96678k 51.5048/s +frodoPIR/client_query/2^18/256B/process_time/real_time_cv 0.56 % 0.57 % 10 1.17% 0.57% +frodoPIR/client_query/2^18/256B/process_time/real_time_min 109 us 107 us 10 247.682k 9.00946k/s +frodoPIR/client_query/2^18/256B/process_time/real_time_max 111 us 109 us 10 255.93k 9.18164k/s +frodoPIR/client_query/2^19/256B/process_time/real_time_mean 216 us 214 us 10 507.34k 4.62894k/s +frodoPIR/client_query/2^19/256B/process_time/real_time_median 216 us 214 us 10 510.256k 4.63521k/s +frodoPIR/client_query/2^19/256B/process_time/real_time_stddev 0.889 us 0.842 us 10 8.17701k 18.9706/s +frodoPIR/client_query/2^19/256B/process_time/real_time_cv 0.41 % 0.39 % 10 1.61% 0.41% +frodoPIR/client_query/2^19/256B/process_time/real_time_min 215 us 213 us 10 492.017k 4.58799k/s +frodoPIR/client_query/2^19/256B/process_time/real_time_max 218 us 216 us 10 517.432k 4.64842k/s +frodoPIR/client_process_response/2^19/256B/process_time/real_time_mean 571 us 855 us 10 133.069k 1.75321k/s +frodoPIR/client_process_response/2^19/256B/process_time/real_time_median 569 us 858 us 10 133.281k 1.75662k/s +frodoPIR/client_process_response/2^19/256B/process_time/real_time_stddev 10.6 us 20.7 us 10 2.51599k 32.3923/s +frodoPIR/client_process_response/2^19/256B/process_time/real_time_cv 1.87 % 2.42 % 10 1.89% 1.85% +frodoPIR/client_process_response/2^19/256B/process_time/real_time_min 557 us 819 us 10 129.047k 1.69035k/s +frodoPIR/client_process_response/2^19/256B/process_time/real_time_max 592 us 888 us 10 136.817k 1.79489k/s +frodoPIR/client_process_response/2^17/256B/process_time/real_time_mean 578 us 649 us 10 73.8788k 1.73523k/s +frodoPIR/client_process_response/2^17/256B/process_time/real_time_median 574 us 651 us 10 73.304k 1.7437k/s +frodoPIR/client_process_response/2^17/256B/process_time/real_time_stddev 28.1 us 33.1 us 10 3.50183k 84.8486/s +frodoPIR/client_process_response/2^17/256B/process_time/real_time_cv 4.87 % 5.11 % 10 4.74% 4.89% +frodoPIR/client_process_response/2^17/256B/process_time/real_time_min 530 us 592 us 10 68.7128k 1.6113k/s +frodoPIR/client_process_response/2^17/256B/process_time/real_time_max 621 us 696 us 10 78.9619k 1.88607k/s +frodoPIR/client_setup/2^16/256B/process_time/real_time_mean 979 ms 979 ms 10 3.04952G 1.02328/s +frodoPIR/client_setup/2^16/256B/process_time/real_time_median 989 ms 989 ms 10 3.04972G 1.01129/s +frodoPIR/client_setup/2^16/256B/process_time/real_time_stddev 43.4 ms 43.4 ms 10 1.60967M 0.0470617/s +frodoPIR/client_setup/2^16/256B/process_time/real_time_cv 4.43 % 4.43 % 10 0.05% 4.60% +frodoPIR/client_setup/2^16/256B/process_time/real_time_min 903 ms 903 ms 10 3.04748G 0.974966/s +frodoPIR/client_setup/2^16/256B/process_time/real_time_max 1026 ms 1026 ms 10 3.05232G 1.10723/s +frodoPIR/client_process_response/2^20/256B/process_time/real_time_mean 591 us 963 us 10 140.443k 1.69144k/s +frodoPIR/client_process_response/2^20/256B/process_time/real_time_median 589 us 949 us 10 140.594k 1.6975k/s +frodoPIR/client_process_response/2^20/256B/process_time/real_time_stddev 8.49 us 30.6 us 10 2.47158k 24.0694/s +frodoPIR/client_process_response/2^20/256B/process_time/real_time_cv 1.44 % 3.18 % 10 1.76% 1.42% +frodoPIR/client_process_response/2^20/256B/process_time/real_time_min 581 us 941 us 10 135.074k 1.64646k/s +frodoPIR/client_process_response/2^20/256B/process_time/real_time_max 607 us 1042 us 10 144.286k 1.72084k/s +frodoPIR/client_prepare_query/2^16/256B/process_time/real_time_mean 9.97 ms 118 ms 10 215.816M 100.293/s +frodoPIR/client_prepare_query/2^16/256B/process_time/real_time_median 10.0 ms 119 ms 10 216.415M 99.9284/s +frodoPIR/client_prepare_query/2^16/256B/process_time/real_time_stddev 0.139 ms 1.82 ms 10 3.52778M 1.422/s +frodoPIR/client_prepare_query/2^16/256B/process_time/real_time_cv 1.39 % 1.54 % 10 1.63% 1.42% +frodoPIR/client_prepare_query/2^16/256B/process_time/real_time_min 9.65 ms 115 ms 10 210.314M 99.0563/s +frodoPIR/client_prepare_query/2^16/256B/process_time/real_time_max 10.1 ms 120 ms 10 220.09M 103.6/s +frodoPIR/server_setup/2^18/256B/process_time/real_time_mean 6.70 s 45.0 s 10 73.0524G 0.149915/s +frodoPIR/server_setup/2^18/256B/process_time/real_time_median 6.68 s 44.8 s 10 72.3798G 0.149604/s +frodoPIR/server_setup/2^18/256B/process_time/real_time_stddev 0.442 s 1.23 s 10 3.70898G 9.43851m/s +frodoPIR/server_setup/2^18/256B/process_time/real_time_cv 6.60 % 2.72 % 10 5.08% 6.30% +frodoPIR/server_setup/2^18/256B/process_time/real_time_min 6.06 s 43.5 s 10 70.097G 0.129646/s +frodoPIR/server_setup/2^18/256B/process_time/real_time_max 7.71 s 48.0 s 10 83.0646G 0.165101/s +frodoPIR/client_setup/2^19/256B/process_time/real_time_mean 7574 ms 7574 ms 10 24.381G 0.13204/s +frodoPIR/client_setup/2^19/256B/process_time/real_time_median 7562 ms 7561 ms 10 24.4142G 0.132248/s +frodoPIR/client_setup/2^19/256B/process_time/real_time_stddev 62.6 ms 62.8 ms 10 60.9751M 1.08313m/s +frodoPIR/client_setup/2^19/256B/process_time/real_time_cv 0.83 % 0.83 % 10 0.25% 0.82% +frodoPIR/client_setup/2^19/256B/process_time/real_time_min 7511 ms 7511 ms 10 24.2367G 0.129832/s +frodoPIR/client_setup/2^19/256B/process_time/real_time_max 7702 ms 7702 ms 10 24.418G 0.133132/s +frodoPIR/server_setup/2^19/256B/process_time/real_time_mean 14.2 s 104 s 10 160.32G 0.0705744/s +frodoPIR/server_setup/2^19/256B/process_time/real_time_median 14.1 s 103 s 10 161.022G 0.0708027/s +frodoPIR/server_setup/2^19/256B/process_time/real_time_stddev 0.364 s 2.64 s 10 7.7105G 1.79889m/s +frodoPIR/server_setup/2^19/256B/process_time/real_time_cv 2.57 % 2.55 % 10 4.81% 2.55% +frodoPIR/server_setup/2^19/256B/process_time/real_time_min 13.7 s 100 s 10 145.98G 0.0675568/s +frodoPIR/server_setup/2^19/256B/process_time/real_time_max 14.8 s 107 s 10 173.936G 0.0727934/s +frodoPIR/server_setup/2^17/256B/process_time/real_time_mean 3.39 s 22.2 s 10 35.6742G 0.294928/s +frodoPIR/server_setup/2^17/256B/process_time/real_time_median 3.37 s 22.6 s 10 36.1179G 0.296538/s +frodoPIR/server_setup/2^17/256B/process_time/real_time_stddev 0.105 s 0.882 s 10 1.86431G 9.16599m/s +frodoPIR/server_setup/2^17/256B/process_time/real_time_cv 3.10 % 3.97 % 10 5.23% 3.11% +frodoPIR/server_setup/2^17/256B/process_time/real_time_min 3.23 s 20.7 s 10 32.7358G 0.283906/s +frodoPIR/server_setup/2^17/256B/process_time/real_time_max 3.52 s 23.4 s 10 38.2234G 0.310073/s +frodoPIR/client_query/2^20/256B/process_time/real_time_mean 446 us 445 us 10 1.03874M 2.24172k/s +frodoPIR/client_query/2^20/256B/process_time/real_time_median 448 us 446 us 10 1.03737M 2.23385k/s +frodoPIR/client_query/2^20/256B/process_time/real_time_stddev 5.49 us 5.41 us 10 31.5635k 28.1559/s +frodoPIR/client_query/2^20/256B/process_time/real_time_cv 1.23 % 1.22 % 10 3.04% 1.26% +frodoPIR/client_query/2^20/256B/process_time/real_time_min 432 us 431 us 10 992.445k 2.21211k/s +frodoPIR/client_query/2^20/256B/process_time/real_time_max 452 us 451 us 10 1.09696M 2.31463k/s +frodoPIR/client_process_response/2^18/256B/process_time/real_time_mean 598 us 779 us 10 94.559k 1.67424k/s +frodoPIR/client_process_response/2^18/256B/process_time/real_time_median 597 us 782 us 10 93.8358k 1.67499k/s +frodoPIR/client_process_response/2^18/256B/process_time/real_time_stddev 16.7 us 22.4 us 10 4.32568k 46.7285/s +frodoPIR/client_process_response/2^18/256B/process_time/real_time_cv 2.80 % 2.87 % 10 4.57% 2.79% +frodoPIR/client_process_response/2^18/256B/process_time/real_time_min 574 us 752 us 10 88.6416k 1.60747k/s +frodoPIR/client_process_response/2^18/256B/process_time/real_time_max 622 us 817 us 10 100.963k 1.74248k/s +frodoPIR/client_prepare_query/2^17/256B/process_time/real_time_mean 18.5 ms 240 ms 10 431.552M 54.1698/s +frodoPIR/client_prepare_query/2^17/256B/process_time/real_time_median 18.5 ms 241 ms 10 434.493M 54.2004/s +frodoPIR/client_prepare_query/2^17/256B/process_time/real_time_stddev 0.244 ms 5.26 ms 10 10.5934M 0.715381/s +frodoPIR/client_prepare_query/2^17/256B/process_time/real_time_cv 1.32 % 2.19 % 10 2.45% 1.32% +frodoPIR/client_prepare_query/2^17/256B/process_time/real_time_min 18.1 ms 229 ms 10 406.941M 53.2494/s +frodoPIR/client_prepare_query/2^17/256B/process_time/real_time_max 18.8 ms 246 ms 10 445.886M 55.2952/s +frodoPIR/server_setup/2^20/256B/process_time/real_time_mean 28.5 s 213 s 10 305.091G 0.0351209/s +frodoPIR/server_setup/2^20/256B/process_time/real_time_median 28.7 s 213 s 10 302.762G 0.0349043/s +frodoPIR/server_setup/2^20/256B/process_time/real_time_stddev 0.609 s 5.93 s 10 11.0259G 769.93u/s +frodoPIR/server_setup/2^20/256B/process_time/real_time_cv 2.14 % 2.78 % 10 3.61% 2.19% +frodoPIR/server_setup/2^20/256B/process_time/real_time_min 27.1 s 206 s 10 290.981G 0.0342801/s +frodoPIR/server_setup/2^20/256B/process_time/real_time_max 29.2 s 222 s 10 329.112G 0.0369177/s +frodoPIR/client_prepare_query/2^18/256B/process_time/real_time_mean 35.4 ms 486 ms 10 865.901M 28.2257/s +frodoPIR/client_prepare_query/2^18/256B/process_time/real_time_median 35.5 ms 488 ms 10 872.547M 28.1949/s +frodoPIR/client_prepare_query/2^18/256B/process_time/real_time_stddev 0.619 ms 7.17 ms 10 18.1316M 0.493974/s +frodoPIR/client_prepare_query/2^18/256B/process_time/real_time_cv 1.75 % 1.48 % 10 2.09% 1.75% +frodoPIR/client_prepare_query/2^18/256B/process_time/real_time_min 34.5 ms 475 ms 10 824.539M 27.4146/s +frodoPIR/client_prepare_query/2^18/256B/process_time/real_time_max 36.5 ms 493 ms 10 881.946M 28.9776/s +frodoPIR/client_setup/2^18/256B/process_time/real_time_mean 3771 ms 3771 ms 10 12.3669G 0.265895/s +frodoPIR/client_setup/2^18/256B/process_time/real_time_median 3833 ms 3833 ms 10 12.3697G 0.260869/s +frodoPIR/client_setup/2^18/256B/process_time/real_time_stddev 208 ms 208 ms 10 13.9428M 0.0147502/s +frodoPIR/client_setup/2^18/256B/process_time/real_time_cv 5.52 % 5.52 % 10 0.11% 5.55% +frodoPIR/client_setup/2^18/256B/process_time/real_time_min 3521 ms 3521 ms 10 12.3481G 0.246642/s +frodoPIR/client_setup/2^18/256B/process_time/real_time_max 4054 ms 4054 ms 10 12.3853G 0.284029/s +frodoPIR/client_prepare_query/2^20/256B/process_time/real_time_mean 138 ms 1965 ms 10 3.46642G 7.22879/s +frodoPIR/client_prepare_query/2^20/256B/process_time/real_time_median 139 ms 1976 ms 10 3.4696G 7.19446/s +frodoPIR/client_prepare_query/2^20/256B/process_time/real_time_stddev 1.42 ms 21.1 ms 10 35.2454M 0.0743133/s +frodoPIR/client_prepare_query/2^20/256B/process_time/real_time_cv 1.02 % 1.07 % 10 1.02% 1.03% +frodoPIR/client_prepare_query/2^20/256B/process_time/real_time_min 136 ms 1929 ms 10 3.39759G 7.14961/s +frodoPIR/client_prepare_query/2^20/256B/process_time/real_time_max 140 ms 1982 ms 10 3.51033G 7.34416/s +frodoPIR/server_respond/2^20/256B/process_time/real_time_mean 99.5 ms 1173 ms 10 1.97878G 10.0565/s +frodoPIR/server_respond/2^20/256B/process_time/real_time_median 99.6 ms 1171 ms 10 1.97791G 10.0422/s +frodoPIR/server_respond/2^20/256B/process_time/real_time_stddev 3.45 ms 31.2 ms 10 79.3244M 0.349206/s +frodoPIR/server_respond/2^20/256B/process_time/real_time_cv 3.47 % 2.66 % 10 4.01% 3.47% +frodoPIR/server_respond/2^20/256B/process_time/real_time_min 94.8 ms 1111 ms 10 1.83851G 9.59048/s +frodoPIR/server_respond/2^20/256B/process_time/real_time_max 104 ms 1216 ms 10 2.07275G 10.5484/s +frodoPIR/server_respond/2^17/256B/process_time/real_time_mean 10.2 ms 103 ms 10 169.632M 97.9035/s +frodoPIR/server_respond/2^17/256B/process_time/real_time_median 10.2 ms 104 ms 10 171.053M 98.4863/s +frodoPIR/server_respond/2^17/256B/process_time/real_time_stddev 0.374 ms 3.22 ms 10 5.70744M 3.51239/s +frodoPIR/server_respond/2^17/256B/process_time/real_time_cv 3.66 % 3.13 % 10 3.36% 3.59% +frodoPIR/server_respond/2^17/256B/process_time/real_time_min 9.73 ms 96.5 ms 10 157.118M 91.4747/s +frodoPIR/server_respond/2^17/256B/process_time/real_time_max 10.9 ms 106 ms 10 176.333M 102.752/s +frodoPIR/server_respond/2^18/256B/process_time/real_time_mean 20.1 ms 227 ms 10 372.789M 49.8509/s +frodoPIR/server_respond/2^18/256B/process_time/real_time_median 20.1 ms 226 ms 10 374.042M 49.7974/s +frodoPIR/server_respond/2^18/256B/process_time/real_time_stddev 0.319 ms 5.85 ms 10 9.95863M 0.785662/s +frodoPIR/server_respond/2^18/256B/process_time/real_time_cv 1.59 % 2.58 % 10 2.67% 1.58% +frodoPIR/server_respond/2^18/256B/process_time/real_time_min 19.6 ms 218 ms 10 357.387M 48.2735/s +frodoPIR/server_respond/2^18/256B/process_time/real_time_max 20.7 ms 235 ms 10 386.252M 50.9897/s +frodoPIR/client_prepare_query/2^19/256B/process_time/real_time_mean 69.3 ms 957 ms 10 1.68532G 14.4326/s +frodoPIR/client_prepare_query/2^19/256B/process_time/real_time_median 68.8 ms 953 ms 10 1.69159G 14.5309/s +frodoPIR/client_prepare_query/2^19/256B/process_time/real_time_stddev 1.58 ms 24.4 ms 10 65.4275M 0.323254/s +frodoPIR/client_prepare_query/2^19/256B/process_time/real_time_cv 2.28 % 2.55 % 10 3.88% 2.24% +frodoPIR/client_prepare_query/2^19/256B/process_time/real_time_min 67.3 ms 905 ms 10 1.51648G 13.7956/s +frodoPIR/client_prepare_query/2^19/256B/process_time/real_time_max 72.5 ms 992 ms 10 1.74798G 14.8494/s +frodoPIR/server_setup/2^16/256B/process_time/real_time_mean 1.72 s 11.3 s 10 18.6947G 0.580374/s +frodoPIR/server_setup/2^16/256B/process_time/real_time_median 1.73 s 11.4 s 10 18.8673G 0.576841/s +frodoPIR/server_setup/2^16/256B/process_time/real_time_stddev 0.043 s 0.306 s 10 484.092M 0.0147395/s +frodoPIR/server_setup/2^16/256B/process_time/real_time_cv 2.48 % 2.71 % 10 2.59% 2.54% +frodoPIR/server_setup/2^16/256B/process_time/real_time_min 1.64 s 10.5 s 10 17.4679G 0.562965/s +frodoPIR/server_setup/2^16/256B/process_time/real_time_max 1.78 s 11.5 s 10 19.0726G 0.609984/s +frodoPIR/server_respond/2^19/256B/process_time/real_time_mean 48.3 ms 554 ms 10 920.533M 20.7528/s +frodoPIR/server_respond/2^19/256B/process_time/real_time_median 48.1 ms 552 ms 10 916.522M 20.8106/s +frodoPIR/server_respond/2^19/256B/process_time/real_time_stddev 1.91 ms 15.0 ms 10 21.216M 0.816012/s +frodoPIR/server_respond/2^19/256B/process_time/real_time_cv 3.95 % 2.70 % 10 2.30% 3.93% +frodoPIR/server_respond/2^19/256B/process_time/real_time_min 45.7 ms 535 ms 10 898.526M 19.4052/s +frodoPIR/server_respond/2^19/256B/process_time/real_time_max 51.5 ms 577 ms 10 965.828M 21.8705/s +frodoPIR/client_query/2^16/256B/process_time/real_time_mean 31.5 us 29.8 us 10 44.5464k 31.7019k/s +frodoPIR/client_query/2^16/256B/process_time/real_time_median 31.3 us 29.6 us 10 44.1522k 31.9171k/s +frodoPIR/client_query/2^16/256B/process_time/real_time_stddev 0.456 us 0.463 us 10 1.25677k 455.483/s +frodoPIR/client_query/2^16/256B/process_time/real_time_cv 1.45 % 1.55 % 10 2.82% 1.44% +frodoPIR/client_query/2^16/256B/process_time/real_time_min 31.0 us 29.3 us 10 42.985k 31.0537k/s +frodoPIR/client_query/2^16/256B/process_time/real_time_max 32.2 us 30.5 us 10 46.4317k 32.2068k/s +frodoPIR/client_setup/2^20/256B/process_time/real_time_mean 14627 ms 14626 ms 10 48.7324G 0.0684256/s +frodoPIR/client_setup/2^20/256B/process_time/real_time_median 14771 ms 14770 ms 10 48.7354G 0.0677011/s +frodoPIR/client_setup/2^20/256B/process_time/real_time_stddev 439 ms 439 ms 10 48.7721M 2.10304m/s +frodoPIR/client_setup/2^20/256B/process_time/real_time_cv 3.00 % 3.00 % 10 0.10% 3.07% +frodoPIR/client_setup/2^20/256B/process_time/real_time_min 13862 ms 13862 ms 10 48.6322G 0.0662292/s +frodoPIR/client_setup/2^20/256B/process_time/real_time_max 15099 ms 15098 ms 10 48.7943G 0.0721371/s +frodoPIR/client_query/2^17/256B/process_time/real_time_mean 57.4 us 55.8 us 10 120.746k 17.4153k/s +frodoPIR/client_query/2^17/256B/process_time/real_time_median 57.4 us 55.8 us 10 120.894k 17.419k/s +frodoPIR/client_query/2^17/256B/process_time/real_time_stddev 0.205 us 0.179 us 10 1.02941k 62.382/s +frodoPIR/client_query/2^17/256B/process_time/real_time_cv 0.36 % 0.32 % 10 0.85% 0.36% +frodoPIR/client_query/2^17/256B/process_time/real_time_min 57.0 us 55.4 us 10 119.049k 17.3367k/s +frodoPIR/client_query/2^17/256B/process_time/real_time_max 57.7 us 56.0 us 10 122.084k 17.5481k/s +``` + +## 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`. + +- Let's begin by cloning the repository. + +```bash +# Just clones FrodoPIR source tree, but not its submodule -based dependencies. +git clone https://github.com/itzmeanjan/frodoPIR.git +# Clones FrodoPIR source tree and also imports submodule -based dependencies. +git clone https://github.com/itzmeanjan/frodoPIR.git --recurse-submodules +``` + +- Move inside the directory holding the cloned repository and import all git submodule -based dependencies. + +```bash +pushd frodoPIR +make -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). + +```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 +```