Skip to content

Commit ec80a67

Browse files
committed
mayo: add Mode interface
1 parent 5e88046 commit ec80a67

27 files changed

+748
-61
lines changed

sign/mayo/doc.go

-15
This file was deleted.

sign/mayo/gen.go

+27
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ var (
8686

8787
func main() {
8888
generateModePackageFiles()
89+
generateModeToplevelFiles()
8990
generateParamsFiles()
9091
generateSourceFiles()
9192
generateSignApiFiles()
@@ -151,6 +152,32 @@ func generateModePackageFiles() {
151152
}
152153
}
153154

155+
// Generates modeX.go from templates/mode.templ.go
156+
func generateModeToplevelFiles() {
157+
tl, err := template.ParseFiles("templates/mode.templ.go")
158+
if err != nil {
159+
panic(err)
160+
}
161+
162+
for _, mode := range Modes {
163+
buf := new(bytes.Buffer)
164+
err := tl.Execute(buf, mode)
165+
if err != nil {
166+
panic(err)
167+
}
168+
169+
res := buf.String()
170+
offset := strings.Index(res, TemplateWarning)
171+
if offset == -1 {
172+
panic("Missing template warning in mode.templ.go")
173+
}
174+
err = os.WriteFile(mode.Pkg()+".go", []byte(res[offset:]), 0o644)
175+
if err != nil {
176+
panic(err)
177+
}
178+
}
179+
}
180+
154181
// Generates modeX/signapi.go from templates/signapi.templ.go
155182
func generateSignApiFiles() {
156183
tl, err := template.ParseFiles("templates/signapi.templ.go")

sign/mayo/mayo.go

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
//go:generate go run gen.go
2+
3+
// Package mayo implements the MAYO signature scheme
4+
// as submitted to round1 of the NIST PQC competition of Additional Signature Scehemes and described in
5+
//
6+
// https://csrc.nist.gov/csrc/media/Projects/pqc-dig-sig/documents/round-1/spec-files/mayo-spec-web.pdf
7+
//
8+
// This implemented the nibble-sliced version as proposed in
9+
//
10+
// https://eprint.iacr.org/2023/1683
11+
//
12+
// and the code is written with heavy reference to
13+
//
14+
// https://github.com/PQCMayo/MAYO-C/tree/nibbling-mayo
15+
package mayo
16+
17+
import (
18+
"crypto"
19+
"io"
20+
)
21+
22+
// PublicKey is a MAYO public key.
23+
//
24+
// The structure contains values precomputed during unpacking/key generation
25+
// and is therefore significantly larger than a packed public key.
26+
type PublicKey interface {
27+
// Packs public key
28+
Bytes() []byte
29+
}
30+
31+
// PrivateKey is a MAYO public key.
32+
//
33+
// The structure contains values precomputed during unpacking/key generation
34+
// and is therefore significantly larger than a packed private key.
35+
type PrivateKey interface {
36+
// Packs private key
37+
Bytes() []byte
38+
39+
crypto.Signer
40+
}
41+
42+
// Mode is a certain configuration of the MAYO signature scheme.
43+
type Mode interface {
44+
// GenerateKey generates a public/private key pair using entropy from rand.
45+
// If rand is nil, crypto/rand.Reader will be used.
46+
GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error)
47+
48+
// NewKeyFromSeed derives a public/private key pair using the given seed.
49+
// Panics if len(seed) != SeedSize()
50+
NewKeyFromSeed(seed []byte) (PublicKey, PrivateKey)
51+
52+
// Sign signs the given message using entropy from rand and returns the signature.
53+
// If rand is nil, crypto/rand.Reader will be used.
54+
// It will panic if sk has not been generated for this mode.
55+
Sign(sk PrivateKey, msg []byte, rand io.Reader) ([]byte, error)
56+
57+
// Verify checks whether the given signature by pk on msg is valid.
58+
// It will panic if pk is of the wrong mode.
59+
Verify(pk PublicKey, msg []byte, signature []byte) bool
60+
61+
// Unpacks a public key. Panics if the buffer is not of PublicKeySize()
62+
// length. Precomputes values to speed up subsequent calls to Verify.
63+
PublicKeyFromBytes([]byte) PublicKey
64+
65+
// Unpacks a private key. Panics if the buffer is not
66+
// of PrivateKeySize() length. Precomputes values to speed up subsequent
67+
// calls to Sign(To).
68+
PrivateKeyFromBytes([]byte) PrivateKey
69+
70+
// SeedSize returns the size of the seed for NewKeyFromSeed
71+
SeedSize() int
72+
73+
// PublicKeySize returns the size of a packed PublicKey
74+
PublicKeySize() int
75+
76+
// PrivateKeySize returns the size of a packed PrivateKey
77+
PrivateKeySize() int
78+
79+
// SignatureSize returns the size of a signature
80+
SignatureSize() int
81+
82+
// Name returns the name of this mode
83+
Name() string
84+
}
85+
86+
var modes = make(map[string]Mode)
87+
88+
// ModeNames returns the list of supported modes.
89+
func ModeNames() []string {
90+
names := []string{}
91+
for name := range modes {
92+
names = append(names, name)
93+
}
94+
return names
95+
}
96+
97+
// ModeByName returns the mode with the given name or nil when not supported.
98+
func ModeByName(name string) Mode {
99+
return modes[name]
100+
}

sign/mayo/mayo_test.go

+136
Large diffs are not rendered by default.

sign/mayo/mode1.go

+87
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sign/mayo/mode1/internal/mayo.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -149,13 +149,13 @@ func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) {
149149
if err != nil {
150150
return nil, nil, err
151151
}
152-
pk, sk := NewKeyFromSeed(seed)
152+
pk, sk := NewKeyFromSeed(&seed)
153153
return pk, sk, nil
154154
}
155155

156-
func NewKeyFromSeed(seed [KeySeedSize]byte) (*PublicKey, *PrivateKey) {
156+
func NewKeyFromSeed(seed *[KeySeedSize]byte) (*PublicKey, *PrivateKey) {
157157
var sk PrivateKey
158-
sk.Unpack(&seed)
158+
sk.Unpack(seed)
159159

160160
return sk.Public(), &sk
161161
}

sign/mayo/mode1/internal/mayo_test.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func TestNewKey(t *testing.T) {
2828
var seed [KeySeedSize]byte
2929
_, _ = hex.Decode(seed[:], []byte(tc.seed))
3030

31-
pk, sk := NewKeyFromSeed(seed)
31+
pk, sk := NewKeyFromSeed(&seed)
3232

3333
var pk2 [PublicKeySize]byte
3434
var sk2 [PrivateKeySize]byte
@@ -68,7 +68,7 @@ func TestVerify(t *testing.T) {
6868
m, _ := hex.DecodeString(tc.message)
6969
s, _ := hex.DecodeString(tc.signature)
7070

71-
pk, _ := NewKeyFromSeed(seed)
71+
pk, _ := NewKeyFromSeed(&seed)
7272

7373
if !Verify(pk, m, s) {
7474
t.Fatal("should verify")
@@ -144,7 +144,7 @@ func TestPQCgenKATSign(t *testing.T) {
144144

145145
g2 := nist.NewDRBG(&seed)
146146
_, _ = g2.Read(eseed[:])
147-
pk, sk := NewKeyFromSeed(eseed)
147+
pk, sk := NewKeyFromSeed(&eseed)
148148

149149
var pk2 [PublicKeySize]byte
150150
var sk2 [PrivateKeySize]byte
@@ -178,7 +178,7 @@ func BenchmarkKeyGen(b *testing.B) {
178178
var seed [KeySeedSize]byte
179179
for i := 0; i < b.N; i++ {
180180
binary.LittleEndian.PutUint64(seed[:], uint64(i))
181-
_, _ = NewKeyFromSeed(seed)
181+
_, _ = NewKeyFromSeed(&seed)
182182
}
183183
}
184184

@@ -198,7 +198,7 @@ func BenchmarkMatMul(b *testing.B) {
198198
func BenchmarkVerify(b *testing.B) {
199199
var seed [KeySeedSize]byte
200200
var msg [8]byte
201-
pk, sk := NewKeyFromSeed(seed)
201+
pk, sk := NewKeyFromSeed(&seed)
202202
sig, _ := Sign(msg[:], sk, nil)
203203
b.ResetTimer()
204204
for i := 0; i < b.N; i++ {
@@ -218,7 +218,7 @@ func (zeroReader) Read(buf []byte) (int, error) {
218218
func BenchmarkSign(b *testing.B) {
219219
var seed [KeySeedSize]byte
220220
var msg [8]byte
221-
_, sk := NewKeyFromSeed(seed)
221+
_, sk := NewKeyFromSeed(&seed)
222222
b.ResetTimer()
223223
for i := 0; i < b.N; i++ {
224224
binary.LittleEndian.PutUint64(msg[:], uint64(i))

sign/mayo/mode1/mayo.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sign/mayo/mode1/signapi.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)