@@ -71,6 +71,20 @@ KyberMode::Mode kyber_mode_from_string(std::string_view str) {
7171 throw Invalid_Argument (fmt (" '{}' is not a valid Kyber mode name" , str));
7272}
7373
74+ /* *
75+ * Constant time implementation for computing an unsigned integer division
76+ * with KyberConstants::Q = 3329.
77+ *
78+ * It enforces the optimization of various compilers,
79+ * replacing the division operation with multiplication and shifts.
80+ *
81+ * @returns (a / KyberConstants::Q)
82+ */
83+ uint16_t ct_int_div_kyber_q (uint32_t a) {
84+ const uint64_t tmp = (static_cast <uint64_t >(a) * 989558401UL ) >> 32 ;
85+ return static_cast <uint16_t >((tmp + ((a - tmp) >> 1 )) >> 11 );
86+ }
87+
7488} // namespace
7589
7690KyberMode::KyberMode (Mode mode) : m_mode(mode) {}
@@ -399,21 +413,12 @@ class Polynomial {
399413
400414 this ->csubq ();
401415
402- auto compress = [](uint32_t t) {
403- // (t << 1) + ((KyberConstants::Q / 2) / KyberConstants::Q) & 1
404- // Note that magic numbers assume that ::Q = 3329
405- t <<= 1 ;
406- t += 1665 ;
407- t *= 80635 ;
408- t >>= 28 ;
409- t &= 1 ;
410- return static_cast <uint8_t >(t);
411- };
412-
413416 for (size_t i = 0 ; i < size () / 8 ; ++i) {
414417 result[i] = 0 ;
415418 for (size_t j = 0 ; j < 8 ; ++j) {
416- result[i] |= compress (this ->m_coeffs [8 * i + j]) << j;
419+ const uint16_t t =
420+ ct_int_div_kyber_q ((static_cast <uint16_t >(this ->m_coeffs [8 * i + j]) << 1 ) + KyberConstants::Q / 2 );
421+ result[i] |= (t & 1 ) << j;
417422 }
418423 }
419424
@@ -564,7 +569,7 @@ class Polynomial {
564569 */
565570 static int16_t barrett_reduce (int16_t a) {
566571 int16_t t;
567- const int16_t v = ((1U << 26 ) + KyberConstants::Q / 2 ) / KyberConstants::Q;
572+ constexpr int16_t v = ((1U << 26 ) + KyberConstants::Q / 2 ) / KyberConstants::Q;
568573
569574 t = static_cast <int32_t >(v) * a >> 26 ;
570575 t *= KyberConstants::Q;
@@ -865,8 +870,7 @@ class Ciphertext {
865870 size_t offset = 0 ;
866871 for (size_t i = 0 ; i < p.size () / 8 ; ++i) {
867872 for (size_t j = 0 ; j < 8 ; ++j) {
868- t[j] =
869- (((static_cast <uint16_t >(p[8 * i + j]) << 4 ) + KyberConstants::Q / 2 ) / KyberConstants::Q) & 15 ;
873+ t[j] = ct_int_div_kyber_q ((static_cast <uint16_t >(p[8 * i + j]) << 4 ) + KyberConstants::Q / 2 ) & 15 ;
870874 }
871875
872876 r[0 + offset] = t[0 ] | (t[1 ] << 4 );
@@ -879,8 +883,7 @@ class Ciphertext {
879883 size_t offset = 0 ;
880884 for (size_t i = 0 ; i < p.size () / 8 ; ++i) {
881885 for (size_t j = 0 ; j < 8 ; ++j) {
882- t[j] =
883- (((static_cast <uint32_t >(p[8 * i + j]) << 5 ) + KyberConstants::Q / 2 ) / KyberConstants::Q) & 31 ;
886+ t[j] = ct_int_div_kyber_q ((static_cast <uint32_t >(p[8 * i + j]) << 5 ) + KyberConstants::Q / 2 ) & 31 ;
884887 }
885888
886889 r[0 + offset] = (t[0 ] >> 0 ) | (t[1 ] << 5 );
0 commit comments