schnorr.go raw

   1  package secp
   2  
   3  import (
   4  	"fmt"
   5  )
   6  
   7  // Keypair represents a secp256k1 keypair for Schnorr signatures
   8  type Keypair [96]byte
   9  
  10  // XOnlyPublicKey represents a 64-byte x-only public key (internal format)
  11  type XOnlyPublicKey [64]byte
  12  
  13  // CreateKeypair creates a keypair from a 32-byte secret key
  14  func (c *Context) CreateKeypair(seckey []byte) (keypair Keypair, err error) {
  15  	if keypairCreate == nil {
  16  		err = fmt.Errorf("schnorrsig module not available")
  17  		return
  18  	}
  19  
  20  	if len(seckey) != PrivateKeySize {
  21  		err = fmt.Errorf("private key must be %d bytes", PrivateKeySize)
  22  		return
  23  	}
  24  
  25  	ret := keypairCreate(c.ctx, &keypair[0], &seckey[0])
  26  	if ret != 1 {
  27  		err = fmt.Errorf("failed to create keypair")
  28  		return
  29  	}
  30  
  31  	return
  32  }
  33  
  34  // KeypairXOnlyPub extracts the x-only public key from a keypair
  35  func (c *Context) KeypairXOnlyPub(keypair Keypair) (xonly XOnlyPublicKey, pkParity int32, err error) {
  36  	if keypairXonlyPub == nil {
  37  		err = fmt.Errorf("schnorrsig module not available")
  38  		return
  39  	}
  40  
  41  	ret := keypairXonlyPub(c.ctx, &xonly[0], &pkParity, &keypair[0])
  42  	if ret != 1 {
  43  		err = fmt.Errorf("failed to extract xonly pubkey")
  44  		return
  45  	}
  46  
  47  	return
  48  }
  49  
  50  // SchnorrSign creates a Schnorr signature (BIP-340)
  51  func (c *Context) SchnorrSign(msg32 []byte, keypair Keypair, auxRand32 []byte) (sig []byte, err error) {
  52  	if schnorrsigSign32 == nil {
  53  		err = fmt.Errorf("schnorrsig module not available")
  54  		return
  55  	}
  56  
  57  	if len(msg32) != 32 {
  58  		err = fmt.Errorf("message must be 32 bytes")
  59  		return
  60  	}
  61  
  62  	var auxPtr *byte
  63  	if len(auxRand32) > 0 {
  64  		if len(auxRand32) != 32 {
  65  			err = fmt.Errorf("aux_rand must be 32 bytes")
  66  			return
  67  		}
  68  		auxPtr = &auxRand32[0]
  69  	}
  70  
  71  	sig = make([]byte, SchnorrSignatureSize)
  72  	ret := schnorrsigSign32(c.ctx, &sig[0], &msg32[0], &keypair[0], auxPtr)
  73  	if ret != 1 {
  74  		err = fmt.Errorf("failed to create Schnorr signature")
  75  		return
  76  	}
  77  
  78  	return
  79  }
  80  
  81  // SchnorrVerify verifies a Schnorr signature (BIP-340)
  82  func (c *Context) SchnorrVerify(sig64 []byte, msg []byte, xonlyPubkey []byte) (valid bool, err error) {
  83  	if schnorrsigVerify == nil {
  84  		err = fmt.Errorf("schnorrsig module not available")
  85  		return
  86  	}
  87  
  88  	if len(sig64) != SchnorrSignatureSize {
  89  		err = fmt.Errorf("signature must be %d bytes", SchnorrSignatureSize)
  90  		return
  91  	}
  92  
  93  	// xonlyPubkey can be either 32 bytes (serialized) or 64 bytes (internal)
  94  	var xonly [64]byte
  95  	if len(xonlyPubkey) == 32 {
  96  		// Parse the 32-byte serialized format
  97  		ret := xonlyPubkeyParse(c.ctx, &xonly[0], &xonlyPubkey[0])
  98  		if ret != 1 {
  99  			err = fmt.Errorf("failed to parse xonly pubkey")
 100  			return
 101  		}
 102  	} else if len(xonlyPubkey) == 64 {
 103  		// Already in internal format
 104  		copy(xonly[:], xonlyPubkey)
 105  	} else {
 106  		err = fmt.Errorf("xonly public key must be 32 or 64 bytes")
 107  		return
 108  	}
 109  
 110  	ret := schnorrsigVerify(c.ctx, &sig64[0], &msg[0], uint64(len(msg)), &xonly[0])
 111  	valid = ret == 1
 112  
 113  	return
 114  }
 115  
 116  // ParseXOnlyPublicKey parses a 32-byte x-only public key
 117  func (c *Context) ParseXOnlyPublicKey(input32 []byte) (xonly []byte, err error) {
 118  	if xonlyPubkeyParse == nil {
 119  		err = fmt.Errorf("schnorrsig module not available")
 120  		return
 121  	}
 122  
 123  	if len(input32) != 32 {
 124  		err = fmt.Errorf("xonly public key must be 32 bytes")
 125  		return
 126  	}
 127  
 128  	xonly = make([]byte, 64) // Internal representation is 64 bytes
 129  	ret := xonlyPubkeyParse(c.ctx, &xonly[0], &input32[0])
 130  	if ret != 1 {
 131  		err = fmt.Errorf("failed to parse xonly public key")
 132  		return
 133  	}
 134  
 135  	return
 136  }
 137  
 138  // SerializeXOnlyPublicKey serializes an x-only public key to 32 bytes
 139  func (c *Context) SerializeXOnlyPublicKey(xonly []byte) (output32 []byte, err error) {
 140  	if xonlyPubkeySerialize == nil {
 141  		err = fmt.Errorf("schnorrsig module not available")
 142  		return
 143  	}
 144  
 145  	if len(xonly) != 64 {
 146  		err = fmt.Errorf("xonly public key must be 64 bytes (internal format)")
 147  		return
 148  	}
 149  
 150  	output32 = make([]byte, 32)
 151  	ret := xonlyPubkeySerialize(c.ctx, &output32[0], &xonly[0])
 152  	if ret != 1 {
 153  		err = fmt.Errorf("failed to serialize xonly public key")
 154  		return
 155  	}
 156  
 157  	return
 158  }
 159  
 160  // XOnlyPublicKeyFromPublicKey converts a regular public key to an x-only public key
 161  func (c *Context) XOnlyPublicKeyFromPublicKey(pubkey []byte) (xonly []byte, pkParity int32, err error) {
 162  	if xonlyPubkeyFromPubkey == nil {
 163  		err = fmt.Errorf("schnorrsig module not available")
 164  		return
 165  	}
 166  
 167  	if len(pubkey) != PublicKeySize {
 168  		err = fmt.Errorf("public key must be %d bytes", PublicKeySize)
 169  		return
 170  	}
 171  
 172  	xonly = make([]byte, 64) // Internal representation
 173  	ret := xonlyPubkeyFromPubkey(c.ctx, &xonly[0], &pkParity, &pubkey[0])
 174  	if ret != 1 {
 175  		err = fmt.Errorf("failed to convert to xonly public key")
 176  		return
 177  	}
 178  
 179  	return
 180  }
 181