//https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates#Mixed_Addition_(with_affine_point)_(8M_+_3S) //U1 = X1 [*Z2^2] //U2 = X2*Z1^2 //S1 = Y1 [*Z2^3] //S2 = Y2*Z1^3 //if (U1 == U2) // if (S1 != S2) // return POINT_AT_INFINITY // else // return POINT_DOUBLE(X1, Y1, Z1) //H = U2 - U1 //R = S2 - S1 //X3 = R^2 - H^3 - 2*U1*H^2 //Y3 = R*(U1*H^2 - X3) - S1*H^3 //Z3 = H*Z1*Z2 //return (X3, Y3, Z3) //http://www.hyperelliptic.org/EFD/oldefd/jacobian.html#mADD //Z2 = [p.Z]^2 //S1 = [q.X] * Z2 - [p.X] //R1 = [+/-q.Y] * [p.Z] * Z2 - [p.Y] //S2 = S1^2 //Z3 = ([p.Z]+S1)^2 - S2 - Z2 //S2 *= 4 //S1 *= S2 //R1 = 2*R1 //Y3 = [p.X]*S2 //X3 = R1^2-S1-2*Y3 //Y3 = R1*(Y3-X3)-2*[p.y]*S1 public void Add(ref JacobianECPoint p, OwnECPoint q, bool subtract = false) { //Mixed addition returns p + q in "7M + 4S" if (p.IsInfinity || q.IsInfinity) { if (!q.IsInfinity) { p.SetFrom(q.X, q.Y, One, q.IsInfinity); if (subtract) { SubtractModP(P, p.Y, p.Y); } } return; } Let(Z2, p.Z); SquareModP(Z2); //Z2 = [p.Z]^2 Let(S1, q.X); MultiplyModP(S1, Z2); SubModP(S1, p.X); //S1 = [q.X] * Z2 - [p.X] Let(R1, q.Y); if (subtract) { SubtractModP(P, R1, R1); } MultiplyModP(R1, p.Z); MultiplyModP(R1, Z2); SubModP(R1, p.Y); //R1 = [+/-q.Y] * [p.Z] * Z2 - [p.Y] if (IsZero(S1)) { if (IsZero(R1)) { //now: p == q GetDouble(ref p); return; } p.SetInfinity(); return; } Let(S2, S1); SquareModP(S2); //S2 = S1^2 Let(Z3, p.Z); AddModP(Z3, S1); SquareModP(Z3); SubModP(Z3, S2); SubModP(Z3, Z2); //Z3 = ([p.Z]+S1)^2 - S2 - Z2 AddScaledModP(S2, S2, 3); //S2 *= 4 MultiplyModP(S1, S2); //S1 *= S2 AddModP(R1, R1); //R1 = 2*R1 Let(y1, p.X); MultiplyModP(y1, S2); //Y3 = [p.X]*S2 Let(x1, R1); SquareModP(x1); SubModP(x1, S1); SubScaledModP(x1, y1, 2); //X3 = R1^2-S1-2*Y3 MultiplyModP(S1, p.Y); SubModP(y1, x1); MultiplyModP(y1, R1); SubScaledModP(y1, S1, 2); //Y3 = R1*(Y3-X3)-2*[p.y]*S1 p.SetFrom(x1, y1, Z3, false); }
public void GetDouble(ref JacobianECPoint p) { //return: 2 * p in "3M + 4S" for a = 0 and "3M + 5S" for a = -3. if (p.IsInfinity) { return; } if (IsZero(p.Y)) { p.SetInfinity(); return; } if (AIsZero) { //https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates //if (Y == 0) // return POINT_AT_INFINITY //S = 4 * X * Y^2 //M = 3*X^2 [+ a* Z^4] //X' = M^2 - 2*S //Y' = M*(S - X') - 8*Y^4 //Z' = 2*Y*Z = (Y+Z)^2 - Y^2 - Z^2 //return (X', Y', Z') Let(R1, p.Y); SquareModP(R1); AddModP(R1, R1); //R1 = 2 * Y^2 Let(Z3, R1); SquareModP(Z3); //Z3 = 4 * Y^4 Let(S1, p.X); MultiplyModP(S1, R1); AddModP(S1, S1); //S1 = S = 4 * X * Y^2 Let(S2, p.X); SquareModP(S2); AddScaledModP(S2, S2, 2); //S2 = M = 3*X^2 [+ a* Z^4] because a == 0. Let(x1, S2); SquareModP(x1); SubScaledModP(x1, S1, 2); //X' = M^2 - 2*S Let(y1, S1); SubModP(y1, x1); MultiplyModP(y1, S2); SubScaledModP(y1, Z3, 2); //Y' = M*(S - X') - 8*Y^4 Let(Z3, p.Y); AddModP(Z3, Z3); MultiplyModP(Z3, p.Z); //Z' = 2*Y*Z p.SetFrom(x1, y1, Z3, false); } else if (AIsMinus3) { //http://www.hyperelliptic.org/EFD/oldefd/jacobian.html#a3DBL //delta:=Z1^2; //gamma:=Y1^2; //beta:=4*X1*gamma; //alpha:=3*(X1-delta)*(X1+delta); //X3:=alpha^2-2*beta; //Z3:=(Y1+Z1)^2-gamma-delta; //Y3:=alpha*(beta-X3)-8*gamma^2; Let(Z2, p.Z); SquareModP(Z2); //Z2:= delta:=Z1^2; Let(y1, p.Y); SquareModP(y1); //y1:= gamma:=Y1^2; Let(R1, p.X); MultiplyModP(R1, y1); AddScaledModP(R1, R1, 3); //R1:= beta:=4*X1*gamma; SubtractModP(p.X, Z2, S1); AdditionModP(p.X, Z2, S2); MultiplyModP(S1, S2); AddScaledModP(S1, S1, 2); //S1:= alpha:=3*(X1-delta)*(X1+delta) because a == -3 AddModP(Z2, y1); //delta = delta + gamma Let(x1, S1); SquareModP(x1); SubScaledModP(x1, R1, 2); //X3:= alpha^2-2*beta; Let(Z3, p.Y); AddModP(Z3, p.Z); SquareModP(Z3); SubModP(Z3, Z2); //Z3 = (Y1+Z1)^2-delta SubModP(R1, x1); MultiplyModP(R1, S1); SquareModP(y1); SubScaledModP(R1, y1, 8); //Y3 = alpha*(beta-X3)-8*gamma^2 p.SetFrom(x1, R1, Z3, false); } else { throw new NotImplementedException(); } }