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