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