Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DNM] Add ML-DSA (FIPS204) #480

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion sign/dilithium/example_test.go
Expand Up @@ -51,6 +51,6 @@ func Example() {
fmt.Printf("O.K.")

// Output:
// Supported modes: [Dilithium2 Dilithium2-AES Dilithium3 Dilithium3-AES Dilithium5 Dilithium5-AES]
// Supported modes: [Dilithium2 Dilithium2-AES Dilithium3 Dilithium3-AES Dilithium5 Dilithium5-AES ML-DSA-44 ML-DSA-65 ML-DSA-87]
// O.K.
}
92 changes: 79 additions & 13 deletions sign/dilithium/gen.go
Expand Up @@ -14,12 +14,11 @@ import (
"strings"
"text/template"

"github.com/cloudflare/circl/sign/dilithium/internal/common/params"
"github.com/cloudflare/circl/sign/internal/dilithium/params"
)

type Mode struct {
Name string
UseAES bool
K int
L int
Eta int
Expand All @@ -28,26 +27,47 @@ type Mode struct {
Tau int
Gamma1Bits int
Gamma2 int
TRSize int
CTildeSize int
}

func (m Mode) Pkg() string {
return strings.ToLower(m.Mode())
}

func (m Mode) PkgPath() string {
if m.NIST() {
return path.Join("..", "mldsa", m.Pkg())
}

return m.Pkg()
}

func (m Mode) Impl() string {
return "impl" + m.Mode()
}

func (m Mode) Mode() string {
if m.NIST() {
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")
}

func (m Mode) NIST() bool {
return strings.HasPrefix(m.Name, "ML-DSA-")
}

var (
Modes = []Mode{
{
Name: "Dilithium2",
UseAES: false,
K: 4,
L: 4,
Eta: 2,
Expand All @@ -56,10 +76,11 @@ var (
Tau: 39,
Gamma1Bits: 17,
Gamma2: (params.Q - 1) / 88,
TRSize: 32,
CTildeSize: 32,
},
{
Name: "Dilithium2-AES",
UseAES: true,
K: 4,
L: 4,
Eta: 2,
Expand All @@ -68,10 +89,11 @@ var (
Tau: 39,
Gamma1Bits: 17,
Gamma2: (params.Q - 1) / 88,
TRSize: 32,
CTildeSize: 32,
},
{
Name: "Dilithium3",
UseAES: false,
K: 6,
L: 5,
Eta: 4,
Expand All @@ -80,10 +102,11 @@ var (
Tau: 49,
Gamma1Bits: 19,
Gamma2: (params.Q - 1) / 32,
TRSize: 32,
CTildeSize: 32,
},
{
Name: "Dilithium3-AES",
UseAES: true,
K: 6,
L: 5,
Eta: 4,
Expand All @@ -92,10 +115,11 @@ var (
Tau: 49,
Gamma1Bits: 19,
Gamma2: (params.Q - 1) / 32,
TRSize: 32,
CTildeSize: 32,
},
{
Name: "Dilithium5",
UseAES: false,
K: 8,
L: 7,
Eta: 2,
Expand All @@ -104,10 +128,11 @@ var (
Tau: 60,
Gamma1Bits: 19,
Gamma2: (params.Q - 1) / 32,
TRSize: 32,
CTildeSize: 32,
},
{
Name: "Dilithium5-AES",
UseAES: true,
K: 8,
L: 7,
Eta: 2,
Expand All @@ -116,6 +141,47 @@ var (
Tau: 60,
Gamma1Bits: 19,
Gamma2: (params.Q - 1) / 32,
TRSize: 32,
CTildeSize: 32,
},
{
Name: "ML-DSA-44",
K: 4,
L: 4,
Eta: 2,
DoubleEtaBits: 3,
Omega: 80,
Tau: 39,
Gamma1Bits: 17,
Gamma2: (params.Q - 1) / 88,
TRSize: 64,
CTildeSize: 32,
},
{
Name: "ML-DSA-65",
K: 6,
L: 5,
Eta: 4,
DoubleEtaBits: 4,
Omega: 55,
Tau: 49,
Gamma1Bits: 19,
Gamma2: (params.Q - 1) / 32,
TRSize: 64,
CTildeSize: 48,
},
{
Name: "ML-DSA-87",
K: 8,
L: 7,
Eta: 2,
DoubleEtaBits: 3,
Omega: 75,
Tau: 60,
Gamma1Bits: 19,
Gamma2: (params.Q - 1) / 32,
TRSize: 64,
CTildeSize: 64,
},
}
TemplateWarning = "// Code generated from"
Expand Down Expand Up @@ -153,7 +219,7 @@ func generateParamsFiles() {
if offset == -1 {
panic("Missing template warning in params.templ.go")
}
err = os.WriteFile(mode.Pkg()+"/internal/params.go",
err = os.WriteFile(mode.PkgPath()+"/internal/params.go",
[]byte(res[offset:]), 0o644)
if err != nil {
panic(err)
Expand Down Expand Up @@ -206,7 +272,7 @@ func generateModePackageFiles() {
if offset == -1 {
panic("Missing template warning in modePkg.templ.go")
}
err = os.WriteFile(mode.Pkg()+"/dilithium.go", []byte(res[offset:]), 0o644)
err = os.WriteFile(mode.PkgPath()+"/dilithium.go", []byte(res[offset:]), 0o644)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -246,10 +312,10 @@ func generateSourceFiles() {
continue
}

fs, err = os.ReadDir(path.Join(mode.Pkg(), "internal"))
fs, err = os.ReadDir(path.Join(mode.PkgPath(), "internal"))
for _, f := range fs {
name := f.Name()
fn := path.Join(mode.Pkg(), "internal", name)
fn := path.Join(mode.PkgPath(), "internal", name)
if ignored(name) {
continue
}
Expand All @@ -273,7 +339,7 @@ func generateSourceFiles() {
}
}
for name, expected := range files {
fn := path.Join(mode.Pkg(), "internal", name)
fn := path.Join(mode.PkgPath(), "internal", name)
expected = []byte(fmt.Sprintf(
"%s mode3/internal/%s by gen.go\n\n%s",
TemplateWarning,
Expand Down
25 changes: 22 additions & 3 deletions sign/dilithium/kat_test.go
Expand Up @@ -6,24 +6,32 @@ package dilithium
import (
"crypto/sha256"
"fmt"
"strings"
"testing"

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

func TestPQCgenKATSign(t *testing.T) {
// Generated from reference implementation commit 61b51a71701b8ae9f546a1e5,
// which can be found at https://github.com/pq-crystals/dilithium
for _, tc := range []struct {
name string
want string
}{
// Generated from reference implementation commit 61b51a71701b8ae9f546a1e5,
// which can be found at https://github.com/pq-crystals/dilithium
{"Dilithium2", "38ed991c5ca11e39ab23945ca37af89e059d16c5474bf8ba96b15cb4e948af2a"},
{"Dilithium3", "8196b32212753f525346201ffec1c7a0a852596fa0b57bd4e2746231dab44d55"},
{"Dilithium5", "7ded97a6e6c809b43b54c248171d7504fa6a0cab651bf288bb00034782667481"},
{"Dilithium2-AES", "b6673f8da5bba7dfae63adbbdf559f4fcfb715d1f91da98d4b52e26203d69196"},
{"Dilithium3-AES", "482f4d672a9f1dc38cc8bcf8b1731b03fe99fcb6f2b73aa4a376b99faf89ccbe"},
{"Dilithium5-AES", "54dfa85013d1b3da4f1d7c6dd270bc91a083cfece3d320c97906da125fd2a48f"},

// Generated from reference implementation commit e7bed6258b9a3703ce78d4ec3,
// which can be found on the standard branch
// of https://github.com/pq-crystals/dilithium
{"ML-DSA-44", "4657f244d1204e5847b3cacea4fc6116579571bee8ac89b8cba6771f303ee260"},
{"ML-DSA-65", "99a95d7ef804020a666f455c5003232d0c0200dfc4f5df85dceb8f56256dcba8"},
{"ML-DSA-87", "3377835fffb7cf9aac52947225c8974335bc05532ddf672a8b706ab8991435a2"},
} {
t.Run(tc.name, func(t *testing.T) {
mode := ModeByName(tc.name)
Expand All @@ -38,7 +46,18 @@ func TestPQCgenKATSign(t *testing.T) {
}
f := sha256.New()
g := nist.NewDRBG(&seed)
fmt.Fprintf(f, "# %s\n\n", tc.name)
nameInKat := tc.name
if !strings.HasPrefix(tc.name, "Dilithium") {
switch tc.name {
case "ML-DSA-44":
nameInKat = "Dilithium2"
case "ML-DSA-65":
nameInKat = "Dilithium3"
case "ML-DSA-87":
nameInKat = "Dilithium5"
}
}
fmt.Fprintf(f, "# %s\n\n", nameInKat)
for i := 0; i < 100; i++ {
mlen := 33 * (i + 1)
g.Fill(seed[:])
Expand Down
91 changes: 91 additions & 0 deletions sign/dilithium/mldsa44.go

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