keypackage.go raw

   1  package marmot
   2  
   3  import (
   4  	"fmt"
   5  	"time"
   6  
   7  	"next.orly.dev/pkg/nostr/encoders/event"
   8  	"next.orly.dev/pkg/nostr/encoders/tag"
   9  	"next.orly.dev/pkg/nostr/interfaces/signer"
  10  	"github.com/emersion/go-mls"
  11  )
  12  
  13  // GenerateKeyPackage creates a new MLS key pair package using the Nostr pubkey
  14  // as the MLS credential identity.
  15  func GenerateKeyPackage(sign signer.I) (*mls.KeyPairPackage, error) {
  16  	cred := mls.NewBasicCredential(sign.Pub())
  17  	kpp, err := mls.GenerateKeyPairPackage(cipherSuite, cred)
  18  	if err != nil {
  19  		return nil, fmt.Errorf("generate key package: %w", err)
  20  	}
  21  	return kpp, nil
  22  }
  23  
  24  // KeyPackageToEvent creates a kind 443 Nostr event containing the serialized
  25  // MLS key package. The event is signed by the provided signer.
  26  func KeyPackageToEvent(kpp *mls.KeyPairPackage, sign signer.I) (*event.E, error) {
  27  	kpBytes := kpp.Public.Bytes()
  28  
  29  	ev := event.New()
  30  	ev.CreatedAt = time.Now().Unix()
  31  	ev.Kind = KindKeyPackage
  32  	ev.Content = kpBytes
  33  	ev.Tags = tag.NewS(
  34  		tag.NewFromAny("mls_protocol_version", "mls10"),
  35  		tag.NewFromAny("mls_ciphersuite", "MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519"),
  36  	)
  37  	if err := ev.Sign(sign); err != nil {
  38  		return nil, fmt.Errorf("sign key package event: %w", err)
  39  	}
  40  	return ev, nil
  41  }
  42  
  43  // EventToKeyPackage extracts an MLS key package from a kind 443 event.
  44  func EventToKeyPackage(ev *event.E) (*mls.KeyPackage, error) {
  45  	if ev.Kind != KindKeyPackage {
  46  		return nil, fmt.Errorf("expected kind %d, got %d", KindKeyPackage, ev.Kind)
  47  	}
  48  	kp, err := mls.UnmarshalKeyPackage(ev.Content)
  49  	if err != nil {
  50  		return nil, fmt.Errorf("unmarshal key package: %w", err)
  51  	}
  52  	return kp, nil
  53  }
  54