1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
package ed25519group
import (
"fmt"
"math/big"
)
// AffinePoint is original representation of points on twisted edwards curve
type AffinePoint struct {
X, Y *big.Int
}
// NotOnCurve is error emmited when the point got is not on the curve
type NotOnCurve struct{}
func (n *NotOnCurve) Error() string {
return "decoded point is not on curve"
}
// NewAffinePoint creates new affine point with big integer's given in string
// format and of provided base.
func NewAffinePoint(x, y string, base int) AffinePoint {
X := new(big.Int)
Y := new(big.Int)
X.SetString(x, base)
Y.SetString(y, base)
return AffinePoint{X, Y}
}
func (a AffinePoint) String() string {
return fmt.Sprintf("X: %s\nY: %s\n", a.X, a.Y)
}
// ToExtended converts AffinePoint to ExtendedPoint representation
func (a *AffinePoint) ToExtended() ExtendedPoint {
X := new(big.Int)
Y := new(big.Int)
T := new(big.Int)
xy := new(big.Int)
X.Mod(a.X, Q)
Y.Mod(a.Y, Q)
Z := big.NewInt(1)
// T = x*y % Q
xy.Mul(a.X, a.Y)
T.Mod(xy, Q)
return ExtendedPoint{X, Y, Z, T}
}
// IsOnCurve returns true if the given point is on curve
func (a *AffinePoint) IsOnCurve() bool {
x, y := a.X, a.Y
var mxx, xx, yy, mxxpyy, dxxyy, xxyy, minusX big.Int
// -x
minusX.Neg(x)
// -x *x
mxx.Mul(&minusX, x)
// x*x
xx.Mul(x, x)
// y*y
yy.Mul(y, y)
// -x*x + y*y
mxxpyy.Add(&mxx, &yy)
// x^2*y^2
xxyy.Mul(&xx, &yy)
// dx^2y^2
dxxyy.Mul(D, &xxyy)
var equation big.Int
// -x^2 + y^2 - 1 - dx^2y^2
equation.Sub(mxxpyy.Sub(&mxxpyy, big.NewInt(1)), &dxxyy)
var result big.Int
result.Mod(&equation, Q)
// Point is on curve if -x^2 + y^2 - 1 - dx^2y^2 % Q == 0
if result.Cmp(big.NewInt(0)) == 0 {
return true
}
return false
}
// Compress encodes the Affine Point into 32 byte little-endian b255 is the sign
func (a *AffinePoint) Compress() []byte {
x, y := a.X, a.Y
result := new(big.Int)
if !IsEven(x) {
// We need y += 1 << 255
var lsh big.Int
lsh.Lsh(big.NewInt(1), 255)
result.Add(y, &lsh)
} else {
result = y
}
resultBytes := result.Bytes()
reverse(resultBytes)
return resultBytes
}
// Decompress reconstructs the AffinePoint from given 32 byte which is
// considered as Y co-ordinate compressed using Compress function above
func (a *AffinePoint) Decompress(s []byte) error {
var clamp, oneShift big.Int
// (1 << 255) - 1
oneShift.Lsh(big.NewInt(1), 255)
clamp.Sub(&oneShift, big.NewInt(1))
// TODO check if bytes is more than 32 then we should throw error
b := make([]byte, len(s))
copy(b, s)
// Reversing is not required?. If I reverse the test fails may be
// because big.Int represents alredy in big endian?.
reverse(b)
unclamped := new(big.Int)
x := new(big.Int)
y := new(big.Int)
unclamped.SetBytes(b)
y.And(unclamped, &clamp)
x = xrecover(y)
var isXEven big.Int
isXEven.And(x, big.NewInt(1))
unclamped.And(unclamped, &oneShift)
if isXEven.Cmp(unclamped) != 0 {
x.Sub(Q, x)
}
a.X = x
a.Y = y
if !a.IsOnCurve() {
return &NotOnCurve{}
}
return nil
}
|