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