initial addition of essential crypto, encoders, workflows and LLM instructions

This commit is contained in:
2025-08-20 05:47:06 +01:00
parent f449a9d415
commit b8db587d7b
159 changed files with 36993 additions and 10 deletions

View File

@@ -0,0 +1,170 @@
//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"
btcec3 "next.orly.dev/pkg/crypto/ec"
"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 *btcec3.SecretKey
pkb, skb []byte
}
var _ signer.I = &Signer{}
// Generate creates a new Signer.
func (s *Signer) Generate() (err error) {
if s.SecretKey, err = btcec3.NewSecretKey(); chk.E(err) {
return
}
s.skb = s.SecretKey.Serialize()
s.BTCECSec, _ = btcec3.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, _ = btcec3.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 = btcec3.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 = btcec3.NewSecretKey(); 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()
}

View File

@@ -0,0 +1,195 @@
//go:build !cgo
package btcec_test
import (
"testing"
"time"
"next.orly.dev/pkg/utils"
"lol.mleku.dev/chk"
"lol.mleku.dev/log"
"next.orly.dev/pkg/crypto/p256k/btcec"
)
func TestSigner_Generate(t *testing.T) {
for _ = range 100 {
var err error
signer := &btcec.Signer{}
var skb []byte
if err = signer.Generate(); chk.E(err) {
t.Fatal(err)
}
skb = signer.Sec()
if err = signer.InitSec(skb); chk.E(err) {
t.Fatal(err)
}
}
}
// func TestBTCECSignerVerify(t *testing.T) {
// evs := make([]*event.E, 0, 10000)
// scanner := bufio.NewScanner(bytes.NewBuffer(examples.Cache))
// buf := make([]byte, 1_000_000)
// scanner.Buffer(buf, len(buf))
// var err error
//
// // Create both btcec and p256k signers
// btcecSigner := &btcec.Signer{}
// p256kSigner := &p256k.Signer{}
//
// for scanner.Scan() {
// var valid bool
// b := scanner.Bytes()
// ev := event.New()
// if _, err = ev.Unmarshal(b); chk.E(err) {
// t.Errorf("failed to marshal\n%s", b)
// } else {
// // We know ev.Verify() works, so we'll use it as a reference
// if valid, err = ev.Verify(); chk.E(err) || !valid {
// t.Errorf("invalid signature\n%s", b)
// continue
// }
// }
//
// // Get the ID from the event
// storedID := ev.ID
// calculatedID := ev.GetIDBytes()
//
// // Check if the stored ID matches the calculated ID
// if !utils.FastEqual(storedID, calculatedID) {
// log.D.Ln("Event ID mismatch: stored ID doesn't match calculated ID")
// // Use the calculated ID for verification as ev.Verify() would do
// ev.ID = calculatedID
// }
//
// if len(ev.ID) != sha256.Size {
// t.Errorf("id should be 32 bytes, got %d", len(ev.ID))
// continue
// }
//
// // Initialize both signers with the same public key
// if err = btcecSigner.InitPub(ev.Pubkey); chk.E(err) {
// t.Errorf("failed to init btcec pub key: %s\n%0x", err, b)
// }
// if err = p256kSigner.InitPub(ev.Pubkey); chk.E(err) {
// t.Errorf("failed to init p256k pub key: %s\n%0x", err, b)
// }
//
// // First try to verify with btcec.Signer
// if valid, err = btcecSigner.Verify(ev.ID, ev.Sig); err == nil && valid {
// // If btcec.Signer verification succeeds, great!
// log.D.Ln("btcec.Signer verification succeeded")
// } else {
// // If btcec.Signer verification fails, try with p256k.Signer
// // Use chk.T(err) like ev.Verify() does
// if valid, err = p256kSigner.Verify(ev.ID, ev.Sig); chk.T(err) {
// // If there's an error, log it but don't fail the test
// log.D.Ln("p256k.Signer verification error:", err)
// } else if !valid {
// // Only fail the test if both verifications fail
// t.Errorf(
// "invalid signature for pub %0x %0x %0x", ev.Pubkey, ev.ID,
// ev.Sig,
// )
// } else {
// log.D.Ln("p256k.Signer verification succeeded where btcec.Signer failed")
// }
// }
//
// evs = append(evs, ev)
// }
// }
// func TestBTCECSignerSign(t *testing.T) {
// evs := make([]*event.E, 0, 10000)
// scanner := bufio.NewScanner(bytes.NewBuffer(examples.Cache))
// buf := make([]byte, 1_000_000)
// scanner.Buffer(buf, len(buf))
// var err error
// signer := &btcec.Signer{}
// var skb []byte
// if err = signer.Generate(); chk.E(err) {
// t.Fatal(err)
// }
// skb = signer.Sec()
// if err = signer.InitSec(skb); chk.E(err) {
// t.Fatal(err)
// }
// verifier := &btcec.Signer{}
// pkb := signer.Pub()
// if err = verifier.InitPub(pkb); chk.E(err) {
// t.Fatal(err)
// }
// counter := 0
// for scanner.Scan() {
// counter++
// if counter > 1000 {
// break
// }
// b := scanner.Bytes()
// ev := event.New()
// if _, err = ev.Unmarshal(b); chk.E(err) {
// t.Errorf("failed to marshal\n%s", b)
// }
// evs = append(evs, ev)
// }
// var valid bool
// sig := make([]byte, schnorr.SignatureSize)
// for _, ev := range evs {
// ev.Pubkey = pkb
// id := ev.GetIDBytes()
// if sig, err = signer.Sign(id); chk.E(err) {
// t.Errorf("failed to sign: %s\n%0x", err, id)
// }
// if valid, err = verifier.Verify(id, sig); chk.E(err) {
// t.Errorf("failed to verify: %s\n%0x", err, id)
// }
// if !valid {
// t.Errorf("invalid signature")
// }
// }
// signer.Zero()
// }
func TestBTCECECDH(t *testing.T) {
n := time.Now()
var err error
var counter int
const total = 50
for _ = range total {
s1 := new(btcec.Signer)
if err = s1.Generate(); chk.E(err) {
t.Fatal(err)
}
s2 := new(btcec.Signer)
if err = s2.Generate(); chk.E(err) {
t.Fatal(err)
}
for _ = range total {
var secret1, secret2 []byte
if secret1, err = s1.ECDH(s2.Pub()); chk.E(err) {
t.Fatal(err)
}
if secret2, err = s2.ECDH(s1.Pub()); chk.E(err) {
t.Fatal(err)
}
if !utils.FastEqual(secret1, secret2) {
counter++
t.Errorf(
"ECDH generation failed to work in both directions, %x %x",
secret1,
secret2,
)
}
}
}
a := time.Now()
duration := a.Sub(n)
log.I.Ln(
"errors", counter, "total", total, "time", duration, "time/op",
int(duration/total),
"ops/sec", int(time.Second)/int(duration/total),
)
}

View File

@@ -0,0 +1,41 @@
//go:build !cgo
package btcec
import (
"lol.mleku.dev/chk"
"next.orly.dev/pkg/encoders/hex"
"next.orly.dev/pkg/interfaces/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 = &Signer{}
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 = &Signer{}
if err = sign.InitPub(pk); chk.E(err) {
return
}
return
}
func HexToBin(hexStr string) (b []byte, err error) {
b = make([]byte, len(hexStr)/2)
if _, err = hex.DecBytes(b, []byte(hexStr)); chk.E(err) {
return
}
return
}