Skip to content

Commit

Permalink
Update to final FIPS 204 standard.
Browse files Browse the repository at this point in the history
Remove old mode API and hook Dilithium and ML-DSA into generic
signature API.

Expose support for randomized ML-DSA mode. (It is not exposed
in the generic signature API.)

Remove old AES variants of Dilithium.

Does not add the HashML-DSA variants (yet).
  • Loading branch information
bwesterb committed Aug 20, 2024
1 parent 72ac15a commit 91c162a
Show file tree
Hide file tree
Showing 95 changed files with 1,861 additions and 9,836 deletions.
84 changes: 0 additions & 84 deletions sign/dilithium/dilithium.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,87 +25,3 @@
// Dilithium3 with Ed448. These packages are a drop in replacements for the
// mode subpackages of this package.
package dilithium

import (
"crypto"
"io"
)

// PublicKey is a Dilithium 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 Dilithium private 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 Dilithium 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 and returns the signature.
// It will panic if sk has not been generated for this mode.
Sign(sk PrivateKey, msg []byte) []byte

// 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]
}
31 changes: 15 additions & 16 deletions sign/dilithium/dilithium_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"encoding/hex"
"testing"

"github.com/cloudflare/circl/sign/schemes"

"github.com/cloudflare/circl/internal/sha3"
)

Expand Down Expand Up @@ -34,29 +36,26 @@ func TestNewKeyFromSeed(t *testing.T) {
"Dilithium5", "3956d812a7961af6e5dad16af15c736c",
"665388291aa01e12e7f94bdc7769db18",
},
{
"Dilithium2-AES", "8466a752b0a09e63e42f66d3174a6471",
"c3f8e705a0d8dfd489b98b205670f393",
},
{
"Dilithium3-AES", "2bb713ba7cb15f3ebf05c4c1fbb1b03c",
"eb2bd8d98630835a3b18594ac436368b",
},
{
"Dilithium5-AES", "a613a08b564ee8717ba4f5ccfddc2693",
"2f541bf6fedd12854d06a6b80090932a",
},
} {
t.Run(tc.name, func(t *testing.T) {
mode := ModeByName(tc.name)
mode := schemes.ByName(tc.name)
if mode == nil {
t.Fatal()
}
var seed [32]byte
pk, sk := mode.NewKeyFromSeed(seed[:])
pk, sk := mode.DeriveKey(seed[:])

ppk, err := pk.MarshalBinary()
if err != nil {
t.Fatal(err)
}
psk, err := sk.MarshalBinary()
if err != nil {
t.Fatal(err)
}

pkh := hexHash(pk.Bytes())
skh := hexHash(sk.Bytes())
pkh := hexHash(ppk)
skh := hexHash(psk)
if pkh != tc.epk {
t.Fatalf("%s expected pk %s, got %s", tc.name, tc.epk, pkh)
}
Expand Down
56 changes: 0 additions & 56 deletions sign/dilithium/example_test.go

This file was deleted.

85 changes: 9 additions & 76 deletions sign/dilithium/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,7 @@ func (m Mode) Mode() string {
return strings.ReplaceAll(m.Name, "-", "")
}

return strings.ReplaceAll(strings.ReplaceAll(m.Name,
"Dilithium", "Mode"), "-AES", "AES")
}

func (m Mode) UseAES() bool {
return strings.HasSuffix(m.Name, "-AES")
return strings.ReplaceAll(m.Name, "Dilithium", "Mode")
}

func (m Mode) NIST() bool {
Expand All @@ -79,19 +74,6 @@ var (
TRSize: 32,
CTildeSize: 32,
},
{
Name: "Dilithium2-AES",
K: 4,
L: 4,
Eta: 2,
DoubleEtaBits: 3,
Omega: 80,
Tau: 39,
Gamma1Bits: 17,
Gamma2: (params.Q - 1) / 88,
TRSize: 32,
CTildeSize: 32,
},
{
Name: "Dilithium3",
K: 6,
Expand All @@ -105,19 +87,6 @@ var (
TRSize: 32,
CTildeSize: 32,
},
{
Name: "Dilithium3-AES",
K: 6,
L: 5,
Eta: 4,
DoubleEtaBits: 4,
Omega: 55,
Tau: 49,
Gamma1Bits: 19,
Gamma2: (params.Q - 1) / 32,
TRSize: 32,
CTildeSize: 32,
},
{
Name: "Dilithium5",
K: 8,
Expand All @@ -131,19 +100,6 @@ var (
TRSize: 32,
CTildeSize: 32,
},
{
Name: "Dilithium5-AES",
K: 8,
L: 7,
Eta: 2,
DoubleEtaBits: 3,
Omega: 75,
Tau: 60,
Gamma1Bits: 19,
Gamma2: (params.Q - 1) / 32,
TRSize: 32,
CTildeSize: 32,
},
{
Name: "ML-DSA-44",
K: 4,
Expand Down Expand Up @@ -189,7 +145,6 @@ var (

func main() {
generateModePackageFiles()
generateModeToplevelFiles()
generateParamsFiles()
generateSourceFiles()
}
Expand Down Expand Up @@ -227,9 +182,9 @@ func generateParamsFiles() {
}
}

// Generates modeX.go from templates/mode.templ.go
func generateModeToplevelFiles() {
tl, err := template.ParseFiles("templates/mode.templ.go")
// Generates modeX/dilithium.go from templates/pkg.templ.go
func generateModePackageFiles() {
tl, err := template.ParseFiles("templates/pkg.templ.go")
if err != nil {
panic(err)
}
Expand All @@ -241,38 +196,16 @@ func generateModeToplevelFiles() {
panic(err)
}

res := string(buf.Bytes())
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)
res, err := format.Source(buf.Bytes())
if err != nil {
panic(err)
}
}
}

// Generates modeX/dilithium.go from templates/modePkg.templ.go
func generateModePackageFiles() {
tl, err := template.ParseFiles("templates/modePkg.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)
panic("error formating code")
}

res := string(buf.Bytes())
offset := strings.Index(res, TemplateWarning)
offset := strings.Index(string(res), TemplateWarning)
if offset == -1 {
panic("Missing template warning in modePkg.templ.go")
panic("Missing template warning in pkg.templ.go")
}
err = os.WriteFile(mode.PkgPath()+"/dilithium.go", []byte(res[offset:]), 0o644)
err = os.WriteFile(mode.PkgPath()+"/dilithium.go", res[offset:], 0o644)
if err != nil {
panic(err)
}
Expand Down
Loading

0 comments on commit 91c162a

Please sign in to comment.