forked from jshiffer/matterbridge
98 lines
2.7 KiB
Go
98 lines
2.7 KiB
Go
package ecc
|
|
|
|
// Package curve25519sign implements a signature scheme based on Curve25519 keys.
|
|
// See https://moderncrypto.org/mail-archive/curves/2014/000205.html for details.
|
|
|
|
import (
|
|
"crypto/ed25519"
|
|
"crypto/sha512"
|
|
|
|
"filippo.io/edwards25519"
|
|
"filippo.io/edwards25519/field"
|
|
)
|
|
|
|
// sign signs the message with privateKey and returns a signature as a byte slice.
|
|
func sign(privateKey *[32]byte, message []byte, random [64]byte) *[64]byte {
|
|
|
|
// Calculate Ed25519 public key from Curve25519 private key
|
|
var A edwards25519.Point
|
|
privateKeyScalar, _ := edwards25519.NewScalar().SetBytesWithClamping(privateKey[:])
|
|
A.ScalarBaseMult(privateKeyScalar)
|
|
publicKey := *(*[32]byte)(A.Bytes())
|
|
|
|
// Calculate r
|
|
diversifier := [32]byte{
|
|
0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
|
|
|
|
var r [64]byte
|
|
hash := sha512.New()
|
|
hash.Write(diversifier[:])
|
|
hash.Write(privateKey[:])
|
|
hash.Write(message)
|
|
hash.Write(random[:])
|
|
hash.Sum(r[:0])
|
|
|
|
// Calculate R
|
|
var rReduced *edwards25519.Scalar
|
|
rReduced, _ = edwards25519.NewScalar().SetUniformBytes(r[:])
|
|
var R edwards25519.Point
|
|
R.ScalarBaseMult(rReduced)
|
|
|
|
var encodedR [32]byte
|
|
encodedR = *(*[32]byte)(R.Bytes())
|
|
|
|
// Calculate S = r + SHA2-512(R || A_ed || msg) * a (mod L)
|
|
var hramDigest [64]byte
|
|
hash.Reset()
|
|
hash.Write(encodedR[:])
|
|
hash.Write(publicKey[:])
|
|
hash.Write(message)
|
|
hash.Sum(hramDigest[:0])
|
|
hramDigestReduced, _ := edwards25519.NewScalar().SetUniformBytes(hramDigest[:])
|
|
|
|
sScalar := edwards25519.NewScalar().MultiplyAdd(hramDigestReduced, privateKeyScalar, rReduced)
|
|
s := *(*[32]byte)(sScalar.Bytes())
|
|
|
|
signature := new([64]byte)
|
|
copy(signature[:], encodedR[:])
|
|
copy(signature[32:], s[:])
|
|
signature[63] |= publicKey[31] & 0x80
|
|
|
|
return signature
|
|
}
|
|
|
|
// verify checks whether the message has a valid signature.
|
|
func verify(publicKey [32]byte, message []byte, signature *[64]byte) bool {
|
|
|
|
publicKey[31] &= 0x7F
|
|
|
|
/* Convert the Curve25519 public key into an Ed25519 public key. In
|
|
particular, convert Curve25519's "montgomery" x-coordinate into an
|
|
Ed25519 "edwards" y-coordinate:
|
|
|
|
ed_y = (mont_x - 1) / (mont_x + 1)
|
|
|
|
NOTE: mont_x=-1 is converted to ed_y=0 since fe_invert is mod-exp
|
|
|
|
Then move the sign bit into the pubkey from the signature.
|
|
*/
|
|
|
|
var edY, one, montX, montXMinusOne, montXPlusOne field.Element
|
|
_, _ = montX.SetBytes(publicKey[:])
|
|
_ = one.One()
|
|
montXMinusOne.Subtract(&montX, &one)
|
|
montXPlusOne.Add(&montX, &one)
|
|
montXPlusOne.Invert(&montXPlusOne)
|
|
edY.Multiply(&montXMinusOne, &montXPlusOne)
|
|
|
|
A_ed := *(*[32]byte)(edY.Bytes())
|
|
|
|
A_ed[31] |= signature[63] & 0x80
|
|
signature[63] &= 0x7F
|
|
|
|
return ed25519.Verify(A_ed[:], message, signature[:])
|
|
}
|