extrakeys.go raw

   1  package p256k1
   2  
   3  import (
   4  	"errors"
   5  	"unsafe"
   6  )
   7  
   8  // XOnlyPubkey represents an x-only public key (32 bytes, just X coordinate)
   9  // Following BIP-340 specification
  10  type XOnlyPubkey struct {
  11  	data [32]byte
  12  }
  13  
  14  // KeyPair represents a keypair consisting of a secret key and public key
  15  // Used for Schnorr signatures
  16  type KeyPair struct {
  17  	seckey [32]byte
  18  	pubkey PublicKey
  19  }
  20  
  21  // XOnlyPubkeyParse parses a 32-byte sequence into an x-only public key
  22  func XOnlyPubkeyParse(input32 []byte) (*XOnlyPubkey, error) {
  23  	if len(input32) != 32 {
  24  		return nil, errors.New("input must be 32 bytes")
  25  	}
  26  
  27  	// Create a point from X coordinate
  28  	var x FieldElement
  29  	if err := x.setB32(input32); err != nil {
  30  		return nil, errors.New("invalid X coordinate")
  31  	}
  32  
  33  	// Try to recover Y coordinate (check if point is on curve)
  34  	var point GroupElementAffine
  35  	if !point.setXOVar(&x, false) {
  36  		// Try with odd Y
  37  		if !point.setXOVar(&x, true) {
  38  			return nil, errors.New("X coordinate does not correspond to a valid point")
  39  		}
  40  	}
  41  
  42  	// Verify point is valid
  43  	if !point.isValid() {
  44  		return nil, errors.New("invalid point")
  45  	}
  46  
  47  	// Create x-only pubkey (just X coordinate)
  48  	var xonly XOnlyPubkey
  49  	copy(xonly.data[:], input32)
  50  	return &xonly, nil
  51  }
  52  
  53  // Serialize serializes an x-only public key to 32 bytes
  54  func (xonly *XOnlyPubkey) Serialize() [32]byte {
  55  	return xonly.data
  56  }
  57  
  58  // XOnlyPubkeyFromPubkey converts a PublicKey to an XOnlyPubkey
  59  // Returns the x-only pubkey and parity (1 if Y was odd, 0 if even)
  60  func XOnlyPubkeyFromPubkey(pubkey *PublicKey) (*XOnlyPubkey, int, error) {
  61  	if pubkey == nil {
  62  		return nil, 0, errors.New("pubkey cannot be nil")
  63  	}
  64  
  65  	// Load public key
  66  	var pt GroupElementAffine
  67  	pt.fromBytes(pubkey.data[:])
  68  	if pt.isInfinity() {
  69  		return nil, 0, errors.New("invalid public key")
  70  	}
  71  
  72  	// Normalize Y coordinate
  73  	pt.y.normalize()
  74  
  75  	// Check parity
  76  	parity := 0
  77  	if pt.y.isOdd() {
  78  		parity = 1
  79  		// Negate point if Y is odd to get even Y
  80  		pt.negate(&pt)
  81  	}
  82  
  83  	// Extract X coordinate
  84  	var xonly XOnlyPubkey
  85  	pt.x.normalize()
  86  	pt.x.getB32(xonly.data[:])
  87  
  88  	return &xonly, parity, nil
  89  }
  90  
  91  // XOnlyPubkeyCmp compares two x-only public keys lexicographically
  92  // Returns: <0 if xonly1 < xonly2, >0 if xonly1 > xonly2, 0 if equal
  93  func XOnlyPubkeyCmp(xonly1, xonly2 *XOnlyPubkey) int {
  94  	if xonly1 == nil || xonly2 == nil {
  95  		panic("xonly pubkey cannot be nil")
  96  	}
  97  
  98  	for i := 31; i >= 0; i-- {
  99  		if xonly1.data[i] < xonly2.data[i] {
 100  			return -1
 101  		}
 102  		if xonly1.data[i] > xonly2.data[i] {
 103  			return 1
 104  		}
 105  	}
 106  	return 0
 107  }
 108  
 109  // KeyPairCreate creates a keypair from a secret key
 110  func KeyPairCreate(seckey []byte) (*KeyPair, error) {
 111  	if len(seckey) != 32 {
 112  		return nil, errors.New("secret key must be 32 bytes")
 113  	}
 114  
 115  	if !ECSeckeyVerify(seckey) {
 116  		return nil, errors.New("invalid secret key")
 117  	}
 118  
 119  	// Create public key
 120  	var pubkey PublicKey
 121  	if err := ECPubkeyCreate(&pubkey, seckey); err != nil {
 122  		return nil, err
 123  	}
 124  
 125  	kp := &KeyPair{}
 126  	copy(kp.seckey[:], seckey)
 127  	kp.pubkey = pubkey
 128  
 129  	return kp, nil
 130  }
 131  
 132  // KeyPairGenerate generates a new random keypair
 133  func KeyPairGenerate() (*KeyPair, error) {
 134  	seckey, pubkey, err := ECKeyPairGenerate()
 135  	if err != nil {
 136  		return nil, err
 137  	}
 138  
 139  	kp := &KeyPair{}
 140  	copy(kp.seckey[:], seckey)
 141  	kp.pubkey = *pubkey
 142  
 143  	return kp, nil
 144  }
 145  
 146  // Seckey returns the secret key
 147  func (kp *KeyPair) Seckey() []byte {
 148  	return kp.seckey[:]
 149  }
 150  
 151  // Pubkey returns the public key
 152  func (kp *KeyPair) Pubkey() *PublicKey {
 153  	return &kp.pubkey
 154  }
 155  
 156  // XOnlyPubkey returns the x-only public key
 157  func (kp *KeyPair) XOnlyPubkey() (*XOnlyPubkey, error) {
 158  	xonly, _, err := XOnlyPubkeyFromPubkey(&kp.pubkey)
 159  	return xonly, err
 160  }
 161  
 162  // Clear clears the keypair to prevent leaking sensitive information
 163  func (kp *KeyPair) Clear() {
 164  	memclear(unsafe.Pointer(&kp.seckey[0]), 32)
 165  	kp.pubkey.data = [64]byte{}
 166  }
 167