polynomial_test.cc 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  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 "polynomial.h"
  16. #include <cmath>
  17. #include <random>
  18. #include <vector>
  19. #include <gmock/gmock.h>
  20. #include <gtest/gtest.h>
  21. #include "constants.h"
  22. #include "montgomery.h"
  23. #include "ntt_parameters.h"
  24. #include "prng/integral_prng_testing_types.h"
  25. #include "serialization.pb.h"
  26. #include "status_macros.h"
  27. #include "testing/coefficient_polynomial.h"
  28. #include "testing/status_matchers.h"
  29. #include "testing/status_testing.h"
  30. #include "testing/testing_prng.h"
  31. namespace {
  32. using ::rlwe::testing::StatusIs;
  33. using ::testing::Eq;
  34. using ::testing::HasSubstr;
  35. using ::testing::Ne;
  36. // Useful typedefs.
  37. using uint_m = rlwe::MontgomeryInt<rlwe::Uint16>;
  38. using CoefficientPolynomial = rlwe::testing::CoefficientPolynomial<uint_m>;
  39. using Polynomial = rlwe::Polynomial<uint_m>;
  40. unsigned int seed = 0;
  41. const absl::string_view kPrngSeed =
  42. "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
  43. // Test fixture to take care of messy setup.
  44. template <typename Prng>
  45. class PolynomialTest : public ::testing::Test {
  46. protected:
  47. PolynomialTest()
  48. : params14_(uint_m::Params::Create(rlwe::kNewhopeModulus).value()),
  49. zero_(uint_m::ImportZero(params14_.get())) {}
  50. void SetUp() override { srand(0); }
  51. void SetParams(int n, int log_n) {
  52. // Prng to generate random values
  53. ASSERT_OK_AND_ASSIGN(auto prng,
  54. Prng::Create(kPrngSeed.substr(0, Prng::SeedLength())));
  55. std::vector<uint_m> p_coeffs(n, zero_);
  56. std::vector<uint_m> q_coeffs(n, zero_);
  57. // Create some random polynomials. Ensure that they are different.
  58. for (int j = 0; j < n; j++) {
  59. ASSERT_OK_AND_ASSIGN(p_coeffs[j],
  60. uint_m::ImportRandom(prng.get(), params14_.get()));
  61. ASSERT_OK_AND_ASSIGN(q_coeffs[j],
  62. uint_m::ImportRandom(prng.get(), params14_.get()));
  63. }
  64. // Ensure the polynomials are different.
  65. uint_m::Int rand_index = rand_r(&seed) % n;
  66. auto one = uint_m::ImportOne(params14_.get());
  67. p_coeffs[rand_index] = q_coeffs[rand_index].Add(one, params14_.get());
  68. p_.reset(new CoefficientPolynomial(p_coeffs, params14_.get()));
  69. q_.reset(new CoefficientPolynomial(q_coeffs, params14_.get()));
  70. // Acquire all of the NTT parameters.
  71. ASSERT_OK_AND_ASSIGN(auto ntt_params, rlwe::InitializeNttParameters<uint_m>(
  72. log_n, params14_.get()));
  73. ntt_params_ =
  74. absl::make_unique<rlwe::NttParameters<uint_m>>(std::move(ntt_params));
  75. // Put p and q in the NTT domain.
  76. ntt_p_ =
  77. Polynomial::ConvertToNtt(p_coeffs, ntt_params_.get(), params14_.get());
  78. ntt_q_ =
  79. Polynomial::ConvertToNtt(q_coeffs, ntt_params_.get(), params14_.get());
  80. }
  81. std::unique_ptr<Prng> MakePrng(absl::string_view seed) {
  82. auto prng = Prng::Create(seed.substr(0, Prng::SeedLength())).value();
  83. return prng;
  84. }
  85. std::unique_ptr<const uint_m::Params> params14_;
  86. std::unique_ptr<rlwe::NttParameters<uint_m>> ntt_params_;
  87. std::unique_ptr<CoefficientPolynomial> p_;
  88. std::unique_ptr<CoefficientPolynomial> q_;
  89. Polynomial ntt_p_;
  90. Polynomial ntt_q_;
  91. uint_m zero_;
  92. };
  93. TYPED_TEST_SUITE(PolynomialTest, rlwe::TestingPrngTypes);
  94. // Ensure that a default NTT polynomial is invalid.
  95. TYPED_TEST(PolynomialTest, DefaultIsInvalid) {
  96. EXPECT_FALSE(Polynomial().IsValid());
  97. }
  98. TYPED_TEST(PolynomialTest, CoeffsCorrectlyReturnsCoefficients) {
  99. auto prng = this->MakePrng(kPrngSeed);
  100. for (int i = 2; i < 11; i++) {
  101. int n = 1 << i;
  102. this->SetParams(n, i);
  103. // coeffs = {1, 0, 0, ...}, ntt_coeffs = {1, 1, 1, ...}
  104. // Test that NTT(coeffs) == ntt_coeffs
  105. std::vector<uint_m::Int> coeffs(n, 0), ntt_coeffs(n, 1);
  106. coeffs[0] = 1;
  107. std::vector<uint_m> v;
  108. for (const uint_m::Int& coeff : coeffs) {
  109. ASSERT_OK_AND_ASSIGN(auto elt,
  110. uint_m::ImportInt(coeff, this->params14_.get()));
  111. v.push_back(elt);
  112. }
  113. Polynomial ntt_v = Polynomial::ConvertToNtt(v, this->ntt_params_.get(),
  114. this->params14_.get());
  115. for (int j = 0; j < n; j++) {
  116. EXPECT_EQ(ntt_v.Coeffs()[j].ExportInt(this->params14_.get()),
  117. ntt_coeffs[j]);
  118. }
  119. // Test that coeffs are the same when explicitly constructed
  120. std::vector<uint_m> coeffs2(n, this->zero_);
  121. for (int j = 0; j < n; j++) {
  122. ASSERT_OK_AND_ASSIGN(
  123. coeffs2[j], uint_m::ImportRandom(prng.get(), this->params14_.get()));
  124. }
  125. Polynomial ntt2 = Polynomial(coeffs2);
  126. std::vector<uint_m> nttcoeffs2 = ntt2.Coeffs();
  127. for (int j = 0; j < n; j++) {
  128. EXPECT_EQ(coeffs2[j], nttcoeffs2[j]);
  129. }
  130. // Test that coeffs are all zero when only length is given
  131. Polynomial ntt3 = Polynomial(n, this->params14_.get());
  132. std::vector<uint_m> nttcoeffs3 = ntt3.Coeffs();
  133. for (int j = 0; j < n; j++) {
  134. EXPECT_EQ(nttcoeffs3[j], this->zero_);
  135. }
  136. }
  137. }
  138. // Ensure that a polynomial converted to NTT form can be converted back.
  139. TYPED_TEST(PolynomialTest, Symmetry) {
  140. for (int i = 2; i < 11; i++) {
  141. this->SetParams(1 << i, i);
  142. EXPECT_TRUE(this->ntt_p_.IsValid());
  143. CoefficientPolynomial p_prime(
  144. this->ntt_p_.InverseNtt(this->ntt_params_.get(), this->params14_.get()),
  145. this->params14_.get());
  146. EXPECT_EQ(*this->p_, p_prime);
  147. }
  148. }
  149. // Ensure that equality holds properly.
  150. TYPED_TEST(PolynomialTest, Equality) {
  151. for (int i = 2; i < 11; i++) {
  152. this->SetParams(1 << i, i);
  153. Polynomial ntt_p_cpy = this->ntt_p_;
  154. Polynomial ntt_q_cpy = this->ntt_q_;
  155. EXPECT_TRUE(this->ntt_p_ == ntt_p_cpy);
  156. EXPECT_TRUE(this->ntt_q_ == ntt_q_cpy);
  157. EXPECT_FALSE(this->ntt_p_ != ntt_p_cpy);
  158. EXPECT_FALSE(this->ntt_q_ != ntt_q_cpy);
  159. EXPECT_TRUE(this->ntt_p_ != this->ntt_q_);
  160. EXPECT_TRUE(this->ntt_q_ != this->ntt_p_);
  161. EXPECT_FALSE(this->ntt_p_ == this->ntt_q_);
  162. EXPECT_FALSE(this->ntt_q_ == this->ntt_p_);
  163. }
  164. }
  165. // Ensure that a polynomial whose size is not a power of two gets rejected.
  166. TYPED_TEST(PolynomialTest, NotPowerOfTwo) {
  167. for (int i = 2; i < 11; i++) {
  168. // j is any value that isn't a power of 2.
  169. for (int j = 1 + (1 << (i - 1)); j < (1 << i); j++) {
  170. this->SetParams(j, i);
  171. EXPECT_FALSE(this->ntt_p_.IsValid());
  172. }
  173. }
  174. }
  175. // Ensure that adding or multiplying two polynomials of different lengths gets
  176. // rejected.
  177. TYPED_TEST(PolynomialTest, BinopOfDifferentLengths) {
  178. for (int i = 2; i < 11; i++) {
  179. for (int j = 2; j < 11; j++) {
  180. if (j == i) {
  181. continue;
  182. }
  183. int bigger = std::max(i, j);
  184. this->SetParams(1 << bigger, bigger);
  185. std::vector<uint_m> x(1 << i, this->zero_);
  186. std::vector<uint_m> y(1 << j, this->zero_);
  187. this->ntt_params_->bitrevs = rlwe::internal::BitrevArray(i);
  188. Polynomial ntt_x = Polynomial::ConvertToNtt(x, this->ntt_params_.get(),
  189. this->params14_.get());
  190. this->ntt_params_->bitrevs = rlwe::internal::BitrevArray(j);
  191. Polynomial ntt_y = Polynomial::ConvertToNtt(y, this->ntt_params_.get(),
  192. this->params14_.get());
  193. EXPECT_TRUE(ntt_x.IsValid());
  194. EXPECT_TRUE(ntt_y.IsValid());
  195. // Lengths are different
  196. EXPECT_FALSE(ntt_x == ntt_y);
  197. EXPECT_THAT(ntt_x.Mul(ntt_y, this->params14_.get()),
  198. StatusIs(::absl::StatusCode::kInvalidArgument,
  199. HasSubstr("do not have the same length")));
  200. EXPECT_THAT(ntt_y.Mul(ntt_x, this->params14_.get()),
  201. StatusIs(::absl::StatusCode::kInvalidArgument,
  202. HasSubstr("do not have the same length")));
  203. EXPECT_THAT(ntt_x.Add(ntt_y, this->params14_.get()),
  204. StatusIs(::absl::StatusCode::kInvalidArgument,
  205. HasSubstr("do not have the same length")));
  206. EXPECT_THAT(ntt_y.Add(ntt_x, this->params14_.get()),
  207. StatusIs(::absl::StatusCode::kInvalidArgument,
  208. HasSubstr("do not have the same length")));
  209. EXPECT_THAT(ntt_x.Sub(ntt_y, this->params14_.get()),
  210. StatusIs(::absl::StatusCode::kInvalidArgument,
  211. HasSubstr("do not have the same length")));
  212. EXPECT_THAT(ntt_y.Sub(ntt_x, this->params14_.get()),
  213. StatusIs(::absl::StatusCode::kInvalidArgument,
  214. HasSubstr("do not have the same length")));
  215. // In-place operations return the original polynomial if invalid
  216. // To check, we keep a copy of the original and check that the output
  217. // remains the same
  218. Polynomial orig_ntt_x = ntt_x;
  219. Polynomial orig_ntt_y = ntt_y;
  220. EXPECT_THAT(ntt_x.MulInPlace(ntt_y, this->params14_.get()),
  221. StatusIs(::absl::StatusCode::kInvalidArgument,
  222. HasSubstr("do not have the same length")));
  223. EXPECT_THAT(ntt_y.MulInPlace(ntt_x, this->params14_.get()),
  224. StatusIs(::absl::StatusCode::kInvalidArgument,
  225. HasSubstr("do not have the same length")));
  226. EXPECT_THAT(ntt_x.AddInPlace(ntt_y, this->params14_.get()),
  227. StatusIs(::absl::StatusCode::kInvalidArgument,
  228. HasSubstr("do not have the same length")));
  229. EXPECT_THAT(ntt_y.AddInPlace(ntt_x, this->params14_.get()),
  230. StatusIs(::absl::StatusCode::kInvalidArgument,
  231. HasSubstr("do not have the same length")));
  232. EXPECT_THAT(ntt_x.SubInPlace(ntt_y, this->params14_.get()),
  233. StatusIs(::absl::StatusCode::kInvalidArgument,
  234. HasSubstr("do not have the same length")));
  235. EXPECT_THAT(ntt_y.SubInPlace(ntt_x, this->params14_.get()),
  236. StatusIs(::absl::StatusCode::kInvalidArgument,
  237. HasSubstr("do not have the same length")));
  238. }
  239. }
  240. }
  241. // Test that the convolution property holds. Let p, q be polynomials.
  242. // CoefficientPolynomial multiplication of p and q =
  243. // NTT_INV(the coordinate-wise product of NTT(p) and NTT(q))
  244. TYPED_TEST(PolynomialTest, Multiply) {
  245. for (int i = 2; i < 11; i++) {
  246. this->SetParams(1 << i, i);
  247. EXPECT_TRUE(this->ntt_p_.IsValid());
  248. EXPECT_TRUE(this->ntt_q_.IsValid());
  249. ASSERT_OK_AND_ASSIGN(Polynomial ntt_res1,
  250. this->ntt_p_.Mul(this->ntt_q_, this->params14_.get()));
  251. ASSERT_OK_AND_ASSIGN(Polynomial ntt_res2,
  252. this->ntt_q_.Mul(this->ntt_p_, this->params14_.get()));
  253. CoefficientPolynomial res1(
  254. ntt_res1.InverseNtt(this->ntt_params_.get(), this->params14_.get()),
  255. this->params14_.get());
  256. CoefficientPolynomial res2(
  257. ntt_res2.InverseNtt(this->ntt_params_.get(), this->params14_.get()),
  258. this->params14_.get());
  259. ASSERT_OK_AND_ASSIGN(CoefficientPolynomial expected,
  260. (*this->p_) * (*this->q_));
  261. EXPECT_EQ(res1, expected);
  262. EXPECT_EQ(res2, expected);
  263. EXPECT_EQ(res1, res2);
  264. }
  265. }
  266. // Test scalar multiplication.
  267. TYPED_TEST(PolynomialTest, ScalarMultiply) {
  268. auto prng = this->MakePrng(kPrngSeed);
  269. ASSERT_OK_AND_ASSIGN(uint_m scalar,
  270. uint_m::ImportRandom(prng.get(), this->params14_.get()));
  271. for (int i = 2; i < 11; i++) {
  272. this->SetParams(1 << i, i);
  273. EXPECT_TRUE(this->ntt_p_.IsValid());
  274. ASSERT_OK_AND_ASSIGN(Polynomial ntt_res,
  275. this->ntt_p_.Mul(scalar, this->params14_.get()));
  276. CoefficientPolynomial res(
  277. ntt_res.InverseNtt(this->ntt_params_.get(), this->params14_.get()),
  278. this->params14_.get());
  279. CoefficientPolynomial expected = (*this->p_) * scalar;
  280. EXPECT_EQ(res, expected);
  281. }
  282. }
  283. // Test that p + (-p) = 0.
  284. TYPED_TEST(PolynomialTest, Negate) {
  285. for (int i = 2; i < 11; i++) {
  286. this->SetParams(1 << i, i);
  287. // An NTT polynomial of all zeros.
  288. Polynomial zeros_ntt = Polynomial::ConvertToNtt(
  289. std::vector<uint_m>(1 << i, this->zero_), this->ntt_params_.get(),
  290. this->params14_.get());
  291. auto minus_p = this->ntt_p_.Negate(this->params14_.get());
  292. ASSERT_OK_AND_ASSIGN(auto p0,
  293. this->ntt_p_.Add(minus_p, this->params14_.get()));
  294. EXPECT_EQ(zeros_ntt, p0);
  295. ASSERT_OK_AND_ASSIGN(p0, minus_p.Add(this->ntt_p_, this->params14_.get()));
  296. EXPECT_EQ(zeros_ntt, p0);
  297. }
  298. }
  299. // Test that p + q = NTT_INV(NTT(p) + NTT(q)).
  300. TYPED_TEST(PolynomialTest, Add) {
  301. for (int i = 2; i < 11; i++) {
  302. this->SetParams(1 << i, i);
  303. EXPECT_TRUE(this->ntt_p_.IsValid());
  304. EXPECT_TRUE(this->ntt_q_.IsValid());
  305. ASSERT_OK_AND_ASSIGN(Polynomial ntt_res1,
  306. this->ntt_p_.Add(this->ntt_q_, this->params14_.get()));
  307. ASSERT_OK_AND_ASSIGN(Polynomial ntt_res2,
  308. this->ntt_q_.Add(this->ntt_p_, this->params14_.get()));
  309. CoefficientPolynomial res1(
  310. ntt_res1.InverseNtt(this->ntt_params_.get(), this->params14_.get()),
  311. this->params14_.get());
  312. CoefficientPolynomial res2(
  313. ntt_res2.InverseNtt(this->ntt_params_.get(), this->params14_.get()),
  314. this->params14_.get());
  315. ASSERT_OK_AND_ASSIGN(CoefficientPolynomial expected,
  316. (*this->p_) + (*this->q_));
  317. EXPECT_EQ(res1, expected);
  318. EXPECT_EQ(res2, expected);
  319. EXPECT_EQ(res1, res2);
  320. }
  321. }
  322. // Test that p - q = NTT_INV(NTT(p) - NTT(q)) and
  323. // q - p = NTT_INV(NTT(q) - NTT(p)).
  324. TYPED_TEST(PolynomialTest, Sub) {
  325. for (int i = 2; i < 11; i++) {
  326. this->SetParams(1 << i, i);
  327. EXPECT_TRUE(this->ntt_p_.IsValid());
  328. EXPECT_TRUE(this->ntt_q_.IsValid());
  329. ASSERT_OK_AND_ASSIGN(Polynomial ntt_res1,
  330. this->ntt_p_.Sub(this->ntt_q_, this->params14_.get()));
  331. ASSERT_OK_AND_ASSIGN(Polynomial ntt_res2,
  332. this->ntt_q_.Sub(this->ntt_p_, this->params14_.get()));
  333. CoefficientPolynomial res1(
  334. ntt_res1.InverseNtt(this->ntt_params_.get(), this->params14_.get()),
  335. this->params14_.get());
  336. CoefficientPolynomial res2(
  337. ntt_res2.InverseNtt(this->ntt_params_.get(), this->params14_.get()),
  338. this->params14_.get());
  339. ASSERT_OK_AND_ASSIGN(CoefficientPolynomial expected_res1,
  340. (*this->p_) - (*this->q_));
  341. ASSERT_OK_AND_ASSIGN(CoefficientPolynomial expected_res2,
  342. (*this->q_) - (*this->p_));
  343. EXPECT_EQ(res1, expected_res1);
  344. EXPECT_EQ(res2, expected_res2);
  345. }
  346. }
  347. TYPED_TEST(PolynomialTest, SubstitutionPowerMalformed) {
  348. // Ensure substitution fails on powers that are negative, even, and greater
  349. // than 2 * kDimension.
  350. for (int i = 2; i < 11; i++) {
  351. this->SetParams(1 << i, i);
  352. EXPECT_THAT(
  353. this->ntt_p_.Substitute(2, this->ntt_params_.get(),
  354. this->params14_.get()),
  355. StatusIs(::absl::StatusCode::kInvalidArgument,
  356. HasSubstr("must be a non-negative odd integer less than")));
  357. // Even when not in debugging mode, the following two tests will yield a
  358. // segmentation fault. We therefore only do the tests in debug mode.
  359. EXPECT_THAT(
  360. this->ntt_p_.Substitute(-10, this->ntt_params_.get(),
  361. this->params14_.get()),
  362. StatusIs(::absl::StatusCode::kInvalidArgument,
  363. HasSubstr("must be a non-negative odd integer less than")));
  364. EXPECT_THAT(
  365. this->ntt_p_.Substitute(2 * (1 << i) + 1, this->ntt_params_.get(),
  366. this->params14_.get()),
  367. StatusIs(::absl::StatusCode::kInvalidArgument,
  368. HasSubstr("must be a non-negative odd integer less than")));
  369. }
  370. }
  371. TYPED_TEST(PolynomialTest, Substitution) {
  372. // Tests substitutions of the form N/2^k + 1.
  373. for (int i = 2; i < 11; i++) {
  374. this->SetParams(1 << i, i);
  375. int dimension = 1 << i;
  376. for (int k = 0; k < i; k++) {
  377. int power = (dimension >> k) + 1;
  378. ASSERT_OK_AND_ASSIGN(
  379. auto ntt_res, this->ntt_p_.Substitute(power, this->ntt_params_.get(),
  380. this->params14_.get()));
  381. CoefficientPolynomial res(
  382. ntt_res.InverseNtt(this->ntt_params_.get(), this->params14_.get()),
  383. this->params14_.get());
  384. ASSERT_OK_AND_ASSIGN(auto r, this->p_->Substitute(power));
  385. EXPECT_EQ(res, r);
  386. }
  387. }
  388. }
  389. TYPED_TEST(PolynomialTest, Serialize) {
  390. for (int i = 2; i < 11; i++) {
  391. this->SetParams(1 << i, i);
  392. ASSERT_OK_AND_ASSIGN(rlwe::SerializedNttPolynomial serialized_p,
  393. this->ntt_p_.Serialize(this->params14_.get()));
  394. ASSERT_OK_AND_ASSIGN(rlwe::SerializedNttPolynomial serialized_q,
  395. this->ntt_q_.Serialize(this->params14_.get()));
  396. // Ensure that a serialized polynomial can be deserialized.
  397. ASSERT_OK_AND_ASSIGN(
  398. auto deserialized_p,
  399. Polynomial::Deserialize(serialized_p, this->params14_.get()));
  400. EXPECT_EQ(this->ntt_p_, deserialized_p);
  401. ASSERT_OK_AND_ASSIGN(
  402. auto deserialized_q,
  403. Polynomial::Deserialize(serialized_q, this->params14_.get()));
  404. EXPECT_EQ(this->ntt_q_, deserialized_q);
  405. // Ensure that the length of a Serialized polynomial is at most
  406. // SerializedSize times the number of coefficients.
  407. EXPECT_LE(serialized_p.coeffs().size(),
  408. this->ntt_p_.Len() * this->params14_->SerializedSize());
  409. EXPECT_LE(serialized_q.coeffs().size(),
  410. this->ntt_q_.Len() * this->params14_->SerializedSize());
  411. }
  412. }
  413. TYPED_TEST(PolynomialTest,
  414. SamplePolynomialFromPrngReturnsPolynomialWithCorrectSize) {
  415. auto prng = this->MakePrng(kPrngSeed);
  416. ASSERT_OK_AND_ASSIGN(auto polynomial,
  417. rlwe::SamplePolynomialFromPrng<uint_m>(
  418. 16, prng.get(), this->params14_.get()));
  419. EXPECT_THAT(polynomial.Len(), Eq(16));
  420. }
  421. TYPED_TEST(PolynomialTest, SamplePolynomialFromPrngFailsWithLengthLessThanOne) {
  422. auto prng = this->MakePrng(kPrngSeed);
  423. EXPECT_THAT(rlwe::SamplePolynomialFromPrng<uint_m>(0, prng.get(),
  424. this->params14_.get()),
  425. StatusIs(::absl::StatusCode::kInvalidArgument,
  426. HasSubstr("must be a non-negative integer")));
  427. EXPECT_THAT(rlwe::SamplePolynomialFromPrng<uint_m>(-10, prng.get(),
  428. this->params14_.get()),
  429. StatusIs(::absl::StatusCode::kInvalidArgument,
  430. HasSubstr("must be a non-negative integer")));
  431. }
  432. TYPED_TEST(PolynomialTest,
  433. SamplePolynomialFromPrngSamplesSamePolynomialFromSameSeed) {
  434. auto prng1 = this->MakePrng(kPrngSeed);
  435. auto prng2 = this->MakePrng(kPrngSeed);
  436. ASSERT_OK_AND_ASSIGN(auto polynomial1,
  437. rlwe::SamplePolynomialFromPrng<uint_m>(
  438. 16, prng1.get(), this->params14_.get()));
  439. ASSERT_OK_AND_ASSIGN(auto polynomial2,
  440. rlwe::SamplePolynomialFromPrng<uint_m>(
  441. 16, prng2.get(), this->params14_.get()));
  442. EXPECT_THAT(polynomial1, Eq(polynomial2));
  443. }
  444. TYPED_TEST(PolynomialTest,
  445. SamplePolynomialFromPrngSamplesOtherPolynomialFromOtherSeed) {
  446. auto prng1 = this->MakePrng(kPrngSeed);
  447. auto prng2 = this->MakePrng(
  448. "0000000000000000000000000000000000000000000000000000000000000000");
  449. ASSERT_OK_AND_ASSIGN(auto polynomial1,
  450. rlwe::SamplePolynomialFromPrng<uint_m>(
  451. 16, prng1.get(), this->params14_.get()));
  452. ASSERT_OK_AND_ASSIGN(auto polynomial2,
  453. rlwe::SamplePolynomialFromPrng<uint_m>(
  454. 16, prng2.get(), this->params14_.get()));
  455. EXPECT_THAT(polynomial1, Ne(polynomial2));
  456. }
  457. } // namespace