p256k1_signer_js.go raw

   1  //go:build js || wasm || tinygo || wasm32
   2  
   3  package signer
   4  
   5  import (
   6  	"errors"
   7  
   8  	"git.smesh.lol/orly/pkg/p256k1/exchange"
   9  	"git.smesh.lol/orly/pkg/p256k1/keys"
  10  	"git.smesh.lol/orly/pkg/p256k1/schnorr"
  11  )
  12  
  13  // P256K1Signer implements the I and Gen interfaces using the p256k1 domain packages (WASM build)
  14  type P256K1Signer struct {
  15  	keypair   *keys.KeyPair
  16  	xonlyPub  *schnorr.XOnlyPubkey
  17  	hasSecret bool
  18  	sigBuf    []byte
  19  	ecdhBuf   []byte
  20  }
  21  
  22  func NewP256K1Signer() *P256K1Signer {
  23  	return &P256K1Signer{hasSecret: false}
  24  }
  25  
  26  func (s *P256K1Signer) Generate() error {
  27  	kp, err := keys.Generate()
  28  	if err != nil {
  29  		return err
  30  	}
  31  	xonly, parity, err := schnorr.XOnlyFromPubkey(kp.Pubkey())
  32  	if err != nil {
  33  		return err
  34  	}
  35  	if parity == 1 {
  36  		seckey, err := keys.NegatePrivate(kp.Seckey())
  37  		if err != nil {
  38  			return errors.New("failed to negate secret key")
  39  		}
  40  		kp, err = keys.Create(seckey)
  41  		if err != nil {
  42  			return err
  43  		}
  44  		xonly, _, err = schnorr.XOnlyFromPubkey(kp.Pubkey())
  45  		if err != nil {
  46  			return err
  47  		}
  48  	}
  49  	s.keypair = kp
  50  	s.xonlyPub = xonly
  51  	s.hasSecret = true
  52  	return nil
  53  }
  54  
  55  func (s *P256K1Signer) InitSec(sec []byte) error {
  56  	if len(sec) != 32 {
  57  		return errors.New("secret key must be 32 bytes")
  58  	}
  59  	kp, err := keys.Create(sec)
  60  	if err != nil {
  61  		return err
  62  	}
  63  	xonly, parity, err := schnorr.XOnlyFromPubkey(kp.Pubkey())
  64  	if err != nil {
  65  		return err
  66  	}
  67  	if parity == 1 {
  68  		seckey, err := keys.NegatePrivate(kp.Seckey())
  69  		if err != nil {
  70  			return errors.New("failed to negate secret key")
  71  		}
  72  		kp, err = keys.Create(seckey)
  73  		if err != nil {
  74  			return err
  75  		}
  76  		xonly, _, err = schnorr.XOnlyFromPubkey(kp.Pubkey())
  77  		if err != nil {
  78  			return err
  79  		}
  80  	}
  81  	s.keypair = kp
  82  	s.xonlyPub = xonly
  83  	s.hasSecret = true
  84  	return nil
  85  }
  86  
  87  func (s *P256K1Signer) InitPub(pub []byte) error {
  88  	if len(pub) != 32 {
  89  		return errors.New("public key must be 32 bytes")
  90  	}
  91  	xonly, err := schnorr.ParseXOnlyPubkey(pub)
  92  	if err != nil {
  93  		return err
  94  	}
  95  	s.xonlyPub = xonly
  96  	s.keypair = nil
  97  	s.hasSecret = false
  98  	return nil
  99  }
 100  
 101  func (s *P256K1Signer) Sec() []byte {
 102  	if !s.hasSecret || s.keypair == nil {
 103  		return nil
 104  	}
 105  	return s.keypair.Seckey()
 106  }
 107  
 108  func (s *P256K1Signer) Pub() []byte {
 109  	if s.xonlyPub == nil {
 110  		return nil
 111  	}
 112  	serialized := s.xonlyPub.Serialize()
 113  	return serialized[:]
 114  }
 115  
 116  func (s *P256K1Signer) Sign(msg []byte) (sig []byte, err error) {
 117  	if !s.hasSecret || s.keypair == nil {
 118  		return nil, errors.New("no secret key available for signing")
 119  	}
 120  	if len(msg) != 32 {
 121  		return nil, errors.New("message must be 32 bytes")
 122  	}
 123  	if cap(s.sigBuf) < 64 {
 124  		s.sigBuf = make([]byte, 64)
 125  	} else {
 126  		s.sigBuf = s.sigBuf[:64]
 127  	}
 128  	if err := schnorr.SignRaw(s.sigBuf, msg, s.keypair, nil); err != nil {
 129  		return nil, err
 130  	}
 131  	return s.sigBuf, nil
 132  }
 133  
 134  func (s *P256K1Signer) Verify(msg, sig []byte) (valid bool, err error) {
 135  	if s.xonlyPub == nil {
 136  		return false, errors.New("no public key available for verification")
 137  	}
 138  	if len(msg) != 32 {
 139  		return false, errors.New("message must be 32 bytes")
 140  	}
 141  	if len(sig) != 64 {
 142  		return false, errors.New("signature must be 64 bytes")
 143  	}
 144  	valid = schnorr.VerifyRaw(sig, msg, s.xonlyPub)
 145  	return valid, nil
 146  }
 147  
 148  func (s *P256K1Signer) Zero() {
 149  	if s.keypair != nil {
 150  		s.keypair.Clear()
 151  		s.keypair = nil
 152  	}
 153  	s.hasSecret = false
 154  	s.xonlyPub = nil
 155  }
 156  
 157  func (s *P256K1Signer) ECDH(pub []byte) (secret []byte, err error) {
 158  	if !s.hasSecret || s.keypair == nil {
 159  		return nil, errors.New("no secret key available for ECDH")
 160  	}
 161  	if len(pub) != 32 {
 162  		return nil, errors.New("public key must be 32 bytes")
 163  	}
 164  	var compressedPub [33]byte
 165  	compressedPub[0] = 0x02
 166  	copy(compressedPub[1:], pub)
 167  	pubkey, err := keys.ParsePublic(compressedPub[:])
 168  	if err != nil {
 169  		return nil, err
 170  	}
 171  	if cap(s.ecdhBuf) < 32 {
 172  		s.ecdhBuf = make([]byte, 32)
 173  	} else {
 174  		s.ecdhBuf = s.ecdhBuf[:32]
 175  	}
 176  	if err := exchange.SharedSecretRaw(s.ecdhBuf, pubkey, s.keypair.Seckey()); err != nil {
 177  		return nil, err
 178  	}
 179  	return s.ecdhBuf, nil
 180  }
 181  
 182  func (s *P256K1Signer) ECDHRaw(pub []byte) (sharedX []byte, err error) {
 183  	if !s.hasSecret || s.keypair == nil {
 184  		return nil, errors.New("no secret key available for ECDH")
 185  	}
 186  	var compressedPub [33]byte
 187  	if len(pub) == 32 {
 188  		compressedPub[0] = 0x02
 189  		copy(compressedPub[1:], pub)
 190  	} else if len(pub) == 33 {
 191  		copy(compressedPub[:], pub)
 192  	} else {
 193  		return nil, errors.New("public key must be 32 bytes (x-only) or 33 bytes (compressed)")
 194  	}
 195  	pubkey, err := keys.ParsePublic(compressedPub[:])
 196  	if err != nil {
 197  		if len(pub) == 32 {
 198  			compressedPub[0] = 0x03
 199  			pubkey, err = keys.ParsePublic(compressedPub[:])
 200  			if err != nil {
 201  				return nil, err
 202  			}
 203  		} else {
 204  			return nil, err
 205  		}
 206  	}
 207  	if cap(s.ecdhBuf) < 32 {
 208  		s.ecdhBuf = make([]byte, 32)
 209  	} else {
 210  		s.ecdhBuf = s.ecdhBuf[:32]
 211  	}
 212  	if err := exchange.XOnlySharedSecretRaw(s.ecdhBuf, pubkey, s.keypair.Seckey()); err != nil {
 213  		return nil, err
 214  	}
 215  	return s.ecdhBuf, nil
 216  }
 217