1// Copyright 2013 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// Package ed25519 implements the Ed25519 signature algorithm. See 6// http://ed25519.cr.yp.to/. 7package ed25519 8 9// This code is a port of the public domain, "ref10" implementation of ed25519 10// from SUPERCOP. 11 12import ( 13 "crypto/sha512" 14 "crypto/subtle" 15 "io" 16 17 "github.com/agl/ed25519/edwards25519" 18) 19 20const ( 21 PublicKeySize = 32 22 PrivateKeySize = 64 23 SignatureSize = 64 24) 25 26// GenerateKey generates a public/private key pair using randomness from rand. 27func GenerateKey(rand io.Reader) (publicKey *[PublicKeySize]byte, privateKey *[PrivateKeySize]byte, err error) { 28 privateKey = new([64]byte) 29 publicKey = new([32]byte) 30 _, err = io.ReadFull(rand, privateKey[:32]) 31 if err != nil { 32 return nil, nil, err 33 } 34 35 h := sha512.New() 36 h.Write(privateKey[:32]) 37 digest := h.Sum(nil) 38 39 digest[0] &= 248 40 digest[31] &= 127 41 digest[31] |= 64 42 43 var A edwards25519.ExtendedGroupElement 44 var hBytes [32]byte 45 copy(hBytes[:], digest) 46 edwards25519.GeScalarMultBase(&A, &hBytes) 47 A.ToBytes(publicKey) 48 49 copy(privateKey[32:], publicKey[:]) 50 return 51} 52 53// Sign signs the message with privateKey and returns a signature. 54func Sign(privateKey *[PrivateKeySize]byte, message []byte) *[SignatureSize]byte { 55 h := sha512.New() 56 h.Write(privateKey[:32]) 57 58 var digest1, messageDigest, hramDigest [64]byte 59 var expandedSecretKey [32]byte 60 h.Sum(digest1[:0]) 61 copy(expandedSecretKey[:], digest1[:]) 62 expandedSecretKey[0] &= 248 63 expandedSecretKey[31] &= 63 64 expandedSecretKey[31] |= 64 65 66 h.Reset() 67 h.Write(digest1[32:]) 68 h.Write(message) 69 h.Sum(messageDigest[:0]) 70 71 var messageDigestReduced [32]byte 72 edwards25519.ScReduce(&messageDigestReduced, &messageDigest) 73 var R edwards25519.ExtendedGroupElement 74 edwards25519.GeScalarMultBase(&R, &messageDigestReduced) 75 76 var encodedR [32]byte 77 R.ToBytes(&encodedR) 78 79 h.Reset() 80 h.Write(encodedR[:]) 81 h.Write(privateKey[32:]) 82 h.Write(message) 83 h.Sum(hramDigest[:0]) 84 var hramDigestReduced [32]byte 85 edwards25519.ScReduce(&hramDigestReduced, &hramDigest) 86 87 var s [32]byte 88 edwards25519.ScMulAdd(&s, &hramDigestReduced, &expandedSecretKey, &messageDigestReduced) 89 90 signature := new([64]byte) 91 copy(signature[:], encodedR[:]) 92 copy(signature[32:], s[:]) 93 return signature 94} 95 96// Verify returns true iff sig is a valid signature of message by publicKey. 97func Verify(publicKey *[PublicKeySize]byte, message []byte, sig *[SignatureSize]byte) bool { 98 if sig[63]&224 != 0 { 99 return false 100 } 101 102 var A edwards25519.ExtendedGroupElement 103 if !A.FromBytes(publicKey) { 104 return false 105 } 106 edwards25519.FeNeg(&A.X, &A.X) 107 edwards25519.FeNeg(&A.T, &A.T) 108 109 h := sha512.New() 110 h.Write(sig[:32]) 111 h.Write(publicKey[:]) 112 h.Write(message) 113 var digest [64]byte 114 h.Sum(digest[:0]) 115 116 var hReduced [32]byte 117 edwards25519.ScReduce(&hReduced, &digest) 118 119 var R edwards25519.ProjectiveGroupElement 120 var b [32]byte 121 copy(b[:], sig[32:]) 122 edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &b) 123 124 var checkR [32]byte 125 R.ToBytes(&checkR) 126 return subtle.ConstantTimeCompare(sig[:32], checkR[:]) == 1 127} 128