| // Copyright 2013 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. |
| |
| // Package ed25519 implements the Ed25519 signature algorithm. See |
| // http://ed25519.cr.yp.to/. |
| package ed25519 |
| |
| // This code is a port of the public domain, "ref10" implementation of ed25519 |
| // from SUPERCOP. |
| |
| import ( |
| "crypto/sha512" |
| "crypto/subtle" |
| "io" |
| |
| "github.com/agl/ed25519/edwards25519" |
| ) |
| |
| const ( |
| PublicKeySize = 32 |
| PrivateKeySize = 64 |
| SignatureSize = 64 |
| ) |
| |
| // GenerateKey generates a public/private key pair using randomness from rand. |
| func GenerateKey(rand io.Reader) (publicKey *[PublicKeySize]byte, privateKey *[PrivateKeySize]byte, err error) { |
| privateKey = new([64]byte) |
| publicKey = new([32]byte) |
| _, err = io.ReadFull(rand, privateKey[:32]) |
| if err != nil { |
| return nil, nil, err |
| } |
| |
| h := sha512.New() |
| h.Write(privateKey[:32]) |
| digest := h.Sum(nil) |
| |
| digest[0] &= 248 |
| digest[31] &= 127 |
| digest[31] |= 64 |
| |
| var A edwards25519.ExtendedGroupElement |
| var hBytes [32]byte |
| copy(hBytes[:], digest) |
| edwards25519.GeScalarMultBase(&A, &hBytes) |
| A.ToBytes(publicKey) |
| |
| copy(privateKey[32:], publicKey[:]) |
| return |
| } |
| |
| // Sign signs the message with privateKey and returns a signature. |
| func Sign(privateKey *[PrivateKeySize]byte, message []byte) *[SignatureSize]byte { |
| h := sha512.New() |
| h.Write(privateKey[:32]) |
| |
| var digest1, messageDigest, hramDigest [64]byte |
| var expandedSecretKey [32]byte |
| h.Sum(digest1[:0]) |
| copy(expandedSecretKey[:], digest1[:]) |
| expandedSecretKey[0] &= 248 |
| expandedSecretKey[31] &= 63 |
| expandedSecretKey[31] |= 64 |
| |
| h.Reset() |
| h.Write(digest1[32:]) |
| h.Write(message) |
| h.Sum(messageDigest[:0]) |
| |
| var messageDigestReduced [32]byte |
| edwards25519.ScReduce(&messageDigestReduced, &messageDigest) |
| var R edwards25519.ExtendedGroupElement |
| edwards25519.GeScalarMultBase(&R, &messageDigestReduced) |
| |
| var encodedR [32]byte |
| R.ToBytes(&encodedR) |
| |
| h.Reset() |
| h.Write(encodedR[:]) |
| h.Write(privateKey[32:]) |
| h.Write(message) |
| h.Sum(hramDigest[:0]) |
| var hramDigestReduced [32]byte |
| edwards25519.ScReduce(&hramDigestReduced, &hramDigest) |
| |
| var s [32]byte |
| edwards25519.ScMulAdd(&s, &hramDigestReduced, &expandedSecretKey, &messageDigestReduced) |
| |
| signature := new([64]byte) |
| copy(signature[:], encodedR[:]) |
| copy(signature[32:], s[:]) |
| return signature |
| } |
| |
| // Verify returns true iff sig is a valid signature of message by publicKey. |
| func Verify(publicKey *[PublicKeySize]byte, message []byte, sig *[SignatureSize]byte) bool { |
| if sig[63]&224 != 0 { |
| return false |
| } |
| |
| var A edwards25519.ExtendedGroupElement |
| if !A.FromBytes(publicKey) { |
| return false |
| } |
| |
| h := sha512.New() |
| h.Write(sig[:32]) |
| h.Write(publicKey[:]) |
| h.Write(message) |
| var digest [64]byte |
| h.Sum(digest[:0]) |
| |
| var hReduced [32]byte |
| edwards25519.ScReduce(&hReduced, &digest) |
| |
| var R edwards25519.ProjectiveGroupElement |
| var b [32]byte |
| copy(b[:], sig[32:]) |
| edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &b) |
| |
| var checkR [32]byte |
| R.ToBytes(&checkR) |
| return subtle.ConstantTimeCompare(sig[:32], checkR[:]) == 1 |
| } |