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 operator*(const BigInt& scalar, const PointGFp& point) { //BOTAN_ASSERT(point.on_the_curve(), "Input is on the curve"); const CurveGFp& curve = point.get_curve(); const size_t scalar_bits = scalar.bits(); std::vector<BigInt> ws(9); if(scalar_bits <= 2) { const byte abs_val = scalar.byte_at(0); if(abs_val == 0) return PointGFp::zero_of(curve); PointGFp result = point; if(abs_val == 2) result.mult2(ws); if(scalar.is_negative()) result.negate(); return result; } PointGFp R[2] = { PointGFp(curve), point }; for(size_t i = scalar_bits; i > 0; i--) { const size_t b = scalar.get_bit(i - 1); R[b ^ 1].add(R[b], ws); R[b].mult2(ws); } if(scalar.is_negative()) R[0].negate(); //BOTAN_ASSERT(R[0].on_the_curve(), "Output is on the curve"); return R[0]; }
PointGFp operator*(const BigInt& scalar, const PointGFp& point) { const CurveGFp& curve = point.get_curve(); if(scalar.is_zero()) return PointGFp(curve); // zero point std::vector<BigInt> ws(9); if(scalar.abs() <= 2) // special cases for small values { byte value = scalar.abs().byte_at(0); PointGFp result = point; if(value == 2) result.mult2(ws); if(scalar.is_negative()) result.negate(); return result; } const size_t scalar_bits = scalar.bits(); #if 0 PointGFp x1 = PointGFp(curve); PointGFp x2 = point; size_t bits_left = scalar_bits; // Montgomery Ladder while(bits_left) { const bool bit_set = scalar.get_bit(bits_left - 1); if(bit_set) { x1.add(x2, ws); x2.mult2(ws); } else { x2.add(x1, ws); x1.mult2(ws); } --bits_left; } if(scalar.is_negative()) x1.negate(); return x1; #else const size_t window_size = 4; std::vector<PointGFp> Ps(1 << window_size); Ps[0] = PointGFp(curve); Ps[1] = point; for(size_t i = 2; i != Ps.size(); ++i) { Ps[i] = Ps[i-1]; Ps[i].add(point, ws); } PointGFp H(curve); // create as zero size_t bits_left = scalar_bits; while(bits_left >= window_size) { for(size_t i = 0; i != window_size; ++i) H.mult2(ws); const u32bit nibble = scalar.get_substring(bits_left - window_size, window_size); H.add(Ps[nibble], ws); bits_left -= window_size; } while(bits_left) { H.mult2(ws); if(scalar.get_bit(bits_left-1)) H.add(point, ws); --bits_left; } if(scalar.is_negative()) H.negate(); return H; #endif }
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; }