Skip to content

Commit 3b1bdfa

Browse files
authored
Merge pull request #19 from b5li/rns
highway-based lazy FMA for RNS polynomial
2 parents 300731a + 09e369a commit 3b1bdfa

File tree

10 files changed

+1067
-10
lines changed

10 files changed

+1067
-10
lines changed

WORKSPACE

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,14 @@ http_archive(
8787
sha256 = "34af2f15cf7367513b352bdcd2493ab14ce43692d2dcd9dfc499492966c64dcf",
8888
strip_prefix = "gflags-2.2.2",
8989
)
90+
91+
# Highway for SIMD operations.
92+
# https://github.com/google/highway
93+
http_archive(
94+
name = "com_github_google_highway",
95+
sha256 = "e9a9e1d2c7a607d4bce48b75f83eb25a8e802e6fe065bcd5dd770b79034ac6b9",
96+
strip_prefix = "highway-3af6ba57bf82c861870f92f0483149439007d652",
97+
urls = [
98+
"https://github.com/google/highway/archive/3af6ba57bf82c861870f92f0483149439007d652.zip",
99+
],
100+
)

shell_encryption/rns/BUILD

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@ cc_library(
314314
srcs = ["rns_ciphertext.cc"],
315315
hdrs = ["rns_ciphertext.h"],
316316
deps = [
317+
":lazy_rns_polynomial",
317318
":rns_error_params",
318319
":rns_polynomial",
319320
":serialization_cc_proto",
@@ -724,6 +725,7 @@ cc_library(
724725
hdrs = ["rns_galois_key.h"],
725726
deps = [
726727
":error_distribution",
728+
":lazy_rns_polynomial",
727729
":rns_bfv_ciphertext",
728730
":rns_bgv_ciphertext",
729731
":rns_ciphertext",
@@ -828,3 +830,66 @@ cc_test(
828830
"@com_google_absl//absl/strings",
829831
],
830832
)
833+
834+
# Highway-based polynomial multiplication.
835+
cc_library(
836+
name = "rns_polynomial_hwy",
837+
srcs = ["rns_polynomial_hwy.cc"],
838+
hdrs = ["rns_polynomial_hwy.h"],
839+
deps = [
840+
"//shell_encryption:integral_types",
841+
"//shell_encryption:montgomery",
842+
"@com_github_google_highway//:hwy",
843+
"@com_google_absl//absl/base:core_headers",
844+
"@com_google_absl//absl/numeric:int128",
845+
"@com_google_absl//absl/status",
846+
"@com_google_absl//absl/status:statusor",
847+
"@com_google_absl//absl/types:span",
848+
],
849+
)
850+
851+
# Lazy RNS polynomial.
852+
cc_library(
853+
name = "lazy_rns_polynomial",
854+
srcs = ["lazy_rns_polynomial.cc"],
855+
hdrs = ["lazy_rns_polynomial.h"],
856+
deps = [
857+
":rns_modulus",
858+
":rns_polynomial",
859+
":rns_polynomial_hwy",
860+
"//shell_encryption:integral_types",
861+
"//shell_encryption:montgomery",
862+
"//shell_encryption:statusor_fork",
863+
"@com_github_google_highway//:hwy",
864+
"@com_google_absl//absl/numeric:int128",
865+
"@com_google_absl//absl/status",
866+
"@com_google_absl//absl/status:statusor",
867+
"@com_google_absl//absl/strings",
868+
"@com_google_absl//absl/types:span",
869+
],
870+
)
871+
872+
cc_test(
873+
name = "lazy_rns_polynomial_test",
874+
srcs = ["lazy_rns_polynomial_test.cc"],
875+
deps = [
876+
":lazy_rns_polynomial",
877+
":rns_context",
878+
":rns_modulus",
879+
":rns_polynomial",
880+
"//shell_encryption:integral_types",
881+
"//shell_encryption:montgomery",
882+
"//shell_encryption:polynomial",
883+
"//shell_encryption:statusor_fork",
884+
"//shell_encryption/rns/testing:parameters",
885+
"//shell_encryption/rns/testing:testing_utils",
886+
"//shell_encryption/testing:matchers",
887+
"//shell_encryption/testing:parameters",
888+
"//shell_encryption/testing:status_testing",
889+
"//shell_encryption/testing:testing_prng",
890+
"@com_github_google_googletest//:gtest_main",
891+
"@com_google_absl//absl/log:check",
892+
"@com_google_absl//absl/status",
893+
"@com_google_absl//absl/strings",
894+
],
895+
)
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
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 <vector>
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<Uint32>;
32+
using ModularInt64 = MontgomeryInt<Uint64>;
33+
34+
template <typename ModularInt>
35+
absl::Status LazyRnsPolynomial<ModularInt>::CheckFusedMulAddInPlaceParameters(
36+
const RnsPolynomial<ModularInt>& a, const RnsPolynomial<ModularInt>& b,
37+
absl::Span<const PrimeModulus<ModularInt>* 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 <typename ModularInt>
58+
absl::Status LazyRnsPolynomial<ModularInt>::FusedMulAddInPlace(
59+
const RnsPolynomial<ModularInt>& a, const RnsPolynomial<ModularInt>& b,
60+
absl::Span<const PrimeModulus<ModularInt>* 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<BigInt>(
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<ModularInt32>::FusedMulAddInPlace(
84+
const RnsPolynomial<ModularInt32>& a, const RnsPolynomial<ModularInt32>& b,
85+
absl::Span<const PrimeModulus<ModularInt32>* 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<Uint32>(
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<ModularInt64>::FusedMulAddInPlace(
104+
const RnsPolynomial<ModularInt64>& a, const RnsPolynomial<ModularInt64>& b,
105+
absl::Span<const PrimeModulus<ModularInt64>* 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<Uint64>(
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<MontgomeryInt<Uint16>>;
122+
template class LazyRnsPolynomial<MontgomeryInt<Uint32>>;
123+
template class LazyRnsPolynomial<MontgomeryInt<Uint64>>;
124+
template class LazyRnsPolynomial<MontgomeryInt<absl::uint128>>;
125+
#ifdef ABSL_HAVE_INTRINSIC_INT128
126+
template class LazyRnsPolynomial<MontgomeryInt<unsigned __int128>>;
127+
#endif
128+
129+
} // namespace rlwe

0 commit comments

Comments
 (0)