github.com/comwrg/go/src@v0.0.0-20220319063731-c238d0440370/crypto/elliptic/p521.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package elliptic 6 7 import ( 8 "crypto/elliptic/internal/fiat" 9 "math/big" 10 ) 11 12 type p521Curve struct { 13 *CurveParams 14 } 15 16 var p521 p521Curve 17 var p521Params *CurveParams 18 19 func initP521() { 20 // See FIPS 186-3, section D.2.5 21 p521.CurveParams = &CurveParams{Name: "P-521"} 22 p521.P, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", 10) 23 p521.N, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449", 10) 24 p521.B, _ = new(big.Int).SetString("051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", 16) 25 p521.Gx, _ = new(big.Int).SetString("c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", 16) 26 p521.Gy, _ = new(big.Int).SetString("11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650", 16) 27 p521.BitSize = 521 28 } 29 30 func (curve p521Curve) Params() *CurveParams { 31 return curve.CurveParams 32 } 33 34 func (curve p521Curve) IsOnCurve(x, y *big.Int) bool { 35 if x.Sign() < 0 || x.Cmp(curve.P) >= 0 || 36 y.Sign() < 0 || y.Cmp(curve.P) >= 0 { 37 return false 38 } 39 40 x1 := bigIntToFiatP521(x) 41 y1 := bigIntToFiatP521(y) 42 b := bigIntToFiatP521(curve.B) // TODO: precompute this value. 43 44 // x³ - 3x + b. 45 x3 := new(fiat.P521Element).Square(x1) 46 x3.Mul(x3, x1) 47 48 threeX := new(fiat.P521Element).Add(x1, x1) 49 threeX.Add(threeX, x1) 50 51 x3.Sub(x3, threeX) 52 x3.Add(x3, b) 53 54 // y² = x³ - 3x + b 55 y2 := new(fiat.P521Element).Square(y1) 56 57 return x3.Equal(y2) == 1 58 } 59 60 type p521Point struct { 61 x, y, z *fiat.P521Element 62 } 63 64 func fiatP521ToBigInt(x *fiat.P521Element) *big.Int { 65 xBytes := x.Bytes() 66 for i := range xBytes[:len(xBytes)/2] { 67 xBytes[i], xBytes[len(xBytes)-i-1] = xBytes[len(xBytes)-i-1], xBytes[i] 68 } 69 return new(big.Int).SetBytes(xBytes) 70 } 71 72 // affineFromJacobian brings a point in Jacobian coordinates back to affine 73 // coordinates, with (0, 0) representing infinity by convention. It also goes 74 // back to big.Int values to match the exposed API. 75 func (curve p521Curve) affineFromJacobian(p *p521Point) (x, y *big.Int) { 76 if p.z.IsZero() == 1 { 77 return new(big.Int), new(big.Int) 78 } 79 80 zinv := new(fiat.P521Element).Invert(p.z) 81 zinvsq := new(fiat.P521Element).Mul(zinv, zinv) 82 83 xx := new(fiat.P521Element).Mul(p.x, zinvsq) 84 zinvsq.Mul(zinvsq, zinv) 85 yy := new(fiat.P521Element).Mul(p.y, zinvsq) 86 87 return fiatP521ToBigInt(xx), fiatP521ToBigInt(yy) 88 } 89 90 func bigIntToFiatP521(x *big.Int) *fiat.P521Element { 91 xBytes := new(big.Int).Mod(x, p521.P).FillBytes(make([]byte, 66)) 92 for i := range xBytes[:len(xBytes)/2] { 93 xBytes[i], xBytes[len(xBytes)-i-1] = xBytes[len(xBytes)-i-1], xBytes[i] 94 } 95 x1, err := new(fiat.P521Element).SetBytes(xBytes) 96 if err != nil { 97 // The input is reduced modulo P and encoded in a fixed size bytes 98 // slice, this should be impossible. 99 panic("internal error: bigIntToFiatP521") 100 } 101 return x1 102 } 103 104 // jacobianFromAffine converts (x, y) affine coordinates into (x, y, z) Jacobian 105 // coordinates. It also converts from big.Int to fiat, which is necessarily a 106 // messy and variable-time operation, which we can't avoid due to the exposed API. 107 func (curve p521Curve) jacobianFromAffine(x, y *big.Int) *p521Point { 108 // (0, 0) is by convention the point at infinity, which can't be represented 109 // in affine coordinates, but is (0, 0, 0) in Jacobian. 110 if x.Sign() == 0 && y.Sign() == 0 { 111 return &p521Point{ 112 x: new(fiat.P521Element), 113 y: new(fiat.P521Element), 114 z: new(fiat.P521Element), 115 } 116 } 117 return &p521Point{ 118 x: bigIntToFiatP521(x), 119 y: bigIntToFiatP521(y), 120 z: new(fiat.P521Element).One(), 121 } 122 } 123 124 func (curve p521Curve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { 125 p1 := curve.jacobianFromAffine(x1, y1) 126 p2 := curve.jacobianFromAffine(x2, y2) 127 return curve.affineFromJacobian(p1.addJacobian(p1, p2)) 128 } 129 130 // addJacobian sets q = p1 + p2, and returns q. The points may overlap. 131 func (q *p521Point) addJacobian(p1, p2 *p521Point) *p521Point { 132 // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl 133 z1IsZero := p1.z.IsZero() 134 z2IsZero := p2.z.IsZero() 135 136 z1z1 := new(fiat.P521Element).Square(p1.z) 137 z2z2 := new(fiat.P521Element).Square(p2.z) 138 139 u1 := new(fiat.P521Element).Mul(p1.x, z2z2) 140 u2 := new(fiat.P521Element).Mul(p2.x, z1z1) 141 h := new(fiat.P521Element).Sub(u2, u1) 142 xEqual := h.IsZero() == 1 143 i := new(fiat.P521Element).Add(h, h) 144 i.Square(i) 145 j := new(fiat.P521Element).Mul(h, i) 146 147 s1 := new(fiat.P521Element).Mul(p1.y, p2.z) 148 s1.Mul(s1, z2z2) 149 s2 := new(fiat.P521Element).Mul(p2.y, p1.z) 150 s2.Mul(s2, z1z1) 151 r := new(fiat.P521Element).Sub(s2, s1) 152 yEqual := r.IsZero() == 1 153 if xEqual && yEqual && z1IsZero == 0 && z2IsZero == 0 { 154 return q.doubleJacobian(p1) 155 } 156 r.Add(r, r) 157 v := new(fiat.P521Element).Mul(u1, i) 158 159 x := new(fiat.P521Element).Set(r) 160 x.Square(x) 161 x.Sub(x, j) 162 x.Sub(x, v) 163 x.Sub(x, v) 164 165 y := new(fiat.P521Element).Set(r) 166 v.Sub(v, x) 167 y.Mul(y, v) 168 s1.Mul(s1, j) 169 s1.Add(s1, s1) 170 y.Sub(y, s1) 171 172 z := new(fiat.P521Element).Add(p1.z, p2.z) 173 z.Square(z) 174 z.Sub(z, z1z1) 175 z.Sub(z, z2z2) 176 z.Mul(z, h) 177 178 x.Select(p2.x, x, z1IsZero) 179 x.Select(p1.x, x, z2IsZero) 180 y.Select(p2.y, y, z1IsZero) 181 y.Select(p1.y, y, z2IsZero) 182 z.Select(p2.z, z, z1IsZero) 183 z.Select(p1.z, z, z2IsZero) 184 185 q.x.Set(x) 186 q.y.Set(y) 187 q.z.Set(z) 188 return q 189 } 190 191 func (curve p521Curve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { 192 p := curve.jacobianFromAffine(x1, y1) 193 return curve.affineFromJacobian(p.doubleJacobian(p)) 194 } 195 196 // doubleJacobian sets q = p + p, and returns q. The points may overlap. 197 func (q *p521Point) doubleJacobian(p *p521Point) *p521Point { 198 // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b 199 delta := new(fiat.P521Element).Square(p.z) 200 gamma := new(fiat.P521Element).Square(p.y) 201 alpha := new(fiat.P521Element).Sub(p.x, delta) 202 alpha2 := new(fiat.P521Element).Add(p.x, delta) 203 alpha.Mul(alpha, alpha2) 204 alpha2.Set(alpha) 205 alpha.Add(alpha, alpha) 206 alpha.Add(alpha, alpha2) 207 208 beta := alpha2.Mul(p.x, gamma) 209 210 q.x.Square(alpha) 211 beta8 := new(fiat.P521Element).Add(beta, beta) 212 beta8.Add(beta8, beta8) 213 beta8.Add(beta8, beta8) 214 q.x.Sub(q.x, beta8) 215 216 q.z.Add(p.y, p.z) 217 q.z.Square(q.z) 218 q.z.Sub(q.z, gamma) 219 q.z.Sub(q.z, delta) 220 221 beta.Add(beta, beta) 222 beta.Add(beta, beta) 223 beta.Sub(beta, q.x) 224 q.y.Mul(alpha, beta) 225 226 gamma.Square(gamma) 227 gamma.Add(gamma, gamma) 228 gamma.Add(gamma, gamma) 229 gamma.Add(gamma, gamma) 230 231 q.y.Sub(q.y, gamma) 232 233 return q 234 } 235 236 func (curve p521Curve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) { 237 B := curve.jacobianFromAffine(Bx, By) 238 p, t := &p521Point{ 239 x: new(fiat.P521Element), 240 y: new(fiat.P521Element), 241 z: new(fiat.P521Element), 242 }, &p521Point{ 243 x: new(fiat.P521Element), 244 y: new(fiat.P521Element), 245 z: new(fiat.P521Element), 246 } 247 248 for _, byte := range scalar { 249 for bitNum := 0; bitNum < 8; bitNum++ { 250 p.doubleJacobian(p) 251 bit := (byte >> (7 - bitNum)) & 1 252 t.addJacobian(p, B) 253 p.x.Select(t.x, p.x, int(bit)) 254 p.y.Select(t.y, p.y, int(bit)) 255 p.z.Select(t.z, p.z, int(bit)) 256 } 257 } 258 259 return curve.affineFromJacobian(p) 260 } 261 262 func (curve p521Curve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) { 263 return curve.ScalarMult(curve.Gx, curve.Gy, k) 264 }