@@ -83,26 +83,47 @@ 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
8790 constexpr auto S = UintT::num_words; // TODO(C++23): Make it static
8891
8992 intx::uint<UintT::num_bits + 64 > t;
90- for ( size_t i = 0 ; i != S; ++i )
93+ if (mod[S - 1 ] < std::numeric_limits< uint64_t >:: max () / 2 )
9194 {
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.
95+ for (size_t i = 0 ; i != S; ++i)
96+ {
97+ uint64_t c = 0 ;
98+ for (size_t j = 0 ; j != S; ++j)
99+ std::tie (c, t[j]) = addmul (t[j], x[j], y[i], c);
100+ auto const c_2 = c;
101+ const auto m = t[0 ] * m_mod_inv;
102+ std::tie (c, std::ignore) = addmul (t[0 ], m, mod[0 ], 0 );
103+ for (size_t j = 1 ; j != S; ++j)
104+ std::tie (c, t[j - 1 ]) = addmul (t[j], m, mod[j], c);
105+ t[S - 1 ] = c_2 + c;
106+ }
107+ }
108+ else
109+ {
110+ for (size_t i = 0 ; i != S; ++i)
111+ {
112+ uint64_t c = 0 ;
113+ for (size_t j = 0 ; j != S; ++j)
114+ std::tie (c, t[j]) = addmul (t[j], x[j], y[i], c);
115+ auto tmp = intx::addc (t[S], c);
116+ t[S] = tmp.value ;
117+ const auto d = tmp.carry ; // TODO: Carry is 0 for sparse modulus.
118+
119+ const auto m = t[0 ] * m_mod_inv;
120+ std::tie (c, std::ignore) = addmul (t[0 ], m, mod[0 ], 0 );
121+ for (size_t j = 1 ; j != S; ++j)
122+ std::tie (c, t[j - 1 ]) = addmul (t[j], m, mod[j], c);
123+ tmp = intx::addc (t[S], c);
124+ t[S - 1 ] = tmp.value ;
125+ t[S] = d + tmp.carry ; // TODO: Carry is 0 for sparse modulus.
126+ }
106127 }
107128
108129 if (t >= mod)
0 commit comments