github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/crypto/internal/edwards25519/edwards25519.go (about) 1 // Copyright (c) 2017 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 edwards25519 6 7 import ( 8 "crypto/internal/edwards25519/field" 9 "errors" 10 ) 11 12 // Point types. 13 14 type projP1xP1 struct { 15 X, Y, Z, T field.Element 16 } 17 18 type projP2 struct { 19 X, Y, Z field.Element 20 } 21 22 // Point represents a point on the edwards25519 curve. 23 // 24 // This type works similarly to math/big.Int, and all arguments and receivers 25 // are allowed to alias. 26 // 27 // The zero value is NOT valid, and it may be used only as a receiver. 28 type Point struct { 29 // Make the type not comparable (i.e. used with == or as a map key), as 30 // equivalent points can be represented by different Go values. 31 _ incomparable 32 33 // The point is internally represented in extended coordinates (X, Y, Z, T) 34 // where x = X/Z, y = Y/Z, and xy = T/Z per https://eprint.iacr.org/2008/522. 35 x, y, z, t field.Element 36 } 37 38 type incomparable [0]func() 39 40 func checkInitialized(points ...*Point) { 41 for _, p := range points { 42 if p.x == (field.Element{}) && p.y == (field.Element{}) { 43 panic("edwards25519: use of uninitialized Point") 44 } 45 } 46 } 47 48 type projCached struct { 49 YplusX, YminusX, Z, T2d field.Element 50 } 51 52 type affineCached struct { 53 YplusX, YminusX, T2d field.Element 54 } 55 56 // Constructors. 57 58 func (v *projP2) Zero() *projP2 { 59 v.X.Zero() 60 v.Y.One() 61 v.Z.One() 62 return v 63 } 64 65 // identity is the point at infinity. 66 var identity, _ = new(Point).SetBytes([]byte{ 67 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) 69 70 // NewIdentityPoint returns a new Point set to the identity. 71 func NewIdentityPoint() *Point { 72 return new(Point).Set(identity) 73 } 74 75 // generator is the canonical curve basepoint. See TestGenerator for the 76 // correspondence of this encoding with the values in RFC 8032. 77 var generator, _ = new(Point).SetBytes([]byte{ 78 0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 79 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 80 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 81 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66}) 82 83 // NewGeneratorPoint returns a new Point set to the canonical generator. 84 func NewGeneratorPoint() *Point { 85 return new(Point).Set(generator) 86 } 87 88 func (v *projCached) Zero() *projCached { 89 v.YplusX.One() 90 v.YminusX.One() 91 v.Z.One() 92 v.T2d.Zero() 93 return v 94 } 95 96 func (v *affineCached) Zero() *affineCached { 97 v.YplusX.One() 98 v.YminusX.One() 99 v.T2d.Zero() 100 return v 101 } 102 103 // Assignments. 104 105 // Set sets v = u, and returns v. 106 func (v *Point) Set(u *Point) *Point { 107 *v = *u 108 return v 109 } 110 111 // Encoding. 112 113 // Bytes returns the canonical 32-byte encoding of v, according to RFC 8032, 114 // Section 5.1.2. 115 func (v *Point) Bytes() []byte { 116 // This function is outlined to make the allocations inline in the caller 117 // rather than happen on the heap. 118 var buf [32]byte 119 return v.bytes(&buf) 120 } 121 122 func (v *Point) bytes(buf *[32]byte) []byte { 123 checkInitialized(v) 124 125 var zInv, x, y field.Element 126 zInv.Invert(&v.z) // zInv = 1 / Z 127 x.Multiply(&v.x, &zInv) // x = X / Z 128 y.Multiply(&v.y, &zInv) // y = Y / Z 129 130 out := copyFieldElement(buf, &y) 131 out[31] |= byte(x.IsNegative() << 7) 132 return out 133 } 134 135 var feOne = new(field.Element).One() 136 137 // SetBytes sets v = x, where x is a 32-byte encoding of v. If x does not 138 // represent a valid point on the curve, SetBytes returns nil and an error and 139 // the receiver is unchanged. Otherwise, SetBytes returns v. 140 // 141 // Note that SetBytes accepts all non-canonical encodings of valid points. 142 // That is, it follows decoding rules that match most implementations in 143 // the ecosystem rather than RFC 8032. 144 func (v *Point) SetBytes(x []byte) (*Point, error) { 145 // Specifically, the non-canonical encodings that are accepted are 146 // 1) the ones where the field element is not reduced (see the 147 // (*field.Element).SetBytes docs) and 148 // 2) the ones where the x-coordinate is zero and the sign bit is set. 149 // 150 // Read more at https://hdevalence.ca/blog/2020-10-04-its-25519am, 151 // specifically the "Canonical A, R" section. 152 153 y, err := new(field.Element).SetBytes(x) 154 if err != nil { 155 return nil, errors.New("edwards25519: invalid point encoding length") 156 } 157 158 // -x² + y² = 1 + dx²y² 159 // x² + dx²y² = x²(dy² + 1) = y² - 1 160 // x² = (y² - 1) / (dy² + 1) 161 162 // u = y² - 1 163 y2 := new(field.Element).Square(y) 164 u := new(field.Element).Subtract(y2, feOne) 165 166 // v = dy² + 1 167 vv := new(field.Element).Multiply(y2, d) 168 vv = vv.Add(vv, feOne) 169 170 // x = +√(u/v) 171 xx, wasSquare := new(field.Element).SqrtRatio(u, vv) 172 if wasSquare == 0 { 173 return nil, errors.New("edwards25519: invalid point encoding") 174 } 175 176 // Select the negative square root if the sign bit is set. 177 xxNeg := new(field.Element).Negate(xx) 178 xx = xx.Select(xxNeg, xx, int(x[31]>>7)) 179 180 v.x.Set(xx) 181 v.y.Set(y) 182 v.z.One() 183 v.t.Multiply(xx, y) // xy = T / Z 184 185 return v, nil 186 } 187 188 func copyFieldElement(buf *[32]byte, v *field.Element) []byte { 189 copy(buf[:], v.Bytes()) 190 return buf[:] 191 } 192 193 // Conversions. 194 195 func (v *projP2) FromP1xP1(p *projP1xP1) *projP2 { 196 v.X.Multiply(&p.X, &p.T) 197 v.Y.Multiply(&p.Y, &p.Z) 198 v.Z.Multiply(&p.Z, &p.T) 199 return v 200 } 201 202 func (v *projP2) FromP3(p *Point) *projP2 { 203 v.X.Set(&p.x) 204 v.Y.Set(&p.y) 205 v.Z.Set(&p.z) 206 return v 207 } 208 209 func (v *Point) fromP1xP1(p *projP1xP1) *Point { 210 v.x.Multiply(&p.X, &p.T) 211 v.y.Multiply(&p.Y, &p.Z) 212 v.z.Multiply(&p.Z, &p.T) 213 v.t.Multiply(&p.X, &p.Y) 214 return v 215 } 216 217 func (v *Point) fromP2(p *projP2) *Point { 218 v.x.Multiply(&p.X, &p.Z) 219 v.y.Multiply(&p.Y, &p.Z) 220 v.z.Square(&p.Z) 221 v.t.Multiply(&p.X, &p.Y) 222 return v 223 } 224 225 // d is a constant in the curve equation. 226 var d, _ = new(field.Element).SetBytes([]byte{ 227 0xa3, 0x78, 0x59, 0x13, 0xca, 0x4d, 0xeb, 0x75, 228 0xab, 0xd8, 0x41, 0x41, 0x4d, 0x0a, 0x70, 0x00, 229 0x98, 0xe8, 0x79, 0x77, 0x79, 0x40, 0xc7, 0x8c, 230 0x73, 0xfe, 0x6f, 0x2b, 0xee, 0x6c, 0x03, 0x52}) 231 var d2 = new(field.Element).Add(d, d) 232 233 func (v *projCached) FromP3(p *Point) *projCached { 234 v.YplusX.Add(&p.y, &p.x) 235 v.YminusX.Subtract(&p.y, &p.x) 236 v.Z.Set(&p.z) 237 v.T2d.Multiply(&p.t, d2) 238 return v 239 } 240 241 func (v *affineCached) FromP3(p *Point) *affineCached { 242 v.YplusX.Add(&p.y, &p.x) 243 v.YminusX.Subtract(&p.y, &p.x) 244 v.T2d.Multiply(&p.t, d2) 245 246 var invZ field.Element 247 invZ.Invert(&p.z) 248 v.YplusX.Multiply(&v.YplusX, &invZ) 249 v.YminusX.Multiply(&v.YminusX, &invZ) 250 v.T2d.Multiply(&v.T2d, &invZ) 251 return v 252 } 253 254 // (Re)addition and subtraction. 255 256 // Add sets v = p + q, and returns v. 257 func (v *Point) Add(p, q *Point) *Point { 258 checkInitialized(p, q) 259 qCached := new(projCached).FromP3(q) 260 result := new(projP1xP1).Add(p, qCached) 261 return v.fromP1xP1(result) 262 } 263 264 // Subtract sets v = p - q, and returns v. 265 func (v *Point) Subtract(p, q *Point) *Point { 266 checkInitialized(p, q) 267 qCached := new(projCached).FromP3(q) 268 result := new(projP1xP1).Sub(p, qCached) 269 return v.fromP1xP1(result) 270 } 271 272 func (v *projP1xP1) Add(p *Point, q *projCached) *projP1xP1 { 273 var YplusX, YminusX, PP, MM, TT2d, ZZ2 field.Element 274 275 YplusX.Add(&p.y, &p.x) 276 YminusX.Subtract(&p.y, &p.x) 277 278 PP.Multiply(&YplusX, &q.YplusX) 279 MM.Multiply(&YminusX, &q.YminusX) 280 TT2d.Multiply(&p.t, &q.T2d) 281 ZZ2.Multiply(&p.z, &q.Z) 282 283 ZZ2.Add(&ZZ2, &ZZ2) 284 285 v.X.Subtract(&PP, &MM) 286 v.Y.Add(&PP, &MM) 287 v.Z.Add(&ZZ2, &TT2d) 288 v.T.Subtract(&ZZ2, &TT2d) 289 return v 290 } 291 292 func (v *projP1xP1) Sub(p *Point, q *projCached) *projP1xP1 { 293 var YplusX, YminusX, PP, MM, TT2d, ZZ2 field.Element 294 295 YplusX.Add(&p.y, &p.x) 296 YminusX.Subtract(&p.y, &p.x) 297 298 PP.Multiply(&YplusX, &q.YminusX) // flipped sign 299 MM.Multiply(&YminusX, &q.YplusX) // flipped sign 300 TT2d.Multiply(&p.t, &q.T2d) 301 ZZ2.Multiply(&p.z, &q.Z) 302 303 ZZ2.Add(&ZZ2, &ZZ2) 304 305 v.X.Subtract(&PP, &MM) 306 v.Y.Add(&PP, &MM) 307 v.Z.Subtract(&ZZ2, &TT2d) // flipped sign 308 v.T.Add(&ZZ2, &TT2d) // flipped sign 309 return v 310 } 311 312 func (v *projP1xP1) AddAffine(p *Point, q *affineCached) *projP1xP1 { 313 var YplusX, YminusX, PP, MM, TT2d, Z2 field.Element 314 315 YplusX.Add(&p.y, &p.x) 316 YminusX.Subtract(&p.y, &p.x) 317 318 PP.Multiply(&YplusX, &q.YplusX) 319 MM.Multiply(&YminusX, &q.YminusX) 320 TT2d.Multiply(&p.t, &q.T2d) 321 322 Z2.Add(&p.z, &p.z) 323 324 v.X.Subtract(&PP, &MM) 325 v.Y.Add(&PP, &MM) 326 v.Z.Add(&Z2, &TT2d) 327 v.T.Subtract(&Z2, &TT2d) 328 return v 329 } 330 331 func (v *projP1xP1) SubAffine(p *Point, q *affineCached) *projP1xP1 { 332 var YplusX, YminusX, PP, MM, TT2d, Z2 field.Element 333 334 YplusX.Add(&p.y, &p.x) 335 YminusX.Subtract(&p.y, &p.x) 336 337 PP.Multiply(&YplusX, &q.YminusX) // flipped sign 338 MM.Multiply(&YminusX, &q.YplusX) // flipped sign 339 TT2d.Multiply(&p.t, &q.T2d) 340 341 Z2.Add(&p.z, &p.z) 342 343 v.X.Subtract(&PP, &MM) 344 v.Y.Add(&PP, &MM) 345 v.Z.Subtract(&Z2, &TT2d) // flipped sign 346 v.T.Add(&Z2, &TT2d) // flipped sign 347 return v 348 } 349 350 // Doubling. 351 352 func (v *projP1xP1) Double(p *projP2) *projP1xP1 { 353 var XX, YY, ZZ2, XplusYsq field.Element 354 355 XX.Square(&p.X) 356 YY.Square(&p.Y) 357 ZZ2.Square(&p.Z) 358 ZZ2.Add(&ZZ2, &ZZ2) 359 XplusYsq.Add(&p.X, &p.Y) 360 XplusYsq.Square(&XplusYsq) 361 362 v.Y.Add(&YY, &XX) 363 v.Z.Subtract(&YY, &XX) 364 365 v.X.Subtract(&XplusYsq, &v.Y) 366 v.T.Subtract(&ZZ2, &v.Z) 367 return v 368 } 369 370 // Negation. 371 372 // Negate sets v = -p, and returns v. 373 func (v *Point) Negate(p *Point) *Point { 374 checkInitialized(p) 375 v.x.Negate(&p.x) 376 v.y.Set(&p.y) 377 v.z.Set(&p.z) 378 v.t.Negate(&p.t) 379 return v 380 } 381 382 // Equal returns 1 if v is equivalent to u, and 0 otherwise. 383 func (v *Point) Equal(u *Point) int { 384 checkInitialized(v, u) 385 386 var t1, t2, t3, t4 field.Element 387 t1.Multiply(&v.x, &u.z) 388 t2.Multiply(&u.x, &v.z) 389 t3.Multiply(&v.y, &u.z) 390 t4.Multiply(&u.y, &v.z) 391 392 return t1.Equal(&t2) & t3.Equal(&t4) 393 } 394 395 // Constant-time operations 396 397 // Select sets v to a if cond == 1 and to b if cond == 0. 398 func (v *projCached) Select(a, b *projCached, cond int) *projCached { 399 v.YplusX.Select(&a.YplusX, &b.YplusX, cond) 400 v.YminusX.Select(&a.YminusX, &b.YminusX, cond) 401 v.Z.Select(&a.Z, &b.Z, cond) 402 v.T2d.Select(&a.T2d, &b.T2d, cond) 403 return v 404 } 405 406 // Select sets v to a if cond == 1 and to b if cond == 0. 407 func (v *affineCached) Select(a, b *affineCached, cond int) *affineCached { 408 v.YplusX.Select(&a.YplusX, &b.YplusX, cond) 409 v.YminusX.Select(&a.YminusX, &b.YminusX, cond) 410 v.T2d.Select(&a.T2d, &b.T2d, cond) 411 return v 412 } 413 414 // CondNeg negates v if cond == 1 and leaves it unchanged if cond == 0. 415 func (v *projCached) CondNeg(cond int) *projCached { 416 v.YplusX.Swap(&v.YminusX, cond) 417 v.T2d.Select(new(field.Element).Negate(&v.T2d), &v.T2d, cond) 418 return v 419 } 420 421 // CondNeg negates v if cond == 1 and leaves it unchanged if cond == 0. 422 func (v *affineCached) CondNeg(cond int) *affineCached { 423 v.YplusX.Swap(&v.YminusX, cond) 424 v.T2d.Select(new(field.Element).Negate(&v.T2d), &v.T2d, cond) 425 return v 426 }