From a03605c57f3b9058f822e35d45a9b6e53653e341 Mon Sep 17 00:00:00 2001 From: MITSUNARI Shigeo Date: Thu, 9 Apr 2020 14:21:20 +0900 Subject: [PATCH] mov ec operation to global --- include/mcl/ec.hpp | 754 ++++++++++++++++++++++++--------------------- 1 file changed, 403 insertions(+), 351 deletions(-) diff --git a/include/mcl/ec.hpp b/include/mcl/ec.hpp index ce63053..31c4c96 100644 --- a/include/mcl/ec.hpp +++ b/include/mcl/ec.hpp @@ -43,32 +43,38 @@ enum Mode { Affine }; +enum ModeCoeffA { + zero, + minus3, + generic +}; + namespace local { // x is negative <=> x < half(:=(p+1)/2) <=> a = 1 -template -bool get_a_flag(const Fp& x) +template +bool get_a_flag(const F& x) { return x.isNegative(); } // Im(x) is negative <=> Im(x) < half(:=(p+1)/2) <=> a = 1 -template -bool get_a_flag(const mcl::Fp2T& x) +template +bool get_a_flag(const mcl::Fp2T& x) { return get_a_flag(x.b); // x = a + bi } } // mcl::ec::local -template -void normalizeJacobi(T& x, T& y, T& z) +template +void normalizeJacobi(F& x, F& y, F& z) { assert(!z.isZero()); - T rz2; - T::inv(z, z); - T::sqr(rz2, z); + F rz2; + F::inv(z, z); + F::sqr(rz2, z); x *= rz2; y *= rz2; y *= z; @@ -76,15 +82,15 @@ void normalizeJacobi(T& x, T& y, T& z) } // Y^2 == X(X^2 + aZ^4) + bZ^6 -template -bool isValidJacobi(const T& a, const T& b, const T& x, const T& y, const T& z) +template +bool isValidJacobi(const F& x, const F& y, const F& z, const F& a, const F& b) { - T y2, x2, z2, z4, t; - T::sqr(x2, x); - T::sqr(y2, y); - T::sqr(z2, z); - T::sqr(z4, z2); - T::mul(t, z4, a); + F y2, x2, z2, z4, t; + F::sqr(x2, x); + F::sqr(y2, y); + F::sqr(z2, z); + F::sqr(z4, z2); + F::mul(t, z4, a); t += x2; t *= x; z4 *= z2; @@ -93,25 +99,176 @@ bool isValidJacobi(const T& a, const T& b, const T& x, const T& y, const T& z) return y2 == t; } -template -void normalizeProj(T& x, T& y, T& z) +/* + |a=0|-3| generic + sqr| 4| 6| 6 + mul| 3| 3| 4 + add| 12|13|13 +*/ +template +void dblJacobi(E& R, const E& P, int specialA, const typename E::Fp& a) +{ + typedef typename E::Fp F; + if (P.isZero()) { + R.clear(); + return; + } + F S, M, t, y2; + F::sqr(y2, P.y); + F::mul(S, P.x, y2); + const bool isPzOne = P.z.isOne(); + S += S; + S += S; + F::sqr(M, P.x); + switch (specialA) { + case zero: + F::add(t, M, M); + M += t; + break; + case minus3: + if (isPzOne) { + M -= P.z; + } else { + F::sqr(t, P.z); + F::sqr(t, t); + M -= t; + } + F::add(t, M, M); + M += t; + break; + case generic: + default: + if (isPzOne) { + t = a; + } else { + F::sqr(t, P.z); + F::sqr(t, t); + t *= a; + } + t += M; + M += M; + M += t; + break; + } + F::sqr(R.x, M); + R.x -= S; + R.x -= S; + if (isPzOne) { + R.z = P.y; + } else { + F::mul(R.z, P.y, P.z); + } + R.z += R.z; + F::sqr(y2, y2); + y2 += y2; + y2 += y2; + y2 += y2; + F::sub(R.y, S, R.x); + R.y *= M; + R.y -= y2; +} + +/* + sqr| 4 + mul| 12 + add| 7 +*/ +template +void addJacobi(E& R, const E& P, const E& Q, int specialA, const typename E::Fp& a) +{ + typedef typename E::Fp F; + if (P.isZero()) { R = Q; return; } + if (Q.isZero()) { R = P; return; } + bool isPzOne = P.z.isOne(); + bool isQzOne = Q.z.isOne(); + F r, U1, S1, H, H3; + if (isPzOne) { + // r = 1; + } else { + F::sqr(r, P.z); + } + if (isQzOne) { + U1 = P.x; + if (isPzOne) { + H = Q.x; + } else { + F::mul(H, Q.x, r); + } + H -= U1; + S1 = P.y; + } else { + F::sqr(S1, Q.z); + F::mul(U1, P.x, S1); + if (isPzOne) { + H = Q.x; + } else { + F::mul(H, Q.x, r); + } + H -= U1; + S1 *= Q.z; + S1 *= P.y; + } + if (isPzOne) { + r = Q.y; + } else { + r *= P.z; + r *= Q.y; + } + r -= S1; + if (H.isZero()) { + if (r.isZero()) { + ec::dblJacobi(R, P, specialA, a); + } else { + R.clear(); + } + return; + } + if (isPzOne) { + if (isQzOne) { + R.z = H; + } else { + F::mul(R.z, H, Q.z); + } + } else { + if (isQzOne) { + F::mul(R.z, P.z, H); + } else { + F::mul(R.z, P.z, Q.z); + R.z *= H; + } + } + F::sqr(H3, H); // H^2 + F::sqr(R.y, r); // r^2 + U1 *= H3; // U1 H^2 + H3 *= H; // H^3 + R.y -= U1; + R.y -= U1; + F::sub(R.x, R.y, H3); + U1 -= R.x; + U1 *= r; + H3 *= S1; + F::sub(R.y, U1, H3); +} + +template +void normalizeProj(F& x, F& y, F& z) { assert(!z.isZero()); - T::inv(z, z); + F::inv(z, z); x *= z; y *= z; z = 1; } // (Y^2 - bZ^2)Z = X(X^2 + aZ^2) -template -bool isValidProj(const T& a, const T& b, const T& x, const T& y, const T& z) +template +bool isValidProj(const F& x, const F& y, const F& z, const F& a, const F& b) { - T y2, x2, z2, t; - T::sqr(x2, x); - T::sqr(y2, y); - T::sqr(z2, z); - T::mul(t, a, z2); + F y2, x2, z2, t; + F::sqr(x2, x); + F::sqr(y2, y); + F::sqr(z2, z); + F::mul(t, a, z2); t += x2; t *= x; z2 *= b; @@ -120,19 +277,220 @@ bool isValidProj(const T& a, const T& b, const T& x, const T& y, const T& z) return y2 == t; } +/* + |a=0|-3| generic + sqr| 4| 5| 5 + mul| 8| 8| 9 + add| 11|12|12 +*/ +template +void dblProj(E& R, const E& P, int specialA, const typename E::Fp& a) +{ + typedef typename E::Fp F; + if (P.isZero()) { + R.clear(); + return; + } + const bool isPzOne = P.z.isOne(); + F w, t, h; + switch (specialA) { + case zero: + F::sqr(w, P.x); + F::add(t, w, w); + w += t; + break; + case minus3: + F::sqr(w, P.x); + if (isPzOne) { + w -= P.z; + } else { + F::sqr(t, P.z); + w -= t; + } + F::add(t, w, w); + w += t; + break; + case generic: + default: + if (isPzOne) { + w = a; + } else { + F::sqr(w, P.z); + w *= a; + } + F::sqr(t, P.x); + w += t; + w += t; + w += t; // w = a z^2 + 3x^2 + break; + } + if (isPzOne) { + R.z = P.y; + } else { + F::mul(R.z, P.y, P.z); // s = yz + } + F::mul(t, R.z, P.x); + t *= P.y; // xys + t += t; + t += t; // 4(xys) ; 4B + F::sqr(h, w); + h -= t; + h -= t; // w^2 - 8B + F::mul(R.x, h, R.z); + t -= h; // h is free + t *= w; + F::sqr(w, P.y); + R.x += R.x; + R.z += R.z; + F::sqr(h, R.z); + w *= h; + R.z *= h; + F::sub(R.y, t, w); + R.y -= w; +} + +/* + sqr| 2 + mul| 12 + add| 7 +*/ +template +void addProj(E& R, const E& P, const E& Q, int specialA, const typename E::Fp& a) +{ + typedef typename E::Fp F; + if (P.isZero()) { R = Q; return; } + if (Q.isZero()) { R = P; return; } + bool isPzOne = P.z.isOne(); + bool isQzOne = Q.z.isOne(); + F r, PyQz, v, A, vv; + if (isQzOne) { + r = P.x; + PyQz = P.y; + } else { + F::mul(r, P.x, Q.z); + F::mul(PyQz, P.y, Q.z); + } + if (isPzOne) { + A = Q.y; + v = Q.x; + } else { + F::mul(A, Q.y, P.z); + F::mul(v, Q.x, P.z); + } + v -= r; + if (v.isZero()) { + if (A == PyQz) { + dblProj(R, P, specialA, a); + } else { + R.clear(); + } + return; + } + F::sub(R.y, A, PyQz); + F::sqr(A, R.y); + F::sqr(vv, v); + r *= vv; + vv *= v; + if (isQzOne) { + R.z = P.z; + } else { + if (isPzOne) { + R.z = Q.z; + } else { + F::mul(R.z, P.z, Q.z); + } + } + // R.z = 1 if isPzOne && isQzOne + if (isPzOne && isQzOne) { + R.z = vv; + } else { + A *= R.z; + R.z *= vv; + } + A -= vv; + vv *= PyQz; + A -= r; + A -= r; + F::mul(R.x, v, A); + r -= A; + R.y *= r; + R.y -= vv; +} + // y^2 == (x^2 + a)x + b -template -bool isValidAffine(const T& a, const T& b, const T& x, const T& y) +template +bool isValidAffine(const F& x, const F& y, const F& a, const F& b) { - T y2, t; - T::sqr(y2, y); - T::sqr(t, x); + F y2, t; + F::sqr(y2, y); + F::sqr(t, x); t += a; t *= x; t += b; return y2 == t; } +// y^2 = x^3 + ax + b +template +static inline void dblAffine(E& R, const E& P, const typename E::Fp& a) +{ + typedef typename E::Fp F; + if (P.isZero()) { + R.clear(); + return; + } + if (P.y.isZero()) { + R.clear(); + return; + } + F t, s; + F::sqr(t, P.x); + F::add(s, t, t); + t += s; + t += a; + F::add(s, P.y, P.y); + t /= s; + F::sqr(s, t); + s -= P.x; + F x3; + F::sub(x3, s, P.x); + F::sub(s, P.x, x3); + s *= t; + F::sub(R.y, s, P.y); + R.x = x3; + R.z = 1; +} + +template +void addAffine(E& R, const E& P, const E& Q, const typename E::Fp& a) +{ + typedef typename E::Fp F; + if (P.isZero()) { R = Q; return; } + if (Q.isZero()) { R = P; return; } + F t; + F::sub(t, Q.x, P.x); + if (t.isZero()) { + if (P.y == Q.y) { + dblAffine(R, P, a); + } else { + R.clear(); + } + return; + } + F s; + F::sub(s, Q.y, P.y); + F::div(t, s, t); + R.z = 1; + F x3; + F::sqr(x3, t); + x3 -= P.x; + x3 -= Q.x; + F::sub(s, P.x, x3); + s *= t; + F::sub(R.y, s, P.y); + R.x = x3; +} + } // mcl::ec /* @@ -142,11 +500,6 @@ bool isValidAffine(const T& a, const T& b, const T& x, const T& y) */ template class EcT : public fp::Serializable > { - enum { - zero, - minus3, - generic - }; public: typedef _Fp Fp; typedef _Fp BaseFp; @@ -185,15 +538,15 @@ private: } bool isValidJacobi() const { - return ec::isValidJacobi(a_, b_, x, y, z); + return ec::isValidJacobi(x, y, z, a_, b_); } bool isValidProj() const { - return ec::isValidProj(a_, b_, x, y, z); + return ec::isValidProj(x, y, z, a_, b_); } bool isValidAffine() const { - return ec::isValidAffine(a_, b_, x, y); + return ec::isValidAffine(x, y, a_, b_); } public: void normalize() @@ -218,11 +571,11 @@ public: a_ = a; b_ = b; if (a_.isZero()) { - specialA_ = zero; + specialA_ = ec::zero; } else if (a_ == -3) { - specialA_ = minus3; + specialA_ = ec::minus3; } else { - specialA_ = generic; + specialA_ = ec::generic; } ioMode_ = 0; verifyOrder_ = false; @@ -302,331 +655,30 @@ public: y.clear(); z.clear(); } - static inline void dblNoVerifyInfJacobi(EcT& R, const EcT& P) - { - Fp S, M, t, y2; - Fp::sqr(y2, P.y); - Fp::mul(S, P.x, y2); - const bool isPzOne = P.z.isOne(); - S += S; - S += S; - Fp::sqr(M, P.x); - switch (specialA_) { - case zero: - Fp::add(t, M, M); - M += t; - break; - case minus3: - if (isPzOne) { - M -= P.z; - } else { - Fp::sqr(t, P.z); - Fp::sqr(t, t); - M -= t; - } - Fp::add(t, M, M); - M += t; - break; - case generic: - default: - if (isPzOne) { - t = a_; - } else { - Fp::sqr(t, P.z); - Fp::sqr(t, t); - t *= a_; - } - t += M; - M += M; - M += t; - break; - } - Fp::sqr(R.x, M); - R.x -= S; - R.x -= S; - if (isPzOne) { - R.z = P.y; - } else { - Fp::mul(R.z, P.y, P.z); - } - R.z += R.z; - Fp::sqr(y2, y2); - y2 += y2; - y2 += y2; - y2 += y2; - Fp::sub(R.y, S, R.x); - R.y *= M; - R.y -= y2; - } - static inline void dblNoVerifyInfProj(EcT& R, const EcT& P) - { - const bool isPzOne = P.z.isOne(); - Fp w, t, h; - switch (specialA_) { - case zero: - Fp::sqr(w, P.x); - Fp::add(t, w, w); - w += t; - break; - case minus3: - Fp::sqr(w, P.x); - if (isPzOne) { - w -= P.z; - } else { - Fp::sqr(t, P.z); - w -= t; - } - Fp::add(t, w, w); - w += t; - break; - case generic: - default: - if (isPzOne) { - w = a_; - } else { - Fp::sqr(w, P.z); - w *= a_; - } - Fp::sqr(t, P.x); - w += t; - w += t; - w += t; // w = a z^2 + 3x^2 - break; - } - if (isPzOne) { - R.z = P.y; - } else { - Fp::mul(R.z, P.y, P.z); // s = yz - } - Fp::mul(t, R.z, P.x); - t *= P.y; // xys - t += t; - t += t; // 4(xys) ; 4B - Fp::sqr(h, w); - h -= t; - h -= t; // w^2 - 8B - Fp::mul(R.x, h, R.z); - t -= h; // h is free - t *= w; - Fp::sqr(w, P.y); - R.x += R.x; - R.z += R.z; - Fp::sqr(h, R.z); - w *= h; - R.z *= h; - Fp::sub(R.y, t, w); - R.y -= w; - } - static inline void dblNoVerifyInfAffine(EcT& R, const EcT& P) - { - Fp t, s; - Fp::sqr(t, P.x); - Fp::add(s, t, t); - t += s; - t += a_; - Fp::add(s, P.y, P.y); - t /= s; - Fp::sqr(s, t); - s -= P.x; - Fp x3; - Fp::sub(x3, s, P.x); - Fp::sub(s, P.x, x3); - s *= t; - Fp::sub(R.y, s, P.y); - R.x = x3; - R.z = 1; - } - static inline void dblNoVerifyInf(EcT& R, const EcT& P) + static inline void dbl(EcT& R, const EcT& P) { switch (mode_) { case ec::Jacobi: - dblNoVerifyInfJacobi(R, P); + ec::dblJacobi(R, P, specialA_, a_); break; case ec::Proj: - dblNoVerifyInfProj(R, P); + ec::dblProj(R, P, specialA_, a_); break; case ec::Affine: - dblNoVerifyInfAffine(R, P); + ec::dblAffine(R, P, a_); break; } } - static inline void dbl(EcT& R, const EcT& P) - { - if (P.isZero()) { - R.clear(); - return; - } - dblNoVerifyInf(R, P); - } - static inline void addJacobi(EcT& R, const EcT& P, const EcT& Q, bool isPzOne, bool isQzOne) - { - Fp r, U1, S1, H, H3; - if (isPzOne) { - // r = 1; - } else { - Fp::sqr(r, P.z); - } - if (isQzOne) { - U1 = P.x; - if (isPzOne) { - H = Q.x; - } else { - Fp::mul(H, Q.x, r); - } - H -= U1; - S1 = P.y; - } else { - Fp::sqr(S1, Q.z); - Fp::mul(U1, P.x, S1); - if (isPzOne) { - H = Q.x; - } else { - Fp::mul(H, Q.x, r); - } - H -= U1; - S1 *= Q.z; - S1 *= P.y; - } - if (isPzOne) { - r = Q.y; - } else { - r *= P.z; - r *= Q.y; - } - r -= S1; - if (H.isZero()) { - if (r.isZero()) { - dblNoVerifyInf(R, P); - } else { - R.clear(); - } - return; - } - if (isPzOne) { - if (isQzOne) { - R.z = H; - } else { - Fp::mul(R.z, H, Q.z); - } - } else { - if (isQzOne) { - Fp::mul(R.z, P.z, H); - } else { - Fp::mul(R.z, P.z, Q.z); - R.z *= H; - } - } - Fp::sqr(H3, H); // H^2 - Fp::sqr(R.y, r); // r^2 - U1 *= H3; // U1 H^2 - H3 *= H; // H^3 - R.y -= U1; - R.y -= U1; - Fp::sub(R.x, R.y, H3); - U1 -= R.x; - U1 *= r; - H3 *= S1; - Fp::sub(R.y, U1, H3); - } - static inline void addProj(EcT& R, const EcT& P, const EcT& Q, bool isPzOne, bool isQzOne) - { - Fp r, PyQz, v, A, vv; - if (isQzOne) { - r = P.x; - PyQz = P.y; - } else { - Fp::mul(r, P.x, Q.z); - Fp::mul(PyQz, P.y, Q.z); - } - if (isPzOne) { - A = Q.y; - v = Q.x; - } else { - Fp::mul(A, Q.y, P.z); - Fp::mul(v, Q.x, P.z); - } - v -= r; - if (v.isZero()) { - if (A == PyQz) { - dblNoVerifyInf(R, P); - } else { - R.clear(); - } - return; - } - Fp::sub(R.y, A, PyQz); - Fp::sqr(A, R.y); - Fp::sqr(vv, v); - r *= vv; - vv *= v; - if (isQzOne) { - R.z = P.z; - } else { - if (isPzOne) { - R.z = Q.z; - } else { - Fp::mul(R.z, P.z, Q.z); - } - } - // R.z = 1 if isPzOne && isQzOne - if (isPzOne && isQzOne) { - R.z = vv; - } else { - A *= R.z; - R.z *= vv; - } - A -= vv; - vv *= PyQz; - A -= r; - A -= r; - Fp::mul(R.x, v, A); - r -= A; - R.y *= r; - R.y -= vv; - } - static inline void addAffine(EcT& R, const EcT& P, const EcT& Q) - { - Fp t; - Fp::sub(t, Q.x, P.x); - if (t.isZero()) { - if (P.y == Q.y) { - dblNoVerifyInf(R, P); - } else { - R.clear(); - } - return; - } - Fp s; - Fp::sub(s, Q.y, P.y); - Fp::div(t, s, t); - R.z = 1; - Fp x3; - Fp::sqr(x3, t); - x3 -= P.x; - x3 -= Q.x; - Fp::sub(s, P.x, x3); - s *= t; - Fp::sub(R.y, s, P.y); - R.x = x3; - } static inline void add(EcT& R, const EcT& P, const EcT& Q) { - if (P.isZero()) { R = Q; return; } - if (Q.isZero()) { R = P; return; } - if (&P == &Q) { - dblNoVerifyInf(R, P); - return; - } - bool isPzOne = P.z.isOne(); - bool isQzOne = Q.z.isOne(); switch (mode_) { case ec::Jacobi: - addJacobi(R, P, Q, isPzOne, isQzOne); + ec::addJacobi(R, P, Q, specialA_, a_); break; case ec::Proj: - addProj(R, P, Q, isPzOne, isQzOne); + ec::addProj(R, P, Q, specialA_, a_); break; case ec::Affine: - addAffine(R, P, Q); + ec::addAffine(R, P, Q, a_); break; } }