keys.go raw

   1  package keys
   2  
   3  import (
   4  	"errors"
   5  
   6  	"next.orly.dev/pkg/p256k1"
   7  )
   8  
   9  // =============================================================================
  10  // Type Aliases (Value Objects)
  11  // =============================================================================
  12  
  13  // PublicKey represents a secp256k1 public key.
  14  type PublicKey = p256k1.PublicKey
  15  
  16  // XOnlyPubkey represents a 32-byte x-only public key (BIP-340).
  17  type XOnlyPubkey = p256k1.XOnlyPubkey
  18  
  19  // KeyPair represents a secret/public key pair (Aggregate Root).
  20  type KeyPair = p256k1.KeyPair
  21  
  22  // Serialization format flags.
  23  const (
  24  	Compressed   = p256k1.ECCompressed   // 33-byte compressed format
  25  	Uncompressed = p256k1.ECUncompressed // 65-byte uncompressed format
  26  )
  27  
  28  // =============================================================================
  29  // Key Pair Management (Aggregate Root Operations)
  30  // =============================================================================
  31  
  32  // Generate creates a new random key pair.
  33  //
  34  // The private key is generated using a cryptographically secure random source.
  35  // Returns an error if key generation fails.
  36  func Generate() (*KeyPair, error) {
  37  	return p256k1.KeyPairGenerate()
  38  }
  39  
  40  // Create creates a key pair from an existing 32-byte private key.
  41  //
  42  // Returns an error if:
  43  //   - privateKey is not exactly 32 bytes
  44  //   - privateKey is zero
  45  //   - privateKey is >= curve order
  46  func Create(privateKey []byte) (*KeyPair, error) {
  47  	return p256k1.KeyPairCreate(privateKey)
  48  }
  49  
  50  // =============================================================================
  51  // Public Key Operations (Value Object Services)
  52  // =============================================================================
  53  
  54  // CreatePublic derives a public key from a 32-byte private key.
  55  func CreatePublic(privateKey []byte) (*PublicKey, error) {
  56  	var pubkey PublicKey
  57  	if err := p256k1.ECPubkeyCreate(&pubkey, privateKey); err != nil {
  58  		return nil, err
  59  	}
  60  	return &pubkey, nil
  61  }
  62  
  63  // ParsePublic parses a public key from serialized form.
  64  //
  65  // Accepts:
  66  //   - 33 bytes: compressed format (0x02 or 0x03 prefix)
  67  //   - 65 bytes: uncompressed format (0x04 prefix)
  68  func ParsePublic(input []byte) (*PublicKey, error) {
  69  	var pubkey PublicKey
  70  	if err := p256k1.ECPubkeyParse(&pubkey, input); err != nil {
  71  		return nil, err
  72  	}
  73  	return &pubkey, nil
  74  }
  75  
  76  // SerializePublic serializes a public key to the specified format.
  77  //
  78  // Returns the serialized bytes and the number of bytes written.
  79  // Use Compressed for 33 bytes, Uncompressed for 65 bytes.
  80  func SerializePublic(pubkey *PublicKey, format uint) []byte {
  81  	var output []byte
  82  	if format == Compressed {
  83  		output = make([]byte, 33)
  84  	} else {
  85  		output = make([]byte, 65)
  86  	}
  87  	n := p256k1.ECPubkeySerialize(output, pubkey, format)
  88  	return output[:n]
  89  }
  90  
  91  // ComparePublic compares two public keys lexicographically.
  92  // Returns <0 if a < b, >0 if a > b, 0 if equal.
  93  func ComparePublic(a, b *PublicKey) int {
  94  	return p256k1.ECPubkeyCmp(a, b)
  95  }
  96  
  97  // =============================================================================
  98  // X-Only Public Key Operations
  99  // =============================================================================
 100  
 101  // ParseXOnly parses a 32-byte x-only public key.
 102  func ParseXOnly(input []byte) (*XOnlyPubkey, error) {
 103  	return p256k1.XOnlyPubkeyParse(input)
 104  }
 105  
 106  // XOnlyFromPublic converts a full public key to x-only format.
 107  // Returns the x-only key and parity (1 if Y was odd, 0 if even).
 108  func XOnlyFromPublic(pubkey *PublicKey) (*XOnlyPubkey, int, error) {
 109  	return p256k1.XOnlyPubkeyFromPubkey(pubkey)
 110  }
 111  
 112  // SerializeXOnly serializes an x-only public key to 32 bytes.
 113  func SerializeXOnly(pubkey *XOnlyPubkey) [32]byte {
 114  	return pubkey.Serialize()
 115  }
 116  
 117  // CompareXOnly compares two x-only public keys lexicographically.
 118  // Returns <0 if a < b, >0 if a > b, 0 if equal.
 119  func CompareXOnly(a, b *XOnlyPubkey) int {
 120  	return p256k1.XOnlyPubkeyCmp(a, b)
 121  }
 122  
 123  // =============================================================================
 124  // Private Key Validation
 125  // =============================================================================
 126  
 127  // ValidatePrivate checks if a 32-byte slice is a valid private key.
 128  //
 129  // Returns true if the key is valid:
 130  //   - Exactly 32 bytes
 131  //   - Non-zero
 132  //   - Less than the curve order
 133  func ValidatePrivate(privateKey []byte) bool {
 134  	return p256k1.ECSeckeyVerify(privateKey)
 135  }
 136  
 137  // =============================================================================
 138  // Key Tweaking (Advanced Operations)
 139  // =============================================================================
 140  
 141  // TweakAddPrivate adds a 32-byte tweak to a private key.
 142  // Computes: result = (privateKey + tweak) mod n
 143  func TweakAddPrivate(privateKey, tweak []byte) ([]byte, error) {
 144  	result := make([]byte, 32)
 145  	copy(result, privateKey)
 146  	if err := p256k1.ECSeckeyTweakAdd(result, tweak); err != nil {
 147  		return nil, err
 148  	}
 149  	return result, nil
 150  }
 151  
 152  // TweakMulPrivate multiplies a private key by a 32-byte tweak.
 153  // Computes: result = (privateKey * tweak) mod n
 154  func TweakMulPrivate(privateKey, tweak []byte) ([]byte, error) {
 155  	result := make([]byte, 32)
 156  	copy(result, privateKey)
 157  	if err := p256k1.ECSeckeyTweakMul(result, tweak); err != nil {
 158  		return nil, err
 159  	}
 160  	return result, nil
 161  }
 162  
 163  // TweakAddPublic adds a 32-byte tweak to a public key.
 164  // Computes: result = pubkey + tweak*G
 165  func TweakAddPublic(pubkey *PublicKey, tweak []byte) (*PublicKey, error) {
 166  	result := *pubkey
 167  	if err := p256k1.ECPubkeyTweakAdd(&result, tweak); err != nil {
 168  		return nil, err
 169  	}
 170  	return &result, nil
 171  }
 172  
 173  // TweakMulPublic multiplies a public key by a 32-byte tweak.
 174  // Computes: result = tweak * pubkey
 175  func TweakMulPublic(pubkey *PublicKey, tweak []byte) (*PublicKey, error) {
 176  	result := *pubkey
 177  	if err := p256k1.ECPubkeyTweakMul(&result, tweak); err != nil {
 178  		return nil, err
 179  	}
 180  	return &result, nil
 181  }
 182  
 183  // =============================================================================
 184  // Private Key Operations
 185  // =============================================================================
 186  
 187  // NegatePrivate negates a private key.
 188  // Computes: result = -privateKey mod n
 189  func NegatePrivate(privateKey []byte) ([]byte, error) {
 190  	result := make([]byte, 32)
 191  	copy(result, privateKey)
 192  	if !p256k1.ECSeckeyNegate(result) {
 193  		return nil, errors.New("invalid private key")
 194  	}
 195  	return result, nil
 196  }
 197