7#ifndef BOTAN_PCURVES_ALGOS_H_
8#define BOTAN_PCURVES_ALGOS_H_
10#include <botan/types.h>
11#include <botan/internal/ct_utils.h>
25 { C::fe_invert2(fe) } -> std::same_as<typename C::FieldElement>;
37 return C::fe_invert2(fe) * fe;
50 { C::fe_sqrt(fe) } -> std::same_as<typename C::FieldElement>;
62 auto z = C::fe_sqrt(fe);
65 z.conditional_assign(!correct, C::FieldElement::zero());
76inline constexpr auto to_affine(
const typename C::ProjectivePoint& pt) {
81 const auto z2_inv = C::fe_invert2(pt.z());
82 const auto z3_inv = z2_inv.square() * pt.z();
83 return typename C::AffinePoint(pt.x() * z2_inv, pt.y() * z3_inv);
86 const auto z2_inv = z_inv.square();
87 const auto z3_inv = z_inv * z2_inv;
88 return typename C::AffinePoint(pt.x() * z2_inv, pt.y() * z3_inv);
98 return pt.x() * C::fe_invert2(pt.z());
101 const auto z2_inv = z_inv.square();
102 return pt.x() * z2_inv;
106template <
typename C,
bool VariableTime = false>
108 using AffinePoint =
typename C::AffinePoint;
110 const size_t N = projective.size();
111 std::vector<AffinePoint> affine;
116 for(
const auto& pt : projective) {
117 any_identity = any_identity || pt.is_identity();
126 if(N <= 2 || any_identity.
as_bool()) {
130 for(
size_t i = 0; i != N; ++i) {
134 std::vector<typename C::FieldElement> c;
144 c.push_back(projective[0].z());
145 for(
size_t i = 1; i != N; ++i) {
146 c.push_back(c[i - 1] * projective[i].z());
150 if constexpr(VariableTime) {
151 return c[N - 1].invert_vartime();
157 for(
size_t i = N - 1; i > 0; --i) {
158 const auto& p = projective[i];
160 const auto z_inv = s_inv * c[i - 1];
161 const auto z2_inv = z_inv.square();
162 const auto z3_inv = z_inv * z2_inv;
164 s_inv = s_inv * p.z();
166 affine.push_back(AffinePoint(p.x() * z2_inv, p.y() * z3_inv));
169 const auto z2_inv = s_inv.square();
170 const auto z3_inv = s_inv * z2_inv;
171 affine.push_back(AffinePoint(projective[0].x() * z2_inv, projective[0].y() * z3_inv));
172 std::reverse(affine.begin(), affine.end());
186template <
typename ProjectivePo
int,
typename FieldElement>
187inline constexpr ProjectivePoint
point_add(
const ProjectivePoint& a,
const ProjectivePoint& b) {
188 const auto a_is_identity = a.is_identity();
189 const auto b_is_identity = b.is_identity();
191 const auto Z1Z1 = a.z().square();
192 const auto Z2Z2 = b.z().square();
193 const auto U1 = a.x() * Z2Z2;
194 const auto U2 = b.x() * Z1Z1;
195 const auto S1 = a.y() * b.z() * Z2Z2;
196 const auto S2 = b.y() * a.z() * Z1Z1;
197 const auto H = U2 - U1;
198 const auto r = S2 - S1;
210 if((r.is_zero() && H.is_zero() && !(a_is_identity && b_is_identity)).as_bool()) {
214 const auto HH = H.square();
215 const auto HHH = H * HH;
216 const auto V = U1 * HH;
217 const auto t2 = r.square();
218 const auto t3 = V + V;
219 const auto t4 = t2 - HHH;
221 const auto t5 = V - X3;
222 const auto t6 = S1 * HHH;
223 const auto t7 = r * t5;
225 const auto t8 = b.z() * H;
226 auto Z3 = a.z() * t8;
229 FieldElement::conditional_assign(X3, Y3, Z3, a_is_identity, b.x(), b.y(), b.z());
232 FieldElement::conditional_assign(X3, Y3, Z3, b_is_identity, a.x(), a.y(), a.z());
234 return ProjectivePoint(X3, Y3, Z3);
237template <
typename ProjectivePo
int,
typename AffinePo
int,
typename FieldElement>
239 const AffinePoint& b,
240 const FieldElement& one) {
241 const auto a_is_identity = a.is_identity();
242 const auto b_is_identity = b.is_identity();
250 const auto Z1Z1 = a.z().square();
251 const auto U2 = b.x() * Z1Z1;
252 const auto S2 = b.y() * a.z() * Z1Z1;
253 const auto H = U2 - a.x();
254 const auto r = S2 - a.y();
266 if((r.is_zero() && H.is_zero() && !(a_is_identity && b_is_identity)).as_bool()) {
270 const auto HH = H.square();
271 const auto HHH = H * HH;
272 const auto V = a.x() * HH;
273 const auto t2 = r.square();
274 const auto t3 = V + V;
275 const auto t4 = t2 - HHH;
277 const auto t5 = V - X3;
278 const auto t6 = a.y() * HHH;
279 const auto t7 = r * t5;
284 FieldElement::conditional_assign(X3, Y3, Z3, a_is_identity, b.x(), b.y(), one);
287 FieldElement::conditional_assign(X3, Y3, Z3, b_is_identity, a.x(), a.y(), a.z());
289 return ProjectivePoint(X3, Y3, Z3);
292template <
typename ProjectivePo
int,
typename AffinePo
int,
typename FieldElement>
294 const AffinePoint& b,
296 const FieldElement& one) {
297 const auto a_is_identity = a.is_identity();
298 const auto b_is_identity = b.is_identity();
307 by.conditional_assign(sub, by.negate());
309 const auto Z1Z1 = a.z().square();
310 const auto U2 = b.x() * Z1Z1;
311 const auto S2 = by * a.z() * Z1Z1;
312 const auto H = U2 - a.x();
313 const auto r = S2 - a.y();
325 if((r.is_zero() && H.is_zero() && !(a_is_identity && b_is_identity)).as_bool()) {
329 const auto HH = H.square();
330 const auto HHH = H * HH;
331 const auto V = a.x() * HH;
332 const auto t2 = r.square();
333 const auto t3 = V + V;
334 const auto t4 = t2 - HHH;
336 const auto t5 = V - X3;
337 const auto t6 = a.y() * HHH;
338 const auto t7 = r * t5;
343 FieldElement::conditional_assign(X3, Y3, Z3, a_is_identity, b.x(), by, one);
346 FieldElement::conditional_assign(X3, Y3, Z3, b_is_identity, a.x(), a.y(), a.z());
348 return ProjectivePoint(X3, Y3, Z3);
361template <
typename ProjectivePo
int>
367 const auto z2 = pt.z().square();
368 const auto m = (pt.x() - z2).mul3() * (pt.x() + z2);
371 const auto y2 = pt.y().square();
372 const auto s = pt.x().mul4() * y2;
373 const auto nx = m.square() - s.mul2();
374 const auto ny = m * (s - nx) - y2.square().mul8();
375 const auto nz = pt.y().mul2() * pt.z();
377 return ProjectivePoint(nx, ny, nz);
380template <
typename ProjectivePo
int>
381inline constexpr ProjectivePoint
dbl_a_zero(
const ProjectivePoint& pt) {
384 const auto m = pt.x().square().mul3();
387 const auto y2 = pt.y().square();
388 const auto s = pt.x().mul4() * y2;
389 const auto nx = m.square() - s.mul2();
390 const auto ny = m * (s - nx) - y2.square().mul8();
391 const auto nz = pt.y().mul2() * pt.z();
393 return ProjectivePoint(nx, ny, nz);
396template <
typename ProjectivePo
int,
typename FieldElement>
397inline constexpr ProjectivePoint
dbl_generic(
const ProjectivePoint& pt,
const FieldElement& A) {
399 const auto z2 = pt.z().square();
400 const auto m = pt.x().square().mul3() + A * z2.square();
403 const auto y2 = pt.y().square();
404 const auto s = pt.x().mul4() * y2;
405 const auto nx = m.square() - s.mul2();
406 const auto ny = m * (s - nx) - y2.square().mul8();
407 const auto nz = pt.y().mul2() * pt.z();
409 return ProjectivePoint(nx, ny, nz);
431template <
typename ProjectivePo
int>
432inline constexpr ProjectivePoint
dbl_n_a_minus_3(
const ProjectivePoint& pt,
size_t n) {
434 auto ny = pt.y().mul2();
436 auto w = nz.square().square();
440 const auto ny2 = ny.square();
441 const auto ny4 = ny2.square();
442 const auto t1 = (nx.square() - w).mul3();
443 const auto t2 = nx * ny2;
444 nx = t1.square() - t2.mul2();
446 ny = t1 * (t2 - nx).mul2() - ny4;
453 return ProjectivePoint(nx, ny.div2(), nz);
456template <
typename ProjectivePo
int>
457inline constexpr ProjectivePoint
dbl_n_a_zero(
const ProjectivePoint& pt,
size_t n) {
459 auto ny = pt.y().mul2();
464 const auto ny2 = ny.square();
465 const auto ny4 = ny2.square();
466 const auto t1 = nx.square().mul3();
467 const auto t2 = nx * ny2;
468 nx = t1.square() - t2.mul2();
470 ny = t1 * (t2 - nx).mul2() - ny4;
473 return ProjectivePoint(nx, ny.div2(), nz);
476template <
typename ProjectivePo
int,
typename FieldElement>
477inline constexpr ProjectivePoint
dbl_n_generic(
const ProjectivePoint& pt,
const FieldElement& A,
size_t n) {
479 auto ny = pt.y().mul2();
481 auto w = nz.square().square() * A;
485 const auto ny2 = ny.square();
486 const auto ny4 = ny2.square();
487 const auto t1 = nx.square().mul3() + w;
488 const auto t2 = nx * ny2;
489 nx = t1.square() - t2.mul2();
491 ny = t1 * (t2 - nx).mul2() - ny4;
498 return ProjectivePoint(nx, ny.div2(), nz);
static constexpr Choice no()
constexpr bool as_bool() const
auto to_affine_x(const typename C::ProjectivePoint &pt)
constexpr CT::Option< typename C::FieldElement > sqrt_field_element(const typename C::FieldElement &fe)
constexpr ProjectivePoint dbl_n_generic(const ProjectivePoint &pt, const FieldElement &A, size_t n)
constexpr ProjectivePoint dbl_a_minus_3(const ProjectivePoint &pt)
constexpr ProjectivePoint dbl_n_a_zero(const ProjectivePoint &pt, size_t n)
auto to_affine_batch(std::span< const typename C::ProjectivePoint > projective)
constexpr ProjectivePoint dbl_a_zero(const ProjectivePoint &pt)
constexpr auto to_affine(const typename C::ProjectivePoint &pt)
constexpr ProjectivePoint point_add_mixed(const ProjectivePoint &a, const AffinePoint &b, const FieldElement &one)
constexpr ProjectivePoint point_add_or_sub_mixed(const ProjectivePoint &a, const AffinePoint &b, CT::Choice sub, const FieldElement &one)
constexpr auto invert_field_element(const typename C::FieldElement &fe)
constexpr ProjectivePoint dbl_n_a_minus_3(const ProjectivePoint &pt, size_t n)
constexpr ProjectivePoint dbl_generic(const ProjectivePoint &pt, const FieldElement &A)
constexpr ProjectivePoint point_add(const ProjectivePoint &a, const ProjectivePoint &b)