| // Copyright 2012 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // We have a implementation in amd64 assembly so this code is only run on |
| // non-amd64 platforms. The amd64 assembly does not support gccgo. |
| // +build !amd64 gccgo |
| |
| package curve25519 |
| |
| import ( |
| "math/big" |
| ) |
| |
| // p is the prime order of the underlying field: 2^255-19 |
| var p *big.Int |
| |
| // pMinus2 is p-2 |
| var pMinus2 *big.Int |
| |
| // a is a parameter of the elliptic curve: 486662 |
| var a *big.Int |
| |
| func init() { |
| p, _ = new(big.Int).SetString("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed", 16) |
| pMinus2, _ = new(big.Int).SetString("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb", 16) |
| a = new(big.Int).SetInt64(486662) |
| } |
| |
| // context contains state shared throughout the computation, including scratch |
| // variables to save on allocation. |
| type context struct { |
| tmp1, tmp2, tmp3, tmp4 *big.Int |
| x1 *big.Int |
| } |
| |
| // add sets (outx, outz) to the sum of two points in the elliptic curve group. |
| // See http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#diffadd-dadd-1987-m |
| // outx and outz should not alias any of the other inputs. |
| func (c *context) add(outx, outz, xn, zn, xm, zm *big.Int) { |
| // x₃ = 4(x·x′ - z·z′)² · z1 |
| // (z1 == 1 here) |
| c.tmp1.Mul(xn, xm) |
| c.tmp2.Mul(zn, zm) |
| c.tmp3.Sub(c.tmp1, c.tmp2) |
| outx.Mul(c.tmp3, c.tmp3) |
| outx.Lsh(outx, 2) |
| outx.Mod(outx, p) |
| |
| // z₃ = 4(x·z′ - z·x′)² · x1 |
| // (x1 == 1 here) |
| c.tmp1.Mul(xm, zn) |
| c.tmp2.Mul(zm, xn) |
| c.tmp3.Sub(c.tmp1, c.tmp2) |
| outz.Mul(c.tmp3, c.tmp3) |
| outz.Mul(outz, c.x1) |
| outz.Lsh(outz, 2) |
| outz.Mod(outz, p) |
| |
| return |
| } |
| |
| // double sets (outx, outz) to 2*(x,z) in the elliptic curve group. See |
| // http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#doubling-dbl-1987-m |
| // outx and outz should not alias any of the other inputs. |
| func (c *context) double(outx, outz, x, z *big.Int) { |
| // x₂ = (x² - z²)² |
| c.tmp1.Mul(x, x) |
| c.tmp2.Mul(z, z) |
| c.tmp3.Sub(c.tmp1, c.tmp2) |
| outx.Mul(c.tmp3, c.tmp3) |
| outx.Mod(outx, p) |
| |
| // z₂ = 4xz·(x² + Axz + z²) |
| c.tmp3.Add(c.tmp1, c.tmp2) |
| c.tmp1.Mul(x, z) |
| c.tmp2.Mul(c.tmp1, a) |
| outz.Add(c.tmp3, c.tmp2) |
| c.tmp2.Lsh(c.tmp1, 2) |
| outz.Mul(outz, c.tmp2) |
| outz.Mod(outz, p) |
| |
| return |
| } |
| |
| func scalarMult(out, in, base *[32]byte) { |
| var baseReversed, inCopy [32]byte |
| for i := 0; i < 32; i++ { |
| baseReversed[31-i] = base[i] |
| inCopy[i] = in[i] |
| } |
| |
| inCopy[31] &= 127 |
| inCopy[31] |= 64 |
| inCopy[0] &= 248 |
| |
| c := &context{new(big.Int), new(big.Int), new(big.Int), new(big.Int), nil} |
| c.x1 = new(big.Int).SetBytes(baseReversed[:]) |
| |
| x1 := new(big.Int).SetInt64(1) |
| z1 := new(big.Int) |
| x2 := new(big.Int).Set(c.x1) |
| z2 := new(big.Int).SetInt64(1) |
| outx := new(big.Int) |
| outz := new(big.Int) |
| |
| for i := 0; i < 32; i++ { |
| b := inCopy[31-i] |
| for j := 0; j < 8; j++ { |
| if b&0x80 != 0 { |
| c.add(outx, outz, x1, z1, x2, z2) |
| x1, z1, outx, outz = outx, outz, x1, z1 |
| c.double(outx, outz, x2, z2) |
| x2, z2, outx, outz = outx, outz, x2, z2 |
| } else { |
| c.add(outx, outz, x1, z1, x2, z2) |
| x2, z2, outx, outz = outx, outz, x2, z2 |
| c.double(outx, outz, x1, z1) |
| x1, z1, outx, outz = outx, outz, x1, z1 |
| } |
| b <<= 1 |
| } |
| } |
| |
| c.tmp1.Exp(z1, pMinus2, p) |
| c.tmp2.Mul(x1, c.tmp1) |
| c.tmp3.Mod(c.tmp2, p) |
| |
| outReversed := c.tmp3.Bytes() |
| for i := 0; i < len(outReversed); i++ { |
| out[i] = outReversed[len(outReversed)-(1+i)] |
| } |
| for i := len(outReversed); i < 32; i++ { |
| out[i] = 0 |
| } |
| } |