github.com/aakash4dev/cometbft@v0.38.2/crypto/sr25519/privkey.go (about) 1 package sr25519 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 8 "github.com/oasisprotocol/curve25519-voi/primitives/sr25519" 9 10 "github.com/aakash4dev/cometbft/crypto" 11 ) 12 13 var ( 14 _ crypto.PrivKey = PrivKey{} 15 16 signingCtx = sr25519.NewSigningContext([]byte{}) 17 ) 18 19 const ( 20 // PrivKeySize is the number of bytes in an Sr25519 private key. 21 PrivKeySize = 32 22 23 KeyType = "sr25519" 24 ) 25 26 // PrivKey implements crypto.PrivKey. 27 type PrivKey struct { 28 msk sr25519.MiniSecretKey 29 kp *sr25519.KeyPair 30 } 31 32 // Bytes returns the byte representation of the PrivKey. 33 func (privKey PrivKey) Bytes() []byte { 34 if privKey.kp == nil { 35 return nil 36 } 37 return privKey.msk[:] 38 } 39 40 // Sign produces a signature on the provided message. 41 func (privKey PrivKey) Sign(msg []byte) ([]byte, error) { 42 if privKey.kp == nil { 43 return nil, fmt.Errorf("sr25519: uninitialized private key") 44 } 45 46 st := signingCtx.NewTranscriptBytes(msg) 47 48 sig, err := privKey.kp.Sign(crypto.CReader(), st) 49 if err != nil { 50 return nil, fmt.Errorf("sr25519: failed to sign message: %w", err) 51 } 52 53 sigBytes, err := sig.MarshalBinary() 54 if err != nil { 55 return nil, fmt.Errorf("sr25519: failed to serialize signature: %w", err) 56 } 57 58 return sigBytes, nil 59 } 60 61 // PubKey gets the corresponding public key from the private key. 62 func (privKey PrivKey) PubKey() crypto.PubKey { 63 if privKey.kp == nil { 64 panic("sr25519: uninitialized private key") 65 } 66 67 b, err := privKey.kp.PublicKey().MarshalBinary() 68 if err != nil { 69 panic("sr25519: failed to serialize public key: " + err.Error()) 70 } 71 72 return PubKey(b) 73 } 74 75 // Equals - you probably don't need to use this. 76 // Runs in constant time based on length of the keys. 77 func (privKey PrivKey) Equals(other crypto.PrivKey) bool { 78 if otherSr, ok := other.(PrivKey); ok { 79 return privKey.msk.Equal(&otherSr.msk) 80 } 81 return false 82 } 83 84 func (privKey PrivKey) Type() string { 85 return KeyType 86 } 87 88 func (privKey PrivKey) MarshalJSON() ([]byte, error) { 89 var b []byte 90 91 // Handle uninitialized private keys gracefully. 92 if privKey.kp != nil { 93 b = privKey.Bytes() 94 } 95 96 return json.Marshal(b) 97 } 98 99 func (privKey *PrivKey) UnmarshalJSON(data []byte) error { 100 for i := range privKey.msk { 101 privKey.msk[i] = 0 102 } 103 privKey.kp = nil 104 105 var b []byte 106 if err := json.Unmarshal(data, &b); err != nil { 107 return fmt.Errorf("sr25519: failed to deserialize JSON: %w", err) 108 } 109 if len(b) == 0 { 110 return nil 111 } 112 113 msk, err := sr25519.NewMiniSecretKeyFromBytes(b) 114 if err != nil { 115 return err 116 } 117 118 sk := msk.ExpandEd25519() 119 120 privKey.msk = *msk 121 privKey.kp = sk.KeyPair() 122 123 return nil 124 } 125 126 // GenPrivKey generates a new sr25519 private key. 127 // It uses OS randomness in conjunction with the current global random seed 128 // in cometbft/libs/rand to generate the private key. 129 func GenPrivKey() PrivKey { 130 return genPrivKey(crypto.CReader()) 131 } 132 133 // genPrivKey generates a new sr25519 private key using the provided reader. 134 func genPrivKey(rng io.Reader) PrivKey { 135 msk, err := sr25519.GenerateMiniSecretKey(rng) 136 if err != nil { 137 panic("sr25519: failed to generate MiniSecretKey: " + err.Error()) 138 } 139 140 sk := msk.ExpandEd25519() 141 142 return PrivKey{ 143 msk: *msk, 144 kp: sk.KeyPair(), 145 } 146 } 147 148 // GenPrivKeyFromSecret hashes the secret with SHA2, and uses 149 // that 32 byte output to create the private key. 150 // NOTE: secret should be the output of a KDF like bcrypt, 151 // if it's derived from user input. 152 func GenPrivKeyFromSecret(secret []byte) PrivKey { 153 seed := crypto.Sha256(secret) // Not Ripemd160 because we want 32 bytes. 154 155 var privKey PrivKey 156 if err := privKey.msk.UnmarshalBinary(seed); err != nil { 157 panic("sr25519: failed to deserialize MiniSecretKey: " + err.Error()) 158 } 159 160 sk := privKey.msk.ExpandEd25519() 161 privKey.kp = sk.KeyPair() 162 163 return privKey 164 }