dcrd/dcrec/edwards/primitives.go
Aaron Campbell 03678bb754 multi: Correct typos.
Correct typos found by reading code and creative grepping.
2019-08-16 17:37:58 -05:00

293 lines
7.5 KiB
Go

// Copyright (c) 2015-2018 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package edwards
import (
"fmt"
"math/big"
"github.com/agl/ed25519/edwards25519"
)
// Some notes on primitives in Ed25519:
// 1) The integers themselves are stored as 32-byte little endian
// representations. If the store value is a point, the bit in
// the 31st byte, seventh position (b[31]>>7) represents whether
// or not the X value retrieved from the Y value should be
// negative or not. Remember, in affine EC space, the negative
// is P - positiveX. The rest of the 255 bits then represent
// the Y-value in little endian.
// 2) For high efficiency, 40 byte field elements (10x int32s) are
// often used to represent integers.
// 3) For further increases in efficiency, the affine (cartesian)
// coordinates are converted into projective (extended or non-
// extended) formats, which include a Z and T or Z value
// respectively.
// 4) Almost *everything* is encoded in little endian, with the
// exception of ECDSA X and Y values of points in affine space.
// reverse reverses a byte string.
func reverse(s *[32]byte) {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
}
// copyBytes copies a byte slice to a 32 byte array.
func copyBytes(aB []byte) *[32]byte {
if aB == nil {
return nil
}
s := new([32]byte)
// If we have a short byte string, expand
// it so that it's long enough.
aBLen := len(aB)
if aBLen < fieldIntSize {
diff := fieldIntSize - aBLen
for i := 0; i < diff; i++ {
aB = append([]byte{0x00}, aB...)
}
}
for i := 0; i < fieldIntSize; i++ {
s[i] = aB[i]
}
return s
}
// copyBytes64 copies a byte slice to a 64 byte array.
func copyBytes64(aB []byte) *[64]byte {
if aB == nil {
return nil
}
s := new([64]byte)
// If we have a short byte string, expand
// it so that it's long enough.
aBLen := len(aB)
if aBLen < 64 {
diff := 64 - aBLen
for i := 0; i < diff; i++ {
aB = append([]byte{0x00}, aB...)
}
}
for i := 0; i < 64; i++ {
s[i] = aB[i]
}
return s
}
// zeroSlice zeroes the memory of a scalar byte slice.
func zeroSlice(s []byte) {
for i := 0; i < PrivScalarSize; i++ {
s[i] = 0x00
}
}
// bigIntToEncodedBytes converts a big integer into its corresponding
// 32 byte little endian representation.
func bigIntToEncodedBytes(a *big.Int) *[32]byte {
s := new([32]byte)
if a == nil {
return s
}
// Caveat: a can be longer than 32 bytes.
aB := a.Bytes()
// If we have a short byte string, expand
// it so that it's long enough.
aBLen := len(aB)
if aBLen < fieldIntSize {
diff := fieldIntSize - aBLen
for i := 0; i < diff; i++ {
aB = append([]byte{0x00}, aB...)
}
}
for i := 0; i < fieldIntSize; i++ {
s[i] = aB[i]
}
// Reverse the byte string --> little endian after
// encoding.
reverse(s)
return s
}
// bigIntToEncodedBytesNoReverse converts a big integer into its corresponding
// 32 byte big endian representation.
func bigIntToEncodedBytesNoReverse(a *big.Int) *[32]byte {
s := new([32]byte)
if a == nil {
return s
}
// Caveat: a can be longer than 32 bytes.
aB := a.Bytes()
// If we have a short byte string, expand
// it so that it's long enough.
aBLen := len(aB)
if aBLen < fieldIntSize {
diff := fieldIntSize - aBLen
for i := 0; i < diff; i++ {
aB = append([]byte{0x00}, aB...)
}
}
for i := 0; i < fieldIntSize; i++ {
s[i] = aB[i]
}
return s
}
// bigIntToFieldElement converts a big little endian integer into its corresponding
// 40 byte field representation.
func bigIntToFieldElement(a *big.Int) *edwards25519.FieldElement {
aB := bigIntToEncodedBytes(a)
fe := new(edwards25519.FieldElement)
edwards25519.FeFromBytes(fe, aB)
return fe
}
// bigIntPointToEncodedBytes converts an affine point to a compressed
// 32 byte integer representation.
func bigIntPointToEncodedBytes(x *big.Int, y *big.Int) *[32]byte {
s := bigIntToEncodedBytes(y)
xB := bigIntToEncodedBytes(x)
xFE := new(edwards25519.FieldElement)
edwards25519.FeFromBytes(xFE, xB)
isNegative := edwards25519.FeIsNegative(xFE) == 1
if isNegative {
s[31] |= (1 << 7)
} else {
s[31] &^= (1 << 7)
}
return s
}
// encodedBytesToBigInt converts a 32 byte little endian representation of
// an integer into a big, big endian integer.
func encodedBytesToBigInt(s *[32]byte) *big.Int {
// Use a copy so we don't screw up our original
// memory.
sCopy := new([32]byte)
for i := 0; i < fieldIntSize; i++ {
sCopy[i] = s[i]
}
reverse(sCopy)
bi := new(big.Int).SetBytes(sCopy[:])
return bi
}
// encodedBytesToBigIntNoReverse converts a 32 byte big endian representation of
// an integer into a big little endian integer.
func encodedBytesToBigIntNoReverse(s *[32]byte) *big.Int {
// Use a copy so we don't screw up our original
// memory.
sCopy := new([32]byte)
for i := 0; i < fieldIntSize; i++ {
sCopy[i] = s[i]
}
bi := new(big.Int).SetBytes(sCopy[:])
return bi
}
// extendedToBigAffine converts projective x, y, and z field elements into
// affine x and y coordinates, and returns whether or not the x value
// returned is negative.
func (curve *TwistedEdwardsCurve) extendedToBigAffine(xi, yi,
zi *edwards25519.FieldElement) (*big.Int, *big.Int, bool) {
var recip, x, y edwards25519.FieldElement
// Normalize to Z=1.
edwards25519.FeInvert(&recip, zi)
edwards25519.FeMul(&x, xi, &recip)
edwards25519.FeMul(&y, yi, &recip)
isNegative := edwards25519.FeIsNegative(&x) == 1
return fieldElementToBigInt(&x), fieldElementToBigInt(&y), isNegative
}
// EncodedBytesToBigIntPoint converts a 32 byte representation of a point
// on the elliptical curve into a big integer point. It returns an error
// if the point does not fall on the curve.
func (curve *TwistedEdwardsCurve) encodedBytesToBigIntPoint(s *[32]byte) (*big.Int, *big.Int, error) {
sCopy := new([32]byte)
for i := 0; i < fieldIntSize; i++ {
sCopy[i] = s[i]
}
xIsNegBytes := sCopy[31]>>7 == 1
p := new(edwards25519.ExtendedGroupElement)
if !p.FromBytes(sCopy) {
return nil, nil, fmt.Errorf("point not on curve")
}
// Normalize the X and Y coordinates in affine space.
x, y, isNegative := curve.extendedToBigAffine(&p.X, &p.Y, &p.Z)
// We got the wrong sign; flip the bit and recalculate.
if xIsNegBytes != isNegative {
x.Sub(curve.P, x)
}
// This should hopefully never happen, since the
// library itself should never let us create a bad
// point.
if !curve.IsOnCurve(x, y) {
return nil, nil, fmt.Errorf("point not on curve")
}
return x, y, nil
}
// encodedBytesToFieldElement converts a 32 byte little endian integer into
// a field element.
func encodedBytesToFieldElement(s *[32]byte) *edwards25519.FieldElement {
fe := new(edwards25519.FieldElement)
edwards25519.FeFromBytes(fe, s)
return fe
}
// fieldElementToBigInt converts a 40 byte field element into a big int.
func fieldElementToBigInt(fe *edwards25519.FieldElement) *big.Int {
s := new([32]byte)
edwards25519.FeToBytes(s, fe)
reverse(s)
aBI := new(big.Int).SetBytes(s[:])
return aBI
}
// fieldElementToEncodedBytes converts a 40 byte field element into a 32 byte
// little endian integer.
func fieldElementToEncodedBytes(fe *edwards25519.FieldElement) *[32]byte {
s := new([32]byte)
edwards25519.FeToBytes(s, fe)
return s
}
// invert inverts a big integer over the Ed25519 curve.
func (curve *TwistedEdwardsCurve) invert(a *big.Int) *big.Int {
sub2 := new(big.Int).Sub(curve.P, two)
inv := new(big.Int).Exp(a, sub2, curve.P)
return inv
}