Files
next.orly.dev/pkg/crypto/p256k/btcec/btcec.go
mleku 110223fc4e Migrate internal module imports to unified package path.
Replaced legacy `*.orly` module imports with `next.orly.dev/pkg` paths across the codebase for consistency. Removed legacy `go.mod` files from sub-packages, consolidating dependency management. Added Dockerfiles and configurations for benchmarking environments.
2025-09-12 16:12:31 +01:00

170 lines
4.5 KiB
Go

//go:build !cgo
// Package btcec implements the signer.I interface for signatures and ECDH with nostr.
package btcec
import (
"lol.mleku.dev/chk"
"lol.mleku.dev/errorf"
"next.orly.dev/pkg/crypto/ec/schnorr"
"next.orly.dev/pkg/crypto/ec/secp256k1"
"next.orly.dev/pkg/interfaces/signer"
)
// Signer is an implementation of signer.I that uses the btcec library.
type Signer struct {
SecretKey *secp256k1.SecretKey
PublicKey *secp256k1.PublicKey
BTCECSec *secp256k1.SecretKey
pkb, skb []byte
}
var _ signer.I = &Signer{}
// Generate creates a new Signer.
func (s *Signer) Generate() (err error) {
if s.SecretKey, err = secp256k1.GenerateSecretKey(); chk.E(err) {
return
}
s.skb = s.SecretKey.Serialize()
s.BTCECSec = secp256k1.PrivKeyFromBytes(s.skb)
s.PublicKey = s.SecretKey.PubKey()
s.pkb = schnorr.SerializePubKey(s.PublicKey)
return
}
// InitSec initialises a Signer using raw secret key bytes.
func (s *Signer) InitSec(sec []byte) (err error) {
if len(sec) != secp256k1.SecKeyBytesLen {
err = errorf.E("sec key must be %d bytes", secp256k1.SecKeyBytesLen)
return
}
s.skb = sec
s.SecretKey = secp256k1.SecKeyFromBytes(sec)
s.PublicKey = s.SecretKey.PubKey()
s.pkb = schnorr.SerializePubKey(s.PublicKey)
s.BTCECSec = secp256k1.PrivKeyFromBytes(s.skb)
return
}
// InitPub initializes a signature verifier Signer from raw public key bytes.
func (s *Signer) InitPub(pub []byte) (err error) {
if s.PublicKey, err = schnorr.ParsePubKey(pub); chk.E(err) {
return
}
s.pkb = pub
return
}
// Sec returns the raw secret key bytes.
func (s *Signer) Sec() (b []byte) {
if s == nil {
return nil
}
return s.skb
}
// Pub returns the raw BIP-340 schnorr public key bytes.
func (s *Signer) Pub() (b []byte) {
if s == nil {
return nil
}
return s.pkb
}
// Sign a message with the Signer. Requires an initialised secret key.
func (s *Signer) Sign(msg []byte) (sig []byte, err error) {
if s.SecretKey == nil {
err = errorf.E("btcec: Signer not initialized")
return
}
var si *schnorr.Signature
if si, err = schnorr.Sign(s.SecretKey, msg); chk.E(err) {
return
}
sig = si.Serialize()
return
}
// Verify a message signature, only requires the public key is initialised.
func (s *Signer) Verify(msg, sig []byte) (valid bool, err error) {
if s.PublicKey == nil {
err = errorf.E("btcec: Pubkey not initialized")
return
}
// First try to verify using the schnorr package
var si *schnorr.Signature
if si, err = schnorr.ParseSignature(sig); err == nil {
valid = si.Verify(msg, s.PublicKey)
return
}
// If parsing the signature failed, log it at debug level
chk.D(err)
// If the signature is exactly 64 bytes, try to verify it directly
// This is to handle signatures created by p256k.Signer which uses libsecp256k1
if len(sig) == schnorr.SignatureSize {
// Create a new signature with the raw bytes
var r secp256k1.FieldVal
var sScalar secp256k1.ModNScalar
// Split the signature into r and s components
if overflow := r.SetByteSlice(sig[0:32]); !overflow {
sScalar.SetByteSlice(sig[32:64])
// Create a new signature and verify it
newSig := schnorr.NewSignature(&r, &sScalar)
valid = newSig.Verify(msg, s.PublicKey)
return
}
}
// If all verification methods failed, return an error
err = errorf.E(
"failed to verify signature:\n%d %s", len(sig), sig,
)
return
}
// Zero wipes the bytes of the secret key.
func (s *Signer) Zero() { s.SecretKey.Key.Zero() }
// ECDH creates a shared secret from a secret key and a provided public key bytes. It is advised
// to hash this result for security reasons.
func (s *Signer) ECDH(pubkeyBytes []byte) (secret []byte, err error) {
var pub *secp256k1.PublicKey
if pub, err = secp256k1.ParsePubKey(
append(
[]byte{0x02}, pubkeyBytes...,
),
); chk.E(err) {
return
}
secret = secp256k1.GenerateSharedSecret(s.BTCECSec, pub)
return
}
// Keygen implements a key generator. Used for such things as vanity npub mining.
type Keygen struct {
Signer
}
// Generate a new key pair. If the result is suitable, the embedded Signer can have its contents
// extracted.
func (k *Keygen) Generate() (pubBytes []byte, err error) {
if k.Signer.SecretKey, err = secp256k1.GenerateSecretKey(); chk.E(err) {
return
}
k.Signer.PublicKey = k.SecretKey.PubKey()
k.Signer.pkb = schnorr.SerializePubKey(k.Signer.PublicKey)
pubBytes = k.Signer.pkb
return
}
// KeyPairBytes returns the raw bytes of the embedded Signer.
func (k *Keygen) KeyPairBytes() (secBytes, cmprPubBytes []byte) {
return k.Signer.SecretKey.Serialize(), k.Signer.PublicKey.SerializeCompressed()
}