mov ec operation to global

update-fork
MITSUNARI Shigeo 5 years ago
parent 88688c210c
commit a03605c57f
  1. 758
      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<class Fp>
bool get_a_flag(const Fp& x)
template<class F>
bool get_a_flag(const F& x)
{
return x.isNegative();
}
// Im(x) is negative <=> Im(x) < half(:=(p+1)/2) <=> a = 1
template<class Fp>
bool get_a_flag(const mcl::Fp2T<Fp>& x)
template<class F>
bool get_a_flag(const mcl::Fp2T<F>& x)
{
return get_a_flag(x.b); // x = a + bi
}
} // mcl::ec::local
template<class T>
void normalizeJacobi(T& x, T& y, T& z)
template<class F>
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<class T>
bool isValidJacobi(const T& a, const T& b, const T& x, const T& y, const T& z)
{
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);
template<class F>
bool isValidJacobi(const F& x, const F& y, const F& z, const F& a, const F& b)
{
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<class T>
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<class E>
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<class E>
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<class F>
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<class T>
bool isValidProj(const T& a, const T& b, const T& x, const T& y, const T& z)
{
T y2, x2, z2, t;
T::sqr(x2, x);
T::sqr(y2, y);
T::sqr(z2, z);
T::mul(t, a, z2);
template<class F>
bool isValidProj(const F& x, const F& y, const F& z, const F& a, const F& b)
{
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<class E>
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<class E>
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<class T>
bool isValidAffine(const T& a, const T& b, const T& x, const T& y)
template<class F>
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<class E>
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<class E>
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 _Fp>
class EcT : public fp::Serializable<EcT<_Fp> > {
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;
}
}

Loading…
Cancel
Save