successful implementation of direct dynamic linking
This commit is contained in:
268
utils.go
Normal file
268
utils.go
Normal file
@@ -0,0 +1,268 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user