├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── MODULE.bazel ├── MODULE.bazel.lock ├── README.md └── shell_encryption ├── BUILD ├── aux_galois_key.h ├── aux_galois_key_test.cc ├── aux_relinearization_key.cc ├── aux_relinearization_key.h ├── aux_relinearization_key_test.cc ├── bits_util.h ├── bits_util_test.cc ├── constants.h ├── context.h ├── context_test.cc ├── dft_transformations.cc ├── dft_transformations.h ├── dft_transformations_hwy.cc ├── dft_transformations_hwy.h ├── dft_transformations_hwy_test.cc ├── dft_transformations_test.cc ├── error_params.h ├── error_params_test.cc ├── gadget.h ├── galois_key.h ├── galois_key_test.cc ├── int256.cc ├── int256.h ├── int256_test.cc ├── integral_types.h ├── modulus_conversion.h ├── montgomery.cc ├── montgomery.h ├── montgomery_test.cc ├── multi_party ├── BUILD ├── polynomial_utilities.h ├── public_key.cc ├── public_key.h ├── public_key_share.cc ├── public_key_share.h ├── public_key_share_test.cc ├── public_key_test.cc ├── public_parameter.cc ├── public_parameter.h ├── public_parameter_test.cc ├── recovery.h ├── recovery_test.cc ├── secret_key_share.cc ├── secret_key_share.h ├── secret_key_share_test.cc ├── serialization.proto └── testing │ ├── BUILD │ └── parameters.h ├── ntt_parameters.cc ├── ntt_parameters.h ├── ntt_parameters_test.cc ├── oblivious_expand.h ├── oblivious_expand_test.cc ├── opt ├── BUILD ├── constant_polynomial.h ├── constant_polynomial_test.cc ├── lazy_polynomial.h └── lazy_polynomial_test.cc ├── polynomial.h ├── polynomial_test.cc ├── prng ├── BUILD ├── LICENSE ├── chacha_prng.cc ├── chacha_prng.h ├── chacha_prng_test.cc ├── chacha_prng_util.cc ├── chacha_prng_util.h ├── hkdf_prng.cc ├── hkdf_prng.h ├── hkdf_prng_test.cc ├── hkdf_prng_util.cc ├── hkdf_prng_util.h ├── integral_prng_testing_types.h ├── prng.h ├── prng_test.cc ├── single_thread_chacha_prng.cc ├── single_thread_chacha_prng.h ├── single_thread_chacha_prng_test.cc ├── single_thread_hkdf_prng.cc ├── single_thread_hkdf_prng.h └── single_thread_hkdf_prng_test.cc ├── public_key_encryption.cc ├── public_key_encryption.h ├── public_key_encryption_test.cc ├── relinearization_key.cc ├── relinearization_key.h ├── relinearization_key_test.cc ├── rns ├── BUILD ├── approximate_encoder.cc ├── approximate_encoder.h ├── approximate_encoder_test.cc ├── coefficient_encoder.cc ├── coefficient_encoder.h ├── coefficient_encoder_test.cc ├── constants.h ├── crt_interpolation.h ├── crt_interpolation_test.cc ├── error_correction.h ├── error_distribution.h ├── error_distribution_test.cc ├── finite_field_encoder.cc ├── finite_field_encoder.h ├── finite_field_encoder_test.cc ├── lazy_rns_polynomial.cc ├── lazy_rns_polynomial.h ├── lazy_rns_polynomial_test.cc ├── message_packing.h ├── message_packing_test.cc ├── rns_bfv_ciphertext.cc ├── rns_bfv_ciphertext.h ├── rns_bfv_ciphertext_test.cc ├── rns_bfv_public_key.cc ├── rns_bfv_public_key.h ├── rns_bfv_public_key_test.cc ├── rns_bgv_ciphertext.cc ├── rns_bgv_ciphertext.h ├── rns_bgv_ciphertext_test.cc ├── rns_bgv_public_key.cc ├── rns_bgv_public_key.h ├── rns_bgv_public_key_test.cc ├── rns_ciphertext.cc ├── rns_ciphertext.h ├── rns_ciphertext_test.cc ├── rns_context.cc ├── rns_context.h ├── rns_context_test.cc ├── rns_error_params.h ├── rns_error_params_test.cc ├── rns_gadget.cc ├── rns_gadget.h ├── rns_gadget_test.cc ├── rns_galois_key.cc ├── rns_galois_key.h ├── rns_galois_key_test.cc ├── rns_integer.h ├── rns_modulus.h ├── rns_polynomial.cc ├── rns_polynomial.h ├── rns_polynomial_hwy.cc ├── rns_polynomial_hwy.h ├── rns_polynomial_test.cc ├── rns_public_key.cc ├── rns_public_key.h ├── rns_relinearization_key.cc ├── rns_relinearization_key.h ├── rns_relinearization_key_test.cc ├── rns_secret_key.cc ├── rns_secret_key.h ├── rns_secret_key_test.cc ├── serialization.proto └── testing │ ├── BUILD │ ├── parameters.h │ └── testing_utils.h ├── sample_error.h ├── sample_error_test.cc ├── sampler ├── BUILD ├── discrete_gaussian.cc ├── discrete_gaussian.h ├── discrete_gaussian_test.cc ├── uniform_ternary.h └── uniform_ternary_test.cc ├── serialization.proto ├── status_macros.h ├── status_macros_test.cc ├── statusor.h ├── symmetric_encryption.h ├── symmetric_encryption_test.cc ├── symmetric_encryption_with_prng.h ├── symmetric_encryption_with_prng_test.cc ├── testing ├── BUILD ├── LICENSE ├── coefficient_polynomial.h ├── coefficient_polynomial.proto ├── coefficient_polynomial_ciphertext.h ├── coefficient_polynomial_ciphertext_test.cc ├── coefficient_polynomial_test.cc ├── parameters.h ├── protobuf_matchers.h ├── protobuf_matchers_test.cc ├── status_matchers.h ├── status_testing.h ├── testing_prng.h └── testing_utils.h ├── transcription.h └── transcription_test.cc /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | bazel-* -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | We'd love to accept your patches and contributions to this project. There are 4 | just a few small guidelines you need to follow. 5 | 6 | ## Contributor License Agreement 7 | 8 | Contributions to this project must be accompanied by a Contributor License 9 | Agreement. You (or your employer) retain the copyright to your contribution, 10 | this simply gives us permission to use and redistribute your contributions as 11 | part of the project. Head over to to see 12 | your current agreements on file or to sign a new one. 13 | 14 | You generally only need to submit a CLA once, so if you've already submitted one 15 | (even if it was for a different project), you probably don't need to do it 16 | again. 17 | 18 | ## Code reviews 19 | 20 | All submissions, including submissions by project members, require review. We 21 | use GitHub pull requests for this purpose. Consult 22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 23 | information on using pull requests. -------------------------------------------------------------------------------- /MODULE.bazel: -------------------------------------------------------------------------------- 1 | module( 2 | name = "shell-encryption", 3 | ) 4 | 5 | bazel_dep(name = "tink_cc", version = "2.4.0", repo_name = "com_github_tink_crypto_tink_cc") 6 | bazel_dep(name = "rules_cc", version = "0.2.9") 7 | bazel_dep(name = "rules_proto", version = "7.1.0") 8 | bazel_dep(name = "protobuf", version = "33.0-rc2", repo_name = "com_google_protobuf") 9 | bazel_dep(name = "googletest", version = "1.17.0.bcr.1", repo_name = "com_github_google_googletest") 10 | bazel_dep(name = "abseil-cpp", version = "20250814.1", repo_name = "com_google_absl") 11 | bazel_dep(name = "boringssl", version = "0.20251002.0") 12 | bazel_dep(name = "glog", version = "0.7.1", repo_name = "com_github_google_glog") 13 | bazel_dep(name = "rules_license", version = "1.0.0") 14 | bazel_dep(name = "highway", version = "1.3.0", repo_name = "com_github_google_highway") 15 | -------------------------------------------------------------------------------- /shell_encryption/bits_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef RLWE_BITS_UTIL_H_ 18 | #define RLWE_BITS_UTIL_H_ 19 | 20 | #include 21 | 22 | #include "absl/numeric/int128.h" 23 | #include "shell_encryption/integral_types.h" 24 | 25 | namespace rlwe { 26 | namespace internal { 27 | 28 | inline unsigned int CountOnesInByte(Uint8 x) { 29 | Uint8 x0 = x & 0x55; 30 | Uint8 x1 = (x >> 1) & 0x55; 31 | x = x0 + x1; 32 | 33 | x0 = x & 0x33; 34 | x1 = (x >> 2) & 0x33; 35 | x = x0 + x1; 36 | 37 | x0 = x & 0x0F; 38 | x1 = (x >> 4) & 0x0F; 39 | return x0 + x1; 40 | } 41 | 42 | inline unsigned int CountOnes64(Uint64 x) { 43 | Uint64 x0 = x & 0x5555555555555555; 44 | Uint64 x1 = (x >> 1) & 0x5555555555555555; 45 | x = x0 + x1; 46 | 47 | x0 = x & 0x3333333333333333; 48 | x1 = (x >> 2) & 0x3333333333333333; 49 | x = x0 + x1; 50 | 51 | x0 = x & 0x0F0F0F0F0F0F0F0F; 52 | x1 = (x >> 4) & 0x0F0F0F0F0F0F0F0F; 53 | x = x0 + x1; 54 | 55 | x0 = x & 0x00FF00FF00FF00FF; 56 | x1 = (x >> 8) & 0x00FF00FF00FF00FF; 57 | x = x0 + x1; 58 | 59 | x0 = x & 0x0000FFFF0000FFFF; 60 | x1 = (x >> 16) & 0x0000FFFF0000FFFF; 61 | x = x0 + x1; 62 | 63 | x0 = x & 0x00000000FFFFFFFF; 64 | x1 = (x >> 32) & 0x00000000FFFFFFFF; 65 | return x0 + x1; 66 | } 67 | 68 | inline unsigned int CountLeadingZeros64(Uint64 x) { 69 | unsigned int zeros = 64; 70 | if (x >> 32) { 71 | zeros -= 32; 72 | x >>= 32; 73 | } 74 | if (x >> 16) { 75 | zeros -= 16; 76 | x >>= 16; 77 | } 78 | if (x >> 8) { 79 | zeros -= 8; 80 | x >>= 8; 81 | } 82 | if (x >> 4) { 83 | zeros -= 4; 84 | x >>= 4; 85 | } 86 | if (x >> 2) { 87 | zeros -= 2; 88 | x >>= 2; 89 | } 90 | if (x >> 1) { 91 | zeros -= 1; 92 | x >>= 1; 93 | } 94 | return zeros - x; 95 | } 96 | 97 | inline unsigned int CountLeadingZeros128(absl::uint128 x) { 98 | if (Uint64 hi = absl::Uint128High64(x)) return CountLeadingZeros64(hi); 99 | return CountLeadingZeros64(absl::Uint128Low64(x)) + 64; 100 | } 101 | 102 | inline unsigned int BitLength(absl::uint128 x) { 103 | return 128 - CountLeadingZeros128(x); 104 | } 105 | 106 | } // namespace internal 107 | } // namespace rlwe 108 | 109 | #endif // RLWE_BITS_UTIL_H_ 110 | -------------------------------------------------------------------------------- /shell_encryption/bits_util_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "shell_encryption/bits_util.h" 16 | 17 | #include 18 | #include 19 | #include "absl/numeric/int128.h" 20 | 21 | using ::testing::Eq; 22 | 23 | namespace { 24 | 25 | TEST(BitsUtilTest, CountOnes64Works) { 26 | EXPECT_THAT(rlwe::internal::CountOnes64(0xFF000000000000FF), Eq(16)); 27 | EXPECT_THAT(rlwe::internal::CountOnes64(0xFF000000000000FE), Eq(15)); 28 | EXPECT_THAT(rlwe::internal::CountOnes64(0xFF0000000000FF00), Eq(16)); 29 | EXPECT_THAT(rlwe::internal::CountOnes64(0x1111111111111111), Eq(16)); 30 | EXPECT_THAT(rlwe::internal::CountOnes64(0x0321212121212121), Eq(16)); 31 | } 32 | 33 | TEST(BitsUtilTest, CountOnesInByte) { 34 | EXPECT_THAT(rlwe::internal::CountOnesInByte(0x00), Eq(0)); 35 | EXPECT_THAT(rlwe::internal::CountOnesInByte(0x01), Eq(1)); 36 | EXPECT_THAT(rlwe::internal::CountOnesInByte(0x11), Eq(2)); 37 | EXPECT_THAT(rlwe::internal::CountOnesInByte(0x22), Eq(2)); 38 | EXPECT_THAT(rlwe::internal::CountOnesInByte(0x44), Eq(2)); 39 | EXPECT_THAT(rlwe::internal::CountOnesInByte(0xFF), Eq(8)); 40 | EXPECT_THAT(rlwe::internal::CountOnesInByte(0xEE), Eq(6)); 41 | } 42 | 43 | TEST(BitsUtilTest, CountLeadingZeros64Works) { 44 | rlwe::Uint64 value = 0x8000000000000000; 45 | for (int i = 0; i < 64; i++) { 46 | EXPECT_THAT(rlwe::internal::CountLeadingZeros64(value), Eq(i)); 47 | value >>= 1; 48 | } 49 | } 50 | 51 | TEST(BitsUtilTest, BitLengthWorks) { 52 | absl::uint128 value = absl::MakeUint128(0x8000000000000000, 0); 53 | for (int i = 0; i <= 128; i++) { 54 | EXPECT_THAT(rlwe::internal::BitLength(value), Eq(128 - i)); 55 | value >>= 1; 56 | } 57 | } 58 | 59 | } // namespace 60 | -------------------------------------------------------------------------------- /shell_encryption/constants.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef RLWE_CONSTANTS_H_ 17 | #define RLWE_CONSTANTS_H_ 18 | 19 | #include 20 | 21 | #include "absl/numeric/int128.h" 22 | #include "shell_encryption/integral_types.h" 23 | 24 | namespace rlwe { 25 | 26 | // To generate parameters for this Ring-LWE system, we need to choose a prime 27 | // modulus q. In order for us to perform NTT transforms on dimension 2^N 28 | // polynomials, we require 2^{N+1} to divide q-1. Thus, we set moduli to be 29 | // primes of the form q = p*2^{N+1} + 1, where N becomes our LogDegreeBound. 30 | 31 | // Parameters from the New Hope key exchange protocol. Note that we are not 32 | // using these parameters for key exchange in this library. 33 | constexpr Uint64 kNewhopeModulus = 12289; 34 | constexpr Uint64 kNewhopeLogDegreeBound = 10; 35 | constexpr Uint64 kNewhopeDegreeBound = 1 << kNewhopeLogDegreeBound; 36 | 37 | // RLWE parameters for a 62 bit modulus. 38 | constexpr Uint64 kModulus62 = 4611686018427322369; 39 | constexpr Uint64 kLogDegreeBound62 = 11; 40 | constexpr Uint64 kDegreeBound62 = 1L << kLogDegreeBound62; 41 | 42 | // Montgomery parameters for a 59-bit modulus. 43 | constexpr Uint64 kModulus59 = 332366567264636929; 44 | constexpr Uint64 kInvModulus59 = 7124357790306815999; 45 | constexpr Uint64 kLogDegreeBound59 = 10; 46 | constexpr Uint64 kDegreeBound59 = 1L << kLogDegreeBound59; 47 | 48 | // RLWE parameters for a 44-bit modulus. 49 | constexpr Uint64 kModulus44 = 17592169240577; 50 | constexpr Uint64 kLogDegreeBound44 = 10; 51 | constexpr Uint64 kDegreeBound44 = 1L << kLogDegreeBound44; 52 | 53 | // RLWE parameters for a 25-bit and a 29-bit moduli, both congruent to 4 modulo 54 | // 5 = (1 << 2) + 1. These moduli will be useful for testing of modulus 55 | // switching. 56 | constexpr Uint64 kModulus29 = 463187969; 57 | constexpr Uint64 kLogDegreeBound29 = 10; 58 | constexpr Uint64 kDegreeBound29 = 1L << kLogDegreeBound29; 59 | constexpr Uint64 kModulus25 = 33538049; 60 | constexpr Uint64 kLogDegreeBound25 = 10; 61 | constexpr Uint64 kDegreeBound25 = 1L << kLogDegreeBound25; 62 | 63 | // RLWE parameters for a 30 bit modulus. 64 | constexpr Uint64 kModulus30 = 1073707009; 65 | constexpr Uint64 kLogDegreeBound30 = 10; 66 | constexpr Uint64 kDegreeBound30 = 1L << kLogDegreeBound30; 67 | 68 | // RLWE parameters for an 80-bit modulus. 69 | // The modulus represented in decimal is 646119422561999443726337. 70 | constexpr absl::uint128 kModulus80 = 71 | absl::MakeUint128(35026, 3764636248688824321); 72 | constexpr Uint64 kLogDegreeBound80 = 11; 73 | constexpr Uint64 kDegreeBound80 = 1L << kLogDegreeBound80; 74 | 75 | constexpr Uint64 kMaxNumCoeffs = 1L << 15; 76 | constexpr Uint64 kMaxLogNumCoeffs = 15; 77 | constexpr Uint64 kMaxVariance = 256; 78 | 79 | } // namespace rlwe 80 | 81 | #endif // RLWE_CONSTANTS_H_ 82 | -------------------------------------------------------------------------------- /shell_encryption/context_test.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include "shell_encryption/context.h" 17 | 18 | #include 19 | #include 20 | #include "absl/numeric/int128.h" 21 | #include "shell_encryption/constants.h" 22 | #include "shell_encryption/integral_types.h" 23 | #include "shell_encryption/montgomery.h" 24 | #include "shell_encryption/status_macros.h" 25 | #include "shell_encryption/testing/parameters.h" 26 | #include "shell_encryption/testing/status_testing.h" 27 | 28 | namespace { 29 | 30 | template 31 | class ContextTest : public ::testing::Test {}; 32 | TYPED_TEST_SUITE(ContextTest, rlwe::testing::ModularIntTypes); 33 | 34 | TYPED_TEST(ContextTest, CreateWorks) { 35 | for (const auto& params : 36 | rlwe::testing::ContextParameters::Value()) { 37 | ASSERT_OK_AND_ASSIGN(auto context, 38 | rlwe::RlweContext::Create(params)); 39 | } 40 | } 41 | 42 | TYPED_TEST(ContextTest, ParametersMatch) { 43 | for (const auto& params : 44 | rlwe::testing::ContextParameters::Value()) { 45 | ASSERT_OK_AND_ASSIGN(auto context, 46 | rlwe::RlweContext::Create(params)); 47 | 48 | ASSERT_EQ(context->GetLogN(), params.log_n); 49 | ASSERT_EQ(context->GetN(), context->GetNttParams()->number_coeffs); 50 | ASSERT_EQ(context->GetLogT(), params.log_t); 51 | ASSERT_EQ(context->GetModulus(), params.modulus); 52 | ASSERT_EQ(context->GetModulus(), context->GetModulusParams()->modulus); 53 | ASSERT_EQ(context->GetVariance(), params.variance); 54 | } 55 | } 56 | 57 | } // namespace 58 | -------------------------------------------------------------------------------- /shell_encryption/dft_transformations.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include "shell_encryption/dft_transformations.h" 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "absl/status/status.h" 24 | 25 | namespace rlwe { 26 | 27 | namespace { 28 | 29 | // Returns true if n is a power of two. 30 | inline bool IsPowerOfTwo(size_t n) { return (n & (n - 1)) == 0; } 31 | 32 | } // namespace 33 | 34 | absl::Status IterativeHalfCooleyTukey( 35 | std::vector>& coeffs, 36 | const std::vector>& psis_bitrev) { 37 | if (!IsPowerOfTwo(coeffs.size())) { 38 | return absl::InvalidArgumentError( 39 | "The size of `coeffs` must be a power of two."); 40 | } 41 | int len = coeffs.size(); 42 | if (psis_bitrev.size() < len) { 43 | return absl::InvalidArgumentError( 44 | "Not enough primitive roots in `psis_bitrev`."); 45 | } 46 | int log_len = log2(len); 47 | for (int i = log_len - 1; i >= 0; i--) { 48 | // Layer i. 49 | const int half_m = 1 << i; 50 | const int m = half_m << 1; 51 | for (int k = 0, index_psi = 1 << (log_len - i); k < coeffs.size(); 52 | k += m, ++index_psi) { 53 | const std::complex psi = psis_bitrev[index_psi]; 54 | for (int j = 0; j < half_m; j++) { 55 | // The Cooley-Tukey butterfly operation. 56 | std::complex t = coeffs[k + j + half_m] * psi; 57 | std::complex u = coeffs[k + j]; 58 | coeffs[k + j] += t; 59 | coeffs[k + j + half_m] = u - t; 60 | } 61 | } 62 | } 63 | return absl::OkStatus(); 64 | } 65 | 66 | absl::Status IterativeHalfGentlemanSande( 67 | std::vector>& coeffs, 68 | const std::vector>& psis_bitrev_inv) { 69 | if (!IsPowerOfTwo(coeffs.size())) { 70 | return absl::InvalidArgumentError( 71 | "The size of `coeffs` must be a power of two."); 72 | } 73 | int len = coeffs.size(); 74 | if (psis_bitrev_inv.size() < len * 2) { 75 | return absl::InvalidArgumentError( 76 | "Not enough primitive roots in `psis_bitrev_inv`."); 77 | } 78 | int log_len = log2(len); 79 | int index_psi_base = 0; 80 | for (int i = 0; i < log_len; i++) { 81 | const int half_m = 1 << i; 82 | const int m = half_m << 1; 83 | for (int k = 0, index_psi_inv = index_psi_base; k < coeffs.size(); 84 | k += m, ++index_psi_inv) { 85 | for (int j = 0; j < half_m; j++) { 86 | // The Gentleman-Sande butterfly operation. 87 | std::complex t = coeffs[k + j + half_m]; 88 | std::complex u = coeffs[k + j]; 89 | coeffs[k + j] += t; 90 | coeffs[k + j + half_m] = (u - t) * psis_bitrev_inv[index_psi_inv]; 91 | } 92 | } 93 | index_psi_base += 1 << (log_len - i); 94 | } 95 | return absl::OkStatus(); 96 | } 97 | 98 | } // namespace rlwe 99 | -------------------------------------------------------------------------------- /shell_encryption/dft_transformations_hwy.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef RLWE_DFT_TRANSFORMATIONS_HWY_H_ 17 | #define RLWE_DFT_TRANSFORMATIONS_HWY_H_ 18 | 19 | #include 20 | #include 21 | 22 | #include "absl/status/status.h" 23 | #include "shell_encryption/ntt_parameters.h" 24 | #include "shell_encryption/status_macros.h" 25 | 26 | namespace rlwe::internal { 27 | 28 | // Performs the forward NTT transformation from R_q = Z[X]/(q, X^N+1) to Z_q^N 29 | // in-place, where q is a prime and N is a power of two such q == 1 (mod 2N). 30 | // The input polynomial is represented by its coefficient vector `coeffs`. 31 | template 32 | extern absl::Status ForwardNumberTheoreticTransformHwy( 33 | std::vector& coeffs, 34 | const NttParameters& ntt_params, 35 | const typename ModularInt::Params& mod_params); 36 | 37 | } // namespace rlwe::internal 38 | 39 | #endif // RLWE_DFT_TRANSFORMATIONS_HWY_H_ 40 | -------------------------------------------------------------------------------- /shell_encryption/dft_transformations_hwy_test.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include "shell_encryption/dft_transformations_hwy.h" 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include "absl/status/status.h" 24 | #include "absl/strings/str_cat.h" 25 | #include "hwy/targets.h" 26 | #include "shell_encryption/context.h" 27 | #include "shell_encryption/dft_transformations.h" 28 | #include "shell_encryption/status_macros.h" 29 | #include "shell_encryption/statusor.h" 30 | #include "shell_encryption/testing/parameters.h" 31 | #include "shell_encryption/testing/status_matchers.h" 32 | #include "shell_encryption/testing/status_testing.h" 33 | #include "shell_encryption/testing/testing_prng.h" 34 | 35 | #undef HWY_TARGET_INCLUDE 36 | #define HWY_TARGET_INCLUDE "shell_encryption/dft_transformations_hwy_test.cc" 37 | #include "hwy/foreach_target.h" // IWYU pragma: keep 38 | #include "hwy/highway.h" 39 | 40 | #if HWY_ONCE || HWY_IDE 41 | 42 | namespace rlwe::internal { 43 | namespace { 44 | 45 | using ::rlwe::testing::StatusIs; 46 | using ::testing::HasSubstr; 47 | 48 | template 49 | class DftTransformationsHwyTest : public ::testing::Test { 50 | using ModularIntParams = typename ModularInt::Params; 51 | 52 | protected: 53 | void SetUp() override { 54 | typename RlweContext::Parameters params = 55 | testing::ContextParameters::Value()[0]; 56 | ASSERT_OK_AND_ASSIGN(context_, RlweContext::Create(params)); 57 | prng_ = std::make_unique(0); 58 | } 59 | 60 | StatusOr> SampleCoeffs( 61 | int log_n, const ModularIntParams* mod_params) const { 62 | std::vector coeffs; 63 | for (int i = 0; i < (1 << log_n); ++i) { 64 | RLWE_ASSIGN_OR_RETURN(ModularInt coeff, 65 | ModularInt::ImportRandom(prng_.get(), mod_params)); 66 | coeffs.push_back(std::move(coeff)); 67 | } 68 | return coeffs; 69 | } 70 | 71 | std::unique_ptr> context_; 72 | std::unique_ptr prng_; 73 | }; 74 | 75 | TYPED_TEST_SUITE(DftTransformationsHwyTest, testing::ModularIntTypes); 76 | 77 | TYPED_TEST(DftTransformationsHwyTest, ForwardNttFailsIfInvalidCoeffsLength) { 78 | // Create a vector of N+1 modular integers, where N is a power of two. 79 | int log_n = this->context_->GetLogN(); 80 | std::vector coeffs( 81 | (1 << log_n) + 1, 82 | TypeParam::ImportZero(this->context_->GetModulusParams())); 83 | 84 | EXPECT_THAT(ForwardNumberTheoreticTransformHwy( 85 | coeffs, *this->context_->GetNttParams(), 86 | *this->context_->GetModulusParams()), 87 | StatusIs(absl::StatusCode::kInvalidArgument, 88 | HasSubstr(absl::StrCat("`coeffs` must have contain ", 89 | (1 << log_n), " elements")))); 90 | } 91 | 92 | TYPED_TEST(DftTransformationsHwyTest, ForwardNumberTheoreticTransform) { 93 | auto context_params = testing::ContextParameters::Value(); 94 | // Add corner test cases where log degree is very small. 95 | context_params.push_back({/*.modulus =*/5, /*.log_n =*/1, /*.log_t =*/1, 96 | /*.variance =*/8}); 97 | context_params.push_back({/*.modulus =*/17, /*.log_n =*/2, /*.log_t =*/1, 98 | /*.variance =*/8}); 99 | for (const auto& params : context_params) { 100 | ASSERT_OK_AND_ASSIGN(auto context, RlweContext::Create(params)); 101 | int log_n = context->GetLogN(); 102 | 103 | ASSERT_OK_AND_ASSIGN( 104 | std::vector coeffs_original, 105 | this->SampleCoeffs(log_n, context->GetModulusParams())); 106 | std::vector coeffs_truth = coeffs_original; 107 | ASSERT_OK(ForwardNumberTheoreticTransform( 108 | coeffs_truth, *context->GetNttParams(), *context->GetModulusParams())); 109 | // It's not really desirable to test different targets in a single test, but 110 | // I can't seem to move these to parameterized tests. 111 | for (auto target : hwy::SupportedAndGeneratedTargets()) { 112 | hwy::SetSupportedTargetsForTest(target); 113 | std::vector coeffs = coeffs_original; 114 | ASSERT_OK(ForwardNumberTheoreticTransformHwy( 115 | coeffs, *context->GetNttParams(), *context->GetModulusParams())); 116 | 117 | EXPECT_EQ(coeffs.size(), (1 << log_n)); 118 | for (int i = 0; i < coeffs.size(); ++i) { 119 | EXPECT_EQ(coeffs[i], coeffs_truth[i]); 120 | } 121 | hwy::SetSupportedTargetsForTest(0); 122 | } 123 | } 124 | } 125 | 126 | } // namespace 127 | } // namespace rlwe::internal 128 | 129 | #endif 130 | -------------------------------------------------------------------------------- /shell_encryption/gadget.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef RLWE_GADGET_H_ 17 | #define RLWE_GADGET_H_ 18 | 19 | #include 20 | #include 21 | 22 | #include "shell_encryption/status_macros.h" 23 | #include "shell_encryption/statusor.h" 24 | 25 | // Common methods for working with "gadgets". These are ways of representing 26 | // large norm (but small dimension) objects with small norm (but large 27 | // dimension) objects. For example, one can take an integer |x| <= q, and write 28 | // 29 | // x = \sum_{i = 0}^{\log_2 q} x_i 2^i 30 | // 31 | // where the x_i are small. One can of course generalize this to digits B != 2. 32 | // The other main type of gadget is taking |x| <= \prod_i p_i for coprime values 33 | // p_i, and mapping 34 | // 35 | // x -> (x mod p_0, x mod p_1, ..., x mod p_k) 36 | // 37 | // For a formal introduction to gadgets, see https://eprint.iacr.org/2018/946. 38 | 39 | namespace rlwe { 40 | 41 | // Method to compute the number of digits needed to represent integers mod 42 | // q in base T. 43 | template 44 | inline int GadgetSize(int log_base, 45 | const typename ModularInt::Params* mod_params) { 46 | return (mod_params->log_modulus + (log_base - 1)) / log_base; 47 | } 48 | 49 | // Return the vector of base-B decomposition of each x mod q, where q is the 50 | // modulus defined in mod_params, ie return a vector of [v_0, ..., v_{k-1}] 51 | // such that sum(v_{j} * B^j) = x[i] mod q, and v_j \in [0, B) 52 | template 53 | StatusOr>> BaseDecompose( 54 | const std::vector& coeffs, 55 | const typename ModularInt::Params* mod_params, const size_t log_base, 56 | int dimension) { 57 | // Determine the dimension, which is ceil(log_base(q)) 58 | std::vector curr_digits(coeffs.size(), 0); 59 | std::transform( 60 | coeffs.begin(), coeffs.end(), curr_digits.begin(), 61 | [mod_params](ModularInt x) { return x.ExportInt(mod_params); }); 62 | 63 | // Compute the mask to extract the log_base least significant 64 | // bits 65 | typename ModularInt::Int mask = 66 | (static_cast(1) << log_base) - 1; 67 | std::vector> result(dimension); 68 | for (int i = 0; i < dimension; i++) { 69 | result[i].reserve(curr_digits.size()); 70 | for (int j = 0; j < curr_digits.size(); ++j) { 71 | RLWE_ASSIGN_OR_RETURN( 72 | auto coefficient_part, 73 | ModularInt::ImportInt((curr_digits[j] & mask), mod_params)); 74 | result[i].push_back(std::move(coefficient_part)); 75 | curr_digits[j] >>= log_base; 76 | } 77 | } 78 | return result; 79 | } 80 | 81 | } // namespace rlwe 82 | 83 | #endif // RLWE_GADGET_H_ 84 | -------------------------------------------------------------------------------- /shell_encryption/integral_types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef RLWE_INTEGRAL_TYPES_H_ 18 | #define RLWE_INTEGRAL_TYPES_H_ 19 | 20 | #include "absl/numeric/int128.h" 21 | 22 | namespace rlwe { 23 | 24 | typedef uint8_t Uint8; 25 | typedef uint16_t Uint16; 26 | typedef uint32_t Uint32; 27 | typedef uint64_t Uint64; 28 | 29 | #ifdef ABSL_HAVE_INTRINSIC_INT128 30 | typedef unsigned __int128 Uint128; 31 | #else 32 | typedef absl::uint128 Uint128; 33 | #endif 34 | 35 | } // namespace rlwe 36 | 37 | #endif // RLWE_INTEGRAL_TYPES_H_ 38 | -------------------------------------------------------------------------------- /shell_encryption/multi_party/public_key.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "shell_encryption/multi_party/public_key.h" 16 | 17 | #include 18 | 19 | #include "absl/numeric/int128.h" 20 | #include "absl/status/status.h" 21 | #include "absl/status/statusor.h" 22 | #include "absl/types/span.h" 23 | #include "shell_encryption/integral_types.h" 24 | #include "shell_encryption/montgomery.h" 25 | #include "shell_encryption/multi_party/public_key_share.h" 26 | #include "shell_encryption/multi_party/public_parameter.h" 27 | #include "shell_encryption/rns/rns_polynomial.h" 28 | #include "shell_encryption/status_macros.h" 29 | 30 | namespace rlwe { 31 | namespace multi_party { 32 | 33 | template 34 | absl::StatusOr> PublicKey::Create( 35 | const PublicParameter* public_parameter, 36 | absl::Span> public_key_shares) { 37 | if (public_parameter == nullptr) { 38 | return absl::InvalidArgumentError("`public_parameter` must not be null."); 39 | } 40 | if (public_key_shares.empty()) { 41 | return absl::InvalidArgumentError("`public_key_shares` must not be empty."); 42 | } 43 | 44 | RLWE_ASSIGN_OR_RETURN(RnsPolynomial key_b, 45 | RnsPolynomial::CreateZero( 46 | public_parameter->LogN(), 47 | public_parameter->Moduli(), /*is_ntt=*/true)); 48 | for (auto const& public_key_share : public_key_shares) { 49 | RLWE_RETURN_IF_ERROR(key_b.AddInPlace(public_key_share.ComponentB(), 50 | public_parameter->Moduli())); 51 | } 52 | return PublicKey(public_parameter, std::move(key_b)); 53 | } 54 | 55 | template 56 | absl::StatusOr> PublicKey::Deserialize( 57 | const SerializedPublicKey& serialized, 58 | const PublicParameter* public_parameter) { 59 | if (public_parameter == nullptr) { 60 | return absl::InvalidArgumentError("`public_parameter` must not be null."); 61 | } 62 | 63 | RLWE_ASSIGN_OR_RETURN(RnsPolynomial key_b, 64 | RnsPolynomial::Deserialize( 65 | serialized.key_b(), public_parameter->Moduli())); 66 | return PublicKey(public_parameter, std::move(key_b)); 67 | } 68 | 69 | template class PublicKey>; 70 | template class PublicKey>; 71 | template class PublicKey>; 72 | #ifdef ABSL_HAVE_INTRINSIC_INT128 73 | template class PublicKey>; 74 | #endif 75 | 76 | } // namespace multi_party 77 | } // namespace rlwe 78 | -------------------------------------------------------------------------------- /shell_encryption/multi_party/public_key_share.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef RLWE_MULTI_PARTY_PUBLIC_KEY_SHARE_H_ 17 | #define RLWE_MULTI_PARTY_PUBLIC_KEY_SHARE_H_ 18 | 19 | #include 20 | 21 | #include "absl/status/status.h" 22 | #include "absl/status/statusor.h" 23 | #include "absl/types/span.h" 24 | #include "shell_encryption/multi_party/public_parameter.h" 25 | #include "shell_encryption/multi_party/secret_key_share.h" 26 | #include "shell_encryption/prng/prng.h" 27 | #include "shell_encryption/rns/rns_modulus.h" 28 | #include "shell_encryption/rns/rns_polynomial.h" 29 | #include "shell_encryption/status_macros.h" 30 | 31 | namespace rlwe { 32 | namespace multi_party { 33 | 34 | // Public key share of the RLWE-based multi-party homomorphic encryption scheme. 35 | // Every secret key share holder derives its own public key share, and by 36 | // combining all public key shares we get the public key of the multi-party 37 | // scheme. 38 | // 39 | // In the current protocol, a public key share is a polynomial b = -a * s + e, 40 | // where `a` is the random "a" component of the public key and is given in the 41 | // public parameter, and `e` is a fresh error polynomial. 42 | template 43 | class PublicKeyShare { 44 | public: 45 | // Returns a public key share based on the given `secret_key_share`. 46 | static absl::StatusOr Create( 47 | const SecretKeyShare* secret_key_share, 48 | const PublicParameter* public_parameter, PrngType prng_type); 49 | 50 | // Creates a new public key share derived from `secret_key_share` and the "a" 51 | // component of the public key as given in `public_parameter`, and populates 52 | // `key_b` with the raw key share polynomial in NTT form. Randomness is 53 | // sampled using `prng`. 54 | // `key_error` is optional and can be null. When it is non-null, `key_error` 55 | // is populated with the error polynomial in NTT form such that 56 | // key_b = -a(X) * secret_key_share + key_error \in Z[X]/(Q, X^N+1), 57 | // where a(X) is the "a" component of the public key. 58 | // `wrap_around` is optional and can be null. When it is non-null, 59 | // `wrap_around` is populated in coefficient form such that 60 | // key_b = -a(X) * secret_key_share + key_error + wrap_around * (X^N + 1) 61 | // over the ring Z[X]/(Q), i.e. the RHS is computed without reduction modulo 62 | // X^N + 1, and the LHS is defined in the first equation above. 63 | // 64 | // The optional `key_error` and `wrap_around` are useful to generate ZK proofs 65 | // about valid public key shares. 66 | // 67 | // Note: When `wrap_around` is non-null, the parameters must be NTT-friendly 68 | // wrt to the larger cyclotomic X^{2N} + 1, i.e. N is a power of 2 and 69 | // the modulus Q must be a product of primes q such that 4N factors q-1. 70 | static absl::Status CreateExplicit( 71 | const RnsPolynomial& secret_key_share, 72 | const PublicParameter* public_parameter, SecurePrng* prng, 73 | RnsPolynomial* key_b, RnsPolynomial* key_error, 74 | RnsPolynomial* wrap_around); 75 | 76 | static absl::StatusOr Deserialize( 77 | const SerializedPublicKeyShare& serialized, 78 | absl::Span* const> moduli); 79 | 80 | absl::StatusOr Serialize() const { 81 | SerializedPublicKeyShare serialized; 82 | RLWE_ASSIGN_OR_RETURN(*serialized.mutable_key_b(), 83 | key_b_.Serialize(moduli_)); 84 | return serialized; 85 | } 86 | 87 | // Accessor to the "b" component in a public key share. 88 | const RnsPolynomial& ComponentB() const { return key_b_; } 89 | 90 | private: 91 | explicit PublicKeyShare(RnsPolynomial key_b, 92 | std::vector*> moduli) 93 | : key_b_(std::move(key_b)), moduli_(std::move(moduli)) {} 94 | 95 | // The "b" component of the public key share. 96 | RnsPolynomial key_b_; 97 | 98 | // The prime moduli constituting the modulus of this ciphertext. 99 | std::vector*> moduli_; 100 | }; 101 | 102 | } // namespace multi_party 103 | } // namespace rlwe 104 | 105 | #endif // RLWE_MULTI_PARTY_PUBLIC_KEY_SHARE_H_ 106 | -------------------------------------------------------------------------------- /shell_encryption/multi_party/public_parameter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef RLWE_MULTI_PARTY_PUBLIC_PARAMETER_H_ 17 | #define RLWE_MULTI_PARTY_PUBLIC_PARAMETER_H_ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "absl/status/status.h" 24 | #include "absl/status/statusor.h" 25 | #include "absl/types/span.h" 26 | #include "shell_encryption/multi_party/serialization.pb.h" 27 | #include "shell_encryption/prng/prng.h" 28 | #include "shell_encryption/rns/rns_context.h" 29 | #include "shell_encryption/rns/rns_modulus.h" 30 | #include "shell_encryption/rns/rns_polynomial.h" 31 | #include "shell_encryption/status_macros.h" 32 | 33 | namespace rlwe { 34 | namespace multi_party { 35 | 36 | // This class stores the public parameter of multi-party additive homomorphic 37 | // encryption protocol, which is used by all parties to generate their public 38 | // key shares. 39 | template 40 | class PublicParameter { 41 | public: 42 | // Deterministic factory function to create a public parameter from a seed. 43 | static absl::StatusOr> CreateFromSeed( 44 | const RnsContext* rns_context, int error_variance, 45 | std::string prng_seed, PrngType prng_type); 46 | 47 | // Factory function to create a fresh public parameter for the parties to 48 | // generate their public key shares. 49 | static absl::StatusOr> Create( 50 | const RnsContext* rns_context, int error_variance, 51 | PrngType prng_type); 52 | 53 | static absl::StatusOr> Deserialize( 54 | const SerializedPublicParameter& serialized, 55 | const RnsContext* rns_context); 56 | 57 | absl::StatusOr Serialize() const { 58 | SerializedPublicParameter serialized; 59 | serialized.set_prng_seed(prng_seed_); 60 | serialized.set_prng_type(prng_type_); 61 | serialized.set_error_variance(error_variance_); 62 | return serialized; 63 | } 64 | 65 | // Accessors. 66 | int ErrorVariance() const { return error_variance_; } 67 | 68 | const RnsPolynomial& PublicKeyComponentA() const { 69 | return key_a_; 70 | } 71 | 72 | absl::Span* const> Moduli() const { 73 | return moduli_; 74 | } 75 | 76 | int LogN() const { return key_a_.LogN(); } 77 | int NumCoeffs() const { return key_a_.NumCoeffs(); } 78 | int NumModuli() const { return moduli_.size(); } 79 | 80 | private: 81 | explicit PublicParameter(std::string prng_seed, PrngType prng_type, 82 | int error_variance, RnsPolynomial key_a, 83 | std::vector*> moduli) 84 | : prng_seed_(std::move(prng_seed)), 85 | prng_type_(prng_type), 86 | error_variance_(error_variance), 87 | key_a_(std::move(key_a)), 88 | moduli_(std::move(moduli)) {} 89 | 90 | // PRNG seed and type for sampling the random polynomial `key_a_`. 91 | const std::string prng_seed_; 92 | const PrngType prng_type_; 93 | 94 | // The variance for generating the public key and for encrypting using the 95 | // public key. 96 | const int error_variance_; 97 | 98 | // The "a" component of the public key. 99 | const RnsPolynomial key_a_; 100 | 101 | // The RNS moduli used by the public key. 102 | const std::vector*> moduli_; 103 | }; 104 | 105 | } // namespace multi_party 106 | } // namespace rlwe 107 | 108 | #endif // RLWE_MULTI_PARTY_PUBLIC_PARAMETER_H_ 109 | -------------------------------------------------------------------------------- /shell_encryption/multi_party/recovery.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef RLWE_MULTI_PARTY_RECOVERY_H_ 17 | #define RLWE_MULTI_PARTY_RECOVERY_H_ 18 | 19 | #include 20 | 21 | #include "absl/status/status.h" 22 | #include "absl/status/statusor.h" 23 | #include "absl/types/span.h" 24 | #include "shell_encryption/multi_party/public_parameter.h" 25 | #include "shell_encryption/rns/coefficient_encoder.h" 26 | #include "shell_encryption/rns/rns_polynomial.h" 27 | #include "shell_encryption/status_macros.h" 28 | 29 | namespace rlwe { 30 | namespace multi_party { 31 | 32 | template > 34 | absl::StatusOr> RecoverMessages( 35 | absl::Span> partial_decryptions, 36 | const RnsPolynomial& ciphertext_component_b, 37 | const PublicParameter& public_parameter, 38 | const Encoder* encoder) { 39 | if (partial_decryptions.empty()) { 40 | return absl::InvalidArgumentError( 41 | "`partial_decryptions` must not be empty."); 42 | } 43 | 44 | auto moduli = public_parameter.Moduli(); 45 | RLWE_ASSIGN_OR_RETURN(RnsPolynomial noisy_plaintext, 46 | RnsPolynomial::CreateZero( 47 | public_parameter.LogN(), moduli, /*is_ntt=*/true)); 48 | 49 | for (auto const& partial_decryption : partial_decryptions) { 50 | RLWE_RETURN_IF_ERROR( 51 | noisy_plaintext.AddInPlace(partial_decryption, moduli)); 52 | } 53 | 54 | return RecoverMessagesFromSum(noisy_plaintext, ciphertext_component_b, 55 | public_parameter, encoder); 56 | } 57 | 58 | template > 60 | absl::StatusOr> RecoverMessagesFromSum( 61 | const RnsPolynomial& sum_partial_decryptions, 62 | const RnsPolynomial& ciphertext_component_b, 63 | const PublicParameter& public_parameter, 64 | const Encoder* encoder) { 65 | if (encoder == nullptr) { 66 | return absl::InvalidArgumentError("`encoder` must not be null."); 67 | } 68 | 69 | auto moduli = public_parameter.Moduli(); 70 | 71 | RLWE_ASSIGN_OR_RETURN( 72 | RnsPolynomial noisy_plaintext, 73 | sum_partial_decryptions.Add(ciphertext_component_b, moduli)); 74 | 75 | // Decode the noisy plaintext polynomial. 76 | return encoder->DecodeBfv(std::move(noisy_plaintext), moduli); 77 | } 78 | 79 | } // namespace multi_party 80 | } // namespace rlwe 81 | 82 | #endif // RLWE_MULTI_PARTY_RECOVERY_H_ 83 | -------------------------------------------------------------------------------- /shell_encryption/multi_party/secret_key_share.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "shell_encryption/multi_party/secret_key_share.h" 16 | 17 | #include 18 | #include 19 | 20 | #include "absl/numeric/int128.h" 21 | #include "absl/status/status.h" 22 | #include "absl/status/statusor.h" 23 | #include "absl/types/span.h" 24 | #include "shell_encryption/integral_types.h" 25 | #include "shell_encryption/montgomery.h" 26 | #include "shell_encryption/multi_party/polynomial_utilities.h" 27 | #include "shell_encryption/prng/prng.h" 28 | #include "shell_encryption/rns/error_distribution.h" 29 | #include "shell_encryption/rns/rns_context.h" 30 | #include "shell_encryption/rns/rns_modulus.h" 31 | #include "shell_encryption/rns/rns_polynomial.h" 32 | #include "shell_encryption/sampler/discrete_gaussian.h" 33 | #include "shell_encryption/status_macros.h" 34 | 35 | namespace rlwe { 36 | namespace multi_party { 37 | 38 | template 39 | absl::StatusOr> SecretKeyShare::Sample( 40 | const RnsContext* rns_context, SecurePrng* prng) { 41 | if (rns_context == nullptr) { 42 | return absl::InvalidArgumentError("`rns_context` must not be null."); 43 | } 44 | if (prng == nullptr) { 45 | return absl::InvalidArgumentError("`prng` must not be null."); 46 | } 47 | 48 | // Sample the secret s with uniform ternary coefficients. 49 | int log_n = rns_context->LogN(); 50 | std::vector*> moduli = 51 | rns_context->MainPrimeModuli(); 52 | RLWE_ASSIGN_OR_RETURN(RnsPolynomial s, 53 | SampleUniformTernary(log_n, moduli, prng)); 54 | return SecretKeyShare(std::move(s), std::move(moduli)); 55 | } 56 | 57 | template 58 | absl::StatusOr> 59 | SecretKeyShare::PartialDecrypt( 60 | const RnsPolynomial& ciphertext_component_a, double s_flood, 61 | const DiscreteGaussianSampler* dg_sampler, SecurePrng* prng, 62 | RnsPolynomial* error_flood, 63 | RnsPolynomial* wrap_around) const { 64 | if (dg_sampler == nullptr) { 65 | return absl::InvalidArgumentError("`dg_sampler` must not be null."); 66 | } 67 | if (prng == nullptr) { 68 | return absl::InvalidArgumentError("`prng` must not be null."); 69 | } 70 | 71 | // Sample e_flood. 72 | RLWE_ASSIGN_OR_RETURN(RnsPolynomial d, 73 | SampleDiscreteGaussian( 74 | LogN(), s_flood, moduli_, dg_sampler, prng)); 75 | if (error_flood != nullptr) { 76 | *error_flood = d; 77 | } 78 | 79 | if (!d.IsNttForm()) { 80 | RLWE_RETURN_IF_ERROR(d.ConvertToNttForm(moduli_)); 81 | } 82 | 83 | RnsPolynomial c1 = ciphertext_component_a; 84 | if (!c1.IsNttForm()) { 85 | RLWE_RETURN_IF_ERROR(c1.ConvertToNttForm(moduli_)); 86 | } 87 | 88 | // c1s = c1 * s. 89 | RLWE_ASSIGN_OR_RETURN(RnsPolynomial c1s, c1.Mul(key_, moduli_)); 90 | 91 | // d = c1 * s + e_flood. 92 | RLWE_RETURN_IF_ERROR(d.AddInPlace(c1s, moduli_)); 93 | 94 | // Optionally save wraparound such that 95 | // d = c1 * s + e_flood + wraparound * (X^N + 1) over Z_Q[X]. 96 | if (wrap_around != nullptr) { 97 | RLWE_ASSIGN_OR_RETURN( 98 | *wrap_around, 99 | rlwe_internal::QuotientOf(c1, key_, c1s, absl::MakeSpan(moduli_))); 100 | } 101 | 102 | return d; 103 | } 104 | 105 | template class SecretKeyShare>; 106 | template class SecretKeyShare>; 107 | template class SecretKeyShare>; 108 | #ifdef ABSL_HAVE_INTRINSIC_INT128 109 | template class SecretKeyShare>; 110 | #endif 111 | 112 | } // namespace multi_party 113 | } // namespace rlwe 114 | -------------------------------------------------------------------------------- /shell_encryption/multi_party/secret_key_share.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef RLWE_MULTI_PARTY_SECRET_KEY_SHARE_H_ 17 | #define RLWE_MULTI_PARTY_SECRET_KEY_SHARE_H_ 18 | 19 | #include 20 | 21 | #include "absl/status/status.h" 22 | #include "absl/status/statusor.h" 23 | #include "absl/types/span.h" 24 | #include "shell_encryption/prng/prng.h" 25 | #include "shell_encryption/rns/rns_context.h" 26 | #include "shell_encryption/rns/rns_modulus.h" 27 | #include "shell_encryption/rns/rns_polynomial.h" 28 | #include "shell_encryption/sampler/discrete_gaussian.h" 29 | 30 | namespace rlwe { 31 | namespace multi_party { 32 | 33 | // Secret key share of the RLWE-based multi-party homomorphic encryption scheme. 34 | // Every secret key share is held by a party in the protocol, and it is used to 35 | // partially decrypt a ciphertext encrypted under the multi-party public key. 36 | template 37 | class SecretKeyShare { 38 | public: 39 | using Integer = typename ModularInt::Int; 40 | 41 | // Samples a secret key share from the uniform ternary distribution, wrt the 42 | // RNS `moduli`. 43 | static absl::StatusOr Sample( 44 | const RnsContext* rns_context, SecurePrng* prng); 45 | 46 | // Returns the partial decryption contribution from this secret key share 47 | // holder, for a ciphertext whose "a" component is given. 48 | absl::StatusOr> PartialDecrypt( 49 | const RnsPolynomial& ciphertext_component_a, double s_flood, 50 | const DiscreteGaussianSampler* dg_sampler, SecurePrng* prng, 51 | RnsPolynomial* error_flood, 52 | RnsPolynomial* wrap_around) const; 53 | 54 | // Accessors 55 | int LogN() const { return key_.LogN(); } 56 | int NumCoeffs() const { return key_.NumCoeffs(); } 57 | int NumModuli() const { return moduli_.size(); } 58 | 59 | // Accessor for the prime moduli chain. 60 | absl::Span* const> Moduli() const { 61 | return moduli_; 62 | } 63 | 64 | // Accessor for the key polynomial 65 | const RnsPolynomial& Key() const { return key_; } 66 | 67 | // For Rust interoperability. Defined in the wrapper library, not here. 68 | friend class SecretKeyShareRawFactory; 69 | 70 | private: 71 | explicit SecretKeyShare(RnsPolynomial key, 72 | std::vector*> moduli) 73 | : key_(std::move(key)), moduli_(std::move(moduli)) {} 74 | 75 | // The key polynomial 76 | RnsPolynomial key_; 77 | 78 | // The prime moduli constituting the modulus of this ciphertext. 79 | std::vector*> moduli_; 80 | }; 81 | 82 | } // namespace multi_party 83 | } // namespace rlwe 84 | 85 | #endif // RLWE_MULTI_PARTY_SECRET_KEY_SHARE_H_ 86 | -------------------------------------------------------------------------------- /shell_encryption/multi_party/serialization.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto2"; 16 | 17 | package rlwe; 18 | 19 | import "shell_encryption/serialization.proto"; 20 | import "shell_encryption/rns/serialization.proto"; 21 | 22 | option optimize_for = LITE_RUNTIME; 23 | 24 | // Public parameter. 25 | message SerializedPublicParameter { 26 | // Seed used to generate the random polynomial "a" in the public parameter. 27 | optional bytes prng_seed = 1; 28 | 29 | // Type of PRNG used to generate the random polynomial "a" 30 | optional PrngType prng_type = 2; 31 | 32 | // The variance of error distribution for generating the public key. 33 | optional int32 error_variance = 3; 34 | } 35 | 36 | // Public key share. 37 | message SerializedPublicKeyShare { 38 | // The "b" components of the public key share. 39 | optional SerializedRnsPolynomial key_b = 1; 40 | } 41 | 42 | // Public key. 43 | message SerializedPublicKey { 44 | // The "b" components of the public key. 45 | optional SerializedRnsPolynomial key_b = 1; 46 | } 47 | -------------------------------------------------------------------------------- /shell_encryption/multi_party/testing/BUILD: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Google LLC. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | load("@rules_cc//cc:cc_library.bzl", "cc_library") 16 | 17 | package(default_visibility = ["//visibility:public"]) 18 | 19 | cc_library( 20 | name = "parameters", 21 | testonly = 1, 22 | hdrs = ["parameters.h"], 23 | deps = [ 24 | "//shell_encryption:integral_types", 25 | "//shell_encryption:montgomery", 26 | "@com_github_google_googletest//:gtest", 27 | ], 28 | ) 29 | -------------------------------------------------------------------------------- /shell_encryption/multi_party/testing/parameters.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef RLWE_MULTI_PARTY_TESTING_PARAMETERS_H_ 17 | #define RLWE_MULTI_PARTY_TESTING_PARAMETERS_H_ 18 | 19 | #include 20 | 21 | #include 22 | #include "shell_encryption/integral_types.h" 23 | #include "shell_encryption/montgomery.h" 24 | 25 | namespace rlwe { 26 | namespace multi_party { 27 | namespace testing { 28 | 29 | using ModularInt32 = MontgomeryInt; 30 | using ModularInt64 = MontgomeryInt; 31 | using ModularIntTypesForMultiParty = 32 | ::testing::Types, rlwe::MontgomeryInt>; 33 | using ModularIntTypesForNegativeTests = ::testing::Types; 34 | 35 | // Aggregate type that holds the parameters defining multi-party BFV protocol. 36 | template 37 | struct MpaheParameters { 38 | int log_n; 39 | std::vector qs; // main prime moduli. 40 | std::vector ps; // auxiliary prime moduli. 41 | typename ModularInt::Int t; // plaintext modulus. 42 | int log_gadget_base; // Bit size of gadget base. 43 | double s_flood; // Gaussian parameter for flooding noise. 44 | }; 45 | 46 | // Returns the testing parameters for the underlying integer type. 47 | template 48 | MpaheParameters GetMultiPartyParameters(); 49 | 50 | // Returns the testing parameters when instantiating RNS using 32-bit integers. 51 | // The prime moduli in `qs` must be NTT-friendly for the higher order cyclotomic 52 | // X^{2N} + 1 to allow efficient computation of the "wrap around" polynomial for 53 | // the public key share. 54 | template <> 55 | inline MpaheParameters GetMultiPartyParameters() { 56 | return 57 | // 60 bits main modulus. 58 | MpaheParameters{.log_n = 11, 59 | .qs = {1073692673, 1073643521}, 60 | .ps = {}, 61 | .t = 10001, 62 | .log_gadget_base = 5, 63 | .s_flood = 1.0e+10}; 64 | } 65 | 66 | // Returns the testing parameters when instantiating RNS using 64-bit integers. 67 | // Same as above, the prime moduli in `qs` must be NTT friendly for X^{2N} + 1. 68 | template <> 69 | inline MpaheParameters GetMultiPartyParameters() { 70 | return 71 | // 69 bits main modulus. 72 | MpaheParameters{.log_n = 12, 73 | .qs = {34359410689ULL, 34359214081ULL}, 74 | .ps = {}, 75 | .t = 54001, 76 | .log_gadget_base = 5, 77 | .s_flood = 4.25839e+13}; 78 | } 79 | 80 | } // namespace testing 81 | } // namespace multi_party 82 | } // namespace rlwe 83 | 84 | #endif // RLWE_MULTI_PARTY_TESTING_PARAMETERS_H_ 85 | -------------------------------------------------------------------------------- /shell_encryption/ntt_parameters.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | #include "shell_encryption/ntt_parameters.h" 16 | 17 | namespace rlwe { 18 | namespace internal { 19 | 20 | // Bit reverse only among the rightmost log_n bytes. 21 | unsigned int Bitrev(unsigned int input, unsigned int log_n) { 22 | unsigned int output = 0; 23 | for (unsigned int i = 0; i < log_n; i++) { 24 | output <<= 1; 25 | output |= input & 0x01; 26 | input >>= 1; 27 | } 28 | 29 | return output; 30 | } 31 | 32 | std::vector BitrevArray(unsigned int log_n) { 33 | unsigned int n = 1 << log_n; 34 | std::vector output(n); 35 | 36 | for (unsigned int i = 0; i < n; i++) { 37 | output[i] = Bitrev(i, log_n); 38 | } 39 | 40 | return output; 41 | } 42 | 43 | } // namespace internal 44 | } // namespace rlwe 45 | -------------------------------------------------------------------------------- /shell_encryption/opt/BUILD: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Google LLC. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | load("@rules_cc//cc:cc_library.bzl", "cc_library") 16 | load("@rules_cc//cc:cc_test.bzl", "cc_test") 17 | 18 | package(default_visibility = ["//visibility:public"]) 19 | 20 | licenses(["notice"]) 21 | 22 | cc_library( 23 | name = "constant_polynomial", 24 | hdrs = ["constant_polynomial.h"], 25 | deps = [ 26 | "//shell_encryption:statusor_fork", 27 | "@com_google_absl//absl/status", 28 | ], 29 | ) 30 | 31 | cc_test( 32 | name = "constant_polynomial_test", 33 | srcs = ["constant_polynomial_test.cc"], 34 | deps = [ 35 | ":constant_polynomial", 36 | "//shell_encryption:context", 37 | "//shell_encryption:polynomial", 38 | "//shell_encryption/testing:parameters", 39 | "//shell_encryption/testing:status_is_fork", 40 | "//shell_encryption/testing:status_testing", 41 | "@com_github_google_googletest//:gtest_main", 42 | ], 43 | ) 44 | 45 | cc_library( 46 | name = "lazy_polynomial", 47 | hdrs = ["lazy_polynomial.h"], 48 | deps = [ 49 | "//shell_encryption:statusor_fork", 50 | "@com_google_absl//absl/status", 51 | "@com_google_absl//absl/strings", 52 | ], 53 | ) 54 | 55 | cc_test( 56 | name = "lazy_polynomial_test", 57 | srcs = ["lazy_polynomial_test.cc"], 58 | deps = [ 59 | ":lazy_polynomial", 60 | "//shell_encryption:context", 61 | "//shell_encryption:montgomery", 62 | "//shell_encryption:polynomial", 63 | "//shell_encryption:statusor_fork", 64 | "//shell_encryption/prng:single_thread_hkdf_prng", 65 | "//shell_encryption/testing:parameters", 66 | "//shell_encryption/testing:status_is_fork", 67 | "//shell_encryption/testing:status_testing", 68 | "@com_github_google_googletest//:gtest_main", 69 | "@com_google_absl//absl/status", 70 | ], 71 | ) 72 | -------------------------------------------------------------------------------- /shell_encryption/opt/constant_polynomial.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef RLWE_OPT_CONSTANT_POLYNOMIAL_H_ 17 | #define RLWE_OPT_CONSTANT_POLYNOMIAL_H_ 18 | 19 | #include 20 | 21 | #include "absl/status/status.h" 22 | #include "shell_encryption/statusor.h" 23 | 24 | namespace rlwe { 25 | 26 | // Forward declaration of a Polynomial. 27 | template 28 | class Polynomial; 29 | 30 | // This class defines a constant polynomial, which cannot be operated on, but 31 | // enable to speed up polynomial multiplications. 32 | template 33 | class ConstantPolynomial { 34 | public: 35 | using Int = typename ModularInt::Int; 36 | 37 | // Delete default constructor. 38 | ConstantPolynomial() = delete; 39 | 40 | // Factory function to create a ConstantPolynomial. 41 | static StatusOr Create( 42 | std::vector constant, std::vector constant_barrett) { 43 | if (constant.size() != constant_barrett.size()) { 44 | return absl::InvalidArgumentError( 45 | "The vectors of Int do not have the same size."); 46 | } 47 | return ConstantPolynomial(std::move(constant), std::move(constant_barrett)); 48 | } 49 | 50 | // Get the length. 51 | size_t Len() const { return coeffs_constant_.size(); } 52 | 53 | private: 54 | // Private constructor. 55 | ConstantPolynomial(std::vector constant, 56 | std::vector constant_barrett) 57 | : coeffs_constant_(std::move(constant)), 58 | coeffs_constant_barrett_(std::move(constant_barrett)) {} 59 | 60 | // Enable MulConstantInPlace() and FusedMulConstantAddInPlace() inside 61 | // Polynomial to access internal members. 62 | friend absl::Status Polynomial::MulConstantInPlace( 63 | const ConstantPolynomial& that, 64 | const typename ModularInt::Params* modular_params); 65 | friend absl::Status Polynomial::FusedMulConstantAddInPlace( 66 | const Polynomial& a, const ConstantPolynomial& b, 67 | const typename ModularInt::Params* modular_params); 68 | 69 | // Constant private members only usable from the Polynomial class. 70 | const std::vector coeffs_constant_; 71 | const std::vector coeffs_constant_barrett_; 72 | }; 73 | 74 | } // namespace rlwe 75 | 76 | #endif // RLWE_OPT_CONSTANT_POLYNOMIAL_H_ 77 | -------------------------------------------------------------------------------- /shell_encryption/opt/constant_polynomial_test.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include "shell_encryption/opt/constant_polynomial.h" 17 | 18 | #include 19 | #include 20 | #include "shell_encryption/context.h" 21 | #include "shell_encryption/polynomial.h" // Needs to be included since Polynomial is forward declarated. 22 | #include "shell_encryption/testing/parameters.h" 23 | #include "shell_encryption/testing/status_matchers.h" 24 | #include "shell_encryption/testing/status_testing.h" 25 | 26 | namespace { 27 | 28 | using rlwe::testing::StatusIs; 29 | 30 | template 31 | class ConstantPolynomialTest : public ::testing::Test {}; 32 | TYPED_TEST_SUITE(ConstantPolynomialTest, rlwe::testing::ModularIntTypes); 33 | 34 | TYPED_TEST(ConstantPolynomialTest, Works) { 35 | for (const auto& params : 36 | rlwe::testing::ContextParameters::Value()) { 37 | ASSERT_OK_AND_ASSIGN(auto context, 38 | rlwe::RlweContext::Create(params)); 39 | std::vector constant, constant_barrett; 40 | 41 | for (auto length_constant : {1, 10, 1024}) { 42 | constant.resize(length_constant); 43 | for (auto length_constant_barrett : {1, 10, 1024}) { 44 | constant_barrett.resize(length_constant_barrett); 45 | 46 | if (length_constant == length_constant_barrett) { 47 | ASSERT_OK_AND_ASSIGN(auto p, 48 | rlwe::ConstantPolynomial::Create( 49 | constant, constant_barrett)); 50 | } else { 51 | EXPECT_THAT( 52 | rlwe::ConstantPolynomial::Create(constant, 53 | constant_barrett), 54 | StatusIs(::absl::StatusCode::kInvalidArgument, 55 | "The vectors of Int do not have the same size.")); 56 | } 57 | } 58 | } 59 | } 60 | } 61 | 62 | } // namespace 63 | -------------------------------------------------------------------------------- /shell_encryption/prng/chacha_prng.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include "shell_encryption/prng/chacha_prng.h" 17 | 18 | #include 19 | 20 | #include "absl/memory/memory.h" 21 | #include "absl/strings/str_cat.h" 22 | #include "absl/strings/string_view.h" 23 | #include "shell_encryption/prng/chacha_prng_util.h" 24 | #include "shell_encryption/status_macros.h" 25 | 26 | namespace rlwe { 27 | 28 | ChaChaPrng::ChaChaPrng(absl::string_view in_key, int position_in_buffer, 29 | int salt_counter, std::vector buffer) 30 | : key_(in_key), 31 | position_in_buffer_(position_in_buffer), 32 | salt_counter_(salt_counter), 33 | buffer_(std::move(buffer)) {} 34 | 35 | rlwe::StatusOr> ChaChaPrng::Create( 36 | absl::string_view in_key) { 37 | if (static_cast(in_key.length()) != SeedLength()) { 38 | return absl::InvalidArgumentError( 39 | absl::StrCat("Cannot create Prng with key of the " 40 | "wrong size. Real ", 41 | "key length of ", in_key.length(), " instead of expected ", 42 | "key length of ", SeedLength(), ".")); 43 | } 44 | int position_in_buffer = 0; 45 | int salt_counter = 0; 46 | std::vector buffer; 47 | RLWE_RETURN_IF_ERROR( 48 | internal::ChaChaPrngResalt(in_key, internal::kChaChaOutputBytes, 49 | &salt_counter, &position_in_buffer, &buffer)); 50 | return absl::WrapUnique(new ChaChaPrng( 51 | in_key, position_in_buffer, salt_counter, std::move(buffer))); 52 | } 53 | 54 | rlwe::StatusOr ChaChaPrng::Rand8() ABSL_LOCKS_EXCLUDED(mu_) { 55 | absl::MutexLock lock(mu_); 56 | return internal::ChaChaPrngRand8(key_, &position_in_buffer_, &salt_counter_, 57 | &buffer_); 58 | } 59 | 60 | rlwe::StatusOr ChaChaPrng::Rand64() ABSL_LOCKS_EXCLUDED(mu_) { 61 | absl::MutexLock lock(mu_); 62 | return internal::ChaChaPrngRand64(key_, &position_in_buffer_, &salt_counter_, 63 | &buffer_); 64 | } 65 | 66 | } // namespace rlwe 67 | -------------------------------------------------------------------------------- /shell_encryption/prng/chacha_prng.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | // An implementation of a PRNG using the ChaCha20 stream cipher. Since this is 17 | // a stream cipher, the key stream can be obtained by "encrypting" the plaintext 18 | // 0....0. 19 | 20 | #ifndef RLWE_CHACHA_PRNG_H_ 21 | #define RLWE_CHACHA_PRNG_H_ 22 | 23 | #include "absl/base/thread_annotations.h" 24 | #include "absl/strings/string_view.h" 25 | #include "absl/synchronization/mutex.h" 26 | #include "shell_encryption/prng/chacha_prng_util.h" 27 | #include "shell_encryption/prng/prng.h" 28 | #include "shell_encryption/statusor.h" 29 | 30 | namespace rlwe { 31 | 32 | class ChaChaPrng : public SecurePrng { 33 | public: 34 | // Constructs a secure pseudorandom number generator using the ChaCha20 stream 35 | // cipher. The parameter in_key is the key for the ChaCha20. 36 | // 37 | // Input keys should contain sufficient randomness (such as those generated by 38 | // the ChaChaPrngGenerateKey function) to ensure the random generated strings 39 | // are pseudorandom. As long as the initial key contains sufficient entropy, 40 | // there is no bound on the number of pseudorandom bytes that can be created. 41 | // 42 | // ChaChaPrng allows replaying pseudorandom outputs. For any fixed input key, 43 | // the pseudorandom outputs of ChaChaPrng will be identical. 44 | // 45 | // For a fixed key and salt, the underlying ChaCha primitive can 46 | // generate 2^32 * 64 pseudorandom bytes. Instead, we will construct a smaller 47 | // pool of 255 * 32 bytes to match the Hkdf Prng. Once, these bytes have been 48 | // exhausted, the prng deterministically re-salts the key using a salting 49 | // counter, thereby constructing a new internal ChaCha that can output more 50 | // pseudorandom bytes. 51 | // 52 | // Fails if the key is not the expected size or on internal cryptographic 53 | // errors. 54 | // 55 | // Thread safe. 56 | static rlwe::StatusOr> 57 | Create(absl::string_view in_key); 58 | 59 | // Returns 8 bits of randomness. 60 | // 61 | // Fails on internal cryptographic errors. 62 | rlwe::StatusOr Rand8() override; 63 | 64 | // Returns 64 bits of randomness. 65 | // 66 | // Fails on internal cryptographic errors. 67 | rlwe::StatusOr Rand64() override; 68 | 69 | // Generate a valid seed for the Prng. 70 | // 71 | // Fails on internal cryptographic errors. 72 | static rlwe::StatusOr GenerateSeed() { 73 | return internal::ChaChaPrngGenerateKey(); 74 | } 75 | 76 | // Output the size of the expected generated seed. 77 | static int SeedLength() { return internal::kChaChaKeyBytesSize; } 78 | 79 | private: 80 | explicit ChaChaPrng(absl::string_view in_key, int position_in_buffer, 81 | int salt_counter, std::vector buffer); 82 | 83 | absl::Mutex mu_; // Guards all values below 84 | 85 | const std::string key_; 86 | int position_in_buffer_ ABSL_GUARDED_BY(mu_); 87 | int salt_counter_ ABSL_GUARDED_BY(mu_); 88 | std::vector buffer_ ABSL_GUARDED_BY(mu_); 89 | }; 90 | 91 | } // namespace rlwe 92 | 93 | #endif // RLWE_CHACHA_PRNG_H_ 94 | -------------------------------------------------------------------------------- /shell_encryption/prng/chacha_prng_test.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | // This file includes specific unit tests files to test populating the buffer 17 | // every internal::kChaChaOutputBytes bytes. 18 | 19 | #include "shell_encryption/prng/chacha_prng.h" 20 | 21 | #include 22 | #include 23 | #include "absl/strings/str_cat.h" 24 | #include "shell_encryption/testing/status_matchers.h" 25 | #include "shell_encryption/testing/status_testing.h" 26 | 27 | namespace rlwe { 28 | 29 | namespace { 30 | 31 | using ::testing::Eq; 32 | using ::testing::Not; 33 | 34 | class ChaChaPrngTest : public ::testing::Test { 35 | protected: 36 | void SetUp() override { 37 | ASSERT_OK_AND_ASSIGN(seed_, ChaChaPrng::GenerateSeed()); 38 | ASSERT_OK_AND_ASSIGN(prng_, ChaChaPrng::Create(seed_)); 39 | } 40 | 41 | std::string seed_; 42 | std::unique_ptr prng_; 43 | }; 44 | 45 | TEST_F(ChaChaPrngTest, TestRand8BeforeAndAfterResalting) { 46 | // Two random 8 bit strings have 1/256 probability of being equal. Instead, 47 | // we check that a sequence of 8 strings from the PRNG before and after 48 | // salting are not all equal. 49 | std::vector> before_resalt(internal::kChaChaOutputBytes); 50 | for (int i = 0; i < internal::kChaChaOutputBytes / 8; ++i) { 51 | SCOPED_TRACE(absl::StrCat("Iteration ", i, ".")); 52 | std::vector rand8s; 53 | for (int j = 0; j < 8; ++j) { 54 | ASSERT_OK_AND_ASSIGN(auto elt, prng_->Rand8()); 55 | rand8s.push_back(elt); 56 | } 57 | before_resalt.push_back(rand8s); 58 | } 59 | for (int i = 0; i < internal::kChaChaOutputBytes / 8; ++i) { 60 | SCOPED_TRACE(absl::StrCat("Iteration ", i, ".")); 61 | std::vector rand8s; 62 | for (int j = 0; j < 8; ++j) { 63 | ASSERT_OK_AND_ASSIGN(auto elt, prng_->Rand8()); 64 | rand8s.push_back(elt); 65 | } 66 | EXPECT_THAT(rand8s, Not(Eq(before_resalt[i]))); 67 | } 68 | } 69 | 70 | TEST_F(ChaChaPrngTest, TestRand64BeforeAndAfterResalting) { 71 | std::vector before_resalt(internal::kChaChaOutputBytes / 8); 72 | for (int i = 0; i < internal::kChaChaOutputBytes / 8; ++i) { 73 | SCOPED_TRACE(absl::StrCat("Iteration ", i, ".")); 74 | ASSERT_OK_AND_ASSIGN(before_resalt[i], prng_->Rand64()); 75 | } 76 | for (int i = 0; i < internal::kChaChaOutputBytes / 8; ++i) { 77 | SCOPED_TRACE(absl::StrCat("Iteration ", i, ".")); 78 | ASSERT_OK_AND_ASSIGN(auto r64, prng_->Rand64()); 79 | EXPECT_NE(before_resalt[i], r64); 80 | } 81 | } 82 | 83 | TEST_F(ChaChaPrngTest, TestRand64WithResaltingInBetween) { 84 | for (int i = 0; i < internal::kChaChaOutputBytes - 1; ++i) { 85 | SCOPED_TRACE(absl::StrCat("Iteration ", i, ".")); 86 | EXPECT_OK(prng_->Rand8()); 87 | } 88 | EXPECT_OK(prng_->Rand64()); 89 | } 90 | 91 | } // namespace 92 | } // namespace rlwe 93 | -------------------------------------------------------------------------------- /shell_encryption/prng/chacha_prng_util.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "shell_encryption/prng/chacha_prng_util.h" 16 | 17 | #include 18 | #include 19 | 20 | #include "absl/memory/memory.h" 21 | #include "absl/strings/str_cat.h" 22 | #include 23 | #include 24 | #include 25 | #include "shell_encryption/status_macros.h" 26 | 27 | namespace rlwe { 28 | namespace internal { 29 | 30 | absl::Status ChaChaPrngResalt(absl::string_view key, int buffer_size, 31 | int* salt_counter, int* position_in_buffer, 32 | std::vector* buffer) { 33 | buffer->assign(buffer_size, 0); 34 | 35 | // Following https://tools.ietf.org/html/rfc7539, Sec 2.3, we create the 36 | // nonce as a kChaChaNonceSize (=12) bytes string, where the 4 first 37 | // bytes are fixed, and the next 8 bytes correspond to the counter. 38 | std::string nonce = "salt00000000"; 39 | if (nonce.size() != kChaChaNonceSize) { 40 | return absl::InternalError("The salt length is incorrect."); 41 | } 42 | Uint64 counter = static_cast(*salt_counter); 43 | for (int i = 0; i < 8; i++) { 44 | nonce[4 + i] = counter & 0xFF; 45 | counter >>= 8; 46 | } 47 | 48 | // We call the CRYPTO_chacha_20() function from OpenSSL. Note that the last 49 | // parameter is a *block* counter. The salt counter needs instead to be 50 | // included in the nonce. 51 | CRYPTO_chacha_20(buffer->data(), buffer->data(), buffer->size(), 52 | reinterpret_cast(key.data()), 53 | reinterpret_cast(nonce.data()), 54 | /* counter = */ 0); 55 | 56 | ++(*salt_counter); 57 | *position_in_buffer = 0; 58 | return absl::OkStatus(); 59 | } 60 | 61 | rlwe::StatusOr ChaChaPrngGenerateKey() { 62 | std::unique_ptr buf(new Uint8[kChaChaKeyBytesSize]); 63 | // BoringSSL documentation says that it always returns 1; while 64 | // OpenSSL documentation says that it returns 1 on success, 0 otherwise. Check 65 | // for an error just in case. 66 | if (RAND_bytes(buf.get(), kChaChaKeyBytesSize) == 0) { 67 | return absl::InternalError("Internal error generating random PRNG key."); 68 | } 69 | return std::string(reinterpret_cast(buf.get()), 70 | kChaChaKeyBytesSize); 71 | } 72 | 73 | rlwe::StatusOr ChaChaPrngRand8(absl::string_view key, 74 | int* position_in_buffer, 75 | int* salt_counter, 76 | std::vector* buffer) { 77 | Uint8 rand; 78 | if (*position_in_buffer >= static_cast(buffer->size())) { 79 | RLWE_RETURN_IF_ERROR(ChaChaPrngResalt(key, kChaChaOutputBytes, salt_counter, 80 | position_in_buffer, buffer)); 81 | } 82 | rand = buffer->at(*position_in_buffer); 83 | ++(*position_in_buffer); 84 | return rand; 85 | } 86 | 87 | rlwe::StatusOr ChaChaPrngRand64(absl::string_view key, 88 | int* position_in_buffer, 89 | int* salt_counter, 90 | std::vector* buffer) { 91 | Uint64 rand64 = 0; 92 | for (int i = 0; i < 8; ++i) { 93 | RLWE_ASSIGN_OR_RETURN(Uint8 rand8, ChaChaPrngRand8(key, position_in_buffer, 94 | salt_counter, buffer)); 95 | rand64 += Uint64{rand8} << (8 * i); 96 | } 97 | return rand64; 98 | } 99 | 100 | } // namespace internal 101 | } // namespace rlwe 102 | -------------------------------------------------------------------------------- /shell_encryption/prng/chacha_prng_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // An implementation of a PRNG using the ChaCha20 stream cipher. Since this is 18 | // a stream cipher, the key stream can be obtained by "encrypting" the plaintext 19 | // 0....0. 20 | 21 | #ifndef RLWE_CHACHA_PRNG_UTIL_H_ 22 | #define RLWE_CHACHA_PRNG_UTIL_H_ 23 | 24 | #include 25 | 26 | #include "absl/status/status.h" 27 | #include "absl/strings/string_view.h" 28 | #include "shell_encryption/integral_types.h" 29 | #include "shell_encryption/statusor.h" 30 | 31 | namespace rlwe { 32 | namespace internal { 33 | 34 | const int kChaChaKeyBytesSize = 32; 35 | const int kChaChaNonceSize = 12; 36 | const int kChaChaOutputBytes = 255 * 32; 37 | 38 | // Once pseudorandom output is exhausted, the salt is updated to construct 39 | // new pseudorandom output. 40 | absl::Status ChaChaPrngResalt( 41 | absl::string_view key, int buffer_size, int* salt_counter, 42 | int* position_in_buffer, std::vector* buffer); 43 | 44 | // Generates a secure key for instantiating an CHACHA. 45 | rlwe::StatusOr ChaChaPrngGenerateKey(); 46 | 47 | // Returns 8 bits of randomness. 48 | // 49 | // Fails on internal cryptographic errors. 50 | rlwe::StatusOr ChaChaPrngRand8( 51 | absl::string_view key, int* position_in_buffer, int* salt_counter, 52 | std::vector* buffer); 53 | 54 | // Returns 64 bits of randomness. 55 | // 56 | // Fails on internal cryptographic errors. 57 | rlwe::StatusOr ChaChaPrngRand64( 58 | absl::string_view key, int* position_in_buffer, int* salt_counter, 59 | std::vector* buffer); 60 | 61 | } // namespace internal 62 | } // namespace rlwe 63 | 64 | #endif // RLWE_CHACHA_PRNG_UTIL_H_ 65 | -------------------------------------------------------------------------------- /shell_encryption/prng/hkdf_prng.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include "shell_encryption/prng/hkdf_prng.h" 17 | 18 | #include 19 | 20 | #include "absl/memory/memory.h" 21 | #include "absl/strings/str_cat.h" 22 | #include "absl/strings/string_view.h" 23 | #include "absl/synchronization/mutex.h" 24 | #include "shell_encryption/prng/hkdf_prng_util.h" 25 | #include "shell_encryption/status_macros.h" 26 | 27 | namespace rlwe { 28 | 29 | HkdfPrng::HkdfPrng(absl::string_view in_key, int position_in_buffer, 30 | int salt_counter, std::vector buffer) 31 | : key_(in_key), 32 | position_in_buffer_(position_in_buffer), 33 | salt_counter_(salt_counter), 34 | buffer_(std::move(buffer)) {} 35 | 36 | rlwe::StatusOr> HkdfPrng::Create( 37 | absl::string_view in_key) { 38 | if (in_key.length() != SeedLength()) { 39 | return absl::InvalidArgumentError( 40 | absl::StrCat("Cannot create Prng with key of the wrong size. Real ", 41 | "key length of ", in_key.length(), " instead of expected ", 42 | "key length of ", SeedLength(), ".")); 43 | } 44 | int position_in_buffer = 0; 45 | int salt_counter = 0; 46 | std::vector buffer; 47 | RLWE_RETURN_IF_ERROR( 48 | internal::HkdfPrngResalt(in_key, internal::kHkdfMaxOutputBytes, 49 | &salt_counter, &position_in_buffer, &buffer)); 50 | return absl::WrapUnique(new HkdfPrng( 51 | in_key, position_in_buffer, salt_counter, std::move(buffer))); 52 | } 53 | 54 | rlwe::StatusOr HkdfPrng::Rand8() ABSL_LOCKS_EXCLUDED(mu_) { 55 | absl::MutexLock lock(mu_); 56 | return internal::HkdfPrngRand8(key_, &position_in_buffer_, &salt_counter_, 57 | &buffer_); 58 | } 59 | 60 | rlwe::StatusOr HkdfPrng::Rand64() ABSL_LOCKS_EXCLUDED(mu_) { 61 | absl::MutexLock lock(mu_); 62 | return internal::HkdfPrngRand64(key_, &position_in_buffer_, &salt_counter_, 63 | &buffer_); 64 | } 65 | 66 | } // namespace rlwe 67 | -------------------------------------------------------------------------------- /shell_encryption/prng/hkdf_prng.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | // An implementation of a PRNG using a HMAC-based key derivation function. 17 | // 18 | // HMAC-based key derivation functions (HKDF, for short) consist of two 19 | // important functions: extract and expand. Given an input key with sufficient 20 | // entropy, the HKDF will extract the entropy into a more uniform, unbiased 21 | // entropy. The HKDF can expand this entropy into many pseudorandom outputs. 22 | // Therefore, the input key must have sufficient entropy to ensure the outputs 23 | // are pseudorandom. The pseudorandom outputs of HKDF are deterministic for any 24 | // fixed input key allowing replay of the pseudorandom outputs by multiple 25 | // clients by sharing the input key. For more information about HKDFs, see [1] 26 | // for an overview and [2] for a full description. 27 | // 28 | // [1] https://en.wikipedia.org/wiki/HKDF 29 | // [2] https://tools.ietf.org/html/rfc5869 30 | 31 | #ifndef RLWE_HKDF_PRNG_H_ 32 | #define RLWE_HKDF_PRNG_H_ 33 | 34 | #include "absl/strings/string_view.h" 35 | #include "absl/synchronization/mutex.h" 36 | #include "shell_encryption/prng/hkdf_prng_util.h" 37 | #include "shell_encryption/prng/prng.h" 38 | #include "shell_encryption/statusor.h" 39 | 40 | namespace rlwe { 41 | 42 | class HkdfPrng : public SecurePrng { 43 | public: 44 | // Constructs a secure pseudorandom number generator using a HMAC-based key 45 | // derivation function (HKDF). The parameter in_key is the key for the HKDF. 46 | // 47 | // Input keys should contain sufficient randomness (such as those generated by 48 | // the GenerateSeed() function) to ensure the random generated strings are 49 | // pseudorandom. As long as the initial key contains sufficient entropy, there 50 | // is no bound on the number of pseudorandom bytes that can be created. 51 | // 52 | // HkdfPrng allows replaying pseudorandom outputs. For any fixed input key, 53 | // the pseudorandom outputs of HkdfPrng will be identical. 54 | // 55 | // For a fixed key and salt, the underlying Hkdf crunchy primitive can 56 | // generate 255 * 32 pseudorandom bytes. Once, these bytes have been 57 | // exhausted, the prng deterministically re-salts the key using a salting 58 | // counter, thereby constructing a new internal Hkdf that can output more 59 | // pseudorandom bytes. 60 | // 61 | // Fails if the key is not the expected size or on internal cryptographic 62 | // errors. 63 | // 64 | // Thread safe. 65 | static rlwe::StatusOr> Create( 66 | absl::string_view in_key); 67 | 68 | // Returns 8 bits of randomness. 69 | // 70 | // Fails on internal cryptographic errors. 71 | rlwe::StatusOr Rand8() override; 72 | 73 | // Returns 64 bits of randomness. 74 | // 75 | // Fails on internal cryptographic errors. 76 | rlwe::StatusOr Rand64() override; 77 | 78 | // Generate a valid seed for the Prng. 79 | // 80 | // Fails on internal cryptographic errors. 81 | static rlwe::StatusOr GenerateSeed() { 82 | return internal::HkdfPrngGenerateKey(); 83 | } 84 | 85 | // Output the size of the expected generated seed. 86 | static int SeedLength() { return internal::kHkdfKeyBytesSize; } 87 | 88 | private: 89 | explicit HkdfPrng(absl::string_view in_key, int position_in_buffer, 90 | int salt_counter, std::vector buffer); 91 | 92 | absl::Mutex mu_; // Guards all values below 93 | 94 | const std::string key_; 95 | int position_in_buffer_ ABSL_GUARDED_BY(mu_); 96 | int salt_counter_ ABSL_GUARDED_BY(mu_); 97 | std::vector buffer_ ABSL_GUARDED_BY(mu_); 98 | }; 99 | 100 | } // namespace rlwe 101 | 102 | #endif // RLWE_HKDF_PRNG_H_ 103 | -------------------------------------------------------------------------------- /shell_encryption/prng/hkdf_prng_test.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | // This file includes specific unit tests files to test populating the buffer 17 | // every internal::kHkdfMaxOutputBytes bytes. 18 | 19 | #include "shell_encryption/prng/hkdf_prng.h" 20 | 21 | #include 22 | #include 23 | #include "absl/strings/str_cat.h" 24 | #include "shell_encryption/testing/status_matchers.h" 25 | #include "shell_encryption/testing/status_testing.h" 26 | 27 | namespace rlwe { 28 | 29 | namespace { 30 | 31 | using ::testing::Eq; 32 | using ::testing::Not; 33 | 34 | class HkdfPrngTest : public ::testing::Test { 35 | protected: 36 | void SetUp() override { 37 | ASSERT_OK_AND_ASSIGN(seed_, HkdfPrng::GenerateSeed()); 38 | ASSERT_OK_AND_ASSIGN(prng_, HkdfPrng::Create(seed_)); 39 | } 40 | 41 | std::string seed_; 42 | std::unique_ptr prng_; 43 | }; 44 | 45 | TEST_F(HkdfPrngTest, TestRand8BeforeAndAfterResalting) { 46 | // Two random 8 bit strings have 1/256 probability of being equal. Instead, 47 | // we check that a sequence of 8 strings from the HKDF before and after 48 | // salting are not all equal. 49 | std::vector> before_resalt(internal::kHkdfMaxOutputBytes); 50 | for (int i = 0; i < internal::kHkdfMaxOutputBytes / 8; ++i) { 51 | SCOPED_TRACE(absl::StrCat("Iteration ", i, ".")); 52 | std::vector rand8s; 53 | for (int j = 0; j < 8; ++j) { 54 | ASSERT_OK_AND_ASSIGN(auto elt, prng_->Rand8()); 55 | rand8s.push_back(elt); 56 | } 57 | before_resalt.push_back(rand8s); 58 | } 59 | for (int i = 0; i < internal::kHkdfMaxOutputBytes / 8; ++i) { 60 | SCOPED_TRACE(absl::StrCat("Iteration ", i, ".")); 61 | std::vector rand8s; 62 | for (int j = 0; j < 8; ++j) { 63 | ASSERT_OK_AND_ASSIGN(auto elt, prng_->Rand8()); 64 | rand8s.push_back(elt); 65 | } 66 | EXPECT_THAT(rand8s, Not(Eq(before_resalt[i]))); 67 | } 68 | } 69 | 70 | TEST_F(HkdfPrngTest, TestRand64BeforeAndAfterResalting) { 71 | std::vector before_resalt(internal::kHkdfMaxOutputBytes / 8); 72 | for (int i = 0; i < internal::kHkdfMaxOutputBytes / 8; ++i) { 73 | SCOPED_TRACE(absl::StrCat("Iteration ", i, ".")); 74 | ASSERT_OK_AND_ASSIGN(before_resalt[i], prng_->Rand64()); 75 | } 76 | for (int i = 0; i < internal::kHkdfMaxOutputBytes / 8; ++i) { 77 | SCOPED_TRACE(absl::StrCat("Iteration ", i, ".")); 78 | ASSERT_OK_AND_ASSIGN(auto r64, prng_->Rand64()); 79 | EXPECT_NE(before_resalt[i], r64); 80 | } 81 | } 82 | 83 | TEST_F(HkdfPrngTest, TestRand64WithResaltingInBetween) { 84 | for (int i = 0; i < internal::kHkdfMaxOutputBytes - 1; ++i) { 85 | SCOPED_TRACE(absl::StrCat("Iteration ", i, ".")); 86 | EXPECT_OK(prng_->Rand8()); 87 | } 88 | EXPECT_OK(prng_->Rand64()); 89 | } 90 | 91 | } // namespace 92 | } // namespace rlwe 93 | -------------------------------------------------------------------------------- /shell_encryption/prng/hkdf_prng_util.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "shell_encryption/prng/hkdf_prng_util.h" 16 | 17 | #include 18 | 19 | #include "absl/memory/memory.h" 20 | #include "absl/strings/str_cat.h" 21 | #include "shell_encryption/status_macros.h" 22 | #include "tink/subtle/common_enums.h" 23 | #include "tink/subtle/hkdf.h" 24 | #include "tink/subtle/random.h" 25 | 26 | namespace rlwe::internal { 27 | 28 | absl::Status HkdfPrngResalt(absl::string_view key, int buffer_size, 29 | int* salt_counter, int* position_in_buffer, 30 | std::vector* buffer) { 31 | std::string salt = absl::StrCat("salt", *salt_counter); 32 | auto status_or_buf = crypto::tink::subtle::Hkdf::ComputeHkdf( 33 | crypto::tink::subtle::SHA256, key, salt, "", buffer_size); 34 | if (!status_or_buf.ok()) { 35 | return status_or_buf.status(); 36 | } 37 | auto buf = std::move(status_or_buf).value(); 38 | buffer->assign(buf.begin(), buf.end()); 39 | ++(*salt_counter); 40 | *position_in_buffer = 0; 41 | 42 | return absl::OkStatus(); 43 | } 44 | 45 | rlwe::StatusOr HkdfPrngGenerateKey() { 46 | return crypto::tink::subtle::Random::GetRandomBytes(kHkdfKeyBytesSize); 47 | } 48 | 49 | rlwe::StatusOr HkdfPrngRand8(absl::string_view key, 50 | int* position_in_buffer, int* salt_counter, 51 | std::vector* buffer) { 52 | Uint8 rand; 53 | if (*position_in_buffer >= buffer->size()) { 54 | RLWE_RETURN_IF_ERROR(HkdfPrngResalt(key, kHkdfMaxOutputBytes, salt_counter, 55 | position_in_buffer, buffer)); 56 | } 57 | rand = buffer->at(*position_in_buffer); 58 | ++(*position_in_buffer); 59 | return rand; 60 | } 61 | 62 | rlwe::StatusOr HkdfPrngRand64(absl::string_view key, 63 | int* position_in_buffer, 64 | int* salt_counter, 65 | std::vector* buffer) { 66 | Uint64 rand64 = 0; 67 | for (int i = 0; i < 8; ++i) { 68 | RLWE_ASSIGN_OR_RETURN(Uint8 rand8, HkdfPrngRand8(key, position_in_buffer, 69 | salt_counter, buffer)); 70 | rand64 += Uint64{rand8} << (8 * i); 71 | } 72 | return rand64; 73 | } 74 | 75 | } // namespace rlwe::internal 76 | -------------------------------------------------------------------------------- /shell_encryption/prng/hkdf_prng_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // An implementation of a PRNG using a HMAC-based key derivation function. 18 | // 19 | // HMAC-based key derivation functions (HKDF, for short) consist of two 20 | // important functions: extract and expand. Given an input key with sufficient 21 | // entropy, the HKDF will extract the entropy into a more uniform, unbiased 22 | // entropy. The HKDF can expand this entropy into many pseudorandom outputs. 23 | // Therefore, the input key must have sufficient entropy to ensure the outputs 24 | // are pseudorandom. The pseudorandom outputs of HKDF are deterministic for any 25 | // fixed input key allowing replay of the pseudorandom outputs by multiple 26 | // clients by sharing the input key. For more information about HKDFs, see [1] 27 | // for an overview and [2] for a full description. 28 | // 29 | // [1] https://en.wikipedia.org/wiki/HKDF 30 | // [2] https://tools.ietf.org/html/rfc5869 31 | 32 | #ifndef RLWE_HKDF_PRNG_UTIL_H_ 33 | #define RLWE_HKDF_PRNG_UTIL_H_ 34 | 35 | #include "absl/status/status.h" 36 | #include "absl/strings/string_view.h" 37 | #include "shell_encryption/integral_types.h" 38 | #include "shell_encryption/statusor.h" 39 | 40 | namespace rlwe::internal { 41 | 42 | const int kHkdfKeyBytesSize = 64; 43 | const int kHkdfMaxOutputBytes = 255 * 32; 44 | 45 | // Once pseudorandom output is exhausted, the salt is updated to construct 46 | // new pseudorandom output. 47 | absl::Status HkdfPrngResalt(absl::string_view key, int buffer_size, 48 | int* salt_counter, int* position_in_buffer, 49 | std::vector* buffer); 50 | 51 | // Generates a secure key for instantiating an HKDF. 52 | rlwe::StatusOr HkdfPrngGenerateKey(); 53 | 54 | // Returns 8 bits of randomness. 55 | // 56 | // Fails on internal cryptographic errors. 57 | rlwe::StatusOr HkdfPrngRand8(absl::string_view key, 58 | int* position_in_buffer, int* salt_counter, 59 | std::vector* buffer); 60 | 61 | // Returns 64 bits of randomness. 62 | // 63 | // Fails on internal cryptographic errors. 64 | rlwe::StatusOr HkdfPrngRand64(absl::string_view key, 65 | int* position_in_buffer, 66 | int* salt_counter, 67 | std::vector* buffer); 68 | 69 | } // namespace rlwe::internal 70 | 71 | #endif // RLWE_HKDF_PRNG_UTIL_H_ 72 | -------------------------------------------------------------------------------- /shell_encryption/prng/integral_prng_testing_types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef RLWE_PRNG_INTEGRAL_PRNG_TYPE_H_ 18 | #define RLWE_PRNG_INTEGRAL_PRNG_TYPE_H_ 19 | 20 | #include 21 | #include 22 | #include "shell_encryption/prng/chacha_prng.h" 23 | #include "shell_encryption/prng/hkdf_prng.h" 24 | #include "shell_encryption/prng/single_thread_chacha_prng.h" 25 | #include "shell_encryption/prng/single_thread_hkdf_prng.h" 26 | 27 | namespace rlwe { 28 | 29 | typedef ::testing::Types 31 | TestingPrngTypes; 32 | 33 | } // namespace rlwe 34 | 35 | #endif // RLWE_PRNG_INTEGRAL_PRNG_TYPE_H_ 36 | -------------------------------------------------------------------------------- /shell_encryption/prng/prng.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef RLWE_PRNG_H_ 17 | #define RLWE_PRNG_H_ 18 | 19 | #include 20 | 21 | #include "absl/strings/string_view.h" 22 | #include "shell_encryption/integral_types.h" 23 | #include "shell_encryption/statusor.h" 24 | 25 | namespace rlwe { 26 | 27 | // An interface for a secure pseudo-random number generator. 28 | class SecurePrng { 29 | public: 30 | virtual rlwe::StatusOr Rand8() = 0; 31 | virtual rlwe::StatusOr Rand64() = 0; 32 | virtual ~SecurePrng() = default; 33 | static rlwe::StatusOr> Create( 34 | absl::string_view seed); 35 | static rlwe::StatusOr GenerateSeed(); 36 | static int SeedLength(); 37 | }; 38 | 39 | } // namespace rlwe 40 | 41 | #endif // RLWE_PRNG_H_ 42 | -------------------------------------------------------------------------------- /shell_encryption/prng/single_thread_chacha_prng.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include "shell_encryption/prng/single_thread_chacha_prng.h" 17 | 18 | #include 19 | 20 | #include "absl/memory/memory.h" 21 | #include "absl/strings/str_cat.h" 22 | #include "shell_encryption/status_macros.h" 23 | 24 | namespace rlwe { 25 | 26 | SingleThreadChaChaPrng::SingleThreadChaChaPrng(absl::string_view in_key, 27 | int position_in_buffer, 28 | int salt_counter, 29 | std::vector buffer) 30 | : key_(in_key), 31 | position_in_buffer_(position_in_buffer), 32 | salt_counter_(salt_counter), 33 | buffer_(std::move(buffer)) {} 34 | 35 | rlwe::StatusOr> 36 | SingleThreadChaChaPrng::Create(absl::string_view in_key) { 37 | if (static_cast(in_key.length()) != SeedLength()) { 38 | return absl::InvalidArgumentError( 39 | absl::StrCat("Cannot create Prng with key of the " 40 | "wrong size. Real ", 41 | "key length of ", in_key.length(), " instead of expected ", 42 | "key length of ", SeedLength(), ".")); 43 | } 44 | int position_in_buffer = 0; 45 | int salt_counter = 0; 46 | std::vector buffer; 47 | RLWE_RETURN_IF_ERROR( 48 | internal::ChaChaPrngResalt(in_key, internal::kChaChaOutputBytes, 49 | &salt_counter, &position_in_buffer, &buffer)); 50 | return absl::WrapUnique(new SingleThreadChaChaPrng( 51 | in_key, position_in_buffer, salt_counter, std::move(buffer))); 52 | } 53 | 54 | rlwe::StatusOr SingleThreadChaChaPrng::Rand8() { 55 | return internal::ChaChaPrngRand8(key_, &position_in_buffer_, &salt_counter_, 56 | &buffer_); 57 | } 58 | 59 | rlwe::StatusOr SingleThreadChaChaPrng::Rand64() { 60 | return internal::ChaChaPrngRand64(key_, &position_in_buffer_, &salt_counter_, 61 | &buffer_); 62 | } 63 | 64 | } // namespace rlwe 65 | -------------------------------------------------------------------------------- /shell_encryption/prng/single_thread_chacha_prng.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | // An implementation of a PRNG using the ChaCha20 stream cipher. Since this is 17 | // a stream cipher, the key stream can be obtained by "encrypting" the plaintext 18 | // 0....0. 19 | 20 | #ifndef RLWE_SINGLE_THREAD_CHACHA_PRNG_H_ 21 | #define RLWE_SINGLE_THREAD_CHACHA_PRNG_H_ 22 | 23 | #include "absl/strings/string_view.h" 24 | #include "shell_encryption/prng/chacha_prng_util.h" 25 | #include "shell_encryption/prng/prng.h" 26 | #include "shell_encryption/statusor.h" 27 | 28 | namespace rlwe { 29 | 30 | class SingleThreadChaChaPrng : public SecurePrng { 31 | public: 32 | // Constructs a secure pseudorandom number generator using the ChaCha20 stream 33 | // cipher. The parameter in_key is the key for the ChaCha20. 34 | // 35 | // This class is for use only in single threaded scenarios. For thread safe 36 | // pseudorandom number generators, use ChaChaPrng instead. 37 | // 38 | // Input keys should contain sufficient randomness (such as those generated by 39 | // the ChaChaPrngGenerateKey function) to ensure the random generated strings 40 | // are pseudorandom. As long as the initial key contains sufficient entropy, 41 | // there is no bound on the number of pseudorandom bytes that can be created. 42 | // 43 | // ChaChaPrng allows replaying pseudorandom outputs. For any fixed input key, 44 | // the pseudorandom outputs of ChaChaPrng will be identical. 45 | // 46 | // For a fixed key and salt, the underlying ChaCha primitive can 47 | // generate 2^32 * 64 pseudorandom bytes. Instead, we will construct a smaller 48 | // pool of 255 * 32 bytes to match the Hkdf Prng. Once, these bytes have been 49 | // exhausted, the prng deterministically re-salts the key using a salting 50 | // counter, thereby constructing a new internal ChaCha that can output more 51 | // pseudorandom bytes. 52 | // 53 | // Fails if the key is not the expected size or on internal cryptographic 54 | // errors. 55 | static rlwe::StatusOr> 56 | Create(absl::string_view in_key); 57 | 58 | // Returns 8 bits of randomness. 59 | // 60 | // Fails on internal cryptographic errors. 61 | rlwe::StatusOr Rand8() override; 62 | 63 | // Returns 64 bits of randomness. 64 | // 65 | // Fails on internal cryptographic errors. 66 | rlwe::StatusOr Rand64() override; 67 | 68 | // Generate a valid seed for the Prng. 69 | // 70 | // Fails on internal cryptographic errors. 71 | static rlwe::StatusOr GenerateSeed() { 72 | return internal::ChaChaPrngGenerateKey(); 73 | } 74 | 75 | // Output the size of the expected generated seed. 76 | static int SeedLength() { return internal::kChaChaKeyBytesSize; } 77 | 78 | private: 79 | explicit SingleThreadChaChaPrng(absl::string_view in_key, 80 | int position_in_buffer, int salt_counter, 81 | std::vector buffer); 82 | 83 | const std::string key_; 84 | int position_in_buffer_; 85 | int salt_counter_; 86 | std::vector buffer_; 87 | }; 88 | 89 | } // namespace rlwe 90 | 91 | #endif // RLWE_SINGLE_THREAD_CHACHA_PRNG_H_ 92 | -------------------------------------------------------------------------------- /shell_encryption/prng/single_thread_chacha_prng_test.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | // This file includes specific unit tests files to test populating the buffer 17 | // every internal::kChaChaOutputBytes bytes. 18 | 19 | #include "shell_encryption/prng/single_thread_chacha_prng.h" 20 | 21 | #include 22 | #include 23 | #include "absl/strings/str_cat.h" 24 | #include "shell_encryption/testing/status_matchers.h" 25 | #include "shell_encryption/testing/status_testing.h" 26 | 27 | namespace rlwe { 28 | 29 | namespace { 30 | 31 | using ::testing::Eq; 32 | using ::testing::Not; 33 | 34 | class SingleThreadChaChaPrngTest : public ::testing::Test { 35 | protected: 36 | void SetUp() override { 37 | ASSERT_OK_AND_ASSIGN(seed_, SingleThreadChaChaPrng::GenerateSeed()); 38 | ASSERT_OK_AND_ASSIGN(prng_, SingleThreadChaChaPrng::Create(seed_)); 39 | } 40 | 41 | std::string seed_; 42 | std::unique_ptr prng_; 43 | }; 44 | 45 | TEST_F(SingleThreadChaChaPrngTest, TestRand8BeforeAndAfterResalting) { 46 | // Two random 8 bit strings have 1/256 probability of being equal. Instead, 47 | // we check that a sequence of 8 strings from the PRNG before and after 48 | // salting are not all equal. 49 | std::vector> before_resalt(internal::kChaChaOutputBytes); 50 | for (int i = 0; i < internal::kChaChaOutputBytes / 8; ++i) { 51 | SCOPED_TRACE(absl::StrCat("Iteration ", i, ".")); 52 | std::vector rand8s; 53 | for (int j = 0; j < 8; ++j) { 54 | ASSERT_OK_AND_ASSIGN(auto elt, prng_->Rand8()); 55 | rand8s.push_back(elt); 56 | } 57 | before_resalt.push_back(rand8s); 58 | } 59 | for (int i = 0; i < internal::kChaChaOutputBytes / 8; ++i) { 60 | SCOPED_TRACE(absl::StrCat("Iteration ", i, ".")); 61 | std::vector rand8s; 62 | for (int j = 0; j < 8; ++j) { 63 | ASSERT_OK_AND_ASSIGN(auto elt, prng_->Rand8()); 64 | rand8s.push_back(elt); 65 | } 66 | EXPECT_THAT(rand8s, Not(Eq(before_resalt[i]))); 67 | } 68 | } 69 | 70 | TEST_F(SingleThreadChaChaPrngTest, TestRand64BeforeAndAfterResalting) { 71 | std::vector before_resalt(internal::kChaChaOutputBytes / 8); 72 | for (int i = 0; i < internal::kChaChaOutputBytes / 8; ++i) { 73 | SCOPED_TRACE(absl::StrCat("Iteration ", i, ".")); 74 | ASSERT_OK_AND_ASSIGN(before_resalt[i], prng_->Rand64()); 75 | } 76 | for (int i = 0; i < internal::kChaChaOutputBytes / 8; ++i) { 77 | SCOPED_TRACE(absl::StrCat("Iteration ", i, ".")); 78 | ASSERT_OK_AND_ASSIGN(auto r64, prng_->Rand64()); 79 | EXPECT_NE(before_resalt[i], r64); 80 | } 81 | } 82 | 83 | TEST_F(SingleThreadChaChaPrngTest, TestRand64WithResaltingInBetween) { 84 | for (int i = 0; i < internal::kChaChaOutputBytes - 1; ++i) { 85 | SCOPED_TRACE(absl::StrCat("Iteration ", i, ".")); 86 | EXPECT_OK(prng_->Rand8()); 87 | } 88 | EXPECT_OK(prng_->Rand64()); 89 | } 90 | 91 | } // namespace 92 | } // namespace rlwe 93 | -------------------------------------------------------------------------------- /shell_encryption/prng/single_thread_hkdf_prng.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include "shell_encryption/prng/single_thread_hkdf_prng.h" 17 | 18 | #include 19 | 20 | #include "absl/memory/memory.h" 21 | #include "absl/strings/str_cat.h" 22 | #include "shell_encryption/prng/hkdf_prng_util.h" 23 | #include "shell_encryption/status_macros.h" 24 | 25 | namespace rlwe { 26 | 27 | SingleThreadHkdfPrng::SingleThreadHkdfPrng(absl::string_view in_key, 28 | int position_in_buffer, 29 | int salt_counter, 30 | std::vector buffer) 31 | : key_(in_key), 32 | position_in_buffer_(position_in_buffer), 33 | salt_counter_(salt_counter), 34 | buffer_(std::move(buffer)) {} 35 | 36 | rlwe::StatusOr> 37 | SingleThreadHkdfPrng::Create(absl::string_view in_key) { 38 | if (in_key.length() != SeedLength()) { 39 | return absl::InvalidArgumentError( 40 | absl::StrCat("Cannot create Prng with key of the wrong size. Real ", 41 | "key length of ", in_key.length(), " instead of expected ", 42 | "key length of ", SeedLength(), ".")); 43 | } 44 | int position_in_buffer = 0; 45 | int salt_counter = 0; 46 | std::vector buffer; 47 | RLWE_RETURN_IF_ERROR( 48 | internal::HkdfPrngResalt(in_key, internal::kHkdfMaxOutputBytes, 49 | &salt_counter, &position_in_buffer, &buffer)); 50 | return absl::WrapUnique(new SingleThreadHkdfPrng( 51 | in_key, position_in_buffer, salt_counter, std::move(buffer))); 52 | } 53 | 54 | rlwe::StatusOr SingleThreadHkdfPrng::Rand8() { 55 | return internal::HkdfPrngRand8(key_, &position_in_buffer_, &salt_counter_, 56 | &buffer_); 57 | } 58 | 59 | rlwe::StatusOr SingleThreadHkdfPrng::Rand64() { 60 | return internal::HkdfPrngRand64(key_, &position_in_buffer_, &salt_counter_, 61 | &buffer_); 62 | } 63 | 64 | } // namespace rlwe 65 | -------------------------------------------------------------------------------- /shell_encryption/prng/single_thread_hkdf_prng.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | // An implementation of a PRNG using a HMAC-based key derivation function. 17 | // 18 | // HMAC-based key derivation functions (HKDF, for short) consist of two 19 | // important functions: extract and expand. Given an input key with sufficient 20 | // entropy, the HKDF will extract the entropy into a more uniform, unbiased 21 | // entropy. The HKDF can expand this entropy into many pseudorandom outputs. 22 | // Therefore, the input key must have sufficient entropy to ensure the outputs 23 | // are pseudorandom. The pseudorandom outputs of HKDF are deterministic for any 24 | // fixed input key allowing replay of the pseudorandom outputs by multiple 25 | // clients by sharing the input key. For more information about HKDFs, see [1] 26 | // for an overview and [2] for a full description. 27 | // 28 | // [1] https://en.wikipedia.org/wiki/HKDF 29 | // [2] https://tools.ietf.org/html/rfc5869 30 | 31 | #ifndef RLWE_SINGLE_THREAD_HKDF_PRNG_H_ 32 | #define RLWE_SINGLE_THREAD_HKDF_PRNG_H_ 33 | 34 | #include "absl/strings/string_view.h" 35 | #include "shell_encryption/prng/hkdf_prng_util.h" 36 | #include "shell_encryption/prng/prng.h" 37 | #include "shell_encryption/statusor.h" 38 | 39 | namespace rlwe { 40 | 41 | class SingleThreadHkdfPrng : public SecurePrng { 42 | public: 43 | // Constructs a secure pseudorandom number generator using a HMAC-based key 44 | // derivation function (HKDF). The parameter in_key is the key for the HKDF. 45 | // 46 | // This class is for use only in single threaded scenarios. For thread safe 47 | // pseudorandom number generators, use HkdfPrng instead. 48 | // 49 | // Input keys should contain sufficient randomness (such as those generated by 50 | // the GenerateKey() function) to ensure the random generated strings are 51 | // pseudorandom. As long as the initial key contains sufficient entropy, there 52 | // is no bound on the number of pseudorandom bytes that can be created. 53 | // 54 | // HkdfPrng allows replaying pseudorandom outputs. For any fixed input key, 55 | // the pseudorandom outputs of HkdfPrng will be identical. 56 | // 57 | // For a fixed key and salt, the underlying Hkdf crunchy primitive can 58 | // generate 255 * 32 pseudorandom bytes. Once, these bytes have been 59 | // exhausted, the prng deterministically re-salts the key using a salting 60 | // counter, thereby constructing a new internal Hkdf that can output more 61 | // pseudorandom bytes. 62 | // 63 | // Fails if the key is not the expected size or on internal cryptographic 64 | // errors. 65 | static rlwe::StatusOr> Create( 66 | absl::string_view in_key); 67 | 68 | // Returns 8 bits of randomness. 69 | // 70 | // Fails on internal cryptographic errors. 71 | rlwe::StatusOr Rand8() override; 72 | 73 | // Returns 64 bits of randomness. 74 | // 75 | // Fails on internal cryptographic errors. 76 | rlwe::StatusOr Rand64() override; 77 | 78 | // Generate a valid seed for the Prng. 79 | // 80 | // Fails on internal cryptographic errors. 81 | static rlwe::StatusOr GenerateSeed() { 82 | return internal::HkdfPrngGenerateKey(); 83 | } 84 | 85 | // Output the size of the expected generated seed. 86 | static int SeedLength() { return internal::kHkdfKeyBytesSize; } 87 | 88 | private: 89 | explicit SingleThreadHkdfPrng(absl::string_view in_key, 90 | int position_in_buffer, int salt_counter, 91 | std::vector buffer); 92 | 93 | const std::string key_; 94 | int position_in_buffer_; 95 | int salt_counter_; 96 | std::vector buffer_; 97 | }; 98 | 99 | } // namespace rlwe 100 | 101 | #endif // RLWE_SINGLE_THREAD_HKDF_PRNG_H_ 102 | -------------------------------------------------------------------------------- /shell_encryption/prng/single_thread_hkdf_prng_test.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | // This file includes specific unit tests files to test populating the buffer 17 | // every internal::kHkdfMaxOutputBytes bytes. 18 | 19 | #include "shell_encryption/prng/single_thread_hkdf_prng.h" 20 | 21 | #include 22 | #include 23 | #include "absl/strings/str_cat.h" 24 | #include "shell_encryption/testing/status_matchers.h" 25 | #include "shell_encryption/testing/status_testing.h" 26 | 27 | namespace rlwe { 28 | 29 | namespace { 30 | 31 | using ::testing::Eq; 32 | using ::testing::Not; 33 | 34 | class SingleThreadHkdfPrngTest : public ::testing::Test { 35 | protected: 36 | void SetUp() override { 37 | ASSERT_OK_AND_ASSIGN(seed_, SingleThreadHkdfPrng::GenerateSeed()); 38 | ASSERT_OK_AND_ASSIGN(prng_, SingleThreadHkdfPrng::Create(seed_)); 39 | } 40 | 41 | std::string seed_; 42 | std::unique_ptr prng_; 43 | }; 44 | 45 | TEST_F(SingleThreadHkdfPrngTest, TestRand8BeforeAndAfterResalting) { 46 | // Two random 8 bit strings have 1/256 probability of being equal. Instead, 47 | // we check that a sequence of 8 strings from the HKDF before and after 48 | // salting are not all equal. 49 | std::vector> before_resalt(internal::kHkdfMaxOutputBytes); 50 | for (int i = 0; i < internal::kHkdfMaxOutputBytes / 8; ++i) { 51 | SCOPED_TRACE(absl::StrCat("Iteration ", i, ".")); 52 | std::vector rand8s; 53 | for (int j = 0; j < 8; ++j) { 54 | ASSERT_OK_AND_ASSIGN(auto elt, prng_->Rand8()); 55 | rand8s.push_back(elt); 56 | } 57 | before_resalt.push_back(rand8s); 58 | } 59 | for (int i = 0; i < internal::kHkdfMaxOutputBytes / 8; ++i) { 60 | SCOPED_TRACE(absl::StrCat("Iteration ", i, ".")); 61 | std::vector rand8s; 62 | for (int j = 0; j < 8; ++j) { 63 | ASSERT_OK_AND_ASSIGN(auto elt, prng_->Rand8()); 64 | rand8s.push_back(elt); 65 | } 66 | EXPECT_THAT(rand8s, Not(Eq(before_resalt[i]))); 67 | } 68 | } 69 | 70 | TEST_F(SingleThreadHkdfPrngTest, TestRand64BeforeAndAfterResalting) { 71 | std::vector before_resalt(internal::kHkdfMaxOutputBytes / 8); 72 | for (int i = 0; i < internal::kHkdfMaxOutputBytes / 8; ++i) { 73 | SCOPED_TRACE(absl::StrCat("Iteration ", i, ".")); 74 | ASSERT_OK_AND_ASSIGN(before_resalt[i], prng_->Rand64()); 75 | } 76 | for (int i = 0; i < internal::kHkdfMaxOutputBytes / 8; ++i) { 77 | SCOPED_TRACE(absl::StrCat("Iteration ", i, ".")); 78 | ASSERT_OK_AND_ASSIGN(auto r64, prng_->Rand64()); 79 | EXPECT_NE(before_resalt[i], r64); 80 | } 81 | } 82 | 83 | TEST_F(SingleThreadHkdfPrngTest, TestRand64WithResaltingInBetween) { 84 | for (int i = 0; i < internal::kHkdfMaxOutputBytes - 1; ++i) { 85 | SCOPED_TRACE(absl::StrCat("Iteration ", i, ".")); 86 | EXPECT_OK(prng_->Rand8()); 87 | } 88 | EXPECT_OK(prng_->Rand64()); 89 | } 90 | 91 | } // namespace 92 | } // namespace rlwe 93 | -------------------------------------------------------------------------------- /shell_encryption/rns/constants.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef RLWE_RNS_CONSTANTS_H_ 17 | #define RLWE_RNS_CONSTANTS_H_ 18 | 19 | #include "absl/numeric/int128.h" 20 | #include "shell_encryption/integral_types.h" 21 | 22 | namespace rlwe { 23 | 24 | // This file declares some commonly used constants for the RNS variant of the 25 | // RLWE encryption scheme. We consider power-of-2 cyclotomic ring Z[X]/(X^N+1) 26 | // and its residue ring Z[X]/(Q*P,X^N+1) for a main modulus Q = q_0 *..* q_{L-1} 27 | // and an auxiliary modulus P = p_0 *..* p_{K-1}, where q_i and p_j are distinct 28 | // primes satisfying q_i == p_j == 1 (mod 2*N) to enable radix-2 NTT. 29 | // Furthermore, to enable modulus reduction for the BGV scheme with minimal 30 | // noise growth, the plaintext modulus t satisfies that q_i == 1 (mod t). 31 | 32 | // Prime moduli for a 60-bit modulus Q*P and N = 2^11 33 | constexpr Uint32 k60BitModulusQ0 = 974849; // 20-bits 34 | constexpr Uint32 k60BitModulusQ1 = 765953; // 20-bits 35 | constexpr Uint32 k60BitModulusP0 = 557057; // 20-bits 36 | constexpr Uint32 k60BitModulusLogN = 11; // N = 2^11 37 | constexpr Uint32 k60BitModulusPlaintextModulus = 17; 38 | 39 | // Prime moduli for a 59-bit modulus Q*P and N = 2^11. 40 | constexpr Uint32 k59BitModulusQ0 = 536375297; // 29-bits 41 | constexpr Uint32 k59BitModulusP0 = 1073655809; // 30-bits 42 | constexpr Uint32 k59BitModulusLogN = 11; 43 | constexpr Uint32 k59BitModulusPlaintextModulus = 17; 44 | 45 | } // namespace rlwe 46 | 47 | #endif // RLWE_RNS_CONSTANTS_H_ 48 | -------------------------------------------------------------------------------- /shell_encryption/rns/crt_interpolation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef RLWE_RNS_CRT_INTERPOLATION_H_ 17 | #define RLWE_RNS_CRT_INTERPOLATION_H_ 18 | 19 | #include 20 | 21 | #include "absl/numeric/int128.h" 22 | #include "absl/status/status.h" 23 | #include "absl/status/statusor.h" 24 | #include "shell_encryption/integral_types.h" 25 | #include "shell_encryption/montgomery.h" 26 | #include "shell_encryption/rns/rns_modulus.h" 27 | 28 | namespace rlwe { 29 | 30 | namespace { 31 | 32 | // Converts an `Integer` value to a `BigInteger` value. We assume `BigInteger` 33 | // is as large as `Integer`. 34 | // This is needed in case there is no conversion operator from `Integer` to 35 | // `BigInteger`. 36 | template 37 | static BigInteger ConvertToBigInteger(Integer value) { 38 | return static_cast(value); 39 | } 40 | 41 | } // namespace 42 | 43 | // Given a list of prime modulus {q_0,..,q_L} as specified in `moduli`, returns 44 | // the list {Q/q_0, .., Q/q_L}, where Q = q_0 * ... * q_L. 45 | template 46 | std::vector RnsModulusComplements( 47 | absl::Span* const> moduli) { 48 | std::vector modulus_hats(moduli.size(), BigInteger{1}); 49 | for (int i = 0; i < moduli.size(); ++i) { 50 | for (int j = 0; j < moduli.size(); ++j) { 51 | if (j != i) { 52 | modulus_hats[i] *= 53 | ConvertToBigInteger( 54 | moduli[j]->Modulus()); 55 | } 56 | } 57 | } 58 | return modulus_hats; 59 | } 60 | 61 | // Returns the coefficients mod Q of the RNS polynomial wrt prime moduli q_0,.., 62 | // q_L, where Q = q_0 * .. * q_L. The RNS polynomial's coefficients are given in 63 | // `coeff_vectors`. 64 | // The CRT interpolation of (a_0,..,a_L), a_i \in Z_{q_i}, is 65 | // a = sum(a_i * [(Q/q_i)^(-1) (mod q_i)] * (Q/q_i), i=0,..,L) mod Q, 66 | // where the constants [(Q/q_i)^(-1) (mod q_i)] are given in `modulus_hat_invs`, 67 | // and the constants Q/q_i are given in `modulus_hats`. 68 | template 69 | absl::StatusOr> CrtInterpolation( 70 | const std::vector>& coeff_vectors, 71 | absl::Span* const> moduli, 72 | absl::Span modulus_hats, 73 | absl::Span modulus_hat_invs) { 74 | using Integer = typename ModularInt::Int; 75 | if (coeff_vectors.empty()) { 76 | return absl::InvalidArgumentError("`coeff_vectors` must not be empty."); 77 | } 78 | int num_moduli = coeff_vectors.size(); 79 | if (moduli.size() != num_moduli) { 80 | return absl::InvalidArgumentError( 81 | absl::StrCat("`moduli` must contain ", num_moduli, " RNS moduli.")); 82 | } 83 | if (modulus_hats.size() != num_moduli) { 84 | return absl::InvalidArgumentError( 85 | absl::StrCat("`modulus_hats` must contain ", num_moduli, " elements.")); 86 | } 87 | if (modulus_hat_invs.size() != num_moduli) { 88 | return absl::InvalidArgumentError(absl::StrCat( 89 | "`modulus_hat_invs` must contain ", num_moduli, " elements.")); 90 | } 91 | 92 | // Compute the composite modulus Q = q_0 * ... * q_L. 93 | BigInteger q{1}; 94 | for (auto prime_modulus : moduli) { 95 | q *= ConvertToBigInteger(prime_modulus->Modulus()); 96 | } 97 | 98 | // Interpolate mod-Q. 99 | int num_coeffs = coeff_vectors[0].size(); 100 | std::vector coeffs_q(num_coeffs, BigInteger{0}); 101 | for (int i = 0; i < num_moduli; ++i) { 102 | auto mod_params_qi = moduli[i]->ModParams(); 103 | for (int j = 0; j < num_coeffs; ++j) { 104 | auto factor = ConvertToBigInteger( 105 | modulus_hat_invs[i].ExportInt(mod_params_qi)); 106 | factor *= modulus_hats[i]; 107 | factor %= q; 108 | factor *= ConvertToBigInteger( 109 | coeff_vectors[i][j].ExportInt(mod_params_qi)); 110 | factor %= q; 111 | coeffs_q[j] += factor; 112 | coeffs_q[j] %= q; 113 | } 114 | } 115 | return coeffs_q; 116 | } 117 | 118 | } // namespace rlwe 119 | 120 | #endif // RLWE_RNS_CRT_INTERPOLATION_H_ 121 | -------------------------------------------------------------------------------- /shell_encryption/rns/error_correction.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef RLWE_RNS_ERROR_CORRECTION_H_ 17 | #define RLWE_RNS_ERROR_CORRECTION_H_ 18 | 19 | #include 20 | #include 21 | 22 | #include "absl/status/statusor.h" 23 | 24 | namespace rlwe { 25 | 26 | // Given `noisy_coeffs` representing integers m + t * e using mod-q values, 27 | // where m in [0, t) and the error t * e are in [-q/2, q/2), returns the 28 | // messages m. This implements the error correction for BGV where the errors 29 | // reside in most significant bits of ciphertext modulus q. 30 | // 31 | // This is essentially the same algorithm as `rlwe::RemoveError()` defined in 32 | // symmetric_encryption.h used by the non-RNS version of rlwe. The difference is 33 | // that this version is parameterized by an integral type that support modulo 34 | // reduction, so it is possible to compute CRT interpolation of noisy plaintext 35 | // RNS polynomial based on small integer types and then error correct it using 36 | // a bigger integer type. 37 | template 38 | absl::StatusOr> RemoveErrorOnMsb( 39 | std::vector noisy_coeffs, Integer q, Integer t) { 40 | Integer zero{0}; 41 | if (t == zero) { 42 | return absl::InvalidArgumentError("`t` cannot be zero."); 43 | } 44 | 45 | Integer q_mod_t = q % t; 46 | Integer q_half = q >> 1; 47 | for (int i = 0; i < noisy_coeffs.size(); ++i) { 48 | if (noisy_coeffs[i] > q_half) { 49 | noisy_coeffs[i] -= q_mod_t; 50 | } 51 | noisy_coeffs[i] %= t; 52 | } 53 | return noisy_coeffs; 54 | } 55 | 56 | } // namespace rlwe 57 | 58 | #endif // RLWE_RNS_ERROR_CORRECTION_H_ 59 | -------------------------------------------------------------------------------- /shell_encryption/rns/lazy_rns_polynomial.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "shell_encryption/rns/lazy_rns_polynomial.h" 16 | 17 | #include 18 | 19 | #include "absl/numeric/int128.h" 20 | #include "absl/status/status.h" 21 | #include "absl/types/span.h" 22 | #include "shell_encryption/integral_types.h" 23 | #include "shell_encryption/montgomery.h" 24 | #include "shell_encryption/rns/rns_modulus.h" 25 | #include "shell_encryption/rns/rns_polynomial.h" 26 | #include "shell_encryption/rns/rns_polynomial_hwy.h" 27 | #include "shell_encryption/status_macros.h" 28 | 29 | namespace rlwe { 30 | 31 | using ModularInt32 = MontgomeryInt; 32 | using ModularInt64 = MontgomeryInt; 33 | 34 | template 35 | absl::Status LazyRnsPolynomial::CheckFusedMulAddInPlaceParameters( 36 | const RnsPolynomial& a, const RnsPolynomial& b, 37 | absl::Span* const> moduli) { 38 | if (!a.IsNttForm() || !b.IsNttForm()) { 39 | return absl::InvalidArgumentError( 40 | "Polynomials `a` and `b` must be in NTT form."); 41 | } 42 | int num_moduli = moduli.size(); 43 | if (a.NumModuli() != num_moduli || b.NumModuli() != num_moduli || 44 | coeff_vectors_.size() != num_moduli) { 45 | return absl::InvalidArgumentError( 46 | "Polynomials `a`, `b`, and this must all be defined wrt `moduli`"); 47 | } 48 | int num_coeffs = coeff_vectors_[0].size(); 49 | if (a.NumCoeffs() != num_coeffs || b.NumCoeffs() != num_coeffs) { 50 | return absl::InvalidArgumentError( 51 | "Polynomials `a` and `b` must have the same number of coefficients as " 52 | "this lazy polynomial."); 53 | } 54 | return absl::OkStatus(); 55 | } 56 | 57 | template 58 | absl::Status LazyRnsPolynomial::FusedMulAddInPlace( 59 | const RnsPolynomial& a, const RnsPolynomial& b, 60 | absl::Span* const> moduli) { 61 | RLWE_RETURN_IF_ERROR(CheckFusedMulAddInPlaceParameters(a, b, moduli)); 62 | if (current_level_ == maximum_level_) { 63 | Refresh(moduli); 64 | } 65 | 66 | int num_moduli = moduli.size(); 67 | int num_coeffs = coeff_vectors_[0].size(); 68 | const auto& a_coeff_vectors = a.Coeffs(); 69 | const auto& b_coeff_vectors = b.Coeffs(); 70 | for (int i = 0; i < num_moduli; ++i) { 71 | for (int j = 0; j < num_coeffs; ++j) { 72 | coeff_vectors_[i][j] += 73 | static_cast( 74 | a_coeff_vectors[i][j].GetMontgomeryRepresentation()) * 75 | b_coeff_vectors[i][j].GetMontgomeryRepresentation(); 76 | } 77 | } 78 | current_level_++; 79 | return absl::OkStatus(); 80 | } 81 | 82 | template <> 83 | absl::Status LazyRnsPolynomial::FusedMulAddInPlace( 84 | const RnsPolynomial& a, const RnsPolynomial& b, 85 | absl::Span* const> moduli) { 86 | RLWE_RETURN_IF_ERROR(CheckFusedMulAddInPlaceParameters(a, b, moduli)); 87 | if (current_level_ == maximum_level_) { 88 | Refresh(moduli); 89 | } 90 | 91 | int num_moduli = moduli.size(); 92 | const auto& a_coeff_vectors = a.Coeffs(); 93 | const auto& b_coeff_vectors = b.Coeffs(); 94 | for (int i = 0; i < num_moduli; ++i) { 95 | internal::BatchFusedMulAddMontgomeryRep( 96 | a_coeff_vectors[i], b_coeff_vectors[i], coeff_vectors_[i]); 97 | } 98 | current_level_++; 99 | return absl::OkStatus(); 100 | } 101 | 102 | template <> 103 | absl::Status LazyRnsPolynomial::FusedMulAddInPlace( 104 | const RnsPolynomial& a, const RnsPolynomial& b, 105 | absl::Span* const> moduli) { 106 | RLWE_RETURN_IF_ERROR(CheckFusedMulAddInPlaceParameters(a, b, moduli)); 107 | if (current_level_ == maximum_level_) { 108 | Refresh(moduli); 109 | } 110 | int num_moduli = moduli.size(); 111 | const auto& a_coeff_vectors = a.Coeffs(); 112 | const auto& b_coeff_vectors = b.Coeffs(); 113 | for (int i = 0; i < num_moduli; ++i) { 114 | internal::BatchFusedMulAddMontgomeryRep( 115 | a_coeff_vectors[i], b_coeff_vectors[i], coeff_vectors_[i]); 116 | } 117 | current_level_++; 118 | return absl::OkStatus(); 119 | } 120 | 121 | template class LazyRnsPolynomial>; 122 | template class LazyRnsPolynomial>; 123 | template class LazyRnsPolynomial>; 124 | template class LazyRnsPolynomial>; 125 | #ifdef ABSL_HAVE_INTRINSIC_INT128 126 | template class LazyRnsPolynomial>; 127 | #endif 128 | 129 | } // namespace rlwe 130 | -------------------------------------------------------------------------------- /shell_encryption/rns/rns_bfv_public_key.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include "shell_encryption/rns/rns_bfv_public_key.h" 17 | 18 | #include "absl/numeric/int128.h" 19 | #include "shell_encryption/integral_types.h" 20 | #include "shell_encryption/montgomery.h" 21 | 22 | namespace rlwe { 23 | 24 | template class RnsBfvPublicKey>; 25 | template class RnsBfvPublicKey>; 26 | template class RnsBfvPublicKey>; 27 | template class RnsBfvPublicKey>; 28 | #ifdef ABSL_HAVE_INTRINSIC_INT128 29 | template class RnsBfvPublicKey>; 30 | #endif 31 | 32 | } // namespace rlwe 33 | 34 | 35 | -------------------------------------------------------------------------------- /shell_encryption/rns/rns_bgv_ciphertext.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include "shell_encryption/rns/rns_bgv_ciphertext.h" 17 | 18 | #include "absl/numeric/int128.h" 19 | #include "shell_encryption/integral_types.h" 20 | #include "shell_encryption/montgomery.h" 21 | 22 | namespace rlwe { 23 | 24 | template class RnsBgvCiphertext>; 25 | template class RnsBgvCiphertext>; 26 | template class RnsBgvCiphertext>; 27 | template class RnsBgvCiphertext>; 28 | #ifdef ABSL_HAVE_INTRINSIC_INT128 29 | template class RnsBgvCiphertext>; 30 | #endif 31 | 32 | } // namespace rlwe 33 | -------------------------------------------------------------------------------- /shell_encryption/rns/rns_bgv_public_key.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include "shell_encryption/rns/rns_bgv_public_key.h" 17 | 18 | #include "absl/numeric/int128.h" 19 | #include "shell_encryption/integral_types.h" 20 | #include "shell_encryption/montgomery.h" 21 | 22 | namespace rlwe { 23 | 24 | template class RnsBgvPublicKey>; 25 | template class RnsBgvPublicKey>; 26 | template class RnsBgvPublicKey>; 27 | template class RnsBgvPublicKey>; 28 | #ifdef ABSL_HAVE_INTRINSIC_INT128 29 | template class RnsBgvPublicKey>; 30 | #endif 31 | 32 | } // namespace rlwe 33 | -------------------------------------------------------------------------------- /shell_encryption/rns/rns_ciphertext.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include "shell_encryption/rns/rns_ciphertext.h" 17 | 18 | #include "absl/numeric/int128.h" 19 | #include "shell_encryption/integral_types.h" 20 | #include "shell_encryption/montgomery.h" 21 | 22 | namespace rlwe { 23 | 24 | template class RnsRlweCiphertext>; 25 | template class RnsRlweCiphertext>; 26 | template class RnsRlweCiphertext>; 27 | template class RnsRlweCiphertext>; 28 | #ifdef ABSL_HAVE_INTRINSIC_INT128 29 | template class RnsRlweCiphertext>; 30 | #endif 31 | 32 | } // namespace rlwe 33 | -------------------------------------------------------------------------------- /shell_encryption/rns/rns_gadget.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef RLWE_RNS_RNS_GADGET_H_ 17 | #define RLWE_RNS_RNS_GADGET_H_ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "absl/algorithm/container.h" 24 | #include "absl/status/status.h" 25 | #include "absl/types/span.h" 26 | #include "shell_encryption/rns/rns_integer.h" 27 | #include "shell_encryption/rns/rns_modulus.h" 28 | #include "shell_encryption/rns/rns_polynomial.h" 29 | #include "shell_encryption/status_macros.h" 30 | 31 | namespace rlwe { 32 | 33 | // The Gadget class represents a gadget vector g with respect to the RNS modulus 34 | // Q = q_0 * ... * q_L, for representing mod-Q numbers using "digits" of quality 35 | // bounded by certain bases B = {b_0, ..., b_L}. The basic operation supported 36 | // by a gadget is decomposition, g^-1(x mod Q) = (x_0 mod q_0, ..., x_L mod q_L) 37 | // such that the inner product between the decomposition and the gadaget vector 38 | // satisfies that mod Q == x. Each component x_i of the 39 | // decomposition is a vector whose entries are bounded by b_i. The length of the 40 | // decomposition which is also the dimension of the gadget vector g, is the sum 41 | // of the lengths of x_i. The implementation assumes all b_i are powers of 2. 42 | // Note that a gadget matrix can be efficiently computed as I \tensor g. 43 | // 44 | // This class implements the so-called digit decomposition gadget with CRT 45 | // representation. A "gadget" in lattice-based cryptography in general is a way 46 | // to encode an element with large norm into a higher-dimension vector of 47 | // "smaller" elements, which has benefits for controlling noise growth. For a 48 | // formal exposition see https://eprint.iacr.org/2018/946. 49 | // 50 | template 51 | class RnsGadget { 52 | using Integer = typename ModularInt::Int; 53 | using ModularIntParams = typename ModularInt::Params; 54 | 55 | public: 56 | // Create a gadget with CRT representation given the log of bases b_i and the 57 | // RNS moduli. Note that a gadget is the concatenation of gadgets in the 58 | // residual ring Z_{qi}: 59 | // g_crt = [ qi_hat * qi_hat_inv * g_i for i in 1..L ] mod Q, 60 | // where Q = q1 * ... * qL, qi_hat = Q / q_i, qi_hat_inv = qi_hat^(-1) mod qi. 61 | static absl::StatusOr Create( 62 | int log_n, std::vector log_bs, 63 | absl::Span q_hats, // {qi_hat mod qi}_i 64 | absl::Span q_hat_invs, // {qi_hat_inv}_i 65 | absl::Span* const> moduli); 66 | 67 | // Returns the gadget decomposition of a RNS polynomial. 68 | // Note that the input polynomial `a` must be in coefficient form, and the 69 | // returned polynomial is in the coefficient form. 70 | absl::StatusOr>> Decompose( 71 | const RnsPolynomial& a, 72 | absl::Span* const> moduli) const; 73 | 74 | // Returns the gadget decomposition of a vector of RNS polynomials. 75 | // The result is a vector containing decompositions of every polynomial in 76 | // the input vector. 77 | // Note that the input polynomials in `as` must all be in coefficient form. 78 | absl::StatusOr>>> Decompose( 79 | absl::Span> as, 80 | absl::Span* const> moduli) const { 81 | std::vector>> as_digits; 82 | as_digits.reserve(as.size()); 83 | for (const auto& a : as) { 84 | RLWE_ASSIGN_OR_RETURN(std::vector> a_digits, 85 | Decompose(a, moduli)); 86 | as_digits.push_back(std::move(a_digits)); 87 | } 88 | return as_digits; 89 | } 90 | 91 | int LogGadgetBase() const { 92 | auto max = std::max_element(log_bs_.begin(), log_bs_.end()); 93 | return *max; 94 | } 95 | 96 | // The dimension of the gadget vector. 97 | int Dimension() const { return absl::c_accumulate(dims_, size_t{0}); } 98 | 99 | const RnsInt& Component(int index) const { return gs_[index]; } 100 | 101 | private: 102 | explicit RnsGadget(std::vector log_bs, std::vector dimensions, 103 | std::vector> gs) 104 | : log_bs_(std::move(log_bs)), 105 | dims_(std::move(dimensions)), 106 | gs_(std::move(gs)) {} 107 | 108 | // The base must be small enough to be represented by the residual int. 109 | std::vector log_bs_; 110 | 111 | // The sub-dimensions, which are the lengths of components of a gadget vector 112 | // wrt RNS prime moduli. 113 | std::vector dims_; 114 | 115 | // The gadget vector {g_i mod q_i}_i, stored as RNS integers. 116 | std::vector> gs_; 117 | }; 118 | 119 | } // namespace rlwe 120 | 121 | #endif // RLWE_RNS_RNS_GADGET_H_ 122 | -------------------------------------------------------------------------------- /shell_encryption/rns/rns_integer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef RLWE_RNS_RNS_INTEGER_H_ 17 | #define RLWE_RNS_RNS_INTEGER_H_ 18 | 19 | #include 20 | 21 | #include "absl/types/span.h" 22 | 23 | namespace rlwe { 24 | 25 | // This class stores an integer z (mod Q) using RNS representation, where 26 | // Q = q_0 * ... * q_{L-1} for distinct primes q_i. The RNS representation 27 | // of z is the vector [z (mod q_i) for i = 0 .. L-1]. 28 | // We assume that L >= 1 and the RNS integer z is not vacuous. 29 | template 30 | struct RnsInt { 31 | std::vector zs; 32 | 33 | // The number of prime moduli for this RNS integer. 34 | int NumModuli() const { return zs.size(); } 35 | 36 | // Returns the RnsInt represented by the first `num_moduli` residue values. 37 | RnsInt Prefix(int num_moduli) const { 38 | std::vector zs_prefix(zs.begin(), zs.begin() + num_moduli); 39 | return RnsInt{std::move(zs_prefix)}; 40 | } 41 | 42 | // Returns the vector of residue values representing this RNS integer. 43 | absl::Span RnsRep() const { return zs; } 44 | 45 | // Returns the vector of the first `num_moduli` residue values. 46 | absl::Span RnsRepPrefix(int num_moduli) const { 47 | return absl::MakeSpan(zs).subspan(0, num_moduli); 48 | } 49 | 50 | // Accessor to the residue value at the given level index. 51 | const ModularInt& Component(int index) const { return zs[index]; } 52 | }; 53 | 54 | } // namespace rlwe 55 | 56 | #endif // RLWE_RNS_RNS_INTEGER_H_ 57 | -------------------------------------------------------------------------------- /shell_encryption/rns/rns_modulus.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef RLWE_RNS_RNS_MODULUS_H_ 17 | #define RLWE_RNS_RNS_MODULUS_H_ 18 | 19 | #include "shell_encryption/montgomery.h" 20 | #include "shell_encryption/ntt_parameters.h" 21 | 22 | namespace rlwe { 23 | 24 | // A RNS modulus Q = q_0 * ... * q_L is the product of prime moduli q_i's. 25 | // By Chinese Remainder Theorem, we have a ring isomorphism between Z_Q and 26 | // Z_{q_0} * ... * Z_{q_L} and so, addition and multiplication mod-Q can be done 27 | // with respect to each q_i independently. This type is an aggregate that holds 28 | // the Montgomery and NTT parameters for a prime modulus q_i that define the 29 | // arithmetic mod q_i and mod (X^N+1) for N a power of two. 30 | template 31 | struct PrimeModulus { 32 | using ModularIntParams = typename ModularInt::Params; 33 | 34 | typename ModularInt::Int Modulus() const { return mod_params->modulus; } 35 | const ModularIntParams* ModParams() const { return mod_params.get(); } 36 | const NttParameters* NttParams() const { 37 | return ntt_params.get(); 38 | } 39 | 40 | std::unique_ptr mod_params; 41 | std::unique_ptr> ntt_params; 42 | }; 43 | 44 | } // namespace rlwe 45 | 46 | #endif // RLWE_RNS_RNS_MODULUS_H_ 47 | -------------------------------------------------------------------------------- /shell_encryption/rns/rns_polynomial_hwy.h: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef RLWE_RNS_RNS_POLYNOMIAL_HWY_H_ 16 | #define RLWE_RNS_RNS_POLYNOMIAL_HWY_H_ 17 | 18 | #include "absl/types/span.h" 19 | #include "hwy/aligned_allocator.h" 20 | #include "shell_encryption/montgomery.h" 21 | 22 | namespace rlwe { 23 | namespace internal { 24 | 25 | // Given vectors `a` and `b`, computes component-wise a[i] * b[i] and add them 26 | // to output[i]. Modular multiplications are computed over the Montgomery form 27 | // without reduction (and store the result in double width BigInt type), and 28 | // are implemented using SIMD instructions via the highway library. 29 | // Note: We assume that `a` and `b` have the same size, and `output` has at 30 | // least the same number of elements. 31 | template 32 | void BatchFusedMulAddMontgomeryRep( 33 | absl::Span> a, 34 | absl::Span> b, 35 | hwy::AlignedVector::value_type>& output); 36 | 37 | // Given vectors `a` and `b`, computes component-wise a[i] * b[i] and add them 38 | // to output[i]. This version does not use highway SIMD intrinsics. 39 | // Note: We assume that `a` and `b` have the same size, and `output` has at 40 | // least the same number of elements. 41 | template 42 | void BatchFusedMulAddMontgomeryRepNoHwy( 43 | absl::Span> a, 44 | absl::Span> b, 45 | hwy::AlignedVector::value_type>& output); 46 | 47 | } // namespace internal 48 | } // namespace rlwe 49 | 50 | #endif // RLWE_RNS_RNS_POLYNOMIAL_HWY_H_ 51 | -------------------------------------------------------------------------------- /shell_encryption/rns/rns_public_key.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include "shell_encryption/rns/rns_public_key.h" 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "absl/numeric/int128.h" 24 | #include "absl/status/status.h" 25 | #include "absl/status/statusor.h" 26 | #include "shell_encryption/integral_types.h" 27 | #include "shell_encryption/montgomery.h" 28 | #include "shell_encryption/prng/prng.h" 29 | #include "shell_encryption/prng/single_thread_chacha_prng.h" 30 | #include "shell_encryption/prng/single_thread_hkdf_prng.h" 31 | #include "shell_encryption/rns/error_distribution.h" 32 | #include "shell_encryption/rns/rns_modulus.h" 33 | #include "shell_encryption/rns/rns_polynomial.h" 34 | #include "shell_encryption/rns/rns_secret_key.h" 35 | #include "shell_encryption/status_macros.h" 36 | 37 | namespace rlwe { 38 | 39 | template 40 | absl::StatusOr> 41 | RnsRlwePublicKey::Create( 42 | const RnsRlweSecretKey& secret_key, int variance, 43 | PrngType prng_type, Integer error_scalar) { 44 | if (variance <= 0) { 45 | return absl::InvalidArgumentError("`variance` must be positive."); 46 | } 47 | 48 | // Create two PRNGs: `prng_pad` is used to sample the random polynomial "a" 49 | // and its seed is stored such that it can be serialized. The other PRNG 50 | // `prng_error` is used to sample the error term and it is not stored. 51 | std::unique_ptr prng_pad, prng_error; 52 | std::string prng_pad_seed, prng_error_seed; 53 | if (prng_type == PRNG_TYPE_HKDF) { 54 | RLWE_ASSIGN_OR_RETURN(prng_pad_seed, SingleThreadHkdfPrng::GenerateSeed()); 55 | RLWE_ASSIGN_OR_RETURN(prng_pad, 56 | SingleThreadHkdfPrng::Create(prng_pad_seed)); 57 | RLWE_ASSIGN_OR_RETURN(prng_error_seed, 58 | SingleThreadHkdfPrng::GenerateSeed()); 59 | RLWE_ASSIGN_OR_RETURN(prng_error, 60 | SingleThreadHkdfPrng::Create(prng_error_seed)); 61 | } else if (prng_type == PRNG_TYPE_CHACHA) { 62 | RLWE_ASSIGN_OR_RETURN(prng_pad_seed, 63 | SingleThreadChaChaPrng::GenerateSeed()); 64 | RLWE_ASSIGN_OR_RETURN(prng_pad, 65 | SingleThreadChaChaPrng::Create(prng_pad_seed)); 66 | RLWE_ASSIGN_OR_RETURN(prng_error_seed, 67 | SingleThreadChaChaPrng::GenerateSeed()); 68 | RLWE_ASSIGN_OR_RETURN(prng_error, 69 | SingleThreadChaChaPrng::Create(prng_error_seed)); 70 | } else { 71 | return absl::InvalidArgumentError("PrngType not specified correctly."); 72 | } 73 | 74 | // b = u * s + t * e for a uniformly random u. 75 | auto moduli = secret_key.Moduli(); 76 | int log_n = secret_key.LogN(); 77 | RLWE_ASSIGN_OR_RETURN(auto u, RnsPolynomial::SampleUniform( 78 | log_n, prng_pad.get(), moduli)); 79 | RLWE_ASSIGN_OR_RETURN( 80 | RnsPolynomial b, 81 | SampleError(log_n, variance, moduli, prng_error.get())); 82 | RLWE_RETURN_IF_ERROR(b.MulInPlace(error_scalar, moduli)); 83 | RLWE_RETURN_IF_ERROR(b.FusedMulAddInPlace(u, secret_key.Key(), moduli)); 84 | 85 | // a = -u 86 | RLWE_RETURN_IF_ERROR(u.NegateInPlace(moduli)); 87 | 88 | // Store the RNS moduli. 89 | std::vector*> moduli_vector; 90 | moduli_vector.insert(moduli_vector.begin(), moduli.begin(), moduli.end()); 91 | 92 | return RnsRlwePublicKey(std::move(u), std::move(b), 93 | std::move(moduli_vector), variance, 94 | prng_pad_seed, prng_type); 95 | } 96 | 97 | template class RnsRlwePublicKey>; 98 | template class RnsRlwePublicKey>; 99 | template class RnsRlwePublicKey>; 100 | template class RnsRlwePublicKey>; 101 | #ifdef ABSL_HAVE_INTRINSIC_INT128 102 | template class RnsRlwePublicKey>; 103 | #endif 104 | 105 | } // namespace rlwe 106 | -------------------------------------------------------------------------------- /shell_encryption/rns/rns_public_key.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef RLWE_RNS_RNS_PUBLIC_KEY_H_ 17 | #define RLWE_RNS_RNS_PUBLIC_KEY_H_ 18 | 19 | #include 20 | #include 21 | 22 | #include "absl/status/statusor.h" 23 | #include "absl/strings/string_view.h" 24 | #include "absl/types/span.h" 25 | #include "shell_encryption/rns/rns_modulus.h" 26 | #include "shell_encryption/rns/rns_polynomial.h" 27 | #include "shell_encryption/rns/rns_secret_key.h" 28 | 29 | namespace rlwe { 30 | 31 | template 32 | class RnsRlwePublicKey { 33 | public: 34 | using Integer = typename ModularInt::Int; 35 | 36 | // Accessors. 37 | int LogN() const { return key_a_.LogN(); } 38 | 39 | int Level() const { return moduli_.size() - 1; } 40 | 41 | int NumCoeffs() const { return key_a_.NumCoeffs(); } 42 | 43 | int NumModuli() const { return moduli_.size(); } 44 | 45 | // Accessor for the prime moduli chain. 46 | absl::Span* const> Moduli() const { 47 | return moduli_; 48 | } 49 | 50 | // Accessors to the two components in a RLWE public key. 51 | const RnsPolynomial& KeyA() const { return key_a_; } 52 | const RnsPolynomial& KeyB() const { return key_b_; } 53 | 54 | protected: 55 | // Generate a public key (b = a*s + scale*e, -a) derived from the given secret 56 | // key, where the randomness a is freshly sampled uniformly random polynomial, 57 | // and the error term e has coefficients sampled from a centered binomial 58 | // distribution of the given variance. The scaling factor `error_scalar` 59 | // should be set to the plaintext modulus for BGV public key, and it should be 60 | // 1 in other schemes. 61 | static absl::StatusOr Create( 62 | const RnsRlweSecretKey& secret_key, int variance, 63 | PrngType prng_type, Integer error_scalar = 1); 64 | 65 | // Allow derived public key classes to access data members. 66 | const std::vector*>& moduli() const { 67 | return moduli_; 68 | } 69 | 70 | int variance() const { return variance_; } 71 | 72 | private: 73 | explicit RnsRlwePublicKey(RnsPolynomial key_a, 74 | RnsPolynomial key_b, 75 | std::vector*> moduli, 76 | int variance, absl::string_view prng_seed, 77 | PrngType prng_type) 78 | : key_a_(std::move(key_a)), 79 | key_b_(std::move(key_b)), 80 | moduli_(std::move(moduli)), 81 | variance_(variance), 82 | prng_seed_(std::string(prng_seed)), 83 | prng_type_(prng_type) {} 84 | 85 | // The two components (b, a) of a RLWE public key. 86 | RnsPolynomial key_a_; 87 | RnsPolynomial key_b_; 88 | 89 | // The RNS moduli used to construct this public key. 90 | std::vector*> moduli_; 91 | 92 | // The variance of the binomial distribution for the error terms in the public 93 | // key and the public key encryptions. 94 | int variance_; 95 | 96 | // Prng seed used to sample the pseudorandom polynomial key_a_ 97 | std::string prng_seed_; 98 | // Prng type 99 | PrngType prng_type_; 100 | }; 101 | 102 | } // namespace rlwe 103 | 104 | #endif // RLWE_RNS_RNS_PUBLIC_KEY_H_ 105 | -------------------------------------------------------------------------------- /shell_encryption/rns/rns_secret_key.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2023 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "shell_encryption/rns/rns_secret_key.h" 16 | 17 | #include 18 | #include 19 | 20 | #include "absl/numeric/int128.h" 21 | #include "absl/status/status.h" 22 | #include "absl/status/statusor.h" 23 | #include "shell_encryption/integral_types.h" 24 | #include "shell_encryption/montgomery.h" 25 | #include "shell_encryption/prng/prng.h" 26 | #include "shell_encryption/rns/error_distribution.h" 27 | #include "shell_encryption/rns/rns_ciphertext.h" 28 | #include "shell_encryption/rns/rns_modulus.h" 29 | #include "shell_encryption/rns/rns_polynomial.h" 30 | #include "shell_encryption/status_macros.h" 31 | 32 | namespace rlwe { 33 | 34 | template 35 | absl::StatusOr> 36 | RnsRlweSecretKey::Sample( 37 | int log_n, int variance, 38 | std::vector*> moduli, SecurePrng* prng) { 39 | if (log_n <= 0) { 40 | return absl::InvalidArgumentError("`log_n` must be positive."); 41 | } 42 | if (variance <= 0) { 43 | return absl::InvalidArgumentError("`variance` must be positive."); 44 | } 45 | if (moduli.empty()) { 46 | return absl::InvalidArgumentError( 47 | "`moduli` must contain at least one element."); 48 | } 49 | if (prng == nullptr) { 50 | return absl::InvalidArgumentError("`prng` must not be null."); 51 | } 52 | 53 | // Sample the secret s from the error distribution. 54 | RLWE_ASSIGN_OR_RETURN(RnsPolynomial s, 55 | SampleError(log_n, variance, moduli, prng)); 56 | return RnsRlweSecretKey(std::move(s), std::move(moduli), variance); 57 | } 58 | 59 | template 60 | absl::StatusOr> 61 | RnsRlweSecretKey::RawDecrypt( 62 | const RnsRlweCiphertext& ciphertext) const { 63 | RnsPolynomial s_power = key_; 64 | RLWE_ASSIGN_OR_RETURN(RnsPolynomial output, 65 | RnsPolynomial::CreateZero(LogN(), moduli_)); 66 | int ciphertext_len = ciphertext.Len(); 67 | for (int i = 0; i < ciphertext_len; ++i) { 68 | // Get the i-th component 69 | RLWE_ASSIGN_OR_RETURN(RnsPolynomial ci, 70 | ciphertext.Component(i)); 71 | 72 | // Compute the next power of the secret polynomial s. 73 | if (i > 1) { 74 | RLWE_RETURN_IF_ERROR(s_power.MulInPlace(key_, moduli_)); 75 | } 76 | // Compute c[i] * s^i. 77 | if (i > 0) { 78 | RLWE_RETURN_IF_ERROR(ci.MulInPlace(s_power, moduli_)); 79 | } 80 | // Add c[i] * s^i to the result. 81 | RLWE_RETURN_IF_ERROR(output.AddInPlace(ci, moduli_)); 82 | } 83 | return output; 84 | } 85 | 86 | template 87 | absl::Status RnsRlweSecretKey::ModReduce() { 88 | if (moduli_.size() <= 1) { 89 | return absl::FailedPreconditionError( 90 | "Cannot perform ModReduce with insufficient number of prime moduli."); 91 | } 92 | RLWE_ASSIGN_OR_RETURN(auto k_ql, key_.DetachLastCoeffVector()); 93 | moduli_.pop_back(); 94 | return absl::OkStatus(); 95 | } 96 | 97 | template class RnsRlweSecretKey>; 98 | template class RnsRlweSecretKey>; 99 | template class RnsRlweSecretKey>; 100 | template class RnsRlweSecretKey>; 101 | #ifdef ABSL_HAVE_INTRINSIC_INT128 102 | template class RnsRlweSecretKey>; 103 | #endif 104 | 105 | } // namespace rlwe 106 | -------------------------------------------------------------------------------- /shell_encryption/rns/serialization.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // proto definitions of RNS variant of the RLWE library. 16 | 17 | syntax = "proto2"; 18 | 19 | package rlwe; 20 | 21 | import "shell_encryption/serialization.proto"; 22 | 23 | option optimize_for = LITE_RUNTIME; 24 | 25 | // RNS polynomial. 26 | message SerializedRnsPolynomial { 27 | // The log (base 2) of the number of coefficients. 28 | optional int32 log_n = 1; 29 | 30 | // The coefficient vectors wrt RNS moduli. 31 | repeated bytes coeff_vectors = 2; 32 | 33 | // Is the polynomial in NTT form? 34 | optional bool is_ntt = 3; 35 | } 36 | 37 | // RNS RLWE ciphertext. 38 | message SerializedRnsRlweCiphertext { 39 | // The component polynomials composing the ciphertext. 40 | repeated SerializedRnsPolynomial components = 1; 41 | 42 | // The power of the secret key that the ciphertext is encrypted with. 43 | optional int32 power_of_s = 2; 44 | 45 | // A heuristic on the amount of error in the ciphertext. 46 | optional double error = 3; 47 | } 48 | 49 | // RNS Galois key. 50 | message SerializedRnsGaloisKey { 51 | // Reserve the tag 1 for the "a" components, in case a Galois key is derived 52 | // from composition of Galois keys instead of generated from fresh. 53 | reserved 1; 54 | 55 | // The "b" components of the Galois key. 56 | repeated SerializedRnsPolynomial key_bs = 2; 57 | 58 | // The substitution power of the source secret key. 59 | optional int32 power = 3; 60 | 61 | // The PRNG seed used to compress the "a" components. 62 | optional bytes prng_seed = 4; 63 | 64 | // The type of the PRNG for sampling the "a" components. 65 | optional PrngType prng_type = 5; 66 | } 67 | -------------------------------------------------------------------------------- /shell_encryption/rns/testing/BUILD: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | load("@rules_cc//cc:cc_library.bzl", "cc_library") 16 | 17 | package(default_visibility = ["//visibility:public"]) 18 | 19 | cc_library( 20 | name = "parameters", 21 | testonly = 1, 22 | hdrs = ["parameters.h"], 23 | deps = [ 24 | "//shell_encryption:integral_types", 25 | "//shell_encryption:montgomery", 26 | "@com_github_google_googletest//:gtest", 27 | "@com_google_absl//absl/numeric:int128", 28 | ], 29 | ) 30 | 31 | cc_library( 32 | name = "testing_utils", 33 | testonly = 1, 34 | hdrs = ["testing_utils.h"], 35 | deps = [ 36 | "//shell_encryption:integral_types", 37 | "//shell_encryption/rns:rns_modulus", 38 | "//shell_encryption/rns:rns_polynomial", 39 | "@com_google_absl//absl/log:check", 40 | "@com_google_absl//absl/numeric:int128", 41 | "@com_google_absl//absl/random", 42 | "@com_google_absl//absl/types:span", 43 | ], 44 | ) 45 | -------------------------------------------------------------------------------- /shell_encryption/rns/testing/testing_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | // This file contains commonly used utilities for testing the RNS extension. 17 | 18 | #ifndef RLWE_RNS_TESTING_TESTING_UTILS_H_ 19 | #define RLWE_RNS_TESTING_TESTING_UTILS_H_ 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "absl/log/check.h" 26 | #include "absl/numeric/int128.h" 27 | #include "absl/random/random.h" 28 | #include "absl/types/span.h" 29 | #include "shell_encryption/integral_types.h" 30 | #include "shell_encryption/rns/rns_modulus.h" 31 | #include "shell_encryption/rns/rns_polynomial.h" 32 | 33 | namespace rlwe { 34 | namespace testing { 35 | 36 | // Returns a vector of `num_values` many random integers in [0, max_value). 37 | // Assumes that `max_value` is smaller than 2^64. 38 | template 39 | std::vector SampleMessages(int num_values, Integer max_value) { 40 | absl::BitGen bitgen; 41 | std::vector messages; 42 | for (int i = 0; i < num_values; ++i) { 43 | Integer message = static_cast( 44 | absl::Uniform(bitgen, 0, static_cast(max_value))); 45 | messages.push_back(message); 46 | } 47 | return messages; 48 | } 49 | 50 | inline std::vector> SampleComplexValues( 51 | int num_values, uint64_t max_value, uint64_t precision) { 52 | absl::BitGen bitgen; 53 | std::vector> values; 54 | for (int i = 0; i < num_values; ++i) { 55 | uint64_t u = absl::Uniform(bitgen, 0, max_value * 2 * precision); 56 | uint64_t v = absl::Uniform(bitgen, 0, max_value * 2 * precision); 57 | int64_t real = static_cast(u) - max_value * precision; 58 | int64_t imag = static_cast(v) - max_value * precision; 59 | std::complex value{static_cast(real) / precision, 60 | static_cast(imag) / precision}; 61 | values.push_back(value); 62 | } 63 | return values; 64 | } 65 | 66 | // Returns a RnsPolynomial in Z[X]/(Q, X^N+1) whose coefficients are random 67 | // 0, 1, or -1 (mod Q). 68 | template 69 | RnsPolynomial SampleTernaryNoises( 70 | int log_n, absl::Span* const> moduli) { 71 | int num_coeffs = 1 << log_n; 72 | int num_moduli = moduli.size(); 73 | absl::BitGen bitgen; 74 | std::vector> coeff_vectors(num_moduli); 75 | for (int i = 0; i < num_coeffs; ++i) { 76 | int8_t e = absl::Uniform(absl::IntervalClosed, bitgen, -1, 1); 77 | for (int j = 0; j < num_moduli; ++j) { 78 | auto mod_params_qj = moduli[j]->ModParams(); 79 | auto e_mod_qj = ModularInt::ImportInt( 80 | e == -1 ? mod_params_qj->modulus : (e == 0 ? 0 : 1), mod_params_qj); 81 | CHECK(e_mod_qj.ok()); 82 | coeff_vectors[j].push_back(std::move(e_mod_qj.value())); 83 | } 84 | } 85 | auto a = RnsPolynomial::Create(coeff_vectors, /*is_ntt=*/false); 86 | CHECK(a.ok()); 87 | return a.value(); 88 | } 89 | 90 | } // namespace testing 91 | } // namespace rlwe 92 | 93 | #endif // RLWE_RNS_TESTING_TESTING_UTILS_H_ 94 | -------------------------------------------------------------------------------- /shell_encryption/sample_error.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef RLWE_SAMPLE_ERROR_H_ 17 | #define RLWE_SAMPLE_ERROR_H_ 18 | 19 | #include 20 | #include 21 | 22 | #include "absl/strings/str_cat.h" 23 | #include "shell_encryption/bits_util.h" 24 | #include "shell_encryption/constants.h" 25 | #include "shell_encryption/error_params.h" 26 | #include "shell_encryption/prng/prng.h" 27 | #include "shell_encryption/status_macros.h" 28 | #include "shell_encryption/statusor.h" 29 | 30 | namespace rlwe { 31 | 32 | // Samples a vector of coefficients from the centered binomial distribution 33 | // with the specified variance. The RLWE proofs rely on 34 | // sampling keys and error values from a discrete Gaussian distribution, but 35 | // the NewHope paper [1] indicates that a centered binomial distribution is 36 | // indistinguishable and is far more efficient, without being susceptible to 37 | // timing attacks. 38 | // 39 | // [1] "Post-quantum key exchange -- a new hope", Erdem Alkim, Leo Ducas, Thomas 40 | // Poppelmann, Peter Schwabe, USENIX Security Sumposium. 41 | // 42 | // All values sampled are multiplied by scalar. 43 | template 44 | static rlwe::StatusOr> SampleFromErrorDistribution( 45 | unsigned int num_coeffs, Uint64 variance, SecurePrng* prng, 46 | const typename ModularInt::Params* modulus_params) { 47 | if (variance > kMaxVariance) { 48 | return absl::InvalidArgumentError(absl::StrCat( 49 | "The variance, ", variance, ", must be at most ", kMaxVariance, ".")); 50 | } 51 | auto zero = ModularInt::ImportZero(modulus_params); 52 | std::vector coeffs(num_coeffs, zero); 53 | 54 | // Sample from the centered binomial distribution. To do so, we sample k pairs 55 | // of bits (a, b), where k = 2 * variance. The sample of the binomial 56 | // distribution is the sum of the differences between each pair of bits. 57 | Uint64 k; 58 | typename ModularInt::Int coefficient; 59 | 60 | for (unsigned int i = 0; i < num_coeffs; i++) { 61 | coefficient = modulus_params->modulus; 62 | k = variance << 1; 63 | 64 | while (k > 0) { 65 | if (k >= 64) { 66 | // Use 64 bits of randomness 67 | RLWE_ASSIGN_OR_RETURN(auto r64, prng->Rand64()); 68 | coefficient += rlwe::internal::CountOnes64(r64); 69 | RLWE_ASSIGN_OR_RETURN(r64, prng->Rand64()); 70 | coefficient -= rlwe::internal::CountOnes64(r64); 71 | k -= 64; 72 | } else if (k >= 8) { 73 | // Use 8 bits of randomness 74 | RLWE_ASSIGN_OR_RETURN(auto r8, prng->Rand8()); 75 | coefficient += rlwe::internal::CountOnesInByte(r8); 76 | RLWE_ASSIGN_OR_RETURN(r8, prng->Rand8()); 77 | coefficient -= rlwe::internal::CountOnesInByte(r8); 78 | k -= 8; 79 | } else { 80 | Uint8 mask = (1 << k) - 1; 81 | RLWE_ASSIGN_OR_RETURN(auto r8, prng->Rand8()); 82 | coefficient += rlwe::internal::CountOnesInByte(r8 & mask); 83 | RLWE_ASSIGN_OR_RETURN(r8, prng->Rand8()); 84 | coefficient -= rlwe::internal::CountOnesInByte(r8 & mask); 85 | break; // all k remaining pairs have been sampled. 86 | } 87 | } 88 | 89 | // coefficient is in the interval [modulus - 2k, modulus + 2k]. We reduce 90 | // it in [0, modulus). Since ModularInt::Int is unsigned, we create a mask 91 | // equal to 0xFF...FF when coefficient >= modulus, and equal to 0 otherwise. 92 | typename ModularInt::Int mask = -(coefficient >= modulus_params->modulus); 93 | coefficient -= mask & modulus_params->modulus; 94 | 95 | RLWE_ASSIGN_OR_RETURN(coeffs[i], 96 | ModularInt::ImportInt(coefficient, modulus_params)); 97 | } 98 | 99 | return coeffs; 100 | } 101 | 102 | } // namespace rlwe 103 | 104 | #endif // RLWE_SAMPLE_ERROR_H_ 105 | -------------------------------------------------------------------------------- /shell_encryption/sample_error_test.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include "shell_encryption/sample_error.h" 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include "shell_encryption/context.h" 25 | #include "shell_encryption/montgomery.h" 26 | #include "shell_encryption/symmetric_encryption.h" 27 | #include "shell_encryption/testing/parameters.h" 28 | #include "shell_encryption/testing/status_matchers.h" 29 | #include "shell_encryption/testing/status_testing.h" 30 | #include "shell_encryption/testing/testing_prng.h" 31 | 32 | namespace { 33 | 34 | using ::rlwe::testing::StatusIs; 35 | using ::testing::HasSubstr; 36 | 37 | const int kTestingRounds = 10; 38 | const std::vector variances = {8, 15, 29, 50}; 39 | 40 | template 41 | class SampleErrorTest : public ::testing::Test {}; 42 | TYPED_TEST_SUITE(SampleErrorTest, rlwe::testing::ModularIntTypes); 43 | 44 | TYPED_TEST(SampleErrorTest, CheckUpperBoundOnNoise) { 45 | using Int = typename TypeParam::Int; 46 | 47 | auto prng = std::make_unique(0); 48 | 49 | for (const auto& params : 50 | rlwe::testing::ContextParameters::Value()) { 51 | ASSERT_OK_AND_ASSIGN(auto context, 52 | rlwe::RlweContext::Create(params)); 53 | 54 | for (auto variance : variances) { 55 | for (int i = 0; i < kTestingRounds; i++) { 56 | ASSERT_OK_AND_ASSIGN(std::vector error, 57 | rlwe::SampleFromErrorDistribution( 58 | context->GetN(), variance, prng.get(), 59 | context->GetModulusParams())); 60 | // Check that each coefficient is in [-2*variance, 2*variance] 61 | for (size_t j = 0; j < context->GetN(); j++) { 62 | Int reduced = error[j].ExportInt(context->GetModulusParams()); 63 | if (reduced > (context->GetModulus() >> 1)) { 64 | EXPECT_LT(context->GetModulus() - reduced, 2 * variance + 1); 65 | } else { 66 | EXPECT_LT(reduced, 2 * variance + 1); 67 | } 68 | } 69 | } 70 | } 71 | } 72 | } 73 | 74 | TYPED_TEST(SampleErrorTest, FailOnTooLargeVariance) { 75 | auto prng = std::make_unique(0); 76 | for (const auto& params : 77 | rlwe::testing::ContextParameters::Value()) { 78 | ASSERT_OK_AND_ASSIGN(auto context, 79 | rlwe::RlweContext::Create(params)); 80 | 81 | rlwe::Uint64 variance = rlwe::kMaxVariance + 1; 82 | EXPECT_THAT( 83 | rlwe::SampleFromErrorDistribution( 84 | context->GetN(), variance, prng.get(), context->GetModulusParams()), 85 | StatusIs( 86 | absl::StatusCode::kInvalidArgument, 87 | HasSubstr(absl::StrCat("The variance, ", variance, 88 | ", must be at most ", rlwe::kMaxVariance)))); 89 | } 90 | } 91 | 92 | } // namespace 93 | -------------------------------------------------------------------------------- /shell_encryption/sampler/BUILD: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Google LLC. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Error distribution samplers 16 | 17 | load("@rules_cc//cc:cc_library.bzl", "cc_library") 18 | load("@rules_cc//cc:cc_test.bzl", "cc_test") 19 | 20 | package(default_visibility = ["//visibility:public"]) 21 | 22 | # Discrete Gaussian sampler implementations for lattice crypto. 23 | cc_library( 24 | name = "discrete_gaussian", 25 | srcs = ["discrete_gaussian.cc"], 26 | hdrs = ["discrete_gaussian.h"], 27 | deps = [ 28 | "//shell_encryption:integral_types", 29 | "//shell_encryption:statusor_fork", 30 | "//shell_encryption/prng", 31 | "@com_google_absl//absl/memory", 32 | "@com_google_absl//absl/numeric:int128", 33 | "@com_google_absl//absl/status", 34 | "@com_google_absl//absl/status:statusor", 35 | "@com_google_absl//absl/strings", 36 | ], 37 | ) 38 | 39 | cc_test( 40 | name = "discrete_gaussian_test", 41 | srcs = ["discrete_gaussian_test.cc"], 42 | deps = [ 43 | ":discrete_gaussian", 44 | "//shell_encryption:integral_types", 45 | "//shell_encryption/testing:status_is_fork", 46 | "//shell_encryption/testing:status_testing", 47 | "//shell_encryption/testing:testing_prng", 48 | "@com_github_google_googletest//:gtest_main", 49 | "@com_google_absl//absl/numeric:int128", 50 | "@com_google_absl//absl/status", 51 | ], 52 | ) 53 | 54 | # Sampling a uniform ternary vector. 55 | cc_library( 56 | name = "uniform_ternary", 57 | hdrs = ["uniform_ternary.h"], 58 | deps = [ 59 | "//shell_encryption:integral_types", 60 | "//shell_encryption:statusor_fork", 61 | "//shell_encryption/prng", 62 | "@com_google_absl//absl/status", 63 | "@com_google_absl//absl/status:statusor", 64 | ], 65 | ) 66 | 67 | cc_test( 68 | name = "uniform_ternary_test", 69 | srcs = ["uniform_ternary_test.cc"], 70 | deps = [ 71 | ":uniform_ternary", 72 | "//shell_encryption:context", 73 | "//shell_encryption:integral_types", 74 | "//shell_encryption:montgomery", 75 | "//shell_encryption/testing:parameters", 76 | "//shell_encryption/testing:status_is_fork", 77 | "//shell_encryption/testing:status_testing", 78 | "//shell_encryption/testing:testing_prng", 79 | "@com_github_google_googletest//:gtest_main", 80 | "@com_google_absl//absl/status", 81 | ], 82 | ) 83 | -------------------------------------------------------------------------------- /shell_encryption/sampler/uniform_ternary.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef RLWE_SAMPLER_UNIFORM_TERNARY_H_ 17 | #define RLWE_SAMPLER_UNIFORM_TERNARY_H_ 18 | 19 | #include 20 | #include 21 | 22 | #include "absl/status/status.h" 23 | #include "absl/status/statusor.h" 24 | #include "shell_encryption/integral_types.h" 25 | #include "shell_encryption/prng/prng.h" 26 | #include "shell_encryption/status_macros.h" 27 | 28 | namespace rlwe { 29 | 30 | // Samples a vector of `num_coeffs` coefficients from the uniform ternary 31 | // distribution on {-1, 0, 1}, where coefficients are reduced modulo q as given 32 | // in `mod_params`. 33 | template 34 | static absl::StatusOr> SampleFromUniformTernary( 35 | int num_coeffs, const typename ModularInt::Params* mod_params, 36 | SecurePrng* prng) { 37 | using Integer = typename ModularInt::Int; 38 | if (num_coeffs <= 0) { 39 | return absl::InvalidArgumentError("`num_coeffs` must be positive."); 40 | } 41 | if (mod_params == nullptr) { 42 | return absl::InvalidArgumentError("`mod_params` must not be null."); 43 | } 44 | if (prng == nullptr) { 45 | return absl::InvalidArgumentError("`prng` must not be null."); 46 | } 47 | 48 | // Below implements a parallel rejection sampling algorithm as suggested in 49 | // "A constant-time sampler for close-to-uniform bitsliced ternary vectors" 50 | // by Pierre Karpman, https://hal.archives-ouvertes.fr/hal-03777885 51 | // An element from {-1, 0, 1} is represented using two bits: 0 as (0,0), 1 as 52 | // (1,0), and -1 as (1,1). The algorithm samples in batches two uniformly 53 | // random 8-bit integers, r0 and r1, and uses a mask to indicate if a certain 54 | // bit in r0 and r1 is the invalid representation (0,1) and needs re-sample. 55 | Integer plus{1}; 56 | Integer minus = mod_params->modulus - 1; 57 | std::vector coeffs; 58 | coeffs.reserve(num_coeffs); 59 | while (num_coeffs > 0) { 60 | int num_filled_coeffs = std::min(num_coeffs, 8); 61 | // The mask to indicate if a bit index requires re-sampling. 62 | Uint8 missing_bits = 63 | num_filled_coeffs < 8 ? (1 << num_filled_coeffs) - 1 : ~0; 64 | Uint8 encoding_bits0 = 0; 65 | Uint8 encoding_bits1 = 0; 66 | while (missing_bits != 0) { 67 | RLWE_ASSIGN_OR_RETURN(Uint8 rand_bits0, prng->Rand8()); 68 | RLWE_ASSIGN_OR_RETURN(Uint8 rand_bits1, prng->Rand8()); 69 | encoding_bits0 ^= (rand_bits0 & missing_bits); 70 | encoding_bits1 ^= (rand_bits1 & missing_bits); 71 | missing_bits = ~encoding_bits0 & encoding_bits1; 72 | } 73 | 74 | for (int i = 0; i < num_filled_coeffs; ++i) { 75 | Uint8 mask = 1 << i; 76 | bool bit0 = ((encoding_bits0 & mask) > 0); 77 | bool bit1 = ((encoding_bits1 & mask) > 0); 78 | Integer is_plus = -static_cast(bit0 && !bit1); 79 | Integer is_minus = -static_cast(bit0 && bit1); 80 | Integer value = (is_plus & plus) | (is_minus & minus); 81 | RLWE_ASSIGN_OR_RETURN(auto coeff, 82 | ModularInt::ImportInt(value, mod_params)); 83 | coeffs.push_back(std::move(coeff)); 84 | } 85 | num_coeffs -= num_filled_coeffs; 86 | } 87 | return coeffs; 88 | } 89 | 90 | } // namespace rlwe 91 | 92 | #endif // RLWE_SAMPLER_UNIFORM_TERNARY_H_ 93 | -------------------------------------------------------------------------------- /shell_encryption/sampler/uniform_ternary_test.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #include "shell_encryption/sampler/uniform_ternary.h" 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include "absl/status/status.h" 24 | #include "shell_encryption/context.h" 25 | #include "shell_encryption/integral_types.h" 26 | #include "shell_encryption/montgomery.h" 27 | #include "shell_encryption/testing/parameters.h" 28 | #include "shell_encryption/testing/status_matchers.h" 29 | #include "shell_encryption/testing/status_testing.h" 30 | #include "shell_encryption/testing/testing_prng.h" 31 | 32 | namespace rlwe { 33 | namespace { 34 | 35 | using ::testing::HasSubstr; 36 | using testing::StatusIs; 37 | 38 | constexpr int kTestingRounds = 10; 39 | 40 | TEST(SampleFromUniformTernary, FailsIfNumCoeffsIsNotPositive) { 41 | using ModularInt = MontgomeryInt; 42 | constexpr Uint32 k_modulus = 17; 43 | ASSERT_OK_AND_ASSIGN(auto mod_params, ModularInt::Params::Create(k_modulus)); 44 | auto prng = testing::TestingPrng(0); 45 | EXPECT_THAT(SampleFromUniformTernary(/*num_coeffs=*/-1, 46 | mod_params.get(), &prng), 47 | StatusIs(absl::StatusCode::kInvalidArgument, 48 | HasSubstr("`num_coeffs` must be positive"))); 49 | EXPECT_THAT(SampleFromUniformTernary(/*num_coeffs=*/0, 50 | mod_params.get(), &prng), 51 | StatusIs(absl::StatusCode::kInvalidArgument, 52 | HasSubstr("`num_coeffs` must be positive"))); 53 | } 54 | 55 | TEST(SampleFromUniformTernary, FailsIfNullModParams) { 56 | using ModularInt = MontgomeryInt; 57 | constexpr int k_num_coeffs = 32; 58 | auto prng = testing::TestingPrng(0); 59 | EXPECT_THAT(SampleFromUniformTernary( 60 | k_num_coeffs, /*mod_params=*/nullptr, &prng), 61 | StatusIs(absl::StatusCode::kInvalidArgument, 62 | HasSubstr("`mod_params` must not be null"))); 63 | } 64 | 65 | TEST(SampleFromUniformTernary, FailsIfNullPrng) { 66 | using ModularInt = MontgomeryInt; 67 | constexpr Uint32 k_modulus = 17; 68 | constexpr int k_num_coeffs = 32; 69 | ASSERT_OK_AND_ASSIGN(auto mod_params, ModularInt::Params::Create(k_modulus)); 70 | EXPECT_THAT(SampleFromUniformTernary( 71 | k_num_coeffs, mod_params.get(), /*prng=*/nullptr), 72 | StatusIs(absl::StatusCode::kInvalidArgument, 73 | HasSubstr("`prng` must not be null"))); 74 | } 75 | 76 | template 77 | class SampleFromUniformTernaryTest : public ::testing::Test {}; 78 | TYPED_TEST_SUITE(SampleFromUniformTernaryTest, testing::ModularIntTypes); 79 | 80 | TYPED_TEST(SampleFromUniformTernaryTest, CheckUpperBoundOnTernaryDistribution) { 81 | using Integer = typename TypeParam::Int; 82 | 83 | auto prng = std::make_unique(0); 84 | 85 | for (const auto& params : 86 | rlwe::testing::ContextParameters::Value()) { 87 | ASSERT_OK_AND_ASSIGN(auto context, 88 | rlwe::RlweContext::Create(params)); 89 | Integer modulus = context->GetModulus(); 90 | for (int i = 0; i < kTestingRounds; i++) { 91 | ASSERT_OK_AND_ASSIGN( 92 | std::vector coeffs, 93 | rlwe::SampleFromUniformTernary( 94 | context->GetN(), context->GetModulusParams(), prng.get())); 95 | 96 | // Check that each coefficient is in [-1, 1] 97 | for (int j = 0; j < context->GetN(); j++) { 98 | Integer reduced = coeffs[j].ExportInt(context->GetModulusParams()); 99 | if (reduced > (modulus >> 1)) { 100 | EXPECT_EQ(modulus - reduced, 1); 101 | } else { 102 | EXPECT_LE(reduced, 1); 103 | } 104 | } 105 | } 106 | } 107 | } 108 | 109 | } // namespace 110 | } // namespace rlwe 111 | -------------------------------------------------------------------------------- /shell_encryption/serialization.proto: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | syntax = "proto2"; 17 | 18 | package rlwe; 19 | 20 | option go_package = "github.com/google/shell-encryption"; 21 | option optimize_for = LITE_RUNTIME; 22 | 23 | // NTT Polynomial 24 | message SerializedNttPolynomial { 25 | 26 | // Coefficients of the polynomial 27 | optional bytes coeffs = 1; 28 | 29 | // Number of coefficients of the polynomial. 30 | optional int32 num_coeffs = 2; 31 | } 32 | 33 | // RLWE Ciphertext 34 | message SerializedSymmetricRlweCiphertext { 35 | // Polynomials composing the ciphertext 36 | repeated SerializedNttPolynomial c = 1; 37 | 38 | // The power of the secret key that the ciphertext is encrypted with. 39 | optional int32 power_of_s = 2; 40 | 41 | // A heuristic on the amount of error in the ciphertext. 42 | optional double error = 3; 43 | } 44 | 45 | // Type of PRNG used to generate randomness. 46 | enum PrngType { 47 | PRNG_TYPE_INVALID = 0; 48 | PRNG_TYPE_HKDF = 1; 49 | PRNG_TYPE_CHACHA = 2; 50 | } 51 | 52 | // RLWE RelinearizationKey 53 | message SerializedRelinearizationKey { 54 | // Polynomial composing the matrix 55 | repeated SerializedNttPolynomial c = 1; 56 | 57 | // The modulus used to decompose the coefficients of the polynomials. Ranges 58 | // from 1 to the number of bits of the modulus. 59 | optional int32 log_decomposition_modulus = 2; 60 | 61 | // For n parts, the key can relinearize an n-component ciphertext to a 62 | // 2-component ciphertext. 63 | optional int32 num_parts = 3; 64 | 65 | // Seed used to compress this key. 66 | optional bytes prng_seed = 4; // Required 67 | 68 | // Type of PRNG used to generate randomness. 69 | optional PrngType prng_type = 6; // Required 70 | 71 | // The power of s that corresponds to the key. The field is 1 if the key is 72 | // RelinearizationKey. 73 | optional int32 power_of_s = 5; 74 | } 75 | 76 | // RLWE GaloisKeys. 77 | message SerializedGaloisKey { 78 | // The key-switching matrix 79 | optional SerializedRelinearizationKey key = 1; 80 | } 81 | 82 | // RLWE Public Key 83 | message SerializedPublicRlweKey { 84 | // Seed used to generate the random polynomial "a" in the public key 85 | optional bytes prng_seed = 1; 86 | // Type of PRNG used to generate the random polynomial "a" 87 | optional PrngType prng_type = 2; 88 | // The polynomial "b" of the public key 89 | optional SerializedNttPolynomial b = 3; 90 | } 91 | 92 | // RLWE AuxModRelinearizationKey 93 | message SerializedAuxModRelinearizationKey { 94 | // Polynomials (both mod-q and mod-p) composing the "b" part of the key matrix 95 | repeated SerializedNttPolynomial b = 1; 96 | 97 | // For n parts, the key can relinearize an (n+1)-component ciphertext (if 98 | // `power_of_s` == 1) or an n-component ciphertext to a 2-component ciphertext 99 | optional int32 num_components = 2; 100 | 101 | // Seed used to generate the random components in the key. 102 | optional bytes prng_seed = 3; // Required 103 | 104 | // Type of PRNG used to generate randomness. 105 | optional PrngType prng_type = 4; // Required 106 | 107 | // The power of s that corresponds to the key. The field is 1 if the key is 108 | // AuxModRelinearizationKey. 109 | optional int32 power_of_s = 5; 110 | } 111 | 112 | // RLWE AuxModRelinearizationKey 113 | message SerializedAuxModGaloisKey { 114 | // The underlying key-switching key 115 | optional SerializedAuxModRelinearizationKey key = 1; 116 | } 117 | -------------------------------------------------------------------------------- /shell_encryption/status_macros.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef RLWE_STATUS_MACROS_H_ 18 | #define RLWE_STATUS_MACROS_H_ 19 | 20 | #include "absl/status/status.h" 21 | #include "shell_encryption/statusor.h" 22 | 23 | // Helper macro that checks if the right hand side (rexpression) evaluates to a 24 | // StatusOr with Status OK, and if so assigns the value to the value on the left 25 | // hand side (lhs), otherwise returns the error status. Example: 26 | // RLWE_RLWE_ASSIGN_OR_RETURN(lhs, rexpression); 27 | #define RLWE_ASSIGN_OR_RETURN(lhs, rexpr) \ 28 | RLWE_ASSIGN_OR_RETURN_IMPL_( \ 29 | RLWE_STATUS_MACROS_IMPL_CONCAT_(_status_or_value, __LINE__), lhs, rexpr) 30 | 31 | // Internal helper. 32 | #define RLWE_ASSIGN_OR_RETURN_IMPL_(statusor, lhs, rexpr) \ 33 | auto statusor = (rexpr); \ 34 | if (ABSL_PREDICT_FALSE(!statusor.ok())) { \ 35 | return std::move(statusor).status(); \ 36 | } \ 37 | lhs = std::move(statusor).value() 38 | 39 | // Internal helper for concatenating macro values. 40 | #define RLWE_STATUS_MACROS_IMPL_CONCAT_INNER_(x, y) x##y 41 | #define RLWE_STATUS_MACROS_IMPL_CONCAT_(x, y) \ 42 | RLWE_STATUS_MACROS_IMPL_CONCAT_INNER_(x, y) 43 | 44 | #define RLWE_RETURN_IF_ERROR(expr) \ 45 | RLWE_RETURN_IF_ERROR_IMPL_( \ 46 | RLWE_STATUS_MACROS_IMPL_CONCAT_(_status, __LINE__), expr) 47 | 48 | #define RLWE_RETURN_IF_ERROR_IMPL_(status, expr) \ 49 | auto status = (expr); \ 50 | if (ABSL_PREDICT_FALSE(!status.ok())) { \ 51 | return status; \ 52 | } 53 | 54 | #endif // RLWE_STATUS_MACROS_H_ 55 | -------------------------------------------------------------------------------- /shell_encryption/status_macros_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "shell_encryption/status_macros.h" 16 | 17 | #include 18 | 19 | #include 20 | #include 21 | #include "absl/status/status.h" 22 | #include "shell_encryption/statusor.h" 23 | 24 | namespace rlwe { 25 | namespace { 26 | 27 | TEST(StatusMacrosTest, TestAssignOrReturn) { 28 | StatusOr> a(StatusOr(2)); 29 | auto f = [&]() -> absl::Status { 30 | RLWE_ASSIGN_OR_RETURN(StatusOr status_or_a, a.value()); 31 | EXPECT_EQ(2, status_or_a.value()); 32 | return absl::OkStatus(); 33 | }; 34 | auto status = f(); 35 | EXPECT_TRUE(status.ok()) << status; 36 | } 37 | 38 | TEST(StatusMacrosTest, TestAssignOrReturnFails) { 39 | auto a = []() -> StatusOr { return absl::InternalError("error"); }; 40 | auto f = [&]() -> absl::Status { 41 | RLWE_ASSIGN_OR_RETURN(auto result, a()); 42 | result++; 43 | return absl::OkStatus(); 44 | }; 45 | auto status = f(); 46 | EXPECT_EQ(absl::StatusCode::kInternal, status.code()); 47 | EXPECT_EQ("error", status.message()); 48 | } 49 | 50 | } // namespace 51 | } // namespace rlwe 52 | -------------------------------------------------------------------------------- /shell_encryption/statusor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef RLWE_STATUSOR_H_ 18 | #define RLWE_STATUSOR_H_ 19 | 20 | #include 21 | 22 | #include "absl/base/attributes.h" 23 | #include "absl/status/status.h" 24 | #include "absl/status/statusor.h" 25 | #include "absl/types/optional.h" 26 | 27 | namespace rlwe { 28 | 29 | template 30 | using StatusOr = absl::StatusOr; 31 | 32 | } // namespace rlwe 33 | 34 | #endif // RLWE_STATUSOR_H_ 35 | -------------------------------------------------------------------------------- /shell_encryption/testing/coefficient_polynomial.proto: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google Inc. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | syntax = "proto2"; 17 | 18 | package rlwe; 19 | 20 | option optimize_for = LITE_RUNTIME; 21 | 22 | // Polynomial in coefficient representation 23 | message SerializedCoefficientPolynomial { 24 | // Coefficients of the polynomial 25 | optional bytes coeffs = 1; 26 | 27 | // Number of coefficients of the polynomial. 28 | optional int32 num_coeffs = 2; 29 | } 30 | -------------------------------------------------------------------------------- /shell_encryption/testing/protobuf_matchers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef RLWE_TESTING_PROTOBUF_MATCHERS_H_ 18 | #define RLWE_TESTING_PROTOBUF_MATCHERS_H_ 19 | 20 | #include "google/protobuf/message.h" 21 | #include "google/protobuf/message_lite.h" 22 | #include "google/protobuf/util/message_differencer.h" 23 | #include 24 | 25 | namespace rlwe { 26 | namespace testing { 27 | 28 | class EqualsProtoImpl 29 | : public ::testing::MatcherInterface { 30 | public: 31 | explicit EqualsProtoImpl(const google::protobuf::Message& other) : other_(&other) {} 32 | 33 | bool MatchAndExplain( 34 | const google::protobuf::Message& message, 35 | ::testing::MatchResultListener* listener) const override { 36 | if (!google::protobuf::util::MessageDifferencer::Equals(message, *other_)) { 37 | *listener << "protobufs were not equal"; 38 | return false; 39 | } 40 | return true; 41 | } 42 | 43 | void DescribeTo(std::ostream* os) const override { 44 | *os << "is equal to another protocol buffer"; 45 | } 46 | 47 | void DescribeNegationTo(std::ostream* os) const override { 48 | *os << "is not equal to another protocol buffer"; 49 | } 50 | 51 | private: 52 | const google::protobuf::Message* other_; // not owned 53 | }; 54 | 55 | class EqualsProtoLiteImpl 56 | : public ::testing::MatcherInterface { 57 | public: 58 | explicit EqualsProtoLiteImpl(const google::protobuf::MessageLite& other) 59 | : other_(&other) {} 60 | 61 | bool MatchAndExplain( 62 | const google::protobuf::MessageLite& message, 63 | ::testing::MatchResultListener* listener) const override { 64 | if (message.SerializeAsString() != other_->SerializeAsString()) { 65 | *listener << "protobufs were not equal"; 66 | return false; 67 | } 68 | return true; 69 | } 70 | 71 | void DescribeTo(std::ostream* os) const override { 72 | *os << "is equal to another protocol buffer"; 73 | } 74 | 75 | void DescribeNegationTo(std::ostream* os) const override { 76 | *os << "is not equal to another protocol buffer"; 77 | } 78 | 79 | private: 80 | const google::protobuf::MessageLite* other_; // not owned 81 | }; 82 | 83 | inline ::testing::Matcher EqualsProto( 84 | const google::protobuf::Message& other) { 85 | return ::testing::Matcher(new EqualsProtoImpl(other)); 86 | } 87 | 88 | inline ::testing::Matcher EqualsProto( 89 | const google::protobuf::MessageLite& other) { 90 | return ::testing::Matcher( 91 | new EqualsProtoLiteImpl(other)); 92 | } 93 | 94 | } // namespace testing 95 | } // namespace rlwe 96 | 97 | #endif // RLWE_TESTING_PROTOBUF_MATCHERS_H_ 98 | -------------------------------------------------------------------------------- /shell_encryption/testing/protobuf_matchers_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "shell_encryption/testing/protobuf_matchers.h" 16 | 17 | #include 18 | #include 19 | #include "shell_encryption/testing/coefficient_polynomial.pb.h" 20 | #include "shell_encryption/testing/status_testing.h" 21 | 22 | namespace { 23 | 24 | TEST(EqualsProtoTest, EqualsProtoWorks) { 25 | rlwe::SerializedCoefficientPolynomial coeffs; 26 | coeffs.set_num_coeffs(10); 27 | EXPECT_THAT(coeffs, rlwe::testing::EqualsProto(coeffs)); 28 | 29 | rlwe::SerializedCoefficientPolynomial coeffs_other; 30 | coeffs_other.set_num_coeffs(20); 31 | EXPECT_THAT(coeffs, ::testing::Not(rlwe::testing::EqualsProto(coeffs_other))); 32 | } 33 | 34 | } // namespace 35 | -------------------------------------------------------------------------------- /shell_encryption/testing/status_matchers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef RLWE_TESTING_STATUS_MATCHERS_H_ 18 | #define RLWE_TESTING_STATUS_MATCHERS_H_ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include "absl/status/status.h" 27 | #include "shell_encryption/statusor.h" 28 | 29 | namespace rlwe { 30 | namespace testing { 31 | 32 | namespace internal { 33 | 34 | // This function and its overload allow the same matcher to be used for Status 35 | // and StatusOr tests. 36 | inline absl::Status GetStatus(const absl::Status& status) { return status; } 37 | 38 | template 39 | inline absl::Status GetStatus(const rlwe::StatusOr& statusor) { 40 | return statusor.status(); 41 | } 42 | 43 | template 44 | class StatusIsImpl : public ::testing::MatcherInterface { 45 | public: 46 | StatusIsImpl(const ::testing::Matcher& code, 47 | const ::testing::Matcher& message) 48 | : code_(code), message_(message) {} 49 | 50 | bool MatchAndExplain( 51 | StatusType status, 52 | ::testing::MatchResultListener* listener) const override { 53 | ::testing::StringMatchResultListener str_listener; 54 | absl::Status real_status = GetStatus(status); 55 | if (!code_.MatchAndExplain(real_status.code(), &str_listener)) { 56 | *listener << str_listener.str(); 57 | return false; 58 | } 59 | if (!message_.MatchAndExplain( 60 | static_cast(real_status.message()), &str_listener)) { 61 | *listener << str_listener.str(); 62 | return false; 63 | } 64 | return true; 65 | } 66 | 67 | void DescribeTo(std::ostream* os) const override { 68 | *os << "has a status code that "; 69 | code_.DescribeTo(os); 70 | *os << " and a message that "; 71 | message_.DescribeTo(os); 72 | } 73 | 74 | void DescribeNegationTo(std::ostream* os) const override { 75 | *os << "has a status code that "; 76 | code_.DescribeNegationTo(os); 77 | *os << " and a message that "; 78 | message_.DescribeNegationTo(os); 79 | } 80 | 81 | private: 82 | ::testing::Matcher code_; 83 | ::testing::Matcher message_; 84 | }; 85 | 86 | class StatusIsPoly { 87 | public: 88 | StatusIsPoly(::testing::Matcher&& code, 89 | ::testing::Matcher&& message) 90 | : code_(code), message_(message) {} 91 | 92 | // Converts this polymorphic matcher to a monomorphic matcher. 93 | template 94 | operator ::testing::Matcher() const { 95 | return ::testing::Matcher( 96 | new StatusIsImpl(code_, message_)); 97 | } 98 | 99 | private: 100 | ::testing::Matcher code_; 101 | ::testing::Matcher message_; 102 | }; 103 | 104 | } // namespace internal 105 | 106 | // This function allows us to avoid a template parameter when writing tests, so 107 | // that we can transparently test both Status and StatusOr returns. 108 | inline internal::StatusIsPoly StatusIs( 109 | ::testing::Matcher&& code, 110 | ::testing::Matcher&& message) { 111 | return internal::StatusIsPoly( 112 | std::forward<::testing::Matcher>(code), 113 | std::forward<::testing::Matcher>(message)); 114 | } 115 | 116 | inline internal::StatusIsPoly StatusIs( 117 | ::testing::Matcher&& code) { 118 | return internal::StatusIsPoly( 119 | std::forward<::testing::Matcher>(code), ::testing::_); 120 | } 121 | 122 | } // namespace testing 123 | } // namespace rlwe 124 | 125 | #endif // RLWE_TESTING_STATUS_MATCHERS_H_ 126 | -------------------------------------------------------------------------------- /shell_encryption/testing/status_testing.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef RLWE_TESTING_STATUS_TESTING_H_ 18 | #define RLWE_TESTING_STATUS_TESTING_H_ 19 | 20 | #include "shell_encryption/status_macros.h" 21 | 22 | #undef ASSERT_OK 23 | #define ASSERT_OK(expr) \ 24 | RLWE_ASSERT_OK_IMPL_(RLWE_STATUS_MACROS_IMPL_CONCAT_(_status, __LINE__), expr) 25 | 26 | #define RLWE_ASSERT_OK_IMPL_(status, expr) \ 27 | auto status = (expr); \ 28 | ASSERT_THAT(status.ok(), ::testing::Eq(true)); 29 | 30 | #undef EXPECT_OK 31 | #define EXPECT_OK(expr) \ 32 | RLWE_EXPECT_OK_IMPL_(RLWE_STATUS_MACROS_IMPL_CONCAT_(_status, __LINE__), expr) 33 | 34 | #define RLWE_EXPECT_OK_IMPL_(status, expr) \ 35 | auto status = (expr); \ 36 | EXPECT_THAT(status.ok(), ::testing::Eq(true)); 37 | 38 | #undef ASSERT_OK_AND_ASSIGN 39 | #define ASSERT_OK_AND_ASSIGN(lhs, rexpr) \ 40 | RLWE_ASSERT_OK_AND_ASSIGN_IMPL_( \ 41 | RLWE_STATUS_MACROS_IMPL_CONCAT_(_status_or_value, __LINE__), lhs, rexpr) 42 | 43 | #define RLWE_ASSERT_OK_AND_ASSIGN_IMPL_(statusor, lhs, rexpr) \ 44 | auto statusor = (rexpr); \ 45 | ASSERT_THAT(statusor.ok(), ::testing::Eq(true)); \ 46 | lhs = std::move(statusor).value() 47 | 48 | #endif // RLWE_TESTING_STATUS_TESTING_H_ 49 | -------------------------------------------------------------------------------- /shell_encryption/testing/testing_prng.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google LLC. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * https://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | #ifndef RLWE_TESTING_TESTING_PRNG_H_ 17 | #define RLWE_TESTING_TESTING_PRNG_H_ 18 | 19 | #include 20 | 21 | #include "shell_encryption/integral_types.h" 22 | #include "shell_encryption/prng/prng.h" 23 | 24 | namespace rlwe { 25 | namespace testing { 26 | 27 | // An insecure pseudo-random number generator for testing. 28 | class TestingPrng : public rlwe::SecurePrng { 29 | public: 30 | explicit TestingPrng(int seed) : generator_(seed) {} 31 | 32 | rlwe::StatusOr Rand8() override { return distr_(generator_); } 33 | 34 | rlwe::StatusOr Rand64() override { return distr_(generator_); } 35 | 36 | private: 37 | std::mt19937_64 generator_; 38 | std::uniform_int_distribution distr_; 39 | }; 40 | 41 | } // namespace testing 42 | } // namespace rlwe 43 | 44 | #endif // RLWE_TESTING_TESTING_PRNG_H_ 45 | -------------------------------------------------------------------------------- /shell_encryption/testing/testing_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // This file contains constants and utilities for testing RLWE operations. 18 | 19 | #ifndef RLWE_TESTING_TESTING_UTILS_H_ 20 | #define RLWE_TESTING_TESTING_UTILS_H_ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "shell_encryption/constants.h" 27 | #include "shell_encryption/montgomery.h" 28 | #include "shell_encryption/polynomial.h" 29 | #include "shell_encryption/prng/single_thread_chacha_prng.h" 30 | #include "shell_encryption/prng/single_thread_hkdf_prng.h" 31 | #include "shell_encryption/status_macros.h" 32 | #include "shell_encryption/symmetric_encryption.h" 33 | #include "shell_encryption/testing/testing_prng.h" 34 | 35 | namespace rlwe { 36 | namespace testing { 37 | 38 | // Set constants. 39 | const Uint64 kDefaultLogT = 2; 40 | const Uint64 kDefaultT = (1 << kDefaultLogT) + 1; 41 | const Uint64 kDefaultVariance = 8; 42 | const Uint64 kCoeffs = kDegreeBound25; 43 | const Uint64 kLogCoeffs = kLogDegreeBound25; 44 | const Uint32 kModulus = kModulus25; 45 | 46 | // Construct montgomery int parameters used for testing rlwe encryption and 47 | // decryption functionality. 48 | inline rlwe::StatusOr>> 49 | ConstructMontgomeryIntParams() { 50 | return MontgomeryIntParams::Create(kModulus); 51 | } 52 | 53 | // Sample a random plaintext. 54 | template 55 | std::vector SamplePlaintext( 56 | Uint64 num_coeffs = kCoeffs, typename ModularInt::Int t = kDefaultT) { 57 | // Seed for the random number generator that is used to create test 58 | // plaintexts. 59 | unsigned int seed = 1; 60 | std::mt19937 mt_rand(seed); 61 | std::vector plaintext(num_coeffs); 62 | for (unsigned int i = 0; i < num_coeffs; i++) { 63 | Uint64 rand = mt_rand(); 64 | typename ModularInt::Int int_rand = 65 | static_cast(rand); 66 | plaintext[i] = int_rand % t; 67 | } 68 | return plaintext; 69 | } 70 | 71 | // Convert a vector of integers to a vector of montgomery integers. 72 | template 73 | rlwe::StatusOr> ConvertToMontgomery( 74 | const std::vector& coeffs, 75 | const rlwe::MontgomeryIntParams* params14) { 76 | auto val = ModularInt::ImportZero(params14); 77 | std::vector output(coeffs.size(), val); 78 | for (unsigned int i = 0; i < output.size(); i++) { 79 | RLWE_ASSIGN_OR_RETURN(output[i], 80 | ModularInt::ImportInt(coeffs[i], params14)); 81 | } 82 | return output; 83 | } 84 | 85 | template 86 | rlwe::StatusOr> GenerateRandomPlaintextPolynomial( 87 | int num_coeffs, Uint64 log_t, const typename ModularInt::Params* params, 88 | const NttParameters* ntt_params) { 89 | if (ntt_params->number_coeffs != num_coeffs) { 90 | return absl::InvalidArgumentError( 91 | "The number of coefficients does not match that of the ntt " 92 | "parameters."); 93 | } 94 | typename ModularInt::Int plaintext_modulus = 95 | (params->One() << log_t) + params->One(); 96 | std::vector plaintext = 97 | SamplePlaintext(num_coeffs, plaintext_modulus); 98 | RLWE_ASSIGN_OR_RETURN(std::vector rands, 99 | ConvertToMontgomery(plaintext, params)); 100 | return Polynomial::ConvertToNtt(rands, ntt_params, params); 101 | } 102 | 103 | inline rlwe::StatusOr GenerateSeed(PrngType prng_type) { 104 | if (prng_type == rlwe::PRNG_TYPE_CHACHA) { 105 | return rlwe::SingleThreadChaChaPrng::GenerateSeed(); 106 | } else if (prng_type == rlwe::PRNG_TYPE_HKDF) { 107 | return rlwe::SingleThreadHkdfPrng::GenerateSeed(); 108 | } else { 109 | return absl::InvalidArgumentError("Invalid specified PRNG type in params."); 110 | } 111 | } 112 | 113 | inline rlwe::StatusOr> CreatePrng( 114 | absl::string_view seed, PrngType prng_type) { 115 | if (prng_type == rlwe::PRNG_TYPE_CHACHA) { 116 | RLWE_ASSIGN_OR_RETURN(auto chacha_prng, 117 | rlwe::SingleThreadChaChaPrng::Create(seed)); 118 | return std::unique_ptr(std::move(chacha_prng)); 119 | } else if (prng_type == rlwe::PRNG_TYPE_HKDF) { 120 | RLWE_ASSIGN_OR_RETURN(auto hkdf_prng, 121 | rlwe::SingleThreadHkdfPrng::Create(seed)); 122 | return std::unique_ptr(std::move(hkdf_prng)); 123 | } else { 124 | return absl::InvalidArgumentError("Invalid specified PRNG type in params."); 125 | } 126 | } 127 | 128 | } // namespace testing 129 | } // namespace rlwe 130 | 131 | #endif // RLWE_TESTING_TESTING_UTILS_H_ 132 | --------------------------------------------------------------------------------