- Replaced all instances of p256k1signer with the new p8k.Signer across various modules, including event creation, policy handling, and database interactions. - Updated related test cases and benchmarks to ensure compatibility with the new signer interface. - Bumped version to v0.25.0 to reflect these significant changes and improvements in cryptographic operations.
269 lines
5.9 KiB
Go
269 lines
5.9 KiB
Go
package secp
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"fmt"
|
|
)
|
|
|
|
// GeneratePrivateKey generates a random 32-byte private key
|
|
func GeneratePrivateKey() (privKey []byte, err error) {
|
|
privKey = make([]byte, PrivateKeySize)
|
|
if _, err = rand.Read(privKey); err != nil {
|
|
err = fmt.Errorf("failed to generate random key: %w", err)
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
// PublicKeyFromPrivate generates a public key from a private key
|
|
// Returns the serialized public key in compressed format
|
|
func PublicKeyFromPrivate(privKey []byte, compressed bool) (pubKey []byte, err error) {
|
|
ctx, err := NewContext(ContextSign)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer ctx.Destroy()
|
|
|
|
internalPubKey, err := ctx.CreatePublicKey(privKey)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
pubKey, err = ctx.SerializePublicKey(internalPubKey, compressed)
|
|
return
|
|
}
|
|
|
|
// SignMessage signs a 32-byte message hash with a private key
|
|
// Returns the signature in compact format (64 bytes)
|
|
func SignMessage(msgHash []byte, privKey []byte) (sig []byte, err error) {
|
|
ctx, err := NewContext(ContextSign)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer ctx.Destroy()
|
|
|
|
internalSig, err := ctx.Sign(msgHash, privKey)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
sig, err = ctx.SerializeSignatureCompact(internalSig)
|
|
return
|
|
}
|
|
|
|
// VerifyMessage verifies a compact signature against a message hash and serialized public key
|
|
func VerifyMessage(msgHash []byte, compactSig []byte, serializedPubKey []byte) (valid bool, err error) {
|
|
ctx, err := NewContext(ContextVerify)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer ctx.Destroy()
|
|
|
|
pubKey, err := ctx.ParsePublicKey(serializedPubKey)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
sig, err := ctx.ParseSignatureCompact(compactSig)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
valid, err = ctx.Verify(msgHash, sig, pubKey)
|
|
return
|
|
}
|
|
|
|
// SignMessageDER signs a message and returns DER-encoded signature
|
|
func SignMessageDER(msgHash []byte, privKey []byte) (derSig []byte, err error) {
|
|
ctx, err := NewContext(ContextSign)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer ctx.Destroy()
|
|
|
|
internalSig, err := ctx.Sign(msgHash, privKey)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
derSig, err = ctx.SerializeSignatureDER(internalSig)
|
|
return
|
|
}
|
|
|
|
// VerifyMessageDER verifies a DER-encoded signature
|
|
func VerifyMessageDER(msgHash []byte, derSig []byte, serializedPubKey []byte) (valid bool, err error) {
|
|
ctx, err := NewContext(ContextVerify)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer ctx.Destroy()
|
|
|
|
pubKey, err := ctx.ParsePublicKey(serializedPubKey)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
sig, err := ctx.ParseSignatureDER(derSig)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
valid, err = ctx.Verify(msgHash, sig, pubKey)
|
|
return
|
|
}
|
|
|
|
// SchnorrSign signs a message with Schnorr signature (BIP-340)
|
|
// Returns 64-byte Schnorr signature
|
|
func SchnorrSign(msgHash []byte, privKey []byte, auxRand []byte) (sig []byte, err error) {
|
|
ctx, err := NewContext(ContextSign)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer ctx.Destroy()
|
|
|
|
keypair, err := ctx.CreateKeypair(privKey)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
sig, err = ctx.SchnorrSign(msgHash, keypair, auxRand)
|
|
return
|
|
}
|
|
|
|
// SchnorrVerifyWithPubKey verifies a Schnorr signature (BIP-340)
|
|
// xonlyPubKey should be 32 bytes
|
|
func SchnorrVerifyWithPubKey(msgHash []byte, sig []byte, xonlyPubKey []byte) (valid bool, err error) {
|
|
ctx, err := NewContext(ContextVerify)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer ctx.Destroy()
|
|
|
|
valid, err = ctx.SchnorrVerify(sig, msgHash, xonlyPubKey)
|
|
return
|
|
}
|
|
|
|
// XOnlyPubKeyFromPrivate generates an x-only public key from a private key
|
|
func XOnlyPubKeyFromPrivate(privKey []byte) (xonly []byte, pkParity int32, err error) {
|
|
ctx, err := NewContext(ContextSign)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer ctx.Destroy()
|
|
|
|
keypair, err := ctx.CreateKeypair(privKey)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
var xonlyInternal XOnlyPublicKey
|
|
xonlyInternal, pkParity, err = ctx.KeypairXOnlyPub(keypair)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
xonly = xonlyInternal[:]
|
|
return
|
|
}
|
|
|
|
// ComputeECDH computes an ECDH shared secret
|
|
func ComputeECDH(serializedPubKey []byte, privKey []byte) (secret []byte, err error) {
|
|
ctx, err := NewContext(ContextSign)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer ctx.Destroy()
|
|
|
|
pubKey, err := ctx.ParsePublicKey(serializedPubKey)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
secret, err = ctx.ECDH(pubKey, privKey)
|
|
return
|
|
}
|
|
|
|
// SignRecoverableCompact signs a message with a recoverable signature
|
|
// Returns compact signature (64 bytes) and recovery ID
|
|
func SignRecoverableCompact(msgHash []byte, privKey []byte) (sig []byte, recID int32, err error) {
|
|
ctx, err := NewContext(ContextSign)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer ctx.Destroy()
|
|
|
|
recSig, err := ctx.SignRecoverable(msgHash, privKey)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
sig, recID, err = ctx.SerializeRecoverableSignatureCompact(recSig)
|
|
return
|
|
}
|
|
|
|
// RecoverPubKey recovers a public key from a recoverable signature
|
|
// Returns serialized public key in compressed format
|
|
func RecoverPubKey(msgHash []byte, compactSig []byte, recID int32, compressed bool) (pubKey []byte, err error) {
|
|
ctx, err := NewContext(ContextSign)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer ctx.Destroy()
|
|
|
|
recSig, err := ctx.ParseRecoverableSignatureCompact(compactSig, recID)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
recoveredPubKey, err := ctx.Recover(recSig, msgHash)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
pubKey, err = ctx.SerializePublicKey(recoveredPubKey, compressed)
|
|
return
|
|
}
|
|
|
|
// ValidatePrivateKey checks if a private key is valid
|
|
func ValidatePrivateKey(privKey []byte) (valid bool, err error) {
|
|
if len(privKey) != PrivateKeySize {
|
|
err = fmt.Errorf("private key must be %d bytes", PrivateKeySize)
|
|
return
|
|
}
|
|
|
|
ctx, err := NewContext(ContextSign)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer ctx.Destroy()
|
|
|
|
_, err = ctx.CreatePublicKey(privKey)
|
|
if err != nil {
|
|
valid = false
|
|
err = nil
|
|
return
|
|
}
|
|
|
|
valid = true
|
|
return
|
|
}
|
|
|
|
// IsPublicKeyValid checks if a serialized public key is valid
|
|
func IsPublicKeyValid(serializedPubKey []byte) (valid bool, err error) {
|
|
ctx, err := NewContext(ContextVerify)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer ctx.Destroy()
|
|
|
|
_, err = ctx.ParsePublicKey(serializedPubKey)
|
|
if err != nil {
|
|
valid = false
|
|
err = nil
|
|
return
|
|
}
|
|
|
|
valid = true
|
|
return
|
|
}
|