Skip to content

Instantly share code, notes, and snippets.

@devlongs
Created September 18, 2024 11:28
Show Gist options
  • Save devlongs/da1b455e5aa1aad2274a327888403be4 to your computer and use it in GitHub Desktop.
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
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