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