195 lines
5.5 KiB
Go
195 lines
5.5 KiB
Go
// Copyright (c) 2014-2015 The btcsuite developers
|
|
// Copyright (c) 2015-2021 The Decred developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// This file is ignored during the regular build due to the following build tag.
|
|
// This build tag is set during go generate.
|
|
// +build gensecp256k1
|
|
|
|
package secp256k1
|
|
|
|
// References:
|
|
// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone)
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"math/big"
|
|
)
|
|
|
|
// compressedBytePoints are dummy points used so the code which generates the
|
|
// real values can compile.
|
|
var compressedBytePoints = ""
|
|
|
|
// SerializedBytePoints returns a serialized byte slice which contains all of
|
|
// the possible points per 8-bit window. This is used to when generating
|
|
// compressedbytepoints.go.
|
|
func SerializedBytePoints() []byte {
|
|
// Calculate G^(2^i) for i in 0..255. These are used to avoid recomputing
|
|
// them for each digit of the 8-bit windows.
|
|
doublingPoints := make([]JacobianPoint, curveParams.BitSize)
|
|
var q JacobianPoint
|
|
bigAffineToJacobian(curveParams.Gx, curveParams.Gy, &q)
|
|
for i := 0; i < curveParams.BitSize; i++ {
|
|
// Q = 2*Q.
|
|
doublingPoints[i] = q
|
|
DoubleNonConst(&q, &q)
|
|
}
|
|
|
|
// Separate the bits into byte-sized windows.
|
|
curveByteSize := curveParams.BitSize / 8
|
|
serialized := make([]byte, curveByteSize*256*2*10*4)
|
|
offset := 0
|
|
for byteNum := 0; byteNum < curveByteSize; byteNum++ {
|
|
// Grab the 8 bits that make up this byte from doubling points.
|
|
startingBit := 8 * (curveByteSize - byteNum - 1)
|
|
windowPoints := doublingPoints[startingBit : startingBit+8]
|
|
|
|
// Compute all points in this window, convert them to affine, and
|
|
// serialize them.
|
|
for i := 0; i < 256; i++ {
|
|
var point JacobianPoint
|
|
for bit := 0; bit < 8; bit++ {
|
|
if i>>uint(bit)&1 == 1 {
|
|
AddNonConst(&point, &windowPoints[bit], &point)
|
|
}
|
|
}
|
|
point.ToAffine()
|
|
|
|
for i := 0; i < len(point.X.n); i++ {
|
|
binary.LittleEndian.PutUint32(serialized[offset:], point.X.n[i])
|
|
offset += 4
|
|
}
|
|
for i := 0; i < len(point.Y.n); i++ {
|
|
binary.LittleEndian.PutUint32(serialized[offset:], point.Y.n[i])
|
|
offset += 4
|
|
}
|
|
}
|
|
}
|
|
|
|
return serialized
|
|
}
|
|
|
|
// sqrt returns the square root of the provided big integer using Newton's
|
|
// method. It's only compiled and used during generation of pre-computed
|
|
// values, so speed is not a huge concern.
|
|
func sqrt(n *big.Int) *big.Int {
|
|
// Initial guess = 2^(log_2(n)/2)
|
|
guess := big.NewInt(2)
|
|
guess.Exp(guess, big.NewInt(int64(n.BitLen()/2)), nil)
|
|
|
|
// Now refine using Newton's method.
|
|
big2 := big.NewInt(2)
|
|
prevGuess := big.NewInt(0)
|
|
for {
|
|
prevGuess.Set(guess)
|
|
guess.Add(guess, new(big.Int).Div(n, guess))
|
|
guess.Div(guess, big2)
|
|
if guess.Cmp(prevGuess) == 0 {
|
|
break
|
|
}
|
|
}
|
|
return guess
|
|
}
|
|
|
|
// EndomorphismVectors runs the first 3 steps of algorithm 3.74 from [GECC] to
|
|
// generate the linearly independent vectors needed to generate a balanced
|
|
// length-two representation of a multiplier such that k = k1 + k2λ (mod N) and
|
|
// returns them. Since the values will always be the same given the fact that N
|
|
// and λ are fixed, the final results can be accelerated by storing the
|
|
// precomputed values.
|
|
func EndomorphismVectors() (a1, b1, a2, b2 *big.Int) {
|
|
bigMinus1 := big.NewInt(-1)
|
|
|
|
// This section uses an extended Euclidean algorithm to generate a
|
|
// sequence of equations:
|
|
// s[i] * N + t[i] * λ = r[i]
|
|
|
|
nSqrt := sqrt(curveParams.N)
|
|
u, v := new(big.Int).Set(curveParams.N), new(big.Int).Set(endomorphismLambda)
|
|
x1, y1 := big.NewInt(1), big.NewInt(0)
|
|
x2, y2 := big.NewInt(0), big.NewInt(1)
|
|
q, r := new(big.Int), new(big.Int)
|
|
qu, qx1, qy1 := new(big.Int), new(big.Int), new(big.Int)
|
|
s, t := new(big.Int), new(big.Int)
|
|
ri, ti := new(big.Int), new(big.Int)
|
|
a1, b1, a2, b2 = new(big.Int), new(big.Int), new(big.Int), new(big.Int)
|
|
found, oneMore := false, false
|
|
for u.Sign() != 0 {
|
|
// q = v/u
|
|
q.Div(v, u)
|
|
|
|
// r = v - q*u
|
|
qu.Mul(q, u)
|
|
r.Sub(v, qu)
|
|
|
|
// s = x2 - q*x1
|
|
qx1.Mul(q, x1)
|
|
s.Sub(x2, qx1)
|
|
|
|
// t = y2 - q*y1
|
|
qy1.Mul(q, y1)
|
|
t.Sub(y2, qy1)
|
|
|
|
// v = u, u = r, x2 = x1, x1 = s, y2 = y1, y1 = t
|
|
v.Set(u)
|
|
u.Set(r)
|
|
x2.Set(x1)
|
|
x1.Set(s)
|
|
y2.Set(y1)
|
|
y1.Set(t)
|
|
|
|
// As soon as the remainder is less than the sqrt of n, the
|
|
// values of a1 and b1 are known.
|
|
if !found && r.Cmp(nSqrt) < 0 {
|
|
// When this condition executes ri and ti represent the
|
|
// r[i] and t[i] values such that i is the greatest
|
|
// index for which r >= sqrt(n). Meanwhile, the current
|
|
// r and t values are r[i+1] and t[i+1], respectively.
|
|
|
|
// a1 = r[i+1], b1 = -t[i+1]
|
|
a1.Set(r)
|
|
b1.Mul(t, bigMinus1)
|
|
found = true
|
|
oneMore = true
|
|
|
|
// Skip to the next iteration so ri and ti are not
|
|
// modified.
|
|
continue
|
|
|
|
} else if oneMore {
|
|
// When this condition executes ri and ti still
|
|
// represent the r[i] and t[i] values while the current
|
|
// r and t are r[i+2] and t[i+2], respectively.
|
|
|
|
// sum1 = r[i]^2 + t[i]^2
|
|
rSquared := new(big.Int).Mul(ri, ri)
|
|
tSquared := new(big.Int).Mul(ti, ti)
|
|
sum1 := new(big.Int).Add(rSquared, tSquared)
|
|
|
|
// sum2 = r[i+2]^2 + t[i+2]^2
|
|
r2Squared := new(big.Int).Mul(r, r)
|
|
t2Squared := new(big.Int).Mul(t, t)
|
|
sum2 := new(big.Int).Add(r2Squared, t2Squared)
|
|
|
|
// if (r[i]^2 + t[i]^2) <= (r[i+2]^2 + t[i+2]^2)
|
|
if sum1.Cmp(sum2) <= 0 {
|
|
// a2 = r[i], b2 = -t[i]
|
|
a2.Set(ri)
|
|
b2.Mul(ti, bigMinus1)
|
|
} else {
|
|
// a2 = r[i+2], b2 = -t[i+2]
|
|
a2.Set(r)
|
|
b2.Mul(t, bigMinus1)
|
|
}
|
|
|
|
// All done.
|
|
break
|
|
}
|
|
|
|
ri.Set(r)
|
|
ti.Set(t)
|
|
}
|
|
|
|
return a1, b1, a2, b2
|
|
}
|