Skip to content

Commit 7f7fdcf

Browse files
authored
Add func to generate MLDSA key pairs (#249)
Add a function to generate MLDSA skey and vkey pairs, analogous to the note.GenerateKey func.
1 parent 8446089 commit 7f7fdcf

2 files changed

Lines changed: 68 additions & 42 deletions

File tree

note/note_cosigv1.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,27 @@ const (
3737
timestampSize = 8
3838
)
3939

40+
41+
// GenerateMLDSASignerKey generates a named signer and verifier key pair. The signer key skey is private and must be kept secret.
42+
func GenerateMLDSASignerKey(name string) (skey string, vkey string, err error) {
43+
if !isValidName(name) {
44+
return "", "", errSignerID
45+
}
46+
secK, err := mldsa.GenerateKey(mldsa.MLDSA44())
47+
if err != nil {
48+
return "", "", err
49+
}
50+
secKBytes := append([]byte{algMLDSA44}, secK.Bytes()...)
51+
pubKBytes := append([]byte{algMLDSA44}, secK.PublicKey().Bytes()...)
52+
53+
h := keyHashMLDSA(name, pubKBytes)
54+
55+
skey = fmt.Sprintf("PRIVATE+KEY+%s+%08x+%s", name, h, base64.StdEncoding.EncodeToString(secKBytes))
56+
vkey = fmt.Sprintf("%s+%08x+%s", name, h, base64.StdEncoding.EncodeToString(pubKBytes))
57+
58+
return skey, vkey, nil
59+
}
60+
4061
// NewMLDSASigner returns a signer for MLDSA cosignature v1.
4162
func NewMLDSASigner(skey string) (*SubtreeSigner, error) {
4263
priv1, skey, _ := strings.Cut(skey, "+")

note/note_cosigv1_test.go

Lines changed: 47 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,9 @@ package note
66

77
import (
88
"crypto/rand"
9-
"encoding/base64"
10-
"fmt"
119
"testing"
1210
"time"
1311

14-
"filippo.io/mldsa"
1512
"golang.org/x/mod/sumdb/note"
1613
)
1714

@@ -51,7 +48,7 @@ func TestSignerRoundtrip(t *testing.T) {
5148
}
5249
}
5350

54-
func TestMLDSASignerVerifierRoundtrip(t *testing.T) {
51+
func TestCosignnatureV1RoundTrip(t *testing.T) {
5552
edSk, edPk := mustGenerateEd25519Key(t, "ed25519")
5653
mlSk, mlPk := mustGenerateMLDSAKey(t, "mldsa")
5754
for _, test := range []struct {
@@ -96,33 +93,6 @@ func TestMLDSASignerVerifierRoundtrip(t *testing.T) {
9693
}
9794
}
9895

99-
func TestSignerVerifierRoundtrip(t *testing.T) {
100-
skey, vkey, err := note.GenerateKey(rand.Reader, "test")
101-
if err != nil {
102-
t.Fatal(err)
103-
}
104-
105-
s, err := NewSignerForCosignatureV1(skey)
106-
if err != nil {
107-
t.Fatal(err)
108-
}
109-
110-
v, err := NewVerifierForCosignatureV1(vkey)
111-
if err != nil {
112-
t.Fatal(err)
113-
}
114-
115-
msg := "test\n123\nf+7CoKgXKE/tNys9TTXcr/ad6U/K3xvznmzew9y6SP0=\n"
116-
n, err := note.Sign(&note.Note{Text: msg}, s)
117-
if err != nil {
118-
t.Fatal(err)
119-
}
120-
121-
if _, err := note.Open(n, note.VerifierList(v)); err != nil {
122-
t.Fatal(err)
123-
}
124-
}
125-
12696
func TestVerifierInvalidSig(t *testing.T) {
12797
skey, _, err := note.GenerateKey(rand.Reader, "test")
12898
if err != nil {
@@ -200,7 +170,7 @@ func TestCoSigV1NewVerifier(t *testing.T) {
200170
wantErr: true,
201171
}, {
202172
name: "incorrect keyhash",
203-
pubK: "rekor.sigstore.dev" + "+" + "00000000" + "+" + sigStoreKeyMaterial,
173+
pubK: "rekor.sigstore.dev+00000000+" + sigStoreKeyMaterial,
204174
wantErr: true,
205175
},
206176
} {
@@ -358,6 +328,49 @@ func TestMLDSAInvalidTimestamp(t *testing.T) {
358328
}
359329
}
360330

331+
func TestGenerateMLDSASignerKey(t *testing.T) {
332+
for _, test := range []struct {
333+
name string
334+
wantErr bool
335+
}{
336+
{
337+
name: "valid",
338+
},
339+
{
340+
name: "invalid name",
341+
wantErr: true,
342+
},
343+
} {
344+
t.Run(test.name, func(t *testing.T) {
345+
skey, vkey, err := GenerateMLDSASignerKey(test.name)
346+
if gotErr := err != nil; gotErr != test.wantErr {
347+
t.Fatalf("GenerateMLDSASignerKey(%q) error = %v, wantErr %v", test.name, err, test.wantErr)
348+
}
349+
if test.wantErr {
350+
return
351+
}
352+
// Roundtrip check
353+
s, err := NewMLDSASigner(skey)
354+
if err != nil {
355+
t.Fatalf("NewMLDSASigner(%q): %v", skey, err)
356+
}
357+
v, err := NewMLDSAVerifier(vkey)
358+
if err != nil {
359+
t.Fatalf("NewMLDSAVerifier(%q): %v", vkey, err)
360+
}
361+
if s.Name() != test.name {
362+
t.Errorf("Signer name = %q, want %q", s.Name(), test.name)
363+
}
364+
if v.Name() != test.name {
365+
t.Errorf("Verifier name = %q, want %q", v.Name(), test.name)
366+
}
367+
if s.KeyHash() != v.KeyHash() {
368+
t.Errorf("Signer hash %08x != Verifier hash %08x", s.KeyHash(), v.KeyHash())
369+
}
370+
})
371+
}
372+
}
373+
361374
func mustGenerateEd25519Key(t *testing.T, name string) (string, string) {
362375
t.Helper()
363376
skey, vkey, err := note.GenerateKey(rand.Reader, name)
@@ -369,17 +382,9 @@ func mustGenerateEd25519Key(t *testing.T, name string) (string, string) {
369382

370383
func mustGenerateMLDSAKey(t *testing.T, name string) (string, string) {
371384
t.Helper()
372-
key, err := mldsa.GenerateKey(mldsa.MLDSA44())
385+
skey, vkey, err := GenerateMLDSASignerKey(name)
373386
if err != nil {
374-
t.Fatalf("Failed to generate MLDSA key: %v", err)
387+
t.Fatalf("GenerateMLDSASignerKey(%q): %v", name, err)
375388
}
376-
privBytes := key.Bytes()
377-
pubBytes := key.PublicKey().Bytes()
378-
379-
pubKeyWithAlg := append([]byte{algMLDSA44}, pubBytes...)
380-
hash := keyHashMLDSA(name, pubKeyWithAlg)
381-
382-
skey := fmt.Sprintf("PRIVATE+KEY+%s+%08x+%s", name, hash, base64.StdEncoding.EncodeToString(append([]byte{algMLDSA44}, privBytes...)))
383-
vkey := fmt.Sprintf("%s+%08x+%s", name, hash, base64.StdEncoding.EncodeToString(pubKeyWithAlg))
384389
return skey, vkey
385390
}

0 commit comments

Comments
 (0)