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-KEM (FIPS 203). #470

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
36 changes: 33 additions & 3 deletions kem/kyber/gen.go
Expand Up @@ -7,8 +7,10 @@ package main

import (
"bytes"
"fmt"
"go/format"
"io/ioutil"
"path"
"strings"
"text/template"
)
Expand All @@ -17,15 +19,43 @@ type Instance struct {
Name string
}

func (m Instance) KemName() string {
if m.NIST() {
return m.Name
}
return m.Name + ".CCAKEM"
}

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

func (m Instance) PkePkg() string {
if !m.NIST() {
return m.Pkg()
}
return strings.ReplaceAll(m.Pkg(), "mlkem", "kyber")
}

func (m Instance) Pkg() string {
return strings.ToLower(m.Name)
return strings.ToLower(strings.ReplaceAll(m.Name, "-", ""))
}

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

var (
Instances = []Instance{
{Name: "Kyber512"},
{Name: "Kyber768"},
{Name: "Kyber1024"},
{Name: "ML-KEM-512"},
{Name: "ML-KEM-768"},
{Name: "ML-KEM-1024"},
}
TemplateWarning = "// Code generated from"
)
Expand All @@ -51,15 +81,15 @@ func generatePackageFiles() {
// Formating output code
code, err := format.Source(buf.Bytes())
if err != nil {
panic("error formating code")
panic(fmt.Sprintf("error formating code: %v", err))
}

res := string(code)
offset := strings.Index(res, TemplateWarning)
if offset == -1 {
panic("Missing template warning in pkg.templ.go")
}
err = ioutil.WriteFile(mode.Pkg()+"/kyber.go", []byte(res[offset:]), 0o644)
err = ioutil.WriteFile(mode.PkgPath()+"/kyber.go", []byte(res[offset:]), 0o644)
if err != nil {
panic(err)
}
Expand Down
28 changes: 21 additions & 7 deletions kem/kyber/kat_test.go
Expand Up @@ -7,6 +7,7 @@ import (
"bytes"
"crypto/sha256"
"fmt"
"strings"
"testing"

"github.com/cloudflare/circl/internal/nist"
Expand All @@ -22,6 +23,11 @@ func TestPQCgenKATKem(t *testing.T) {
{"Kyber1024", "89248f2f33f7f4f7051729111f3049c409a933ec904aedadf035f30fa5646cd5"},
{"Kyber768", "a1e122cad3c24bc51622e4c242d8b8acbcd3f618fee4220400605ca8f9ea02c2"},
{"Kyber512", "e9c2bd37133fcb40772f81559f14b1f58dccd1c816701be9ba6214d43baf4547"},

// Computed from reference implementation standard branch
{"ML-KEM-512", "4b88ac7643ff60209af1175e025f354272e88df827a0ce1c056e403629b88e04"},
{"ML-KEM-768", "21b4a1e1ea34a13c26a9da5eeb9325afb5ca11596ca6f3704c3f2637e3ea7524"},
{"ML-KEM-1024", "6471398b0a728ee1ef39e93bb89b526fbf59587a3662edadbcfc6c88a512cd71"},
}
for _, kat := range kats {
kat := kat
Expand All @@ -45,18 +51,26 @@ func testPQCgenKATKem(t *testing.T, name, expected string) {
}
f := sha256.New()
g := nist.NewDRBG(&seed)
fmt.Fprintf(f, "# %s\n\n", name)

// The "standard" branch reference implementation still uses Kyber
// as name instead of ML-KEM.
fmt.Fprintf(f, "# %s\n\n", strings.ReplaceAll(name, "ML-KEM-", "Kyber"))
for i := 0; i < 100; i++ {
g.Fill(seed[:])
fmt.Fprintf(f, "count = %d\n", i)
fmt.Fprintf(f, "seed = %X\n", seed)
g2 := nist.NewDRBG(&seed)

// This is not equivalent to g2.Fill(kseed[:]). As the reference
// implementation calls randombytes twice generating the keypair,
// we have to do that as well.
g2.Fill(kseed[:32])
g2.Fill(kseed[32:])
if strings.HasPrefix(name, "ML-KEM") {
// https://github.com/pq-crystals/kyber/commit/830e0ba1a7fdba6cde03f8139b0d41ad2102b860
g2.Fill(kseed[:])
} else {
// This is not equivalent to g2.Fill(kseed[:]). As the reference
// implementation calls randombytes twice generating the keypair,
// we have to do that as well.
g2.Fill(kseed[:32])
g2.Fill(kseed[32:])
}

g2.Fill(eseed)
pk, sk := scheme.DeriveKeyPair(kseed)
Expand All @@ -73,6 +87,6 @@ func testPQCgenKATKem(t *testing.T, name, expected string) {
fmt.Fprintf(f, "ss = %X\n\n", ss)
}
if fmt.Sprintf("%x", f.Sum(nil)) != expected {
t.Fatal()
t.Fatalf("%s %x %s", name, f.Sum(nil), expected)
}
}
14 changes: 8 additions & 6 deletions kem/kyber/kyber1024/kyber.go

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

14 changes: 8 additions & 6 deletions kem/kyber/kyber512/kyber.go

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

14 changes: 8 additions & 6 deletions kem/kyber/kyber768/kyber.go

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

43 changes: 37 additions & 6 deletions kem/kyber/templates/pkg.templ.go

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

5 changes: 5 additions & 0 deletions kem/mlkem/doc.go
@@ -0,0 +1,5 @@
// Package mlkem implements IND-CCA2 secure ML-KEM key encapsulation
// mechanism (KEM) as defined in FIPS 203.
package kyber

// See ../kyber/gen.go and ../kyber/kat_test.go.