github.com/emmansun/gmsm@v0.29.1/sm9/bn256/params.go (about) 1 package bn256 2 3 import "math/big" 4 5 // CurveParams contains the parameters of an elliptic curve and also provides 6 // a generic, non-constant time implementation of Curve. 7 type CurveParams struct { 8 P *big.Int // the order of the underlying field 9 N *big.Int // the order of the base point 10 B *big.Int // the constant of the curve equation 11 Gx, Gy *big.Int // (x,y) of the base point 12 BitSize int // the size of the underlying field 13 Name string // the canonical name of the curve 14 } 15 16 func (curve *CurveParams) Params() *CurveParams { 17 return curve 18 } 19 20 // CurveParams operates, internally, on Jacobian coordinates. For a given 21 // (x, y) position on the curve, the Jacobian coordinates are (x1, y1, z1) 22 // where x = x1/z1² and y = y1/z1³. The greatest speedups come when the whole 23 // calculation can be performed within the transform (as in ScalarMult and 24 // ScalarBaseMult). But even for Add and Double, it's faster to apply and 25 // reverse the transform than to operate in affine coordinates. 26 27 // polynomial returns x³ + b. 28 func (curve *CurveParams) polynomial(x *big.Int) *big.Int { 29 x3 := new(big.Int).Mul(x, x) 30 x3.Mul(x3, x) 31 32 x3.Add(x3, curve.B) 33 x3.Mod(x3, curve.P) 34 35 return x3 36 } 37 38 func (curve *CurveParams) IsOnCurve(x, y *big.Int) bool { 39 if x.Sign() < 0 || x.Cmp(curve.P) >= 0 || 40 y.Sign() < 0 || y.Cmp(curve.P) >= 0 { 41 return false 42 } 43 44 // y² = x³ + b 45 y2 := new(big.Int).Mul(y, y) 46 y2.Mod(y2, curve.P) 47 48 return curve.polynomial(x).Cmp(y2) == 0 49 } 50 51 // zForAffine returns a Jacobian Z value for the affine point (x, y). If x and 52 // y are zero, it assumes that they represent the point at infinity because (0, 53 // 0) is not on the any of the curves handled here. 54 func zForAffine(x, y *big.Int) *big.Int { 55 z := new(big.Int) 56 if x.Sign() != 0 || y.Sign() != 0 { 57 z.SetInt64(1) 58 } 59 return z 60 } 61 62 // affineFromJacobian reverses the Jacobian transform. See the comment at the 63 // top of the file. If the point is ∞ it returns 0, 0. 64 func (curve *CurveParams) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) { 65 if z.Sign() == 0 { 66 return new(big.Int), new(big.Int) 67 } 68 69 zinv := new(big.Int).ModInverse(z, curve.P) 70 zinvsq := new(big.Int).Mul(zinv, zinv) 71 72 xOut = new(big.Int).Mul(x, zinvsq) 73 xOut.Mod(xOut, curve.P) 74 zinvsq.Mul(zinvsq, zinv) 75 yOut = new(big.Int).Mul(y, zinvsq) 76 yOut.Mod(yOut, curve.P) 77 return 78 } 79 80 func (curve *CurveParams) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { 81 z1 := zForAffine(x1, y1) 82 z2 := zForAffine(x2, y2) 83 return curve.affineFromJacobian(curve.addJacobian(x1, y1, z1, x2, y2, z2)) 84 } 85 86 // addJacobian takes two points in Jacobian coordinates, (x1, y1, z1) and 87 // (x2, y2, z2) and returns their sum, also in Jacobian form. 88 func (curve *CurveParams) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) { 89 // See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl 90 x3, y3, z3 := new(big.Int), new(big.Int), new(big.Int) 91 if z1.Sign() == 0 { 92 x3.Set(x2) 93 y3.Set(y2) 94 z3.Set(z2) 95 return x3, y3, z3 96 } 97 if z2.Sign() == 0 { 98 x3.Set(x1) 99 y3.Set(y1) 100 z3.Set(z1) 101 return x3, y3, z3 102 } 103 104 z1z1 := new(big.Int).Mul(z1, z1) 105 z1z1.Mod(z1z1, curve.P) 106 z2z2 := new(big.Int).Mul(z2, z2) 107 z2z2.Mod(z2z2, curve.P) 108 109 u1 := new(big.Int).Mul(x1, z2z2) 110 u1.Mod(u1, curve.P) 111 u2 := new(big.Int).Mul(x2, z1z1) 112 u2.Mod(u2, curve.P) 113 h := new(big.Int).Sub(u2, u1) 114 xEqual := h.Sign() == 0 115 if h.Sign() == -1 { 116 h.Add(h, curve.P) 117 } 118 i := new(big.Int).Lsh(h, 1) 119 i.Mul(i, i) 120 j := new(big.Int).Mul(h, i) 121 122 s1 := new(big.Int).Mul(y1, z2) 123 s1.Mul(s1, z2z2) 124 s1.Mod(s1, curve.P) 125 s2 := new(big.Int).Mul(y2, z1) 126 s2.Mul(s2, z1z1) 127 s2.Mod(s2, curve.P) 128 r := new(big.Int).Sub(s2, s1) 129 if r.Sign() == -1 { 130 r.Add(r, curve.P) 131 } 132 yEqual := r.Sign() == 0 133 if xEqual && yEqual { 134 return curve.doubleJacobian(x1, y1, z1) 135 } 136 r.Lsh(r, 1) 137 v := new(big.Int).Mul(u1, i) 138 139 x3.Set(r) 140 x3.Mul(x3, x3) 141 x3.Sub(x3, j) 142 x3.Sub(x3, v) 143 x3.Sub(x3, v) 144 x3.Mod(x3, curve.P) 145 146 y3.Set(r) 147 v.Sub(v, x3) 148 y3.Mul(y3, v) 149 s1.Mul(s1, j) 150 s1.Lsh(s1, 1) 151 y3.Sub(y3, s1) 152 y3.Mod(y3, curve.P) 153 154 z3.Add(z1, z2) 155 z3.Mul(z3, z3) 156 z3.Sub(z3, z1z1) 157 z3.Sub(z3, z2z2) 158 z3.Mul(z3, h) 159 z3.Mod(z3, curve.P) 160 161 return x3, y3, z3 162 } 163 164 func (curve *CurveParams) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { 165 z1 := zForAffine(x1, y1) 166 return curve.affineFromJacobian(curve.doubleJacobian(x1, y1, z1)) 167 } 168 169 // doubleJacobian takes a point in Jacobian coordinates, (x, y, z), and 170 // returns its double, also in Jacobian form. 171 func (curve *CurveParams) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) { 172 // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3 173 a := new(big.Int).Mul(x, x) 174 a.Mod(a, curve.P) 175 b := new(big.Int).Mul(y, y) 176 b.Mod(b, curve.P) 177 c := new(big.Int).Mul(b, b) 178 c.Mod(c, curve.P) 179 180 d := new(big.Int).Add(x, b) 181 d.Mul(d, d) 182 d.Sub(d, a) 183 d.Sub(d, c) 184 d.Lsh(d, 1) 185 if d.Sign() < 0 { 186 d.Add(d, curve.P) 187 } else { 188 d.Mod(d, curve.P) 189 } 190 191 e := new(big.Int).Lsh(a, 1) 192 e.Add(e, a) 193 f := new(big.Int).Mul(e, e) 194 x3 := new(big.Int).Lsh(d, 1) 195 x3.Sub(f, x3) 196 if x3.Sign() < 0 { 197 x3.Add(x3, curve.P) 198 } else { 199 x3.Mod(x3, curve.P) 200 } 201 202 y3 := new(big.Int).Sub(d, x3) 203 y3.Mul(y3, e) 204 c.Lsh(c, 3) 205 y3.Sub(y3, c) 206 if y3.Sign() < 0 { 207 y3.Add(y3, curve.P) 208 } else { 209 y3.Mod(y3, curve.P) 210 } 211 212 z3 := new(big.Int).Mul(y, z) 213 z3.Lsh(z3, 1) 214 z3.Mod(z3, curve.P) 215 216 return x3, y3, z3 217 } 218 219 func (curve *CurveParams) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) { 220 Bz := new(big.Int).SetInt64(1) 221 x, y, z := new(big.Int), new(big.Int), new(big.Int) 222 223 for _, byte := range k { 224 for bitNum := 0; bitNum < 8; bitNum++ { 225 x, y, z = curve.doubleJacobian(x, y, z) 226 if byte&0x80 == 0x80 { 227 x, y, z = curve.addJacobian(Bx, By, Bz, x, y, z) 228 } 229 byte <<= 1 230 } 231 } 232 233 return curve.affineFromJacobian(x, y, z) 234 } 235 236 func (curve *CurveParams) ScalarBaseMult(k []byte) (*big.Int, *big.Int) { 237 return curve.ScalarMult(curve.Gx, curve.Gy, k) 238 }