You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
104 lines
3.0 KiB
104 lines
3.0 KiB
2 years ago
|
package main
|
||
|
|
||
|
type WCurve struct {
|
||
|
p, r, a, b, h bigint
|
||
|
g *JacobiPoint
|
||
|
montA, conversionFromM bigint
|
||
|
conversion bigint
|
||
|
}
|
||
|
|
||
|
func NewWCurve() *WCurve {
|
||
|
curve := WCurve{}
|
||
|
|
||
|
curve.p = NewBigintFromString("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed", 16)
|
||
|
curve.r = NewBigintFromString("1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed", 16)
|
||
|
curve.montA = NewBigintFromString("486662", 10)
|
||
|
curve.a = NewBigintFromString("2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa984914a144", 16)
|
||
|
curve.b = NewBigintFromString("7b425ed097b425ed097b425ed097b425ed097b425ed097b4260b5e9c7710c864", 16)
|
||
|
curve.h = NewBigintFromString("8", 10)
|
||
|
|
||
|
curve.conversionFromM = curve.montA.Mul(modinv(NewBigint(3), curve.p)).Mod(curve.p)
|
||
|
curve.conversion = curve.p.Sub(curve.montA.Mul(modinv(NewBigint(3), curve.p))).Mod(curve.p)
|
||
|
curve.g = curve.liftX(NewBigint(9), false)
|
||
|
return &curve
|
||
|
}
|
||
|
|
||
|
func (curve *WCurve) Eq(other *WCurve) bool {
|
||
|
return curve.p.Eq(other.p) &&
|
||
|
curve.a.Mod(curve.p).Eq(other.a.Mod(curve.p)) &&
|
||
|
curve.b.Mod(curve.p).Eq(other.b.Mod(curve.p))
|
||
|
}
|
||
|
|
||
|
func (curve *WCurve) containsPoint(x, y bigint) bool {
|
||
|
p1 := x.Mul(x).Add(curve.a).Mul(x).Add(curve.b)
|
||
|
return y.Mul(y).Sub(p1).Mod(curve.p).EqInt(0)
|
||
|
}
|
||
|
|
||
|
func (curve *WCurve) genPublicKey(priv []byte) (pub []byte, parity bool) {
|
||
|
if len(priv) != 32 {
|
||
|
panic("invalid private key length")
|
||
|
}
|
||
|
|
||
|
p := NewBigintFromBytes(priv)
|
||
|
pt := curve.g.Mul(p)
|
||
|
return curve.toMontgomery(pt)
|
||
|
}
|
||
|
|
||
|
func (self *WCurve) toMontgomery(pt *JacobiPoint) (bytes []byte, parity bool) {
|
||
|
x := pt.AffineX().Add(self.conversion).Mod(self.p)
|
||
|
return x.ToBytes(32), pt.AffineY().AndInt(1).EqInt(1)
|
||
|
}
|
||
|
|
||
|
func (self *WCurve) liftX(x bigint, parity bool) *JacobiPoint {
|
||
|
x = x.Mod(self.p)
|
||
|
ySquared := x.Mul(x).Mul(x).Add(self.montA.Mul(x).Mul(x).Add(x)).Mod(self.p)
|
||
|
x = x.Add(self.conversionFromM).Mod(self.p)
|
||
|
ys0, ys1 := primeModSqrt(ySquared, self.p)
|
||
|
if ys0.Empty() && ys1.Empty() {
|
||
|
return nil
|
||
|
} else {
|
||
|
pt1 := NewJacobiPoint(self, x, ys0, NewBigint(1), self.r)
|
||
|
pt2 := NewJacobiPoint(self, x, ys1, NewBigint(1), self.r)
|
||
|
|
||
|
if pt1.AffineY().AndInt(1).EqInt(1) && parity {
|
||
|
return pt1
|
||
|
} else if pt2.AffineY().AndInt(1).EqInt(1) && parity {
|
||
|
return pt2
|
||
|
} else if pt1.AffineY().AndInt(1).EqInt(0) && !parity {
|
||
|
return pt1
|
||
|
} else {
|
||
|
return pt2
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (self *WCurve) redp1(bytes []byte, parity bool) *JacobiPoint {
|
||
|
x := getSHA2Digest(bytes)
|
||
|
for {
|
||
|
x2 := getSHA2Digest(x)
|
||
|
pt := self.liftX(NewBigintFromBytes(x2), parity)
|
||
|
if pt == nil {
|
||
|
x = NewBigintFromBytes(x).AddInt(1).ToBytes(32)
|
||
|
} else {
|
||
|
return pt
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (self *WCurve) check(a *JacobiPoint) bool {
|
||
|
ax := a.AffineX()
|
||
|
ay := a.AffineY()
|
||
|
|
||
|
left := ay.Mul(ay).Mod(self.p)
|
||
|
right := ax.Mul(ax).Mul(ax).Add(self.a.Mul(ax)).Add(self.b).Mod(self.p)
|
||
|
return left.Eq(right)
|
||
|
}
|
||
|
|
||
|
func (self *WCurve) multiplyByG(a bigint) *JacobiPoint {
|
||
|
return self.g.Mul(a)
|
||
|
}
|
||
|
|
||
|
func (self *WCurve) finiteFieldValue(a bigint) bigint {
|
||
|
return a.Mod(self.r)
|
||
|
}
|