Files
lattigo/utils/factorization/weierstrass.go
2023-03-21 10:44:10 +01:00

137 lines
3.0 KiB
Go

package factorization
import (
"math/big"
"github.com/tuneinsight/lattigo/v4/utils/sampling"
)
// Weierstrass is an elliptic curve y^2 = x^3 + ax + b mod N.
type Weierstrass struct {
A, B, N *big.Int
}
// Point represents an elliptic curve point in standard coordinates.
type Point struct {
X, Y *big.Int
}
// Add adds two Weierstrass points together with respect
// to the underlying Weierstrass curve.
// This method does not check if the points lie on
// the underlying curve.
func (w *Weierstrass) Add(P, Q Point) Point {
tmp := new(big.Int)
xR, yR := new(big.Int), new(big.Int)
if P.X.Cmp(tmp.SetUint64(0)) == 0 && P.Y.Cmp(tmp.SetUint64(1)) == 0 {
return Point{xR.Set(Q.X), yR.Set(Q.Y)}
}
if Q.X.Cmp(tmp.SetUint64(0)) == 0 && Q.Y.Cmp(tmp.SetUint64(1)) == 0 {
return Point{xR.Set(P.X), yR.Set(P.Y)}
}
xP, yP := P.X, P.Y
xQ, yQ := Q.X, Q.Y
N := w.N
if xP.Cmp(xQ) == 0 && yP.Cmp(new(big.Int).Sub(N, yQ)) == 0 {
return Point{xR.SetUint64(0), yR.SetUint64(0)}
}
S := new(big.Int) // slope
if xP != xQ {
// S = (yQ-yP)/(xQ-xP)
S.Sub(yQ, yP)
tmp.Sub(xQ, xP)
tmp.ModInverse(tmp, N)
S.Mul(S, tmp)
S.Mod(S, N)
} else {
// S = (3*(xP^2) + a)/(2*yP)
S.Mul(xP, xP)
S.Mod(S, N)
S.Mul(S, new(big.Int).SetUint64(3))
S.Add(S, w.A)
S.Mod(S, N)
tmp.Add(yP, yP)
tmp.ModInverse(tmp, N)
S.Mul(S, tmp)
S.Mod(S, N)
}
// s^2 - xP - xQ
xR.Mul(S, S)
xR.Mod(xR, N)
xR.Sub(xR, xP)
xR.Sub(xR, xQ)
xR.Mod(xR, N)
// s*(xP-xR)-yP
yR.Sub(xP, xR)
yR.Mul(yR, S)
yR.Mod(yR, N)
yR.Sub(yR, yP)
yR.Mod(yR, N)
return Point{X: xR, Y: yR}
}
// NewRandomWeierstrassCurve generates a new random Weierstrass curve modulo N,
// along with a random point that lies on the curve.
func NewRandomWeierstrassCurve(N *big.Int) (Weierstrass, Point) {
var A, B, xG, yG *big.Int
for {
// Select random values for A, xG and yG
A = sampling.RandInt(N)
xG = sampling.RandInt(N)
yG = sampling.RandInt(N)
// Deduces B from Y^2 = X^3 + A * X + B evaluated at point (xG, yG)
yGpow2 := new(big.Int).Mul(yG, yG)
yGpow2.Mod(yGpow2, N)
xGpow3 := new(big.Int).Mul(xG, xG)
xGpow3.Mod(xGpow3, N)
xGpow3.Sub(xGpow3, A)
xGpow3.Mul(xGpow3, xG)
xGpow3.Mod(xGpow3, N)
B = new(big.Int).Sub(yGpow2, xGpow3) // B = yG^2 - xG*(xG^2 - A)
B.Mod(B, N)
// Checks that 4A^3 + 27B^2 != 0
fourACube := new(big.Int).Add(A, A)
fourACube.Mul(fourACube, fourACube)
fourACube.Mod(fourACube, N)
fourACube.Mul(fourACube, A)
twentySevenBSquare := new(big.Int).Mul(B, B)
twentySevenBSquare.Mod(twentySevenBSquare, N)
twentySevenBSquare.Mul(twentySevenBSquare, new(big.Int).SetUint64(27))
twentySevenBSquare.Mod(twentySevenBSquare, N)
jInvariantQuotient := new(big.Int).Add(fourACube, twentySevenBSquare)
jInvariantQuotient.Mod(jInvariantQuotient, N)
if jInvariantQuotient.Cmp(new(big.Int).SetUint64(0)) != 0 && new(big.Int).GCD(nil, nil, N, jInvariantQuotient).Cmp(new(big.Int).SetUint64(1)) == 0 {
return Weierstrass{
A: A,
B: B,
N: N,
}, Point{X: xG, Y: yG}
}
}
}