1 // @file trapdoor-dcrtpoly-impl.cpp Provides the utility for sampling trapdoor
2 // lattices as described in https://eprint.iacr.org/2017/844.pdf
3 // https://eprint.iacr.org/2018/946, and "Implementing Token-Based Obfuscation
4 // under (Ring) LWE" as described in https://eprint.iacr.org/2018/1222.pdf.
5 // @author TPOC: contact@palisade-crypto.org
6 //
7 // @copyright Copyright (c) 2019, New Jersey Institute of Technology (NJIT)
8 // All rights reserved.
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are met:
11 // 1. Redistributions of source code must retain the above copyright notice,
12 // this list of conditions and the following disclaimer.
13 // 2. Redistributions in binary form must reproduce the above copyright notice,
14 // this list of conditions and the following disclaimer in the documentation
15 // and/or other materials provided with the distribution. THIS SOFTWARE IS
16 // PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
17 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 // EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
20 // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27 // Forward definition of implementation classes for DCRTPoly
28
29 #include "dgsampling.cpp"
30 #include "math/matrix.h"
31 #include "trapdoor.cpp"
32
33 namespace lbcrypto {
34
35 template class LatticeGaussSampUtility<DCRTPoly>;
36 template class RLWETrapdoorPair<DCRTPoly>;
37 template class RLWETrapdoorUtility<DCRTPoly>;
38 // template class Matrix<DCRTPoly>;
39
40 // Trapdoor generation method as described in Algorithm 1 of
41 // https://eprint.iacr.org/2017/844.pdf and
42 // "Implementing Token-Based Obfuscation under (Ring) LWE"
43 template <>
44 std::pair<Matrix<DCRTPoly>, RLWETrapdoorPair<DCRTPoly>>
TrapdoorGen(shared_ptr<ParmType> params,double stddev,int64_t base,bool bal)45 RLWETrapdoorUtility<DCRTPoly>::TrapdoorGen(shared_ptr<ParmType> params,
46 double stddev, int64_t base,
47 bool bal) {
48 auto zero_alloc = DCRTPoly::Allocator(params, EVALUATION);
49 auto gaussian_alloc = DCRTPoly::MakeDiscreteGaussianCoefficientAllocator(
50 params, COEFFICIENT, stddev);
51 auto uniform_alloc =
52 DCRTPoly::MakeDiscreteUniformAllocator(params, EVALUATION);
53
54 NativeInteger q = params->GetParams()[0]->GetModulus();
55
56 size_t digitCount = (long)ceil(log2(q.ConvertToDouble()) / log2(base));
57
58 size_t k = params->GetParams().size() * digitCount;
59
60 if (bal == true) {
61 k++; // for a balanced digit representation, there is an extra digit
62 // required
63 }
64
65 auto a = uniform_alloc();
66
67 Matrix<DCRTPoly> r(zero_alloc, 1, k, gaussian_alloc);
68 Matrix<DCRTPoly> e(zero_alloc, 1, k, gaussian_alloc);
69
70 // Converts discrete gaussians to Evaluation representation
71 r.SetFormat(Format::EVALUATION);
72 e.SetFormat(Format::EVALUATION);
73
74 Matrix<DCRTPoly> g = Matrix<DCRTPoly>(zero_alloc, 1, k).GadgetVector(base);
75
76 Matrix<DCRTPoly> A(zero_alloc, 1, k + 2);
77 A(0, 0) = 1;
78 A(0, 1) = a;
79
80 for (size_t i = 0; i < k; ++i) {
81 A(0, i + 2) = g(0, i) - (a * r(0, i) + e(0, i));
82 }
83
84 return std::pair<Matrix<DCRTPoly>, RLWETrapdoorPair<DCRTPoly>>(
85 A, RLWETrapdoorPair<DCRTPoly>(r, e));
86 }
87
88 template <>
89 std::pair<Matrix<DCRTPoly>, RLWETrapdoorPair<DCRTPoly>>
TrapdoorGenSquareMat(shared_ptr<ParmType> params,double stddev,size_t d,int64_t base,bool bal)90 RLWETrapdoorUtility<DCRTPoly>::TrapdoorGenSquareMat(shared_ptr<ParmType> params,
91 double stddev, size_t d,
92 int64_t base, bool bal) {
93 auto zero_alloc = DCRTPoly::Allocator(params, EVALUATION);
94 auto gaussian_alloc = DCRTPoly::MakeDiscreteGaussianCoefficientAllocator(
95 params, COEFFICIENT, stddev);
96 auto uniform_alloc =
97 DCRTPoly::MakeDiscreteUniformAllocator(params, EVALUATION);
98
99 NativeInteger q = params->GetParams()[0]->GetModulus();
100
101 size_t digitCount = (long)ceil(log2(q.ConvertToDouble()) / log2(base));
102
103 size_t k = params->GetParams().size() * digitCount;
104
105 if (bal == true) {
106 k++; // for a balanced digit representation, there is an extra digit
107 // required
108 }
109
110 Matrix<DCRTPoly> R(zero_alloc, d, d * k, gaussian_alloc);
111 Matrix<DCRTPoly> E(zero_alloc, d, d * k, gaussian_alloc);
112
113 Matrix<DCRTPoly> Abar(zero_alloc, d, d, uniform_alloc);
114
115 // Converts discrete gaussians to Evaluation representation
116 R.SetFormat(Format::EVALUATION);
117 E.SetFormat(Format::EVALUATION);
118
119 Matrix<DCRTPoly> G =
120 Matrix<DCRTPoly>(zero_alloc, d, d * k).GadgetVector(base);
121
122 Matrix<DCRTPoly> A(zero_alloc, d, d * 2);
123
124 for (size_t i = 0; i < d; i++) {
125 for (size_t j = 0; j < d; j++) {
126 A(i, j) = Abar(i, j);
127 if (i == j)
128 A(i, j + d) = 1;
129 else
130 A(i, j + d) = 0;
131 }
132 }
133
134 Matrix<DCRTPoly> A1 = G - (Abar * R + E);
135
136 A.HStack(A1);
137
138 return std::pair<Matrix<DCRTPoly>, RLWETrapdoorPair<DCRTPoly>>(
139 A, RLWETrapdoorPair<DCRTPoly>(R, E));
140 }
141
142 // Gaussian sampling as described in Alogorithm 2 of
143 // https://eprint.iacr.org/2017/844.pdf
144
145 template <>
GaussSamp(size_t n,size_t k,const Matrix<DCRTPoly> & A,const RLWETrapdoorPair<DCRTPoly> & T,const DCRTPoly & u,DggType & dgg,DggType & dggLargeSigma,int64_t base)146 Matrix<DCRTPoly> RLWETrapdoorUtility<DCRTPoly>::GaussSamp(
147 size_t n, size_t k, const Matrix<DCRTPoly>& A,
148 const RLWETrapdoorPair<DCRTPoly>& T, const DCRTPoly& u, DggType& dgg,
149 DggType& dggLargeSigma, int64_t base) {
150 DEBUG_FLAG(false);
151 TimeVar t1, t1_tot, t2, t2_tot;
152 TIC(t1);
153 TIC(t1_tot);
154 const shared_ptr<ParmType> params = u.GetParams();
155 auto zero_alloc = DCRTPoly::Allocator(params, EVALUATION);
156
157 double c = (base + 1) * SIGMA;
158
159 // spectral bound s
160 double s = SPECTRAL_BOUND(n, k, base);
161
162 DEBUG("c " << c << " s " << s);
163
164 // perturbation vector in evaluation representation
165 auto pHat = std::make_shared<Matrix<DCRTPoly>>(zero_alloc, k + 2, 1);
166 DEBUG("t1a: " << TOC(t1));
167 TIC(t1);
168 ZSampleSigmaP(n, s, c, T, dgg, dggLargeSigma, pHat);
169 DEBUG("t1b: " << TOC(t1)); // this takes the most time 61
170 TIC(t1);
171 // It is assumed that A has dimension 1 x (k + 2) and pHat has the dimension
172 // of (k + 2) x 1 perturbedSyndrome is in the evaluation representation
173 DCRTPoly perturbedSyndrome = u - (A.Mult(*pHat))(0, 0);
174
175 DEBUG("t1c: " << TOC(t1)); // takes 2
176 TIC(t1);
177 DEBUG("t1d: " << TOC(t1)); // takes 0
178 Matrix<int64_t> zHatBBI([]() { return 0; }, k, n);
179 DEBUG("t1: " << TOC(t1_tot)); // takes 64
180 TIC(t2);
181 TIC(t2_tot);
182 perturbedSyndrome.SetFormat(Format::COEFFICIENT);
183 DEBUG("t2a: " << TOC(t2)); // takes 1
184 TIC(t2);
185
186 size_t size = perturbedSyndrome.GetNumOfElements();
187
188 for (size_t u = 0; u < size; u++) {
189 uint32_t kRes = k / size;
190
191 NativeInteger qu = params->GetParams()[u]->GetModulus();
192
193 Matrix<int64_t> digits([]() { return 0; }, kRes, n);
194 LatticeGaussSampUtility<NativePoly>::GaussSampGqArbBase(
195 perturbedSyndrome.GetElementAtIndex(u), c, kRes, qu, base, dgg,
196 &digits);
197 for (size_t p = 0; p < kRes; p++) {
198 for (size_t j = 0; j < n; j++) {
199 zHatBBI(p + u * kRes, j) = digits(p, j);
200 }
201 }
202 }
203
204 DEBUG("t2b: " << TOC(t2)); // takes 36
205 TIC(t2);
206 // Convert zHat from a matrix of BBI to a vector of Element ring elements
207 // zHat is in the coefficient representation
208 Matrix<DCRTPoly> zHat =
209 SplitInt64AltIntoElements<DCRTPoly>(zHatBBI, n, params);
210
211 DEBUG("t2c: " << TOC(t2)); // takes 0
212 // Now converting it to the evaluation representation before multiplication
213 zHat.SetFormat(Format::EVALUATION);
214 DEBUG("t2d: " << TOC(t2)); // takes 17
215 DEBUG("t2: " << TOC(t2_tot));
216
217 Matrix<DCRTPoly> zHatPrime(zero_alloc, k + 2, 1);
218
219 zHatPrime(0, 0) = (*pHat)(0, 0) + T.m_e.Mult(zHat)(0, 0);
220 zHatPrime(1, 0) = (*pHat)(1, 0) + T.m_r.Mult(zHat)(0, 0);
221
222 for (size_t row = 2; row < k + 2; ++row)
223 zHatPrime(row, 0) = (*pHat)(row, 0) + zHat(row - 2, 0);
224
225 return zHatPrime;
226 }
227
228 // Gaussian sampling as described in "Implementing Token-Based Obfuscation under
229 // Ring (LWE)"
230
231 template <>
GaussSampSquareMat(size_t n,size_t k,const Matrix<DCRTPoly> & A,const RLWETrapdoorPair<DCRTPoly> & T,const Matrix<DCRTPoly> & U,DggType & dgg,DggType & dggLargeSigma,int64_t base)232 Matrix<DCRTPoly> RLWETrapdoorUtility<DCRTPoly>::GaussSampSquareMat(
233 size_t n, size_t k, const Matrix<DCRTPoly>& A,
234 const RLWETrapdoorPair<DCRTPoly>& T, const Matrix<DCRTPoly>& U,
235 DggType& dgg, DggType& dggLargeSigma, int64_t base) {
236 const shared_ptr<ParmType> params = U(0, 0).GetParams();
237 auto zero_alloc = DCRTPoly::Allocator(params, EVALUATION);
238
239 double c = (base + 1) * SIGMA;
240
241 size_t d = T.m_r.GetRows();
242
243 // spectral bound s
244 double s = SPECTRAL_BOUND_D(n, k, base, d);
245
246 // perturbation vector in evaluation representation
247 auto pHat = std::make_shared<Matrix<DCRTPoly>>(zero_alloc, d * (k + 2), d);
248
249 SamplePertSquareMat(n, s, c, T, dgg, dggLargeSigma, pHat);
250
251 // It is assumed that A has dimension d x d*(k + 2) and pHat has the dimension
252 // of d*(k + 2) x d perturbedSyndrome is in the evaluation representation
253 Matrix<DCRTPoly> perturbedSyndrome = U - (A.Mult(*pHat));
254
255 perturbedSyndrome.SetFormat(Format::COEFFICIENT);
256
257 size_t size = perturbedSyndrome(0, 0).GetNumOfElements();
258
259 Matrix<DCRTPoly> zHatMat(zero_alloc, d * k, d);
260
261 for (size_t i = 0; i < d; i++) {
262 for (size_t j = 0; j < d; j++) {
263 Matrix<int64_t> zHatBBI([]() { return 0; }, k, n);
264
265 for (size_t u = 0; u < size; u++) {
266 uint32_t kRes = k / size;
267
268 NativeInteger qu = params->GetParams()[u]->GetModulus();
269
270 Matrix<int64_t> digits([]() { return 0; }, kRes, n);
271
272 LatticeGaussSampUtility<NativePoly>::GaussSampGqArbBase(
273 perturbedSyndrome(i, j).GetElementAtIndex(u), c, kRes, qu, base,
274 dgg, &digits);
275
276 for (size_t p = 0; p < kRes; p++) {
277 for (size_t jj = 0; jj < n; jj++) {
278 zHatBBI(p + u * kRes, jj) = digits(p, jj);
279 }
280 }
281 }
282
283 // Convert zHat from a matrix of BBI to a vector of DCRTPoly ring elements
284 // zHat is in the coefficient representation
285 Matrix<DCRTPoly> zHat =
286 SplitInt64AltIntoElements<DCRTPoly>(zHatBBI, n, params);
287
288 // Now converting it to the evaluation representation before
289 // multiplication
290 zHat.SetFormat(Format::EVALUATION);
291
292 for (size_t p = 0; p < k; p++) zHatMat(i * k + p, j) = zHat(p, 0);
293 }
294 }
295
296 Matrix<DCRTPoly> zHatPrime(zero_alloc, d * (k + 2), d);
297
298 Matrix<DCRTPoly> rZhat = T.m_r.Mult(zHatMat); // d x d
299 Matrix<DCRTPoly> eZhat = T.m_e.Mult(zHatMat); // d x d
300
301 for (size_t j = 0; j < d; j++) { // columns
302 for (size_t i = 0; i < d; i++) {
303 zHatPrime(i, j) = (*pHat)(i, j) + rZhat(i, j);
304 zHatPrime(i + d, j) = (*pHat)(i + d, j) + eZhat(i, j);
305
306 for (size_t p = 0; p < k; p++) {
307 zHatPrime(i * k + p + 2 * d, j) =
308 (*pHat)(i * k + p + 2 * d, j) + zHatMat(i * k + p, j);
309 }
310 }
311 }
312
313 return zHatPrime;
314 }
315
316 } // namespace lbcrypto
317