Browse Source
- Replaced the p256k package with p256k1.mleku.dev/signer across the codebase, updating all instances where the previous signer was utilized. - Removed the deprecated p256k package, including all related files and tests, to streamline the codebase and improve maintainability. - Updated various components, including event handling, database interactions, and protocol implementations, to ensure compatibility with the new signer interface. - Enhanced tests to validate the new signing functionality and ensure robustness across the application. - Bumped version to v0.23.3 to reflect these changes.main
50 changed files with 312 additions and 972 deletions
@ -1,68 +0,0 @@
@@ -1,68 +0,0 @@
|
||||
# p256k1 |
||||
|
||||
This is a library that uses the `bitcoin-core` optimized secp256k1 elliptic |
||||
curve signatures library for `nostr` schnorr signatures. |
||||
|
||||
If you need to build it without `libsecp256k1` C library, you must disable cgo: |
||||
|
||||
export CGO_ENABLED='0' |
||||
|
||||
This enables the fallback `btcec` pure Go library to be used in its place. This |
||||
CGO setting is not default for Go, so it must be set in order to disable this. |
||||
|
||||
The standard `libsecp256k1-0` and `libsecp256k1-dev` available through the |
||||
ubuntu dpkg repositories do not include support for the BIP-340 schnorr |
||||
signatures or the ECDH X-only shared secret generation algorithm, so you must |
||||
follow the following instructions to get the benefits of using this library. It |
||||
is 4x faster at signing and generating shared secrets so it is a must if your |
||||
intention is to use it for high throughput systems like a network transport. |
||||
|
||||
The easy way to install it, if you have ubuntu/debian, is the script |
||||
[../ubuntu_install_libsecp256k1.sh](../../../scripts/ubuntu_install_libsecp256k1.sh), |
||||
it |
||||
handles the dependencies and runs the build all in one step for you. Note that |
||||
it |
||||
|
||||
For ubuntu, you need these: |
||||
|
||||
sudo apt -y install build-essential autoconf libtool |
||||
|
||||
For other linux distributions, the process is the same but the dependencies are |
||||
likely different. The main thing is it requires make, gcc/++, autoconf and |
||||
libtool to run. The most important thing to point out is that you must enable |
||||
the schnorr signatures feature, and ECDH. |
||||
|
||||
The directory `p256k/secp256k1` needs to be initialized, built and installed, |
||||
like so: |
||||
|
||||
```bash |
||||
cd secp256k1 |
||||
git submodule init |
||||
git submodule update |
||||
``` |
||||
|
||||
Then to build, you can refer to the [instructions](./secp256k1/README.md) or |
||||
just use the default autotools: |
||||
|
||||
```bash |
||||
./autogen.sh |
||||
./configure --enable-module-schnorrsig --enable-module-ecdh --prefix=/usr |
||||
make |
||||
sudo make install |
||||
``` |
||||
|
||||
On WSL2 you may have to attend to various things to make this work, setting up |
||||
your basic locale (uncomment one or more in `/etc/locale.gen`, and run |
||||
`locale-gen`), installing the basic build tools (build-essential or base-devel) |
||||
and of course git, curl, wget, libtool and |
||||
autoconf. |
||||
|
||||
## ECDH |
||||
|
||||
TODO: Currently the use of the libsecp256k1 library for ECDH, used in nip-04 and |
||||
nip-44 encryption is not enabled, because the default version uses the Y |
||||
coordinate and this is incorrect for nostr. It will be enabled soon... for now |
||||
it is done with the `btcec` fallback version. This is slower, however previous |
||||
tests have shown that this ECDH library is fast enough to enable 8mb/s |
||||
throughput per CPU thread when used to generate a distinct secret for TCP |
||||
packets. The C library will likely raise this to 20mb/s or more. |
||||
@ -1,21 +0,0 @@
@@ -1,21 +0,0 @@
|
||||
//go:build !cgo
|
||||
|
||||
package p256k |
||||
|
||||
import ( |
||||
"lol.mleku.dev/log" |
||||
p256k1signer "p256k1.mleku.dev/signer" |
||||
) |
||||
|
||||
func init() { |
||||
log.T.Ln("using p256k1.mleku.dev/signer (pure Go/Btcec)") |
||||
} |
||||
|
||||
// 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 |
||||
|
||||
// Keygen is an alias for the P256K1Gen type from p256k1.mleku.dev/signer (btcec version).
|
||||
type Keygen = p256k1signer.P256K1Gen |
||||
|
||||
var NewKeygen = p256k1signer.NewP256K1Gen |
||||
@ -1,169 +0,0 @@
@@ -1,169 +0,0 @@
|
||||
//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() |
||||
} |
||||
@ -1,194 +0,0 @@
@@ -1,194 +0,0 @@
|
||||
//go:build !cgo
|
||||
|
||||
package btcec_test |
||||
|
||||
import ( |
||||
"testing" |
||||
"time" |
||||
|
||||
"lol.mleku.dev/chk" |
||||
"lol.mleku.dev/log" |
||||
"next.orly.dev/pkg/crypto/p256k/btcec" |
||||
"next.orly.dev/pkg/utils" |
||||
) |
||||
|
||||
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), |
||||
) |
||||
} |
||||
@ -1,41 +0,0 @@
@@ -1,41 +0,0 @@
|
||||
//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 |
||||
} |
||||
@ -1,9 +0,0 @@
@@ -1,9 +0,0 @@
|
||||
// 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.
|
||||
//
|
||||
// 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 |
||||
@ -1,41 +0,0 @@
@@ -1,41 +0,0 @@
|
||||
//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 |
||||
} |
||||
@ -1,41 +0,0 @@
@@ -1,41 +0,0 @@
|
||||
//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.NewP256K1Signer() |
||||
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.NewP256K1Signer() |
||||
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 |
||||
} |
||||
@ -1,20 +0,0 @@
@@ -1,20 +0,0 @@
|
||||
//go:build cgo
|
||||
|
||||
package p256k |
||||
|
||||
import ( |
||||
"lol.mleku.dev/log" |
||||
p256k1signer "p256k1.mleku.dev/signer" |
||||
) |
||||
|
||||
func init() { |
||||
log.T.Ln("using p256k1.mleku.dev/signer (CGO)") |
||||
} |
||||
|
||||
// Signer is an alias for the P256K1Signer type from p256k1.mleku.dev/signer (cgo version).
|
||||
type Signer = p256k1signer.P256K1Signer |
||||
|
||||
// Keygen is an alias for the P256K1Gen type from p256k1.mleku.dev/signer (cgo version).
|
||||
type Keygen = p256k1signer.P256K1Gen |
||||
|
||||
var NewKeygen = p256k1signer.NewP256K1Gen |
||||
@ -1,161 +0,0 @@
@@ -1,161 +0,0 @@
|
||||
//go:build cgo
|
||||
|
||||
package p256k_test |
||||
|
||||
import ( |
||||
"testing" |
||||
"time" |
||||
|
||||
"lol.mleku.dev/chk" |
||||
"lol.mleku.dev/log" |
||||
"next.orly.dev/pkg/crypto/p256k" |
||||
"next.orly.dev/pkg/interfaces/signer" |
||||
"next.orly.dev/pkg/utils" |
||||
) |
||||
|
||||
func TestSigner_Generate(t *testing.T) { |
||||
for _ = range 10000 { |
||||
var err error |
||||
sign := &p256k.Signer{} |
||||
var skb []byte |
||||
if err = sign.Generate(); chk.E(err) { |
||||
t.Fatal(err) |
||||
} |
||||
skb = sign.Sec() |
||||
if err = sign.InitSec(skb); chk.E(err) { |
||||
t.Fatal(err) |
||||
} |
||||
} |
||||
} |
||||
|
||||
// func TestSignerVerify(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 := &p256k.Signer{}
|
||||
// for scanner.Scan() {
|
||||
// var valid bool
|
||||
// b := scanner.Bytes()
|
||||
// bc := make([]byte, 0, len(b))
|
||||
// bc = append(bc, b...)
|
||||
// ev := event.New()
|
||||
// if _, err = ev.Unmarshal(b); chk.E(err) {
|
||||
// t.Errorf("failed to marshal\n%s", b)
|
||||
// } else {
|
||||
// if valid, err = ev.Verify(); chk.T(err) || !valid {
|
||||
// t.Errorf("invalid signature\n%s", bc)
|
||||
// continue
|
||||
// }
|
||||
// }
|
||||
// id := ev.GetIDBytes()
|
||||
// if len(id) != sha256.Size {
|
||||
// t.Errorf("id should be 32 bytes, got %d", len(id))
|
||||
// continue
|
||||
// }
|
||||
// if err = signer.InitPub(ev.Pubkey); chk.T(err) {
|
||||
// t.Errorf("failed to init pub key: %s\n%0x", err, ev.Pubkey)
|
||||
// continue
|
||||
// }
|
||||
// if valid, err = signer.Verify(id, ev.Sig); chk.E(err) {
|
||||
// t.Errorf("failed to verify: %s\n%0x", err, ev.ID)
|
||||
// continue
|
||||
// }
|
||||
// if !valid {
|
||||
// t.Errorf(
|
||||
// "invalid signature for\npub %0x\neid %0x\nsig %0x\n%s",
|
||||
// ev.Pubkey, id, ev.Sig, bc,
|
||||
// )
|
||||
// continue
|
||||
// }
|
||||
// // fmt.Printf("%s\n", bc)
|
||||
// // evs = append(evs, ev)
|
||||
// }
|
||||
// }
|
||||
|
||||
// func TestSignerSign(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 := &p256k.Signer{}
|
||||
// var skb, pkb []byte
|
||||
// if skb, pkb, _, _, err = p256k.Generate(); chk.E(err) {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// log.I.S(skb, pkb)
|
||||
// if err = signer.InitSec(skb); chk.E(err) {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// verifier := &p256k.Signer{}
|
||||
// if err = verifier.InitPub(pkb); chk.E(err) {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// for scanner.Scan() {
|
||||
// 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 TestECDH(t *testing.T) { |
||||
n := time.Now() |
||||
var err error |
||||
var s1, s2 signer.I |
||||
var counter int |
||||
const total = 100 |
||||
for _ = range total { |
||||
s1, s2 = &p256k.Signer{}, &p256k.Signer{} |
||||
if err = s1.Generate(); chk.E(err) { |
||||
t.Fatal(err) |
||||
} |
||||
for _ = range total { |
||||
if err = s2.Generate(); chk.E(err) { |
||||
t.Fatal(err) |
||||
} |
||||
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*total, "time", duration, "time/op", |
||||
duration/total/total, "ops/sec", |
||||
float64(time.Second)/float64(duration/total/total), |
||||
) |
||||
} |
||||
@ -1,76 +0,0 @@
@@ -1,76 +0,0 @@
|
||||
//go:build cgo
|
||||
|
||||
package p256k_test |
||||
|
||||
// func TestVerify(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
|
||||
// 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 {
|
||||
// if valid, err = ev.Verify(); chk.E(err) || !valid {
|
||||
// t.Errorf("btcec: invalid signature\n%s", b)
|
||||
// continue
|
||||
// }
|
||||
// }
|
||||
// id := ev.GetIDBytes()
|
||||
// if len(id) != sha256.Size {
|
||||
// t.Errorf("id should be 32 bytes, got %d", len(id))
|
||||
// continue
|
||||
// }
|
||||
// if err = p256k.VerifyFromBytes(id, ev.Sig, ev.Pubkey); chk.E(err) {
|
||||
// t.Error(err)
|
||||
// continue
|
||||
// }
|
||||
// evs = append(evs, ev)
|
||||
// }
|
||||
// }
|
||||
|
||||
// func TestSign(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
|
||||
// var sec1 *p256k.Sec
|
||||
// var pub1 *p256k.XPublicKey
|
||||
// var pb []byte
|
||||
// if _, pb, sec1, pub1, err = p256k.Generate(); chk.E(err) {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// for scanner.Scan() {
|
||||
// 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)
|
||||
// }
|
||||
// sig := make([]byte, schnorr.SignatureSize)
|
||||
// for _, ev := range evs {
|
||||
// ev.Pubkey = pb
|
||||
// var uid *p256k.Uchar
|
||||
// if uid, err = p256k.Msg(ev.GetIDBytes()); chk.E(err) {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// if sig, err = p256k.Sign(uid, sec1.Sec()); chk.E(err) {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// ev.Sig = sig
|
||||
// var usig *p256k.Uchar
|
||||
// if usig, err = p256k.Sig(sig); chk.E(err) {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// if !p256k.Verify(uid, usig, pub1.Key) {
|
||||
// t.Errorf("invalid signature")
|
||||
// }
|
||||
// }
|
||||
// p256k.Zero(&sec1.Key)
|
||||
// }
|
||||
@ -0,0 +1,89 @@
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env bash |
||||
# Run GitHub Actions workflow locally using act |
||||
# Usage: ./scripts/test-workflow-local.sh [job-name] |
||||
# job-name: optional, defaults to 'build'. Can be 'build' or 'release' |
||||
|
||||
set -e |
||||
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) |
||||
WORKFLOW_FILE="${SCRIPT_DIR}/../.github/workflows/go.yml" |
||||
JOB_NAME="${1:-build}" |
||||
|
||||
# Check if act is installed |
||||
if ! command -v act >/dev/null 2>&1; then |
||||
echo "Error: 'act' is not installed" |
||||
echo "Install it with:" |
||||
echo " curl https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash" |
||||
echo " # or on macOS: brew install act" |
||||
exit 1 |
||||
fi |
||||
|
||||
echo "=== Running GitHub Actions workflow locally ===" |
||||
echo "Workflow: .github/workflows/go.yml" |
||||
echo "Job: $JOB_NAME" |
||||
echo "" |
||||
|
||||
case "$JOB_NAME" in |
||||
build) |
||||
echo "Running build job..." |
||||
act push --workflows "$WORKFLOW_FILE" --job build |
||||
;; |
||||
release) |
||||
echo "Running release job (simulating tag push)..." |
||||
# Simulate a tag push event with a valid tag format |
||||
# The workflow requires build to run first and succeed |
||||
echo "Step 1: Running build job (required dependency)..." |
||||
if ! act push --workflows "$WORKFLOW_FILE" --job build; then |
||||
echo "Error: Build job failed. Release job cannot proceed." |
||||
exit 1 |
||||
fi |
||||
|
||||
echo "" |
||||
echo "Step 2: Running release job..." |
||||
echo "Note: GitHub release creation may fail locally (no valid token), but binary building will be tested" |
||||
# Use a tag that matches the workflow pattern: v[0-9]+.[0-9]+.[0-9]+ |
||||
# Provide a dummy GITHUB_TOKEN to prevent immediate failure |
||||
# The release won't actually be created, but the workflow will test binary building |
||||
# Temporarily disable exit on error to allow release step to fail gracefully |
||||
set +e |
||||
GITHUB_REF=refs/tags/v1.0.0 \ |
||||
GITHUB_TOKEN=dummy_token_for_local_testing \ |
||||
act push \ |
||||
--workflows "$WORKFLOW_FILE" \ |
||||
--job release \ |
||||
--secret GITHUB_TOKEN=dummy_token_for_local_testing \ |
||||
--eventpath /dev/stdin <<EOF |
||||
{ |
||||
"ref": "refs/tags/v1.0.0", |
||||
"pusher": {"name": "test"}, |
||||
"repository": { |
||||
"name": "next.orly.dev", |
||||
"full_name": "test/next.orly.dev" |
||||
}, |
||||
"head_commit": { |
||||
"id": "test123" |
||||
} |
||||
} |
||||
EOF |
||||
RELEASE_EXIT_CODE=$? |
||||
set -e |
||||
|
||||
# Check if binary building succeeded (exit code 0) or if only release creation failed |
||||
if [ $RELEASE_EXIT_CODE -eq 0 ]; then |
||||
echo "✓ Release job completed successfully (including binary building)" |
||||
else |
||||
echo "⚠ Release job completed with errors (likely GitHub release creation failed)" |
||||
echo " This is expected in local testing. Binary building should have succeeded." |
||||
echo " Check the output above to verify 'Build Release Binaries' step succeeded." |
||||
fi |
||||
;; |
||||
*) |
||||
echo "Error: Unknown job '$JOB_NAME'" |
||||
echo "Valid jobs: build, release" |
||||
exit 1 |
||||
;; |
||||
esac |
||||
|
||||
echo "" |
||||
echo "=== Workflow completed ===" |
||||
|
||||
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash |
||||
# Manual test script for .github/workflows/go.yml |
||||
# This replicates the build job steps locally |
||||
|
||||
set -e |
||||
|
||||
echo "=== Testing GitHub Actions Workflow Locally ===" |
||||
echo "" |
||||
|
||||
# Check Go version |
||||
echo "Checking Go version..." |
||||
go version |
||||
echo "" |
||||
|
||||
# Build without cgo |
||||
echo "Building with cgo disabled..." |
||||
CGO_ENABLED=0 go build -v ./... |
||||
echo "" |
||||
|
||||
# Test without cgo |
||||
echo "Testing with cgo disabled..." |
||||
CGO_ENABLED=0 go test -v $(go list ./... | xargs -n1 sh -c 'ls $0/*_test.go 1>/dev/null 2>&1 && echo $0' | grep .) |
||||
echo "" |
||||
|
||||
echo "=== Build job completed successfully ===" |
||||
|
||||
Loading…
Reference in new issue