PointGFp multi_exponentiate(const PointGFp& x, const BigInt& z1, const PointGFp& y, const BigInt& z2) { const size_t z_bits = round_up(std::max(z1.bits(), z2.bits()), 2); std::vector<BigInt> ws(PointGFp::WORKSPACE_SIZE); PointGFp x2 = x; x2.mult2(ws); const PointGFp x3(x2.plus(x, ws)); PointGFp y2 = y; y2.mult2(ws); const PointGFp y3(y2.plus(y, ws)); const PointGFp M[16] = { x.zero(), // 0000 x, // 0001 x2, // 0010 x3, // 0011 y, // 0100 y.plus(x, ws), // 0101 y.plus(x2, ws), // 0110 y.plus(x3, ws), // 0111 y2, // 1000 y2.plus(x, ws), // 1001 y2.plus(x2, ws), // 1010 y2.plus(x3, ws), // 1011 y3, // 1100 y3.plus(x, ws), // 1101 y3.plus(x2, ws), // 1110 y3.plus(x3, ws), // 1111 }; PointGFp H = x.zero(); for(size_t i = 0; i != z_bits; i += 2) { if(i > 0) { H.mult2(ws); H.mult2(ws); } const uint8_t z1_b = z1.get_substring(z_bits - i - 2, 2); const uint8_t z2_b = z2.get_substring(z_bits - i - 2, 2); const uint8_t z12 = (4*z2_b) + z1_b; H.add(M[z12], ws); } if(z1.is_negative() != z2.is_negative()) H.negate(); return H; }
PointGFp Blinded_Point_Multiply::blinded_multiply(const BigInt& scalar_in, RandomNumberGenerator& rng) { if(scalar_in.is_negative()) throw std::invalid_argument("Blinded_Point_Multiply scalar must be positive"); #if BOTAN_POINTGFP_SCALAR_BLINDING_BITS > 0 // Choose a small mask m and use k' = k + m*order (Coron's 1st countermeasure) const BigInt mask(rng, BOTAN_POINTGFP_SCALAR_BLINDING_BITS, false); const BigInt scalar = scalar_in + m_order * mask; #else const BigInt& scalar = scalar_in; #endif const size_t scalar_bits = scalar.bits(); // Randomize each point representation (Coron's 3rd countermeasure) for(size_t i = 0; i != m_U.size(); ++i) m_U[i].randomize_repr(rng); #if BOTAN_POINTGFP_BLINDED_MULTIPLY_USE_MONTGOMERY_LADDER PointGFp R = m_U.at(3*m_h + 2); // base point int32_t alpha = 0; R.randomize_repr(rng); /* Algorithm 7 from "Randomizing the Montgomery Powering Ladder" Duc-Phong Le, Chik How Tan and Michael Tunstall http://eprint.iacr.org/2015/657 It takes a random walk through (a subset of) the set of addition chains that end in k. */ for(size_t i = scalar_bits; i > 0; i--) { const int32_t ki = scalar.get_bit(i); // choose gamma from -h,...,h const int32_t gamma = static_cast<int32_t>((rng.next_byte() % (2*m_h))) - m_h; const int32_t l = gamma - 2*alpha + ki - (ki ^ 1); R.mult2(m_ws); R.add(m_U.at(3*m_h + 1 + l), m_ws); alpha = gamma; } const int32_t k0 = scalar.get_bit(0); R.add(m_U[3*m_h + 1 - alpha - (k0 ^ 1)], m_ws); #else // N-bit windowing exponentiation: size_t windows = round_up(scalar_bits, m_h) / m_h; PointGFp R = m_U[0]; if(windows > 0) { windows--; const u32bit nibble = scalar.get_substring(windows*m_h, m_h); R.add(m_U[nibble], m_ws); /* Randomize after adding the first nibble as before the addition R is zero, and we cannot effectively randomize the point representation of the zero point. */ R.randomize_repr(rng); while(windows) { for(size_t i = 0; i != m_h; ++i) R.mult2(m_ws); const u32bit nibble = scalar.get_substring((windows-1)*m_h, m_h); R.add(m_U[nibble], m_ws); windows--; } } #endif //BOTAN_ASSERT(R.on_the_curve(), "Output is on the curve"); return R; }