From 0123c2d6f5b17cddd1337aa75a341e5a0b22e953 Mon Sep 17 00:00:00 2001 From: mleku Date: Sun, 2 Nov 2025 16:43:58 +0000 Subject: [PATCH] Update dependencies and refactor p256k crypto package - Bumped version of lol.mleku.dev from v1.0.4 to v1.0.5. - Added new dependencies: p256k1.mleku.dev and several indirect dependencies for improved cryptographic functionality. - Refactored p256k package to utilize p256k1.mleku.dev/signer for signature operations, replacing the previous btcec implementation. - Removed the secp256k1.go file, consolidating the crypto logic under the new p256k1 library. - Updated documentation to reflect changes in the signer interface and usage. --- go.mod | 8 +- go.sum | 16 +- pkg/crypto/p256k/btcec.go | 20 +- pkg/crypto/p256k/doc.go | 11 +- pkg/crypto/p256k/helpers-btcec.go | 41 +++ pkg/crypto/p256k/helpers.go | 5 +- pkg/crypto/p256k/p256k.go | 134 +--------- pkg/crypto/p256k/secp256k1.go | 426 ------------------------------ 8 files changed, 87 insertions(+), 574 deletions(-) create mode 100644 pkg/crypto/p256k/helpers-btcec.go delete mode 100644 pkg/crypto/p256k/secp256k1.go diff --git a/go.mod b/go.mod index cfd03af..d66bb20 100644 --- a/go.mod +++ b/go.mod @@ -20,13 +20,18 @@ require ( golang.org/x/lint v0.0.0-20241112194109-818c5a804067 golang.org/x/net v0.46.0 honnef.co/go/tools v0.6.1 - lol.mleku.dev v1.0.4 + lol.mleku.dev v1.0.5 lukechampine.com/frand v1.5.1 + p256k1.mleku.dev v1.0.1 ) require ( github.com/BurntSushi/toml v1.5.0 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.6 // indirect + github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/decred/dcrd/crypto/blake256 v1.0.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/dgraph-io/ristretto/v2 v2.3.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/felixge/fgprof v0.9.5 // indirect @@ -35,6 +40,7 @@ require ( github.com/google/flatbuffers v25.9.23+incompatible // indirect github.com/google/pprof v0.0.0-20251007162407-5df77e3f7d1d // indirect github.com/klauspost/compress v1.18.1 // indirect + github.com/minio/sha256-simd v1.0.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/templexxx/cpu v0.1.1 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect diff --git a/go.sum b/go.sum index 25b3649..f434e7d 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,10 @@ github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/adrg/xdg v0.5.3 h1:xRnxJXne7+oWDatRhR1JLnvuccuIeCoBu2rtuLqQB78= github.com/adrg/xdg v0.5.3/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ= +github.com/btcsuite/btcd/btcec/v2 v2.3.6 h1:IzlsEr9olcSRKB/n7c4351F3xHKxS2lma+1UFGCYd4E= +github.com/btcsuite/btcd/btcec/v2 v2.3.6/go.mod h1:m22FrOAiuxl/tht9wIqAoGHcbnCCaPWyauO8y2LGGtQ= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= +github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs= @@ -16,6 +20,10 @@ github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= github.com/dgraph-io/badger/v4 v4.8.0 h1:JYph1ChBijCw8SLeybvPINizbDKWZ5n/GYbz2yhN/bs= github.com/dgraph-io/badger/v4 v4.8.0/go.mod h1:U6on6e8k/RTbUWxqKR0MvugJuVmkxSNc79ap4917h4w= github.com/dgraph-io/ristretto/v2 v2.3.0 h1:qTQ38m7oIyd4GAed/QkUZyPFNMnvVWyazGXRwvOt5zk= @@ -60,6 +68,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= +github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA= github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= @@ -138,7 +148,9 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.6.1 h1:R094WgE8K4JirYjBaOpz/AvTyUu/3wbmAoskKN/pxTI= honnef.co/go/tools v0.6.1/go.mod h1:3puzxxljPCe8RGJX7BIy1plGbxEOZni5mR2aXe3/uk4= -lol.mleku.dev v1.0.4 h1:SOngs7erj8J3nXz673kYFgXQHFO+jkCI1E2iOlpyzV8= -lol.mleku.dev v1.0.4/go.mod h1:DQ0WnmkntA9dPLCXgvtIgYt5G0HSqx3wSTLolHgWeLA= +lol.mleku.dev v1.0.5 h1:irwfwz+Scv74G/2OXmv05YFKOzUNOVZ735EAkYgjgM8= +lol.mleku.dev v1.0.5/go.mod h1:JlsqP0CZDLKRyd85XGcy79+ydSRqmFkrPzYFMYxQ+zs= lukechampine.com/frand v1.5.1 h1:fg0eRtdmGFIxhP5zQJzM1lFDbD6CUfu/f+7WgAZd5/w= lukechampine.com/frand v1.5.1/go.mod h1:4VstaWc2plN4Mjr10chUD46RAVGWhpkZ5Nja8+Azp0Q= +p256k1.mleku.dev v1.0.1 h1:4ZQ+2xNfKpL6+e9urKP6f/QdHKKUNIEsqvFwogpluZw= +p256k1.mleku.dev v1.0.1/go.mod h1:gY2ybEebhiSgSDlJ8ERgAe833dn2EDqs7aBsvwpgu0s= diff --git a/pkg/crypto/p256k/btcec.go b/pkg/crypto/p256k/btcec.go index d6a6286..b9d2801 100644 --- a/pkg/crypto/p256k/btcec.go +++ b/pkg/crypto/p256k/btcec.go @@ -4,22 +4,18 @@ package p256k import ( "lol.mleku.dev/log" - "next.orly.dev/pkg/crypto/p256k/btcec" + p256k1signer "p256k1.mleku.dev/signer" ) func init() { - log.T.Ln("using btcec signature library") + log.T.Ln("using p256k1.mleku.dev/signer (pure Go/Btcec)") } -// BTCECSigner is always available but enabling it disables the use of -// github.com/bitcoin-core/secp256k1 CGO signature implementation and points it at the btec -// version. +// Signer is an alias for the BtcecSigner type from p256k1.mleku.dev/signer (btcec version). +// This is used when CGO is not available. +type Signer = p256k1signer.BtcecSigner -type Signer = btcec.Signer -type Keygen = btcec.Keygen +// Keygen is an alias for the P256K1Gen type from p256k1.mleku.dev/signer (btcec version). +type Keygen = p256k1signer.P256K1Gen -func NewKeygen() (k *Keygen) { return new(Keygen) } - -var NewSecFromHex = btcec.NewSecFromHex[string] -var NewPubFromHex = btcec.NewPubFromHex[string] -var HexToBin = btcec.HexToBin +var NewKeygen = p256k1signer.NewP256K1Gen \ No newline at end of file diff --git a/pkg/crypto/p256k/doc.go b/pkg/crypto/p256k/doc.go index d88e08e..8ba5e97 100644 --- a/pkg/crypto/p256k/doc.go +++ b/pkg/crypto/p256k/doc.go @@ -1,6 +1,9 @@ -// Package p256k is a signer interface that (by default) uses the -// bitcoin/libsecp256k1 library for fast signature creation and verification of -// the BIP-340 nostr X-only signatures and public keys, and ECDH. +// Package p256k provides a signer interface that uses p256k1.mleku.dev library for +// fast signature creation and verification of BIP-340 nostr X-only signatures and +// public keys, and ECDH. // -// Currently the ECDH is only implemented with the btcec library. +// The package provides type aliases to p256k1.mleku.dev/signer: +// - cgo: Uses the CGO-optimized version from p256k1.mleku.dev +// - btcec: Uses the btcec version from p256k1.mleku.dev +// - default: Uses the pure Go version from p256k1.mleku.dev package p256k diff --git a/pkg/crypto/p256k/helpers-btcec.go b/pkg/crypto/p256k/helpers-btcec.go new file mode 100644 index 0000000..aec2c54 --- /dev/null +++ b/pkg/crypto/p256k/helpers-btcec.go @@ -0,0 +1,41 @@ +//go:build !cgo + +package p256k + +import ( + "lol.mleku.dev/chk" + "next.orly.dev/pkg/encoders/hex" + "next.orly.dev/pkg/interfaces/signer" + p256k1signer "p256k1.mleku.dev/signer" +) + +func NewSecFromHex[V []byte | string](skh V) (sign signer.I, err error) { + sk := make([]byte, len(skh)/2) + if _, err = hex.DecBytes(sk, []byte(skh)); chk.E(err) { + return + } + sign = p256k1signer.NewBtcecSigner() + if err = sign.InitSec(sk); chk.E(err) { + return + } + return +} + +func NewPubFromHex[V []byte | string](pkh V) (sign signer.I, err error) { + pk := make([]byte, len(pkh)/2) + if _, err = hex.DecBytes(pk, []byte(pkh)); chk.E(err) { + return + } + sign = p256k1signer.NewBtcecSigner() + if err = sign.InitPub(pk); chk.E(err) { + return + } + return +} + +func HexToBin(hexStr string) (b []byte, err error) { + if b, err = hex.DecAppend(b, []byte(hexStr)); chk.E(err) { + return + } + return +} diff --git a/pkg/crypto/p256k/helpers.go b/pkg/crypto/p256k/helpers.go index 1f4a740..0a2c07d 100644 --- a/pkg/crypto/p256k/helpers.go +++ b/pkg/crypto/p256k/helpers.go @@ -6,6 +6,7 @@ import ( "lol.mleku.dev/chk" "next.orly.dev/pkg/encoders/hex" "next.orly.dev/pkg/interfaces/signer" + p256k1signer "p256k1.mleku.dev/signer" ) func NewSecFromHex[V []byte | string](skh V) (sign signer.I, err error) { @@ -13,7 +14,7 @@ func NewSecFromHex[V []byte | string](skh V) (sign signer.I, err error) { if _, err = hex.DecBytes(sk, []byte(skh)); chk.E(err) { return } - sign = &Signer{} + sign = p256k1signer.NewP256K1Signer() if err = sign.InitSec(sk); chk.E(err) { return } @@ -25,7 +26,7 @@ func NewPubFromHex[V []byte | string](pkh V) (sign signer.I, err error) { if _, err = hex.DecBytes(pk, []byte(pkh)); chk.E(err) { return } - sign = &Signer{} + sign = p256k1signer.NewP256K1Signer() if err = sign.InitPub(pk); chk.E(err) { return } diff --git a/pkg/crypto/p256k/p256k.go b/pkg/crypto/p256k/p256k.go index c44d653..3ff20f7 100644 --- a/pkg/crypto/p256k/p256k.go +++ b/pkg/crypto/p256k/p256k.go @@ -2,139 +2,19 @@ package p256k -import "C" import ( - "lol.mleku.dev/chk" - "lol.mleku.dev/errorf" "lol.mleku.dev/log" - "next.orly.dev/pkg/crypto/ec" - "next.orly.dev/pkg/crypto/ec/secp256k1" - "next.orly.dev/pkg/interfaces/signer" + p256k1signer "p256k1.mleku.dev/signer" ) func init() { - log.T.Ln("using bitcoin/secp256k1 signature library") + log.T.Ln("using p256k1.mleku.dev/signer (CGO)") } -// Signer implements the signer.I interface. -// -// Either the Sec or Pub must be populated, the former is for generating -// signatures, the latter is for verifying them. -// -// When using this library only for verification, a constructor that converts -// from bytes to PubKey is needed prior to calling Verify. -type Signer struct { - // SecretKey is the secret key. - SecretKey *SecKey - // PublicKey is the public key. - PublicKey *PubKey - // BTCECSec is needed for ECDH as currently the CGO bindings don't include it - BTCECSec *btcec.SecretKey - skb, pkb []byte -} +// Signer is an alias for the P256K1Signer type from p256k1.mleku.dev/signer (cgo version). +type Signer = p256k1signer.P256K1Signer -var _ signer.I = &Signer{} +// Keygen is an alias for the P256K1Gen type from p256k1.mleku.dev/signer (cgo version). +type Keygen = p256k1signer.P256K1Gen -// Generate a new Signer key pair using the CGO bindings to libsecp256k1 -func (s *Signer) Generate() (err error) { - var cs *Sec - var cx *XPublicKey - if s.skb, s.pkb, cs, cx, err = Generate(); chk.E(err) { - return - } - s.SecretKey = &cs.Key - s.PublicKey = cx.Key - s.BTCECSec, _ = btcec.PrivKeyFromBytes(s.skb) - return -} - -func (s *Signer) InitSec(skb []byte) (err error) { - var cs *Sec - var cx *XPublicKey - // var cp *PublicKey - if s.pkb, cs, cx, err = FromSecretBytes(skb); chk.E(err) { - if err.Error() != "provided secret generates a public key with odd Y coordinate, fixed version returned" { - log.E.Ln(err) - return - } - } - s.skb = skb - s.SecretKey = &cs.Key - s.PublicKey = cx.Key - // s.ECPublicKey = cp.Key - // needed for ecdh - s.BTCECSec, _ = btcec.PrivKeyFromBytes(s.skb) - return -} - -func (s *Signer) InitPub(pub []byte) (err error) { - var up *Pub - if up, err = PubFromBytes(pub); chk.E(err) { - return - } - s.PublicKey = &up.Key - s.pkb = up.PubB() - return -} - -func (s *Signer) Sec() (b []byte) { - if s == nil { - return nil - } - return s.skb -} -func (s *Signer) Pub() (b []byte) { - if s == nil { - return nil - } - return s.pkb -} - -// func (s *Signer) ECPub() (b []byte) { return s.pkb } - -func (s *Signer) Sign(msg []byte) (sig []byte, err error) { - if s.SecretKey == nil { - err = errorf.E("p256k: I secret not initialized") - return - } - u := ToUchar(msg) - if sig, err = Sign(u, s.SecretKey); chk.E(err) { - return - } - return -} - -func (s *Signer) Verify(msg, sig []byte) (valid bool, err error) { - if s.PublicKey == nil { - err = errorf.E("p256k: Pubkey not initialized") - return - } - var uMsg, uSig *Uchar - if uMsg, err = Msg(msg); chk.E(err) { - return - } - if uSig, err = Sig(sig); chk.E(err) { - return - } - valid = Verify(uMsg, uSig, s.PublicKey) - if !valid { - err = errorf.E("p256k: invalid signature") - } - return -} - -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 = btcec.GenerateSharedSecret(s.BTCECSec, pub) - return -} - -func (s *Signer) Zero() { Zero(s.SecretKey) } +var NewKeygen = p256k1signer.NewP256K1Gen \ No newline at end of file diff --git a/pkg/crypto/p256k/secp256k1.go b/pkg/crypto/p256k/secp256k1.go deleted file mode 100644 index c76bb5e..0000000 --- a/pkg/crypto/p256k/secp256k1.go +++ /dev/null @@ -1,426 +0,0 @@ -//go:build cgo - -package p256k - -import ( - "crypto/rand" - "unsafe" - - "lol.mleku.dev/chk" - "lol.mleku.dev/errorf" - "lol.mleku.dev/log" - "next.orly.dev/pkg/crypto/ec/schnorr" - "next.orly.dev/pkg/crypto/ec/secp256k1" - "next.orly.dev/pkg/crypto/sha256" -) - -/* -#cgo LDFLAGS: -lsecp256k1 -#include -#include -#include -*/ -import "C" - -type ( - Context = C.secp256k1_context - Uchar = C.uchar - Cint = C.int - SecKey = C.secp256k1_keypair - PubKey = C.secp256k1_xonly_pubkey - ECPubKey = C.secp256k1_pubkey -) - -var ( - ctx *Context -) - -func CreateContext() *Context { - return C.secp256k1_context_create( - C.SECP256K1_CONTEXT_SIGN | - C.SECP256K1_CONTEXT_VERIFY, - ) -} - -func GetRandom() (u *Uchar) { - rnd := make([]byte, 32) - _, _ = rand.Read(rnd) - return ToUchar(rnd) -} - -func AssertLen(b []byte, length int, name string) (err error) { - if len(b) != length { - err = errorf.E("%s should be %d bytes, got %d", name, length, len(b)) - } - return -} - -func RandomizeContext(ctx *C.secp256k1_context) { - C.secp256k1_context_randomize(ctx, GetRandom()) - return -} - -func CreateRandomContext() (c *Context) { - c = CreateContext() - RandomizeContext(c) - return -} - -func init() { - if ctx = CreateContext(); ctx == nil { - panic("failed to create secp256k1 context") - } -} - -func ToUchar(b []byte) (u *Uchar) { return (*Uchar)(unsafe.Pointer(&b[0])) } - -type Sec struct { - Key SecKey -} - -func GenSec() (sec *Sec, err error) { - if _, _, sec, _, err = Generate(); chk.E(err) { - return - } - return -} - -func SecFromBytes(sk []byte) (sec *Sec, err error) { - sec = new(Sec) - if C.secp256k1_keypair_create(ctx, &sec.Key, ToUchar(sk)) != 1 { - err = errorf.E("failed to parse private key") - return - } - return -} - -func (s *Sec) Sec() *SecKey { return &s.Key } - -func (s *Sec) Pub() (p *Pub, err error) { - p = new(Pub) - if C.secp256k1_keypair_xonly_pub(ctx, &p.Key, nil, s.Sec()) != 1 { - err = errorf.E("pubkey derivation failed") - return - } - return -} - -// type PublicKey struct { -// Key *C.secp256k1_pubkey -// } -// -// func NewPublicKey() *PublicKey { -// return &PublicKey{ -// Key: &C.secp256k1_pubkey{}, -// } -// } - -type XPublicKey struct { - Key *C.secp256k1_xonly_pubkey -} - -func NewXPublicKey() *XPublicKey { - return &XPublicKey{ - Key: &C.secp256k1_xonly_pubkey{}, - } -} - -// FromSecretBytes parses and processes what should be a secret key. If it is a correct key within the curve order, but -// with a public key having an odd Y coordinate, it returns an error with the fixed key. -func FromSecretBytes(skb []byte) ( - pkb []byte, - sec *Sec, - pub *XPublicKey, - // ecPub *PublicKey, - err error, -) { - xpkb := make([]byte, schnorr.PubKeyBytesLen) - // clen := C.size_t(secp256k1.PubKeyBytesLenCompressed - 1) - pkb = make([]byte, schnorr.PubKeyBytesLen) - var parity Cint - // ecPub = NewPublicKey() - pub = NewXPublicKey() - sec = &Sec{} - uskb := ToUchar(skb) - res := C.secp256k1_keypair_create(ctx, &sec.Key, uskb) - if res != 1 { - err = errorf.E("failed to create secp256k1 keypair") - return - } - // C.secp256k1_keypair_pub(ctx, ecPub.Key, &sec.Key) - // C.secp256k1_ec_pubkey_serialize(ctx, ToUchar(ecpkb), &clen, ecPub.Key, - // C.SECP256K1_EC_COMPRESSED) - // if ecpkb[0] != 2 { - // log.W.ToSliceOfBytes("odd pubkey from %0x -> %0x", skb, ecpkb) - // Negate(skb) - // uskb = ToUchar(skb) - // res = C.secp256k1_keypair_create(ctx, &sec.Key, uskb) - // if res != 1 { - // err = errorf.E("failed to create secp256k1 keypair") - // return - // } - // C.secp256k1_keypair_pub(ctx, ecPub.Key, &sec.Key) - // C.secp256k1_ec_pubkey_serialize(ctx, ToUchar(ecpkb), &clen, ecPub.Key, C.SECP256K1_EC_COMPRESSED) - // C.secp256k1_keypair_xonly_pub(ctx, pub.Key, &parity, &sec.Key) - // err = errors.New("provided secret generates a public key with odd Y coordinate, fixed version returned") - // } - C.secp256k1_keypair_xonly_pub(ctx, pub.Key, &parity, &sec.Key) - C.secp256k1_xonly_pubkey_serialize(ctx, ToUchar(xpkb), pub.Key) - pkb = xpkb - // log.I.S(sec, pub, skb, pkb) - return -} - -// Generate gathers entropy to generate a full set of bytes and CGO values of it and derived from it to perform -// signature and ECDH operations. -func Generate() ( - skb, pkb []byte, - sec *Sec, - pub *XPublicKey, - err error, -) { - skb = make([]byte, secp256k1.SecKeyBytesLen) - pkb = make([]byte, schnorr.PubKeyBytesLen) - upkb := ToUchar(pkb) - var parity Cint - pub = NewXPublicKey() - sec = &Sec{} - for { - if _, err = rand.Read(skb); chk.E(err) { - return - } - uskb := ToUchar(skb) - if res := C.secp256k1_keypair_create(ctx, &sec.Key, uskb); res != 1 { - err = errorf.E("failed to create secp256k1 keypair") - continue - } - C.secp256k1_keypair_xonly_pub(ctx, pub.Key, &parity, &sec.Key) - C.secp256k1_xonly_pubkey_serialize(ctx, upkb, pub.Key) - break - } - return -} - -// Negate inverts a secret key so an odd prefix bit becomes even and vice versa. -func Negate(uskb []byte) { C.secp256k1_ec_seckey_negate(ctx, ToUchar(uskb)) } - -type ECPub struct { - Key ECPubKey -} - -// ECPubFromSchnorrBytes converts a BIP-340 public key to its even standard 33 byte encoding. -// -// This function is for the purpose of getting a key to do ECDH from an x-only key. -func ECPubFromSchnorrBytes(xkb []byte) (pub *ECPub, err error) { - if err = AssertLen(xkb, schnorr.PubKeyBytesLen, "pubkey"); chk.E(err) { - return - } - pub = &ECPub{} - p := append([]byte{0}, xkb...) - if C.secp256k1_ec_pubkey_parse( - ctx, &pub.Key, ToUchar(p), - secp256k1.PubKeyBytesLenCompressed, - ) != 1 { - err = errorf.E("failed to parse pubkey from %0x", p) - log.I.S(pub) - return - } - return -} - -// // ECPubFromBytes parses a pubkey from 33 bytes to the bitcoin-core/secp256k1 struct. -// func ECPubFromBytes(pkb []byte) (pub *ECPub, err error) { -// if err = AssertLen(pkb, secp256k1.PubKeyBytesLenCompressed, "pubkey"); chk.E(err) { -// return -// } -// pub = &ECPub{} -// if C.secp256k1_ec_pubkey_parse(ctx, &pub.Key, ToUchar(pkb), -// secp256k1.PubKeyBytesLenCompressed) != 1 { -// err = errorf.E("failed to parse pubkey from %0x", pkb) -// log.I.S(pub) -// return -// } -// return -// } - -// Pub is a schnorr BIP-340 public key. -type Pub struct { - Key PubKey -} - -// PubFromBytes creates a public key from raw bytes. -func PubFromBytes(pk []byte) (pub *Pub, err error) { - if err = AssertLen(pk, schnorr.PubKeyBytesLen, "pubkey"); chk.E(err) { - return - } - pub = new(Pub) - if C.secp256k1_xonly_pubkey_parse(ctx, &pub.Key, ToUchar(pk)) != 1 { - err = errorf.E("failed to parse pubkey from %0x", pk) - return - } - return -} - -// PubB returns the contained public key as bytes. -func (p *Pub) PubB() (b []byte) { - b = make([]byte, schnorr.PubKeyBytesLen) - C.secp256k1_xonly_pubkey_serialize(ctx, ToUchar(b), &p.Key) - return -} - -// Pub returns the public key as a PubKey. -func (p *Pub) Pub() *PubKey { return &p.Key } - -// ToBytes returns the contained public key as bytes. -func (p *Pub) ToBytes() (b []byte, err error) { - b = make([]byte, schnorr.PubKeyBytesLen) - if C.secp256k1_xonly_pubkey_serialize(ctx, ToUchar(b), p.Pub()) != 1 { - err = errorf.E("pubkey serialize failed") - return - } - return -} - -// Sign a message and return a schnorr BIP-340 64 byte signature. -func Sign(msg *Uchar, sk *SecKey) (sig []byte, err error) { - sig = make([]byte, schnorr.SignatureSize) - c := CreateRandomContext() - if C.secp256k1_schnorrsig_sign32( - c, ToUchar(sig), msg, sk, - GetRandom(), - ) != 1 { - err = errorf.E("failed to sign message") - return - } - return -} - -// SignFromBytes Signs a message using a provided secret key and message as raw bytes. -func SignFromBytes(msg, sk []byte) (sig []byte, err error) { - var umsg *Uchar - if umsg, err = Msg(msg); chk.E(err) { - return - } - var sec *Sec - if sec, err = SecFromBytes(sk); chk.E(err) { - return - } - return Sign(umsg, sec.Sec()) -} - -// Msg checks that a message hash is correct, and converts it for use with a Signer. -func Msg(b []byte) (id *Uchar, err error) { - if err = AssertLen(b, sha256.Size, "id"); chk.E(err) { - return - } - id = ToUchar(b) - return -} - -// Sig checks that a signature bytes is correct, and converts it for use with a Signer. -func Sig(b []byte) (sig *Uchar, err error) { - if err = AssertLen(b, schnorr.SignatureSize, "sig"); chk.E(err) { - return - } - sig = ToUchar(b) - return -} - -// Verify a message signature matches the provided PubKey. -func Verify(msg, sig *Uchar, pk *PubKey) (valid bool) { - return C.secp256k1_schnorrsig_verify(ctx, sig, msg, 32, pk) == 1 -} - -// VerifyFromBytes a signature from the raw bytes of the message hash, signature and public key -func VerifyFromBytes(msg, sig, pk []byte) (err error) { - var umsg, usig *Uchar - if umsg, err = Msg(msg); chk.E(err) { - return - } - if usig, err = Sig(sig); chk.E(err) { - return - } - var pub *Pub - if pub, err = PubFromBytes(pk); chk.E(err) { - return - } - valid := Verify(umsg, usig, pub.Pub()) - if !valid { - err = errorf.E("failed to verify signature") - } - return -} - -// Zero wipes the memory of a SecKey by overwriting it three times with random data and then -// zeroing it. -func Zero(sk *SecKey) { - b := (*[96]byte)(unsafe.Pointer(sk))[:96] - for range 3 { - rand.Read(b) - // reverse the order and negate - lb := len(b) - l := lb / 2 - for j := range l { - b[j] = ^b[lb-1-j] - } - } - for i := range b { - b[i] = 0 - } -} - -// Keygen is an implementation of a key miner designed to be used for vanity key generation with X-only BIP-340 keys. -type Keygen struct { - secBytes, comprPubBytes []byte - secUchar, cmprPubUchar *Uchar - sec *Sec - // ecpub *PublicKey - cmprLen C.size_t -} - -// NewKeygen allocates the required buffers for deriving a key. This should only be done once to avoid garbage and make -// the key mining as fast as possible. -// -// This allocates everything and creates proper CGO variables needed for the generate function so they only need to be -// allocated once per thread. -func NewKeygen() (k *Keygen) { - k = new(Keygen) - k.cmprLen = C.size_t(secp256k1.PubKeyBytesLenCompressed) - k.secBytes = make([]byte, secp256k1.SecKeyBytesLen) - k.comprPubBytes = make([]byte, secp256k1.PubKeyBytesLenCompressed) - k.secUchar = ToUchar(k.secBytes) - k.cmprPubUchar = ToUchar(k.comprPubBytes) - k.sec = &Sec{} - // k.ecpub = NewPublicKey() - return -} - -// Generate takes a pair of buffers for the secret and ec pubkey bytes and gathers new entropy and returns a valid -// secret key and the compressed pubkey bytes for the partial collision search. -// -// The first byte of pubBytes must be sliced off before deriving the hex/Bech32 forms of the nostr public key. -func (k *Keygen) Generate() ( - sec *Sec, - pub *XPublicKey, - pubBytes []byte, - err error, -) { - if _, err = rand.Read(k.secBytes); chk.E(err) { - return - } - if res := C.secp256k1_keypair_create( - ctx, &k.sec.Key, k.secUchar, - ); res != 1 { - err = errorf.E("failed to create secp256k1 keypair") - return - } - var parity Cint - C.secp256k1_keypair_xonly_pub(ctx, pub.Key, &parity, &sec.Key) - // C.secp256k1_keypair_pub(ctx, k.ecpub.Key, &k.sec.Key) - // C.secp256k1_ec_pubkey_serialize(ctx, k.cmprPubUchar, &k.cmprLen, k.ecpub.Key, - // C.SECP256K1_EC_COMPRESSED) - // pubBytes = k.comprPubBytes - C.secp256k1_xonly_pubkey_serialize(ctx, ToUchar(pubBytes), pub.Key) - // pubBytes = - return -}