github.com/lazyledger/lazyledger-core@v0.35.0-dev.0.20210613111200-4c651f053571/crypto/ed25519/ed25519.go (about) 1 package ed25519 2 3 import ( 4 "bytes" 5 "crypto/ed25519" 6 "crypto/subtle" 7 "fmt" 8 "io" 9 10 "github.com/hdevalence/ed25519consensus" 11 12 "github.com/lazyledger/lazyledger-core/crypto" 13 "github.com/lazyledger/lazyledger-core/crypto/tmhash" 14 tmjson "github.com/lazyledger/lazyledger-core/libs/json" 15 ) 16 17 //------------------------------------- 18 19 var _ crypto.PrivKey = PrivKey{} 20 21 const ( 22 PrivKeyName = "tendermint/PrivKeyEd25519" 23 PubKeyName = "tendermint/PubKeyEd25519" 24 // PubKeySize is is the size, in bytes, of public keys as used in this package. 25 PubKeySize = 32 26 // PrivateKeySize is the size, in bytes, of private keys as used in this package. 27 PrivateKeySize = 64 28 // Size of an Edwards25519 signature. Namely the size of a compressed 29 // Edwards25519 point, and a field element. Both of which are 32 bytes. 30 SignatureSize = 64 31 // SeedSize is the size, in bytes, of private key seeds. These are the 32 // private key representations used by RFC 8032. 33 SeedSize = 32 34 35 KeyType = "ed25519" 36 ) 37 38 func init() { 39 tmjson.RegisterType(PubKey{}, PubKeyName) 40 tmjson.RegisterType(PrivKey{}, PrivKeyName) 41 } 42 43 // PrivKey implements crypto.PrivKey. 44 type PrivKey []byte 45 46 // Bytes returns the privkey byte format. 47 func (privKey PrivKey) Bytes() []byte { 48 return []byte(privKey) 49 } 50 51 // Sign produces a signature on the provided message. 52 // This assumes the privkey is wellformed in the golang format. 53 // The first 32 bytes should be random, 54 // corresponding to the normal ed25519 private key. 55 // The latter 32 bytes should be the compressed public key. 56 // If these conditions aren't met, Sign will panic or produce an 57 // incorrect signature. 58 func (privKey PrivKey) Sign(msg []byte) ([]byte, error) { 59 signatureBytes := ed25519.Sign(ed25519.PrivateKey(privKey), msg) 60 return signatureBytes, nil 61 } 62 63 // PubKey gets the corresponding public key from the private key. 64 // 65 // Panics if the private key is not initialized. 66 func (privKey PrivKey) PubKey() crypto.PubKey { 67 // If the latter 32 bytes of the privkey are all zero, privkey is not 68 // initialized. 69 initialized := false 70 for _, v := range privKey[32:] { 71 if v != 0 { 72 initialized = true 73 break 74 } 75 } 76 77 if !initialized { 78 panic("Expected ed25519 PrivKey to include concatenated pubkey bytes") 79 } 80 81 pubkeyBytes := make([]byte, PubKeySize) 82 copy(pubkeyBytes, privKey[32:]) 83 return PubKey(pubkeyBytes) 84 } 85 86 // Equals - you probably don't need to use this. 87 // Runs in constant time based on length of the keys. 88 func (privKey PrivKey) Equals(other crypto.PrivKey) bool { 89 if otherEd, ok := other.(PrivKey); ok { 90 return subtle.ConstantTimeCompare(privKey[:], otherEd[:]) == 1 91 } 92 93 return false 94 } 95 96 func (privKey PrivKey) Type() string { 97 return KeyType 98 } 99 100 // GenPrivKey generates a new ed25519 private key. 101 // It uses OS randomness in conjunction with the current global random seed 102 // in tendermint/libs/common to generate the private key. 103 func GenPrivKey() PrivKey { 104 return genPrivKey(crypto.CReader()) 105 } 106 107 // genPrivKey generates a new ed25519 private key using the provided reader. 108 func genPrivKey(rand io.Reader) PrivKey { 109 seed := make([]byte, SeedSize) 110 111 _, err := io.ReadFull(rand, seed) 112 if err != nil { 113 panic(err) 114 } 115 116 return PrivKey(ed25519.NewKeyFromSeed(seed)) 117 } 118 119 // GenPrivKeyFromSecret hashes the secret with SHA2, and uses 120 // that 32 byte output to create the private key. 121 // NOTE: secret should be the output of a KDF like bcrypt, 122 // if it's derived from user input. 123 func GenPrivKeyFromSecret(secret []byte) PrivKey { 124 seed := crypto.Sha256(secret) // Not Ripemd160 because we want 32 bytes. 125 126 return PrivKey(ed25519.NewKeyFromSeed(seed)) 127 } 128 129 //------------------------------------- 130 131 var _ crypto.PubKey = PubKey{} 132 133 // PubKeyEd25519 implements crypto.PubKey for the Ed25519 signature scheme. 134 type PubKey []byte 135 136 // Address is the SHA256-20 of the raw pubkey bytes. 137 func (pubKey PubKey) Address() crypto.Address { 138 if len(pubKey) != PubKeySize { 139 panic("pubkey is incorrect size") 140 } 141 return crypto.Address(tmhash.SumTruncated(pubKey)) 142 } 143 144 // Bytes returns the PubKey byte format. 145 func (pubKey PubKey) Bytes() []byte { 146 return []byte(pubKey) 147 } 148 149 func (pubKey PubKey) VerifySignature(msg []byte, sig []byte) bool { 150 // make sure we use the same algorithm to sign 151 if len(sig) != SignatureSize { 152 return false 153 } 154 155 return ed25519consensus.Verify(ed25519.PublicKey(pubKey), msg, sig) 156 } 157 158 func (pubKey PubKey) String() string { 159 return fmt.Sprintf("PubKeyEd25519{%X}", []byte(pubKey)) 160 } 161 162 func (pubKey PubKey) Type() string { 163 return KeyType 164 } 165 166 func (pubKey PubKey) Equals(other crypto.PubKey) bool { 167 if otherEd, ok := other.(PubKey); ok { 168 return bytes.Equal(pubKey[:], otherEd[:]) 169 } 170 171 return false 172 }