Created
September 18, 2024 11:28
-
-
Save devlongs/da1b455e5aa1aad2274a327888403be4 to your computer and use it in GitHub Desktop.
This code generates private keys, public keys, public addresses, signing messages and verifyinig signatures
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package crypto | |
import ( | |
"crypto/ed25519" | |
"crypto/rand" | |
"encoding/hex" | |
"errors" | |
"io" | |
) | |
const ( | |
privKeyLen = 64 | |
pubKeyLen = 32 | |
seedLen = 32 | |
addressLen = 20 | |
) | |
var ( | |
ErrInvalidSeedLength = errors.New("invalid seed length, must be 32 bytes") | |
ErrInvalidHexString = errors.New("invalid hex string") | |
) | |
type PrivateKey struct { | |
key ed25519.PrivateKey | |
} | |
// NewPrivateKeyFromString creates a PrivateKey from a hex-encoded string | |
func NewPrivateKeyFromString(s string) (*PrivateKey, error) { | |
b, err := hex.DecodeString(s) | |
if err != nil { | |
return nil, ErrInvalidHexString | |
} | |
return NewPrivateKeyFromSeed(b) | |
} | |
// NewPrivateKeyFromSeed creates a PrivateKey from a given seed | |
func NewPrivateKeyFromSeed(seed []byte) (*PrivateKey, error) { | |
if len(seed) != seedLen { | |
return nil, ErrInvalidSeedLength | |
} | |
return &PrivateKey{ | |
key: ed25519.NewKeyFromSeed(seed), | |
}, nil | |
} | |
// GeneratePrivateKey generates a new PrivateKey with a random seed | |
func GeneratePrivateKey() (*PrivateKey, error) { | |
seed := make([]byte, seedLen) | |
if _, err := io.ReadFull(rand.Reader, seed); err != nil { | |
return nil, err | |
} | |
return NewPrivateKeyFromSeed(seed) | |
} | |
// Bytes returns the raw private key bytes | |
func (p *PrivateKey) Bytes() []byte { | |
return p.key | |
} | |
// Sign signs a message and returns a Signature | |
func (p *PrivateKey) Sign(msg []byte) *Signature { | |
return &Signature{ | |
value: ed25519.Sign(p.key, msg), | |
} | |
} | |
// Public returns the associated PublicKey | |
func (p *PrivateKey) Public() *PublicKey { | |
return &PublicKey{ | |
key: p.key[privKeyLen-pubKeyLen:], // Extract the public key from the private key | |
} | |
} | |
type PublicKey struct { | |
key ed25519.PublicKey | |
} | |
// Address returns the Address derived from the public key | |
func (p *PublicKey) Address() Address { | |
return Address{ | |
value: p.key[len(p.key)-addressLen:], // Get the last 20 bytes for the address | |
} | |
} | |
// Bytes returns the raw public key bytes | |
func (p *PublicKey) Bytes() []byte { | |
return p.key | |
} | |
type Signature struct { | |
value []byte | |
} | |
// Bytes returns the raw signature bytes | |
func (s *Signature) Bytes() []byte { | |
return s.value | |
} | |
// Verify checks whether the signature is valid for the given message and public key | |
func (s *Signature) Verify(pubKey *PublicKey, msg []byte) bool { | |
return ed25519.Verify(pubKey.key, msg, s.value) | |
} | |
type Address struct { | |
value []byte | |
} | |
// Bytes returns the raw address bytes | |
func (a Address) Bytes() []byte { | |
return a.value | |
} | |
// String returns the address as a hex-encoded string | |
func (a Address) String() string { | |
return hex.EncodeToString(a.value) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment