Skip to content

Commit

Permalink
mayo: add Mode interface
Browse files Browse the repository at this point in the history
  • Loading branch information
ilway25 committed Mar 12, 2024
1 parent 5e88046 commit ec80a67
Show file tree
Hide file tree
Showing 27 changed files with 748 additions and 61 deletions.
15 changes: 0 additions & 15 deletions sign/mayo/doc.go

This file was deleted.

27 changes: 27 additions & 0 deletions sign/mayo/gen.go
Expand Up @@ -86,6 +86,7 @@ var (

func main() {
generateModePackageFiles()
generateModeToplevelFiles()
generateParamsFiles()
generateSourceFiles()
generateSignApiFiles()
Expand Down Expand Up @@ -151,6 +152,32 @@ func generateModePackageFiles() {
}
}

// Generates modeX.go from templates/mode.templ.go
func generateModeToplevelFiles() {
tl, err := template.ParseFiles("templates/mode.templ.go")
if err != nil {
panic(err)
}

for _, mode := range Modes {
buf := new(bytes.Buffer)
err := tl.Execute(buf, mode)
if err != nil {
panic(err)
}

res := buf.String()
offset := strings.Index(res, TemplateWarning)
if offset == -1 {
panic("Missing template warning in mode.templ.go")
}
err = os.WriteFile(mode.Pkg()+".go", []byte(res[offset:]), 0o644)
if err != nil {
panic(err)
}
}
}

// Generates modeX/signapi.go from templates/signapi.templ.go
func generateSignApiFiles() {
tl, err := template.ParseFiles("templates/signapi.templ.go")
Expand Down
100 changes: 100 additions & 0 deletions sign/mayo/mayo.go
@@ -0,0 +1,100 @@
//go:generate go run gen.go

// Package mayo implements the MAYO signature scheme
// as submitted to round1 of the NIST PQC competition of Additional Signature Scehemes and described in
//
// https://csrc.nist.gov/csrc/media/Projects/pqc-dig-sig/documents/round-1/spec-files/mayo-spec-web.pdf
//
// This implemented the nibble-sliced version as proposed in
//
// https://eprint.iacr.org/2023/1683
//
// and the code is written with heavy reference to
//
// https://github.com/PQCMayo/MAYO-C/tree/nibbling-mayo
package mayo

import (
"crypto"
"io"
)

// PublicKey is a MAYO public key.
//
// The structure contains values precomputed during unpacking/key generation
// and is therefore significantly larger than a packed public key.
type PublicKey interface {
// Packs public key
Bytes() []byte
}

// PrivateKey is a MAYO public key.
//
// The structure contains values precomputed during unpacking/key generation
// and is therefore significantly larger than a packed private key.
type PrivateKey interface {
// Packs private key
Bytes() []byte

crypto.Signer
}

// Mode is a certain configuration of the MAYO signature scheme.
type Mode interface {
// GenerateKey generates a public/private key pair using entropy from rand.
// If rand is nil, crypto/rand.Reader will be used.
GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error)

// NewKeyFromSeed derives a public/private key pair using the given seed.
// Panics if len(seed) != SeedSize()
NewKeyFromSeed(seed []byte) (PublicKey, PrivateKey)

// Sign signs the given message using entropy from rand and returns the signature.
// If rand is nil, crypto/rand.Reader will be used.
// It will panic if sk has not been generated for this mode.
Sign(sk PrivateKey, msg []byte, rand io.Reader) ([]byte, error)

// Verify checks whether the given signature by pk on msg is valid.
// It will panic if pk is of the wrong mode.
Verify(pk PublicKey, msg []byte, signature []byte) bool

// Unpacks a public key. Panics if the buffer is not of PublicKeySize()
// length. Precomputes values to speed up subsequent calls to Verify.
PublicKeyFromBytes([]byte) PublicKey

// Unpacks a private key. Panics if the buffer is not
// of PrivateKeySize() length. Precomputes values to speed up subsequent
// calls to Sign(To).
PrivateKeyFromBytes([]byte) PrivateKey

// SeedSize returns the size of the seed for NewKeyFromSeed
SeedSize() int

// PublicKeySize returns the size of a packed PublicKey
PublicKeySize() int

// PrivateKeySize returns the size of a packed PrivateKey
PrivateKeySize() int

// SignatureSize returns the size of a signature
SignatureSize() int

// Name returns the name of this mode
Name() string
}

var modes = make(map[string]Mode)

// ModeNames returns the list of supported modes.
func ModeNames() []string {
names := []string{}
for name := range modes {
names = append(names, name)
}
return names
}

// ModeByName returns the mode with the given name or nil when not supported.
func ModeByName(name string) Mode {
return modes[name]
}
136 changes: 136 additions & 0 deletions sign/mayo/mayo_test.go

Large diffs are not rendered by default.

87 changes: 87 additions & 0 deletions sign/mayo/mode1.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions sign/mayo/mode1/internal/mayo.go
Expand Up @@ -149,13 +149,13 @@ func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) {
if err != nil {
return nil, nil, err
}
pk, sk := NewKeyFromSeed(seed)
pk, sk := NewKeyFromSeed(&seed)
return pk, sk, nil
}

func NewKeyFromSeed(seed [KeySeedSize]byte) (*PublicKey, *PrivateKey) {
func NewKeyFromSeed(seed *[KeySeedSize]byte) (*PublicKey, *PrivateKey) {
var sk PrivateKey
sk.Unpack(&seed)
sk.Unpack(seed)

return sk.Public(), &sk
}
Expand Down
12 changes: 6 additions & 6 deletions sign/mayo/mode1/internal/mayo_test.go
Expand Up @@ -28,7 +28,7 @@ func TestNewKey(t *testing.T) {
var seed [KeySeedSize]byte
_, _ = hex.Decode(seed[:], []byte(tc.seed))

pk, sk := NewKeyFromSeed(seed)
pk, sk := NewKeyFromSeed(&seed)

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

pk, _ := NewKeyFromSeed(seed)
pk, _ := NewKeyFromSeed(&seed)

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

g2 := nist.NewDRBG(&seed)
_, _ = g2.Read(eseed[:])
pk, sk := NewKeyFromSeed(eseed)
pk, sk := NewKeyFromSeed(&eseed)

var pk2 [PublicKeySize]byte
var sk2 [PrivateKeySize]byte
Expand Down Expand Up @@ -178,7 +178,7 @@ func BenchmarkKeyGen(b *testing.B) {
var seed [KeySeedSize]byte
for i := 0; i < b.N; i++ {
binary.LittleEndian.PutUint64(seed[:], uint64(i))
_, _ = NewKeyFromSeed(seed)
_, _ = NewKeyFromSeed(&seed)
}
}

Expand All @@ -198,7 +198,7 @@ func BenchmarkMatMul(b *testing.B) {
func BenchmarkVerify(b *testing.B) {
var seed [KeySeedSize]byte
var msg [8]byte
pk, sk := NewKeyFromSeed(seed)
pk, sk := NewKeyFromSeed(&seed)
sig, _ := Sign(msg[:], sk, nil)
b.ResetTimer()
for i := 0; i < b.N; i++ {
Expand All @@ -218,7 +218,7 @@ func (zeroReader) Read(buf []byte) (int, error) {
func BenchmarkSign(b *testing.B) {
var seed [KeySeedSize]byte
var msg [8]byte
_, sk := NewKeyFromSeed(seed)
_, sk := NewKeyFromSeed(&seed)
b.ResetTimer()
for i := 0; i < b.N; i++ {
binary.LittleEndian.PutUint64(msg[:], uint64(i))
Expand Down
2 changes: 1 addition & 1 deletion sign/mayo/mode1/mayo.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion sign/mayo/mode1/signapi.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit ec80a67

Please sign in to comment.