Skip to content
Sonr Crypto
Esc
navigateopen⌘Jpreview
On this page

ECIES

Encrypt a payload to a secp256k1 public key. A thin wrapper over github.com/ecies/go/v2 with one significant seed hazard.

github.com/sonr-io/crypto/ecies is a thin wrapper — three files, 70 lines of code — over github.com/ecies/go/v2. ECIES (Elliptic Curve Integrated Encryption Scheme) is hybrid public-key encryption: the sender generates an ephemeral keypair, does ECDH against the recipient’s static public key, derives a symmetric key, and encrypts the payload under an AEAD. The recipient needs no prior interaction — just their own private key and the ciphertext.

Reach for this when you need to encrypt a payload to a public key you already have, with no handshake and no shared state.

Do not reach for this when you need forward secrecy for the recipient, authenticated sender identity (ECIES gives you confidentiality, not sender authentication — sign separately with mpc or an ECDSA key), or a symmetric key you already share (use AEAD directly).

The API surface

type PrivateKey = eciesgo.PrivateKey // type ALIAS, not a wrapper struct
type PublicKey  = eciesgo.PublicKey  // type ALIAS

func GenerateKey() (*PrivateKey, error)
func GenerateKeyFromSeed(seed []byte) (*PrivateKey, error)
func HashSeed(seed []byte) []byte

func Encrypt(pub *PublicKey, plaintext []byte) ([]byte, error)
func Decrypt(priv *PrivateKey, ciphertext []byte) ([]byte, error)

That is the entire package. Encrypt and Decrypt are one-line forwards to eciesgo.Encrypt and eciesgo.Decrypt.

Curve

GenerateKey and GenerateKeyFromSeed both build their key on curves.SP256(), which returns ecc.P256k1() from github.com/dustinxie/ecc — i.e. secp256k1, the same curve as mpc and secp256k1 did:key identifiers. See Foundations → Curves for the curve abstraction.

Note the constructors bypass eciesgo.GenerateKey and assemble the struct by hand from ecdsa.GenerateKey(curve, rand.Reader):

p, err := ecdsa.GenerateKey(curve, rand.Reader)
return &PrivateKey{
	PublicKey: &PublicKey{Curve: curve, X: p.X, Y: p.Y},
	D:         p.D,
}, nil

Usage

package main

import (
	"fmt"

	"github.com/sonr-io/crypto/ecies"
)

func main() {
	// Recipient generates a keypair and publishes the public key.
	priv, err := ecies.GenerateKey()
	if err != nil {
		panic(err)
	}

	// Sender encrypts to the public key. No prior interaction needed.
	ciphertext, err := ecies.Encrypt(priv.PublicKey, []byte("hello"))
	if err != nil {
		panic(err)
	}

	// Recipient decrypts with the private key.
	plaintext, err := ecies.Decrypt(priv, ciphertext)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(plaintext)) // hello
}

GenerateKey is grounded in TestGenerateKey and GenerateKeyFromSeed in TestGenerateFromSeed (ecies/keys_test.go). The encrypt/decrypt round trip above is not covered by any test in the package — see the caveats.

HashSeed and seeded keys

HashSeed(seed []byte) []byte is blake3.Sum512(seed) from lukechampine.com/blake3, returned as a 64-byte slice. Its purpose is to stretch an arbitrary-length input up to enough bytes for GenerateKeyFromSeed, which reads from the seed as an entropy source:

seed := ecies.HashSeed([]byte("some high-entropy passphrase or master secret"))
priv, err := ecies.GenerateKeyFromSeed(seed)

Caveats

Next

Last updated on September 2, 2026

Was this page helpful?