@@ -83,26 +83,48 @@ class ModArith
8383 // Based on 2.3.2 from
8484 // High-Speed Algorithms & Architectures For Number-Theoretic Cryptosystems
8585 // https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf
86+ // and on 2.2 from
87+ // EdMSM: Multi-Scalar-Multiplication for SNARKs and Faster Montgomery multiplication
88+ // https://eprint.iacr.org/2022/1400.pdf
8689
90+ constexpr uint64_t most_significant_mod_word_limit {std::numeric_limits<uint64_t >::max () >> 1 };
8791 constexpr auto S = UintT::num_words; // TODO(C++23): Make it static
8892
8993 intx::uint<UintT::num_bits + 64 > t;
90- for ( size_t i = 0 ; i != S; ++i )
94+ if (mod[S - 1 ] < most_significant_mod_word_limit )
9195 {
92- uint64_t c = 0 ;
93- for (size_t j = 0 ; j != S; ++j)
94- std::tie (c, t[j]) = addmul (t[j], x[j], y[i], c);
95- auto tmp = intx::addc (t[S], c);
96- t[S] = tmp.value ;
97- const auto d = tmp.carry ; // TODO: Carry is 0 for sparse modulus.
98-
99- const auto m = t[0 ] * m_mod_inv;
100- std::tie (c, std::ignore) = addmul (t[0 ], m, mod[0 ], 0 );
101- for (size_t j = 1 ; j != S; ++j)
102- std::tie (c, t[j - 1 ]) = addmul (t[j], m, mod[j], c);
103- tmp = intx::addc (t[S], c);
104- t[S - 1 ] = tmp.value ;
105- t[S] = d + tmp.carry ; // TODO: Carry is 0 for sparse modulus.
96+ for (size_t i = 0 ; i != S; ++i)
97+ {
98+ uint64_t c = 0 ;
99+ for (size_t j = 0 ; j != S; ++j)
100+ std::tie (c, t[j]) = addmul (t[j], x[j], y[i], c);
101+ auto const c_2 = c;
102+ const auto m = t[0 ] * m_mod_inv;
103+ std::tie (c, std::ignore) = addmul (t[0 ], m, mod[0 ], 0 );
104+ for (size_t j = 1 ; j != S; ++j)
105+ std::tie (c, t[j - 1 ]) = addmul (t[j], m, mod[j], c);
106+ t[S - 1 ] = c_2 + c;
107+ }
108+ }
109+ else
110+ {
111+ for (size_t i = 0 ; i != S; ++i)
112+ {
113+ uint64_t c = 0 ;
114+ for (size_t j = 0 ; j != S; ++j)
115+ std::tie (c, t[j]) = addmul (t[j], x[j], y[i], c);
116+ auto tmp = intx::addc (t[S], c);
117+ t[S] = tmp.value ;
118+ const auto d = tmp.carry ; // TODO: Carry is 0 for sparse modulus.
119+
120+ const auto m = t[0 ] * m_mod_inv;
121+ std::tie (c, std::ignore) = addmul (t[0 ], m, mod[0 ], 0 );
122+ for (size_t j = 1 ; j != S; ++j)
123+ std::tie (c, t[j - 1 ]) = addmul (t[j], m, mod[j], c);
124+ tmp = intx::addc (t[S], c);
125+ t[S - 1 ] = tmp.value ;
126+ t[S] = d + tmp.carry ; // TODO: Carry is 0 for sparse modulus.
127+ }
106128 }
107129
108130 if (t >= mod)
0 commit comments