From 91c162a685380c9f5bcaac6158bc3da434e7810b Mon Sep 17 00:00:00 2001 From: Bas Westerbaan Date: Tue, 20 Aug 2024 14:25:25 +0200 Subject: [PATCH] Update to final FIPS 204 standard. 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). --- sign/dilithium/dilithium.go | 84 --- sign/dilithium/dilithium_test.go | 31 +- sign/dilithium/example_test.go | 56 -- sign/dilithium/gen.go | 85 +-- sign/dilithium/kat_test.go | 33 +- sign/dilithium/mldsa44.go | 91 ---- sign/dilithium/mldsa65.go | 91 ---- sign/dilithium/mldsa87.go | 91 ---- sign/dilithium/mode2.go | 90 ---- sign/dilithium/mode2/dilithium.go | 142 +++++- sign/dilithium/mode2/internal/dilithium.go | 22 +- .../mode2/internal/dilithium_test.go | 46 +- sign/dilithium/mode2/internal/params.go | 1 - sign/dilithium/mode2/internal/sample.go | 97 ++-- sign/dilithium/mode2/internal/sample_test.go | 132 ++--- sign/dilithium/mode2aes.go | 90 ---- sign/dilithium/mode2aes/dilithium.go | 185 ------- sign/dilithium/mode2aes/internal/dilithium.go | 482 ------------------ .../mode2aes/internal/dilithium_test.go | 144 ------ sign/dilithium/mode2aes/internal/mat.go | 59 --- sign/dilithium/mode2aes/internal/pack.go | 270 ---------- sign/dilithium/mode2aes/internal/pack_test.go | 93 ---- sign/dilithium/mode2aes/internal/params.go | 19 - .../mode2aes/internal/params_test.go | 99 ---- sign/dilithium/mode2aes/internal/rounding.go | 142 ------ .../mode2aes/internal/rounding_test.go | 81 --- sign/dilithium/mode2aes/internal/sample.go | 370 -------------- .../mode2aes/internal/sample_test.go | 266 ---------- sign/dilithium/mode2aes/internal/vec.go | 281 ---------- sign/dilithium/mode3.go | 90 ---- sign/dilithium/mode3/dilithium.go | 142 +++++- sign/dilithium/mode3/internal/dilithium.go | 22 +- .../mode3/internal/dilithium_test.go | 46 +- sign/dilithium/mode3/internal/params.go | 1 - sign/dilithium/mode3/internal/sample.go | 97 ++-- sign/dilithium/mode3/internal/sample_test.go | 132 ++--- sign/dilithium/mode3aes.go | 90 ---- sign/dilithium/mode3aes/dilithium.go | 185 ------- sign/dilithium/mode3aes/internal/dilithium.go | 482 ------------------ .../mode3aes/internal/dilithium_test.go | 144 ------ sign/dilithium/mode3aes/internal/mat.go | 59 --- sign/dilithium/mode3aes/internal/pack.go | 270 ---------- sign/dilithium/mode3aes/internal/pack_test.go | 93 ---- sign/dilithium/mode3aes/internal/params.go | 19 - .../mode3aes/internal/params_test.go | 101 ---- sign/dilithium/mode3aes/internal/rounding.go | 142 ------ .../mode3aes/internal/rounding_test.go | 81 --- sign/dilithium/mode3aes/internal/sample.go | 370 -------------- .../mode3aes/internal/sample_test.go | 266 ---------- sign/dilithium/mode3aes/internal/vec.go | 281 ---------- sign/dilithium/mode5.go | 90 ---- sign/dilithium/mode5/dilithium.go | 142 +++++- sign/dilithium/mode5/internal/dilithium.go | 22 +- .../mode5/internal/dilithium_test.go | 46 +- sign/dilithium/mode5/internal/params.go | 1 - sign/dilithium/mode5/internal/sample.go | 97 ++-- sign/dilithium/mode5/internal/sample_test.go | 132 ++--- sign/dilithium/mode5aes.go | 90 ---- sign/dilithium/mode5aes/dilithium.go | 185 ------- sign/dilithium/mode5aes/internal/dilithium.go | 482 ------------------ .../mode5aes/internal/dilithium_test.go | 144 ------ sign/dilithium/mode5aes/internal/mat.go | 59 --- sign/dilithium/mode5aes/internal/pack.go | 270 ---------- sign/dilithium/mode5aes/internal/pack_test.go | 93 ---- sign/dilithium/mode5aes/internal/params.go | 19 - .../mode5aes/internal/params_test.go | 100 ---- sign/dilithium/mode5aes/internal/rounding.go | 142 ------ .../mode5aes/internal/rounding_test.go | 81 --- sign/dilithium/mode5aes/internal/sample.go | 370 -------------- .../mode5aes/internal/sample_test.go | 266 ---------- sign/dilithium/mode5aes/internal/vec.go | 281 ---------- sign/dilithium/templates/mode.templ.go | 100 ---- sign/dilithium/templates/params.templ.go | 1 - .../{modePkg.templ.go => pkg.templ.go} | 241 ++++++++- sign/mldsa/mldsa44/dilithium.go | 180 ++++++- sign/mldsa/mldsa44/internal/dilithium.go | 22 +- sign/mldsa/mldsa44/internal/dilithium_test.go | 46 +- sign/mldsa/mldsa44/internal/params.go | 1 - sign/mldsa/mldsa44/internal/sample.go | 97 ++-- sign/mldsa/mldsa44/internal/sample_test.go | 132 ++--- sign/mldsa/mldsa65/dilithium.go | 180 ++++++- sign/mldsa/mldsa65/internal/dilithium.go | 22 +- sign/mldsa/mldsa65/internal/dilithium_test.go | 46 +- sign/mldsa/mldsa65/internal/params.go | 1 - sign/mldsa/mldsa65/internal/sample.go | 97 ++-- sign/mldsa/mldsa65/internal/sample_test.go | 132 ++--- sign/mldsa/mldsa87/dilithium.go | 180 ++++++- sign/mldsa/mldsa87/internal/dilithium.go | 22 +- sign/mldsa/mldsa87/internal/dilithium_test.go | 46 +- sign/mldsa/mldsa87/internal/params.go | 1 - sign/mldsa/mldsa87/internal/sample.go | 97 ++-- sign/mldsa/mldsa87/internal/sample_test.go | 132 ++--- sign/schemes/schemes.go | 14 + sign/schemes/schemes_test.go | 6 + sign/sign.go | 3 + 95 files changed, 1861 insertions(+), 9836 deletions(-) delete mode 100644 sign/dilithium/example_test.go delete mode 100644 sign/dilithium/mldsa44.go delete mode 100644 sign/dilithium/mldsa65.go delete mode 100644 sign/dilithium/mldsa87.go delete mode 100644 sign/dilithium/mode2.go delete mode 100644 sign/dilithium/mode2aes.go delete mode 100644 sign/dilithium/mode2aes/dilithium.go delete mode 100644 sign/dilithium/mode2aes/internal/dilithium.go delete mode 100644 sign/dilithium/mode2aes/internal/dilithium_test.go delete mode 100644 sign/dilithium/mode2aes/internal/mat.go delete mode 100644 sign/dilithium/mode2aes/internal/pack.go delete mode 100644 sign/dilithium/mode2aes/internal/pack_test.go delete mode 100644 sign/dilithium/mode2aes/internal/params.go delete mode 100644 sign/dilithium/mode2aes/internal/params_test.go delete mode 100644 sign/dilithium/mode2aes/internal/rounding.go delete mode 100644 sign/dilithium/mode2aes/internal/rounding_test.go delete mode 100644 sign/dilithium/mode2aes/internal/sample.go delete mode 100644 sign/dilithium/mode2aes/internal/sample_test.go delete mode 100644 sign/dilithium/mode2aes/internal/vec.go delete mode 100644 sign/dilithium/mode3.go delete mode 100644 sign/dilithium/mode3aes.go delete mode 100644 sign/dilithium/mode3aes/dilithium.go delete mode 100644 sign/dilithium/mode3aes/internal/dilithium.go delete mode 100644 sign/dilithium/mode3aes/internal/dilithium_test.go delete mode 100644 sign/dilithium/mode3aes/internal/mat.go delete mode 100644 sign/dilithium/mode3aes/internal/pack.go delete mode 100644 sign/dilithium/mode3aes/internal/pack_test.go delete mode 100644 sign/dilithium/mode3aes/internal/params.go delete mode 100644 sign/dilithium/mode3aes/internal/params_test.go delete mode 100644 sign/dilithium/mode3aes/internal/rounding.go delete mode 100644 sign/dilithium/mode3aes/internal/rounding_test.go delete mode 100644 sign/dilithium/mode3aes/internal/sample.go delete mode 100644 sign/dilithium/mode3aes/internal/sample_test.go delete mode 100644 sign/dilithium/mode3aes/internal/vec.go delete mode 100644 sign/dilithium/mode5.go delete mode 100644 sign/dilithium/mode5aes.go delete mode 100644 sign/dilithium/mode5aes/dilithium.go delete mode 100644 sign/dilithium/mode5aes/internal/dilithium.go delete mode 100644 sign/dilithium/mode5aes/internal/dilithium_test.go delete mode 100644 sign/dilithium/mode5aes/internal/mat.go delete mode 100644 sign/dilithium/mode5aes/internal/pack.go delete mode 100644 sign/dilithium/mode5aes/internal/pack_test.go delete mode 100644 sign/dilithium/mode5aes/internal/params.go delete mode 100644 sign/dilithium/mode5aes/internal/params_test.go delete mode 100644 sign/dilithium/mode5aes/internal/rounding.go delete mode 100644 sign/dilithium/mode5aes/internal/rounding_test.go delete mode 100644 sign/dilithium/mode5aes/internal/sample.go delete mode 100644 sign/dilithium/mode5aes/internal/sample_test.go delete mode 100644 sign/dilithium/mode5aes/internal/vec.go delete mode 100644 sign/dilithium/templates/mode.templ.go rename sign/dilithium/templates/{modePkg.templ.go => pkg.templ.go} (53%) diff --git a/sign/dilithium/dilithium.go b/sign/dilithium/dilithium.go index 2a4b61b28..9a4334e24 100644 --- a/sign/dilithium/dilithium.go +++ b/sign/dilithium/dilithium.go @@ -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] -} diff --git a/sign/dilithium/dilithium_test.go b/sign/dilithium/dilithium_test.go index 59ba804a6..25e11dfec 100644 --- a/sign/dilithium/dilithium_test.go +++ b/sign/dilithium/dilithium_test.go @@ -4,6 +4,8 @@ import ( "encoding/hex" "testing" + "github.com/cloudflare/circl/sign/schemes" + "github.com/cloudflare/circl/internal/sha3" ) @@ -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) } diff --git a/sign/dilithium/example_test.go b/sign/dilithium/example_test.go deleted file mode 100644 index bf687b202..000000000 --- a/sign/dilithium/example_test.go +++ /dev/null @@ -1,56 +0,0 @@ -package dilithium_test - -import ( - "fmt" - "sort" - - "github.com/cloudflare/circl/sign/dilithium" -) - -func Example() { - // Check supported modes - modes := dilithium.ModeNames() - sort.Strings(modes) - fmt.Printf("Supported modes: %v\n", modes) - - // Pick Dilithium mode III. - mode := dilithium.ModeByName("Dilithium3") - if mode == nil { - panic("Mode3 not supported") - } - - // Alternatively one could simply write - // - // mode := dilithium.Mode3 - - // Generates a keypair. - pk, sk, err := mode.GenerateKey(nil) - if err != nil { - panic(err) - } - // (Alternatively one can derive a keypair from a seed, - // see mode.NewKeyFromSeed().) - - // Packs public and private key - packedSk := sk.Bytes() - packedPk := pk.Bytes() - - // Load it again - sk2 := mode.PrivateKeyFromBytes(packedSk) - pk2 := mode.PublicKeyFromBytes(packedPk) - - // Creates a signature on our message with the generated private key. - msg := []byte("Some message") - signature := mode.Sign(sk2, msg) - - // Checks whether a signature is correct - if !mode.Verify(pk2, msg, signature) { - panic("incorrect signature") - } - - fmt.Printf("O.K.") - - // Output: - // Supported modes: [Dilithium2 Dilithium2-AES Dilithium3 Dilithium3-AES Dilithium5 Dilithium5-AES ML-DSA-44 ML-DSA-65 ML-DSA-87] - // O.K. -} diff --git a/sign/dilithium/gen.go b/sign/dilithium/gen.go index 64d134714..6b136ec07 100644 --- a/sign/dilithium/gen.go +++ b/sign/dilithium/gen.go @@ -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 { @@ -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, @@ -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, @@ -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, @@ -189,7 +145,6 @@ var ( func main() { generateModePackageFiles() - generateModeToplevelFiles() generateParamsFiles() generateSourceFiles() } @@ -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) } @@ -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) } diff --git a/sign/dilithium/kat_test.go b/sign/dilithium/kat_test.go index dae3690ac..3bb9adae1 100644 --- a/sign/dilithium/kat_test.go +++ b/sign/dilithium/kat_test.go @@ -10,6 +10,7 @@ import ( "testing" "github.com/cloudflare/circl/internal/nist" + "github.com/cloudflare/circl/sign/schemes" ) func TestPQCgenKATSign(t *testing.T) { @@ -22,19 +23,18 @@ func TestPQCgenKATSign(t *testing.T) { {"Dilithium2", "38ed991c5ca11e39ab23945ca37af89e059d16c5474bf8ba96b15cb4e948af2a"}, {"Dilithium3", "8196b32212753f525346201ffec1c7a0a852596fa0b57bd4e2746231dab44d55"}, {"Dilithium5", "7ded97a6e6c809b43b54c248171d7504fa6a0cab651bf288bb00034782667481"}, - {"Dilithium2-AES", "b6673f8da5bba7dfae63adbbdf559f4fcfb715d1f91da98d4b52e26203d69196"}, - {"Dilithium3-AES", "482f4d672a9f1dc38cc8bcf8b1731b03fe99fcb6f2b73aa4a376b99faf89ccbe"}, - {"Dilithium5-AES", "54dfa85013d1b3da4f1d7c6dd270bc91a083cfece3d320c97906da125fd2a48f"}, + // TODO Update to final FIPS 204 standard. Test vectors below are for the IPD. + // // 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"}, + // {"ML-DSA-44", "4657f244d1204e5847b3cacea4fc6116579571bee8ac89b8cba6771f303ee260"}, + // {"ML-DSA-65", "99a95d7ef804020a666f455c5003232d0c0200dfc4f5df85dceb8f56256dcba8"}, + // {"ML-DSA-87", "3377835fffb7cf9aac52947225c8974335bc05532ddf672a8b706ab8991435a2"}, } { t.Run(tc.name, func(t *testing.T) { - mode := ModeByName(tc.name) + mode := schemes.ByName(tc.name) if mode == nil { t.Fatal() } @@ -71,17 +71,26 @@ func TestPQCgenKATSign(t *testing.T) { g2 := nist.NewDRBG(&seed) g2.Fill(eseed[:]) - pk, sk := mode.NewKeyFromSeed(eseed[:]) + pk, sk := mode.DeriveKey(eseed[:]) - fmt.Fprintf(f, "pk = %X\n", pk.Bytes()) - fmt.Fprintf(f, "sk = %X\n", sk.Bytes()) + ppk, err := pk.MarshalBinary() + if err != nil { + t.Fatal(err) + } + psk, err := sk.MarshalBinary() + if err != nil { + t.Fatal(err) + } + + fmt.Fprintf(f, "pk = %X\n", ppk) + fmt.Fprintf(f, "sk = %X\n", psk) fmt.Fprintf(f, "smlen = %d\n", mlen+mode.SignatureSize()) - sig := mode.Sign(sk, msg[:]) + sig := mode.Sign(sk, msg[:], nil) fmt.Fprintf(f, "sm = %X%X\n\n", sig, msg) - if !mode.Verify(pk, msg[:], sig) { + if !mode.Verify(pk, msg[:], sig, nil) { t.Fatal() } } diff --git a/sign/dilithium/mldsa44.go b/sign/dilithium/mldsa44.go deleted file mode 100644 index 5df54821e..000000000 --- a/sign/dilithium/mldsa44.go +++ /dev/null @@ -1,91 +0,0 @@ -// Code generated from mode.templ.go. DO NOT EDIT. - -package dilithium - -import ( - "fmt" - "io" - - "github.com/cloudflare/circl/sign/mldsa/mldsa44" - - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// implMLDSA44 implements the mode.Mode interface for ML-DSA-44. -type implMLDSA44 struct{} - -// MLDSA44 is ML-DSA-44. -var MLDSA44 Mode = &implMLDSA44{} - -func (m *implMLDSA44) GenerateKey(rand io.Reader) ( - PublicKey, PrivateKey, error) { - return mldsa44.GenerateKey(rand) -} - -func (m *implMLDSA44) NewKeyFromSeed(seed []byte) (PublicKey, - PrivateKey) { - if len(seed) != common.SeedSize { - panic(fmt.Sprintf("seed must be of length %d", common.SeedSize)) - } - seedBuf := [common.SeedSize]byte{} - copy(seedBuf[:], seed) - return mldsa44.NewKeyFromSeed(&seedBuf) -} - -func (m *implMLDSA44) Sign(sk PrivateKey, msg []byte) []byte { - isk := sk.(*mldsa44.PrivateKey) - ret := [mldsa44.SignatureSize]byte{} - mldsa44.SignTo(isk, msg, ret[:]) - return ret[:] -} - -func (m *implMLDSA44) Verify(pk PublicKey, msg []byte, signature []byte) bool { - ipk := pk.(*mldsa44.PublicKey) - return mldsa44.Verify(ipk, msg, signature) -} - -func (m *implMLDSA44) PublicKeyFromBytes(data []byte) PublicKey { - var ret mldsa44.PublicKey - if len(data) != mldsa44.PublicKeySize { - panic("packed public key must be of mldsa44.PublicKeySize bytes") - } - var buf [mldsa44.PublicKeySize]byte - copy(buf[:], data) - ret.Unpack(&buf) - return &ret -} - -func (m *implMLDSA44) PrivateKeyFromBytes(data []byte) PrivateKey { - var ret mldsa44.PrivateKey - if len(data) != mldsa44.PrivateKeySize { - panic("packed private key must be of mldsa44.PrivateKeySize bytes") - } - var buf [mldsa44.PrivateKeySize]byte - copy(buf[:], data) - ret.Unpack(&buf) - return &ret -} - -func (m *implMLDSA44) SeedSize() int { - return common.SeedSize -} - -func (m *implMLDSA44) PublicKeySize() int { - return mldsa44.PublicKeySize -} - -func (m *implMLDSA44) PrivateKeySize() int { - return mldsa44.PrivateKeySize -} - -func (m *implMLDSA44) SignatureSize() int { - return mldsa44.SignatureSize -} - -func (m *implMLDSA44) Name() string { - return "ML-DSA-44" -} - -func init() { - modes["ML-DSA-44"] = MLDSA44 -} diff --git a/sign/dilithium/mldsa65.go b/sign/dilithium/mldsa65.go deleted file mode 100644 index bb035227b..000000000 --- a/sign/dilithium/mldsa65.go +++ /dev/null @@ -1,91 +0,0 @@ -// Code generated from mode.templ.go. DO NOT EDIT. - -package dilithium - -import ( - "fmt" - "io" - - "github.com/cloudflare/circl/sign/mldsa/mldsa65" - - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// implMLDSA65 implements the mode.Mode interface for ML-DSA-65. -type implMLDSA65 struct{} - -// MLDSA65 is ML-DSA-65. -var MLDSA65 Mode = &implMLDSA65{} - -func (m *implMLDSA65) GenerateKey(rand io.Reader) ( - PublicKey, PrivateKey, error) { - return mldsa65.GenerateKey(rand) -} - -func (m *implMLDSA65) NewKeyFromSeed(seed []byte) (PublicKey, - PrivateKey) { - if len(seed) != common.SeedSize { - panic(fmt.Sprintf("seed must be of length %d", common.SeedSize)) - } - seedBuf := [common.SeedSize]byte{} - copy(seedBuf[:], seed) - return mldsa65.NewKeyFromSeed(&seedBuf) -} - -func (m *implMLDSA65) Sign(sk PrivateKey, msg []byte) []byte { - isk := sk.(*mldsa65.PrivateKey) - ret := [mldsa65.SignatureSize]byte{} - mldsa65.SignTo(isk, msg, ret[:]) - return ret[:] -} - -func (m *implMLDSA65) Verify(pk PublicKey, msg []byte, signature []byte) bool { - ipk := pk.(*mldsa65.PublicKey) - return mldsa65.Verify(ipk, msg, signature) -} - -func (m *implMLDSA65) PublicKeyFromBytes(data []byte) PublicKey { - var ret mldsa65.PublicKey - if len(data) != mldsa65.PublicKeySize { - panic("packed public key must be of mldsa65.PublicKeySize bytes") - } - var buf [mldsa65.PublicKeySize]byte - copy(buf[:], data) - ret.Unpack(&buf) - return &ret -} - -func (m *implMLDSA65) PrivateKeyFromBytes(data []byte) PrivateKey { - var ret mldsa65.PrivateKey - if len(data) != mldsa65.PrivateKeySize { - panic("packed private key must be of mldsa65.PrivateKeySize bytes") - } - var buf [mldsa65.PrivateKeySize]byte - copy(buf[:], data) - ret.Unpack(&buf) - return &ret -} - -func (m *implMLDSA65) SeedSize() int { - return common.SeedSize -} - -func (m *implMLDSA65) PublicKeySize() int { - return mldsa65.PublicKeySize -} - -func (m *implMLDSA65) PrivateKeySize() int { - return mldsa65.PrivateKeySize -} - -func (m *implMLDSA65) SignatureSize() int { - return mldsa65.SignatureSize -} - -func (m *implMLDSA65) Name() string { - return "ML-DSA-65" -} - -func init() { - modes["ML-DSA-65"] = MLDSA65 -} diff --git a/sign/dilithium/mldsa87.go b/sign/dilithium/mldsa87.go deleted file mode 100644 index d3d98420a..000000000 --- a/sign/dilithium/mldsa87.go +++ /dev/null @@ -1,91 +0,0 @@ -// Code generated from mode.templ.go. DO NOT EDIT. - -package dilithium - -import ( - "fmt" - "io" - - "github.com/cloudflare/circl/sign/mldsa/mldsa87" - - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// implMLDSA87 implements the mode.Mode interface for ML-DSA-87. -type implMLDSA87 struct{} - -// MLDSA87 is ML-DSA-87. -var MLDSA87 Mode = &implMLDSA87{} - -func (m *implMLDSA87) GenerateKey(rand io.Reader) ( - PublicKey, PrivateKey, error) { - return mldsa87.GenerateKey(rand) -} - -func (m *implMLDSA87) NewKeyFromSeed(seed []byte) (PublicKey, - PrivateKey) { - if len(seed) != common.SeedSize { - panic(fmt.Sprintf("seed must be of length %d", common.SeedSize)) - } - seedBuf := [common.SeedSize]byte{} - copy(seedBuf[:], seed) - return mldsa87.NewKeyFromSeed(&seedBuf) -} - -func (m *implMLDSA87) Sign(sk PrivateKey, msg []byte) []byte { - isk := sk.(*mldsa87.PrivateKey) - ret := [mldsa87.SignatureSize]byte{} - mldsa87.SignTo(isk, msg, ret[:]) - return ret[:] -} - -func (m *implMLDSA87) Verify(pk PublicKey, msg []byte, signature []byte) bool { - ipk := pk.(*mldsa87.PublicKey) - return mldsa87.Verify(ipk, msg, signature) -} - -func (m *implMLDSA87) PublicKeyFromBytes(data []byte) PublicKey { - var ret mldsa87.PublicKey - if len(data) != mldsa87.PublicKeySize { - panic("packed public key must be of mldsa87.PublicKeySize bytes") - } - var buf [mldsa87.PublicKeySize]byte - copy(buf[:], data) - ret.Unpack(&buf) - return &ret -} - -func (m *implMLDSA87) PrivateKeyFromBytes(data []byte) PrivateKey { - var ret mldsa87.PrivateKey - if len(data) != mldsa87.PrivateKeySize { - panic("packed private key must be of mldsa87.PrivateKeySize bytes") - } - var buf [mldsa87.PrivateKeySize]byte - copy(buf[:], data) - ret.Unpack(&buf) - return &ret -} - -func (m *implMLDSA87) SeedSize() int { - return common.SeedSize -} - -func (m *implMLDSA87) PublicKeySize() int { - return mldsa87.PublicKeySize -} - -func (m *implMLDSA87) PrivateKeySize() int { - return mldsa87.PrivateKeySize -} - -func (m *implMLDSA87) SignatureSize() int { - return mldsa87.SignatureSize -} - -func (m *implMLDSA87) Name() string { - return "ML-DSA-87" -} - -func init() { - modes["ML-DSA-87"] = MLDSA87 -} diff --git a/sign/dilithium/mode2.go b/sign/dilithium/mode2.go deleted file mode 100644 index 113715025..000000000 --- a/sign/dilithium/mode2.go +++ /dev/null @@ -1,90 +0,0 @@ -// Code generated from mode.templ.go. DO NOT EDIT. - -package dilithium - -import ( - "fmt" - "io" - - "github.com/cloudflare/circl/sign/dilithium/mode2" - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// implMode2 implements the mode.Mode interface for Dilithium2. -type implMode2 struct{} - -// Mode2 is Dilithium in mode "Dilithium2". -var Mode2 Mode = &implMode2{} - -func (m *implMode2) GenerateKey(rand io.Reader) ( - PublicKey, PrivateKey, error) { - return mode2.GenerateKey(rand) -} - -func (m *implMode2) NewKeyFromSeed(seed []byte) (PublicKey, - PrivateKey) { - if len(seed) != common.SeedSize { - panic(fmt.Sprintf("seed must be of length %d", common.SeedSize)) - } - seedBuf := [common.SeedSize]byte{} - copy(seedBuf[:], seed) - return mode2.NewKeyFromSeed(&seedBuf) -} - -func (m *implMode2) Sign(sk PrivateKey, msg []byte) []byte { - isk := sk.(*mode2.PrivateKey) - ret := [mode2.SignatureSize]byte{} - mode2.SignTo(isk, msg, ret[:]) - return ret[:] -} - -func (m *implMode2) Verify(pk PublicKey, msg []byte, signature []byte) bool { - ipk := pk.(*mode2.PublicKey) - return mode2.Verify(ipk, msg, signature) -} - -func (m *implMode2) PublicKeyFromBytes(data []byte) PublicKey { - var ret mode2.PublicKey - if len(data) != mode2.PublicKeySize { - panic("packed public key must be of mode2.PublicKeySize bytes") - } - var buf [mode2.PublicKeySize]byte - copy(buf[:], data) - ret.Unpack(&buf) - return &ret -} - -func (m *implMode2) PrivateKeyFromBytes(data []byte) PrivateKey { - var ret mode2.PrivateKey - if len(data) != mode2.PrivateKeySize { - panic("packed private key must be of mode2.PrivateKeySize bytes") - } - var buf [mode2.PrivateKeySize]byte - copy(buf[:], data) - ret.Unpack(&buf) - return &ret -} - -func (m *implMode2) SeedSize() int { - return common.SeedSize -} - -func (m *implMode2) PublicKeySize() int { - return mode2.PublicKeySize -} - -func (m *implMode2) PrivateKeySize() int { - return mode2.PrivateKeySize -} - -func (m *implMode2) SignatureSize() int { - return mode2.SignatureSize -} - -func (m *implMode2) Name() string { - return "Dilithium2" -} - -func init() { - modes["Dilithium2"] = Mode2 -} diff --git a/sign/dilithium/mode2/dilithium.go b/sign/dilithium/mode2/dilithium.go index 16ce78351..113708a32 100644 --- a/sign/dilithium/mode2/dilithium.go +++ b/sign/dilithium/mode2/dilithium.go @@ -1,11 +1,9 @@ -// Code generated from modePkg.templ.go. DO NOT EDIT. - +// Code generated from pkg.templ.go. DO NOT EDIT. // mode2 implements the CRYSTALS-Dilithium signature scheme Dilithium2 // as submitted to round3 of the NIST PQC competition and described in // // https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf - package mode2 import ( @@ -13,10 +11,9 @@ import ( "errors" "io" - common "github.com/cloudflare/circl/sign/internal/dilithium" - + "github.com/cloudflare/circl/sign" "github.com/cloudflare/circl/sign/dilithium/mode2/internal" - + common "github.com/cloudflare/circl/sign/internal/dilithium" ) const ( @@ -54,20 +51,27 @@ func NewKeyFromSeed(seed *[SeedSize]byte) (*PublicKey, *PrivateKey) { // SignTo signs the given message and writes the signature into signature. // It will panic if signature is not of length at least SignatureSize. -func SignTo(sk *PrivateKey, msg []byte, signature []byte) { +func SignTo(sk *PrivateKey, msg, sig []byte) { + var rnd [32]byte + internal.SignTo( (*internal.PrivateKey)(sk), - msg, - signature, + func(w io.Writer) { + w.Write(msg) + }, + rnd, + sig, ) } // Verify checks whether the given signature by pk on msg is valid. -func Verify(pk *PublicKey, msg []byte, signature []byte) bool { +func Verify(pk *PublicKey, msg, sig []byte) bool { return internal.Verify( (*internal.PublicKey)(pk), - msg, - signature, + func(w io.Writer) { + _, _ = w.Write(msg) + }, + sig, ) } @@ -147,15 +151,15 @@ func (sk *PrivateKey) UnmarshalBinary(data []byte) error { // interface. The package-level SignTo function might be more convenient // to use. func (sk *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ( - signature []byte, err error) { - var sig [SignatureSize]byte + sig []byte, err error) { + var ret [SignatureSize]byte if opts.HashFunc() != crypto.Hash(0) { return nil, errors.New("dilithium: cannot sign hashed message") } + SignTo(sk, msg, ret[:]) - SignTo(sk, msg, sig[:]) - return sig[:], nil + return ret[:], nil } // Computes the public key corresponding to this private key. @@ -183,3 +187,109 @@ func (pk *PublicKey) Equal(other crypto.PublicKey) bool { } return (*internal.PublicKey)(pk).Equal((*internal.PublicKey)(castOther)) } + +// Boilerplate for generic signatures API + +type scheme struct{} + +var sch sign.Scheme = &scheme{} + +// Scheme returns a generic signature interface for Dilithium2. +func Scheme() sign.Scheme { return sch } + +func (*scheme) Name() string { return "Dilithium2" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SignatureSize() int { return SignatureSize } +func (*scheme) SeedSize() int { return SeedSize } + +// TODO TLSIdentifier() and OID() + +func (*scheme) SupportsContext() bool { + return false +} + +func (*scheme) GenerateKey() (sign.PublicKey, sign.PrivateKey, error) { + return GenerateKey(nil) +} + +func (*scheme) Sign( + sk sign.PrivateKey, + msg []byte, + opts *sign.SignatureOpts, +) []byte { + sig := make([]byte, SignatureSize) + + priv, ok := sk.(*PrivateKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + panic(sign.ErrContextNotSupported) + } + SignTo(priv, msg, sig) + + return sig +} + +func (*scheme) Verify( + pk sign.PublicKey, + msg, sig []byte, + opts *sign.SignatureOpts, +) bool { + pub, ok := pk.(*PublicKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + panic(sign.ErrContextNotSupported) + } + return Verify(pub, msg, sig) +} + +func (*scheme) DeriveKey(seed []byte) (sign.PublicKey, sign.PrivateKey) { + if len(seed) != SeedSize { + panic(sign.ErrSeedSize) + } + var seed2 [SeedSize]byte + copy(seed2[:], seed) + return NewKeyFromSeed(&seed2) +} + +func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (sign.PublicKey, error) { + if len(buf) != PublicKeySize { + return nil, sign.ErrPubKeySize + } + + var ( + buf2 [PublicKeySize]byte + ret PublicKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (sign.PrivateKey, error) { + if len(buf) != PrivateKeySize { + return nil, sign.ErrPrivKeySize + } + + var ( + buf2 [PrivateKeySize]byte + ret PrivateKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (sk *PrivateKey) Scheme() sign.Scheme { + return sch +} + +func (sk *PublicKey) Scheme() sign.Scheme { + return sch +} diff --git a/sign/dilithium/mode2/internal/dilithium.go b/sign/dilithium/mode2/internal/dilithium.go index 7869d0475..609ab3a4c 100644 --- a/sign/dilithium/mode2/internal/dilithium.go +++ b/sign/dilithium/mode2/internal/dilithium.go @@ -244,7 +244,10 @@ func (sk *PrivateKey) computeT0andT1(t0, t1 *VecK) { } // Verify checks whether the given signature by pk on msg is valid. -func Verify(pk *PublicKey, msg []byte, signature []byte) bool { +// +// For Dilithium this is the top-level verification function. +// In ML-DSA, this is ML-DSA.Verify_internal. +func Verify(pk *PublicKey, msg func(io.Writer), signature []byte) bool { var sig unpackedSignature var mu [64]byte var zh VecL @@ -262,7 +265,7 @@ func Verify(pk *PublicKey, msg []byte, signature []byte) bool { // μ = CRH(tr ‖ msg) h := sha3.NewShake256() _, _ = h.Write(pk.tr[:]) - _, _ = h.Write(msg) + msg(&h) _, _ = h.Read(mu[:]) // Compute Az @@ -279,7 +282,7 @@ func Verify(pk *PublicKey, msg []byte, signature []byte) bool { // which is small enough for NTT(). Az2dct1.MulBy2toD(&pk.t1) Az2dct1.NTT() - PolyDeriveUniformBall(&ch, sig.c[:32]) + PolyDeriveUniformBall(&ch, sig.c[:]) ch.NTT() for i := 0; i < K; i++ { Az2dct1[i].MulHat(&Az2dct1[i], &ch) @@ -307,8 +310,11 @@ func Verify(pk *PublicKey, msg []byte, signature []byte) bool { // SignTo signs the given message and writes the signature into signature. // +// For Dilithium this is the top-level signing function. For ML-DSA +// this is ML-DSA.Sign_internal. +// //nolint:funlen -func SignTo(sk *PrivateKey, msg []byte, signature []byte) { +func SignTo(sk *PrivateKey, msg func(io.Writer), rnd [32]byte, signature []byte) { var mu, rhop [64]byte var w1Packed [PolyW1Size * K]byte var y, yh VecL @@ -324,16 +330,14 @@ func SignTo(sk *PrivateKey, msg []byte, signature []byte) { // μ = CRH(tr ‖ msg) h := sha3.NewShake256() _, _ = h.Write(sk.tr[:]) - _, _ = h.Write(msg) + msg(&h) _, _ = h.Read(mu[:]) // ρ' = CRH(key ‖ μ) h.Reset() _, _ = h.Write(sk.key[:]) if NIST { - // We implement the deterministic variant where rnd is all zeroes. - // TODO expose randomized variant? - _, _ = h.Write(make([]byte, 32)) + _, _ = h.Write(rnd[:]) } _, _ = h.Write(mu[:]) _, _ = h.Read(rhop[:]) @@ -373,7 +377,7 @@ func SignTo(sk *PrivateKey, msg []byte, signature []byte) { _, _ = h.Write(w1Packed[:]) _, _ = h.Read(sig.c[:]) - PolyDeriveUniformBall(&ch, sig.c[:32]) + PolyDeriveUniformBall(&ch, sig.c[:]) ch.NTT() // Ensure ‖ w₀ - c·s2 ‖_∞ < γ₂ - β. diff --git a/sign/dilithium/mode2/internal/dilithium_test.go b/sign/dilithium/mode2/internal/dilithium_test.go index 825e7da08..91dd478e0 100644 --- a/sign/dilithium/mode2/internal/dilithium_test.go +++ b/sign/dilithium/mode2/internal/dilithium_test.go @@ -4,6 +4,7 @@ package internal import ( "encoding/binary" + "io" "testing" common "github.com/cloudflare/circl/sign/internal/dilithium" @@ -36,32 +37,38 @@ func BenchmarkVerify(b *testing.B) { // Note that the expansion of the matrix A is done at Unpacking/Keygen // instead of at the moment of verification (as in the reference // implementation.) - var seed [32]byte - var msg [8]byte - var sig [SignatureSize]byte + var ( + seed [32]byte + msg [8]byte + sig [SignatureSize]byte + rnd [32]byte + ) pk, sk := NewKeyFromSeed(&seed) - SignTo(sk, msg[:], sig[:]) + SignTo(sk, func(w io.Writer) { w.Write(msg[:]) }, rnd, sig[:]) b.ResetTimer() for i := 0; i < b.N; i++ { // We should generate a new signature for every verify attempt, // as this influences the time a little bit. This difference, however, // is small and generating a new signature in between creates a lot // pressure on the allocator which makes an accurate measurement hard. - Verify(pk, msg[:], sig[:]) + Verify(pk, func(w io.Writer) { w.Write(msg[:]) }, sig[:]) } } func BenchmarkSign(b *testing.B) { // Note that the expansion of the matrix A is done at Unpacking/Keygen // instead of at the moment of signing (as in the reference implementation.) - var seed [32]byte - var msg [8]byte - var sig [SignatureSize]byte + var ( + seed [32]byte + msg [8]byte + sig [SignatureSize]byte + rnd [32]byte + ) _, sk := NewKeyFromSeed(&seed) b.ResetTimer() for i := 0; i < b.N; i++ { binary.LittleEndian.PutUint64(msg[:], uint64(i)) - SignTo(sk, msg[:], sig[:]) + SignTo(sk, func(w io.Writer) { w.Write(msg[:]) }, rnd, sig[:]) } } @@ -85,13 +92,16 @@ func BenchmarkPublicFromPrivate(b *testing.B) { } func TestSignThenVerifyAndPkSkPacking(t *testing.T) { - var seed [common.SeedSize]byte - var sig [SignatureSize]byte - var msg [8]byte - var pkb [PublicKeySize]byte - var skb [PrivateKeySize]byte - var pk2 PublicKey - var sk2 PrivateKey + var ( + seed [common.SeedSize]byte + sig [SignatureSize]byte + msg [8]byte + pkb [PublicKeySize]byte + skb [PrivateKeySize]byte + pk2 PublicKey + sk2 PrivateKey + rnd [32]byte + ) for i := uint64(0); i < 100; i++ { binary.LittleEndian.PutUint64(seed[:], i) pk, sk := NewKeyFromSeed(&seed) @@ -100,8 +110,8 @@ func TestSignThenVerifyAndPkSkPacking(t *testing.T) { } for j := uint64(0); j < 10; j++ { binary.LittleEndian.PutUint64(msg[:], j) - SignTo(sk, msg[:], sig[:]) - if !Verify(pk, msg[:], sig[:]) { + SignTo(sk, func(w io.Writer) { w.Write(msg[:]) }, rnd, sig[:]) + if !Verify(pk, func(w io.Writer) { w.Write(msg[:]) }, sig[:]) { t.Fatal() } } diff --git a/sign/dilithium/mode2/internal/params.go b/sign/dilithium/mode2/internal/params.go index 74810fbad..c3341f6de 100644 --- a/sign/dilithium/mode2/internal/params.go +++ b/sign/dilithium/mode2/internal/params.go @@ -4,7 +4,6 @@ package internal const ( Name = "Dilithium2" - UseAES = false K = 4 L = 4 Eta = 2 diff --git a/sign/dilithium/mode2/internal/sample.go b/sign/dilithium/mode2/internal/sample.go index 62c261332..b37370a4e 100644 --- a/sign/dilithium/mode2/internal/sample.go +++ b/sign/dilithium/mode2/internal/sample.go @@ -12,7 +12,7 @@ import ( // DeriveX4Available indicates whether the system supports the quick fourway // sampling variants like PolyDeriveUniformX4. -var DeriveX4Available = keccakf1600.IsEnabledX4() && !UseAES +var DeriveX4Available = keccakf1600.IsEnabledX4() // For each i, sample ps[i] uniformly from the given seed and nonces[i]. // ps[i] may be nil and is ignored in that case. @@ -91,13 +91,9 @@ func PolyDeriveUniformX4(ps [4]*common.Poly, seed *[32]byte, nonces [4]uint16) { // p will be normalized. func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { var i, length int - var buf [12 * 16]byte // fits 168B SHAKE-128 rate and 12 16B AES blocks + var buf [12 * 16]byte // fits 168B SHAKE-128 rate - if UseAES { - length = 12 * 16 - } else { - length = 168 - } + length = 168 sample := func() { // Note that 3 divides into 168 and 12*16, so we use up buf completely. @@ -113,25 +109,16 @@ func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { } } - if UseAES { - h := common.NewAesStream128(seed, nonce) + var iv [32 + 2]byte // 32 byte seed + uint16 nonce + h := sha3.NewShake128() + copy(iv[:32], seed[:]) + iv[32] = uint8(nonce) + iv[33] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) - for i < common.N { - h.SqueezeInto(buf[:length]) - sample() - } - } else { - var iv [32 + 2]byte // 32 byte seed + uint16 nonce - h := sha3.NewShake128() - copy(iv[:32], seed[:]) - iv[32] = uint8(nonce) - iv[33] = uint8(nonce >> 8) - _, _ = h.Write(iv[:]) - - for i < common.N { - _, _ = h.Read(buf[:168]) - sample() - } + for i < common.N { + _, _ = h.Read(buf[:168]) + sample() } } @@ -142,13 +129,9 @@ func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { func PolyDeriveUniformLeqEta(p *common.Poly, seed *[64]byte, nonce uint16) { // Assumes 2 < η < 8. var i, length int - var buf [9 * 16]byte // fits 136B SHAKE-256 rate and 9 16B AES blocks + var buf [9 * 16]byte // fits 136B SHAKE-256 rate - if UseAES { - length = 9 * 16 - } else { - length = 136 - } + length = 136 sample := func() { // We use rejection sampling @@ -181,28 +164,19 @@ func PolyDeriveUniformLeqEta(p *common.Poly, seed *[64]byte, nonce uint16) { } } - if UseAES { - h := common.NewAesStream256(seed, nonce) - - for i < common.N { - h.SqueezeInto(buf[:length]) - sample() - } - } else { - var iv [64 + 2]byte // 64 byte seed + uint16 nonce + var iv [64 + 2]byte // 64 byte seed + uint16 nonce - h := sha3.NewShake256() - copy(iv[:64], seed[:]) - iv[64] = uint8(nonce) - iv[65] = uint8(nonce >> 8) + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) - // 136 is SHAKE-256 rate - _, _ = h.Write(iv[:]) + // 136 is SHAKE-256 rate + _, _ = h.Write(iv[:]) - for i < common.N { - _, _ = h.Read(buf[:136]) - sample() - } + for i < common.N { + _, _ = h.Read(buf[:136]) + sample() } } @@ -223,18 +197,13 @@ func VecLDeriveUniformLeGamma1(v *VecL, seed *[64]byte, nonce uint16) { func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { var buf [PolyLeGamma1Size]byte - if UseAES { - h := common.NewAesStream256(seed, nonce) - h.SqueezeInto(buf[:]) - } else { - var iv [66]byte - h := sha3.NewShake256() - copy(iv[:64], seed[:]) - iv[64] = uint8(nonce) - iv[65] = uint8(nonce >> 8) - _, _ = h.Write(iv[:]) - _, _ = h.Read(buf[:]) - } + var iv [66]byte + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) + _, _ = h.Read(buf[:]) PolyUnpackLeGamma1(p, buf[:]) } @@ -251,7 +220,7 @@ func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed []byte) { state := perm.Initialize(false) // Absorb the seed in the four states - for i := 0; i < 32/8; i++ { + for i := 0; i < CTildeSize/8; i++ { v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) for j := 0; j < 4; j++ { state[i*4+j] = v @@ -260,7 +229,7 @@ func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed []byte) { // SHAKE256 domain separator and padding for j := 0; j < 4; j++ { - state[(32/8)*4+j] ^= 0x1f + state[(CTildeSize/8)*4+j] ^= 0x1f state[16*4+j] ^= 0x80 << 56 } perm.Permute() diff --git a/sign/dilithium/mode2/internal/sample_test.go b/sign/dilithium/mode2/internal/sample_test.go index 2059599eb..32931c94f 100644 --- a/sign/dilithium/mode2/internal/sample_test.go +++ b/sign/dilithium/mode2/internal/sample_test.go @@ -12,94 +12,46 @@ import ( func TestVectorDeriveUniform(t *testing.T) { var p, p2 common.Poly var seed [32]byte - if UseAES { - p2 = common.Poly{ - 6724291, 310295, 6949524, 4464039, 1482136, 2522903, - 7025059, 3006320, 7286364, 7516512, 3361305, 1955529, - 4765954, 1725325, 6933066, 4299100, 6625173, 4272792, - 583034, 4971409, 2259140, 7715362, 3975394, 2341624, - 5481174, 8150082, 365246, 5491939, 1083120, 7517301, - 3104783, 2475292, 184149, 6425226, 4591622, 5964030, - 4729604, 5471092, 1828227, 1082044, 2516245, 1692580, - 3274844, 5443294, 7256740, 4989638, 3191250, 7479519, - 5124211, 5603858, 1230692, 2513454, 2828034, 4254312, - 1512596, 5245430, 5517392, 2814840, 932545, 6826733, - 3511094, 4075348, 3233981, 7268882, 2913733, 4870249, - 4123492, 8124406, 4016949, 5478752, 2750895, 603525, - 5724798, 3985430, 3483012, 6434230, 3136996, 8297976, - 4107616, 7307748, 6962904, 7544473, 1193110, 3448595, - 4814773, 5607932, 8221314, 1054046, 1541208, 1866050, - 8227412, 2925778, 5293953, 2065416, 4972769, 3616283, - 7990594, 1105530, 7121836, 1170740, 7417431, 633146, - 253820, 7235019, 3539504, 6807707, 451390, 5481526, - 2859902, 1063061, 4579730, 7126652, 7033767, 4294814, - 1414604, 7620048, 1953268, 8304556, 1156814, 1182881, - 5311519, 3057534, 5277666, 682843, 2070398, 2874278, - 4859533, 6376664, 6694074, 1590242, 2620706, 8331066, - 5643845, 5037538, 2891516, 7004879, 3754327, 5031296, - 5463118, 2420870, 8116529, 5517696, 7435129, 3873963, - 710407, 713806, 175647, 4274571, 2655021, 7319503, - 3027243, 7129679, 4213435, 2429323, 4643873, 4568526, - 649664, 1720514, 6497260, 2683517, 7672754, 7105190, - 3148405, 5898369, 5667677, 8050874, 1587139, 7315260, - 4337416, 2202680, 2338714, 557467, 6752058, 2469794, - 485071, 1617604, 3590498, 2151466, 2005823, 7727956, - 7776292, 6783433, 6787146, 1732833, 3596857, 7436284, - 4483349, 4970142, 4472608, 6478342, 1236215, 5695744, - 2280717, 2889355, 3233946, 5187812, 978685, 5177364, - 2922353, 4824807, 5302883, 6739803, 8092453, 5883903, - 816553, 6041174, 8317591, 1459178, 5332455, 1835058, - 1368601, 2820950, 3479224, 2589540, 7992934, 3421045, - 4657128, 8292902, 4153567, 3553988, 7830320, 6722913, - 2555309, 4149801, 8328975, 1560545, 7757473, 3106458, - 4310856, 7135453, 3481032, 652626, 1841361, 8126828, - 6250018, 300536, 7380070, 8174419, 1418793, 6208185, - 3906256, 6679016, 1605701, 3561489, 5819724, 5746996, - 8044214, 7087187, 7102330, 4962927, 4253983, 7108567, - 4119736, 6584065, 441634, 6941656, - } - } else { - p2 = common.Poly{ - 2901364, 562527, 5258502, 3885002, 4190126, 4460268, 6884052, - 3514511, 5383040, 213206, 2155865, 5179607, 3551954, 2312357, - 6066350, 8126097, 1179080, 4787182, 6552182, 6713644, - 1561067, 7626063, 7859743, 5052321, 7032876, 7815031, 157938, - 1865184, 490802, 5717642, 3451902, 7000218, 3743250, 1677431, - 1875427, 5596150, 671623, 3819041, 6247594, 1014875, 4933545, - 7122446, 6682963, 3388398, 3335295, 943002, 1145083, 3113071, - 105967, 1916675, 7474561, 1107006, 700548, 2147909, 1603855, - 5049181, 437882, 6118899, 5656914, 6731065, 3066622, 865453, - 5427634, 981549, 4650873, 861291, 4003872, 5104220, 6171453, - 3723302, 7426315, 6137283, 4874820, 6052561, 53441, 5032874, - 5614778, 2248550, 1756499, 8280764, 8263880, 7600081, - 5118374, 795344, 7543392, 6869925, 1841187, 4181568, 584562, - 7483939, 4938664, 6863397, 5126354, 5218129, 6236086, - 4149293, 379169, 4368487, 7490569, 3409215, 1580463, 3081737, - 1278732, 7109719, 7371700, 2097931, 399836, 1700274, 7188595, - 6830029, 1548850, 6593138, 6849097, 1518037, 2859442, - 7772265, 7325153, 3281191, 7856131, 4995056, 4684325, - 1351194, 8223904, 6817307, 2484146, 131782, 397032, 7436778, - 7973479, 3171829, 5624626, 3540123, 7150120, 8313283, - 3604714, 1043574, 117692, 7797783, 7909392, 903315, 7335342, - 7501562, 5826142, 2709813, 8245473, 2369045, 2782257, - 5762833, 6474114, 6862031, 424522, 594248, 2626630, 7659983, - 5642869, 4075194, 1592129, 245547, 5271031, 3205046, 982375, - 267873, 1286496, 7230481, 3208972, 7485411, 676111, 4944500, - 2959742, 5934456, 1414847, 6067948, 1709895, 4648315, 126008, - 8258986, 2183134, 2302072, 4674924, 4306056, 7465311, - 6500270, 4247428, 4016815, 4973426, 294287, 2456847, 3289700, - 2732169, 1159447, 5569724, 140001, 3237977, 8007761, 5874533, - 255652, 3119586, 2102434, 6248250, 8152822, 8006066, 7708625, - 6997719, 6260212, 6186962, 6636650, 7836834, 7998017, - 2061516, 1197591, 1706544, 733027, 2392907, 2700000, 8254598, - 4488002, 160495, 2985325, 2036837, 2703633, 6406550, 3579947, - 6195178, 5552390, 6804584, 6305468, 5731980, 6095195, - 3323409, 1322661, 6690942, 3374630, 5615167, 479044, 3136054, - 4380418, 2833144, 7829577, 1770522, 6056687, 240415, 14780, - 3740517, 5224226, 3547288, 2083124, 4699398, 3654239, - 5624978, 585593, 3655369, 2281739, 3338565, 1908093, 7784706, - 4352830, - } + p2 = common.Poly{ + 2901364, 562527, 5258502, 3885002, 4190126, 4460268, 6884052, + 3514511, 5383040, 213206, 2155865, 5179607, 3551954, 2312357, + 6066350, 8126097, 1179080, 4787182, 6552182, 6713644, + 1561067, 7626063, 7859743, 5052321, 7032876, 7815031, 157938, + 1865184, 490802, 5717642, 3451902, 7000218, 3743250, 1677431, + 1875427, 5596150, 671623, 3819041, 6247594, 1014875, 4933545, + 7122446, 6682963, 3388398, 3335295, 943002, 1145083, 3113071, + 105967, 1916675, 7474561, 1107006, 700548, 2147909, 1603855, + 5049181, 437882, 6118899, 5656914, 6731065, 3066622, 865453, + 5427634, 981549, 4650873, 861291, 4003872, 5104220, 6171453, + 3723302, 7426315, 6137283, 4874820, 6052561, 53441, 5032874, + 5614778, 2248550, 1756499, 8280764, 8263880, 7600081, + 5118374, 795344, 7543392, 6869925, 1841187, 4181568, 584562, + 7483939, 4938664, 6863397, 5126354, 5218129, 6236086, + 4149293, 379169, 4368487, 7490569, 3409215, 1580463, 3081737, + 1278732, 7109719, 7371700, 2097931, 399836, 1700274, 7188595, + 6830029, 1548850, 6593138, 6849097, 1518037, 2859442, + 7772265, 7325153, 3281191, 7856131, 4995056, 4684325, + 1351194, 8223904, 6817307, 2484146, 131782, 397032, 7436778, + 7973479, 3171829, 5624626, 3540123, 7150120, 8313283, + 3604714, 1043574, 117692, 7797783, 7909392, 903315, 7335342, + 7501562, 5826142, 2709813, 8245473, 2369045, 2782257, + 5762833, 6474114, 6862031, 424522, 594248, 2626630, 7659983, + 5642869, 4075194, 1592129, 245547, 5271031, 3205046, 982375, + 267873, 1286496, 7230481, 3208972, 7485411, 676111, 4944500, + 2959742, 5934456, 1414847, 6067948, 1709895, 4648315, 126008, + 8258986, 2183134, 2302072, 4674924, 4306056, 7465311, + 6500270, 4247428, 4016815, 4973426, 294287, 2456847, 3289700, + 2732169, 1159447, 5569724, 140001, 3237977, 8007761, 5874533, + 255652, 3119586, 2102434, 6248250, 8152822, 8006066, 7708625, + 6997719, 6260212, 6186962, 6636650, 7836834, 7998017, + 2061516, 1197591, 1706544, 733027, 2392907, 2700000, 8254598, + 4488002, 160495, 2985325, 2036837, 2703633, 6406550, 3579947, + 6195178, 5552390, 6804584, 6305468, 5731980, 6095195, + 3323409, 1322661, 6690942, 3374630, 5615167, 479044, 3136054, + 4380418, 2833144, 7829577, 1770522, 6056687, 240415, 14780, + 3740517, 5224226, 3547288, 2083124, 4699398, 3654239, + 5624978, 585593, 3655369, 2281739, 3338565, 1908093, 7784706, + 4352830, } for i := 0; i < 32; i++ { seed[i] = byte(i) @@ -152,7 +104,7 @@ func TestDeriveUniformLeGamma1(t *testing.T) { func TestDeriveUniformBall(t *testing.T) { var p common.Poly - var seed [32]byte + var seed [CTildeSize]byte for i := 0; i < 100; i++ { binary.LittleEndian.PutUint64(seed[:], uint64(i)) PolyDeriveUniformBall(&p, seed[:]) @@ -200,7 +152,7 @@ func TestDeriveUniformBallX4(t *testing.T) { } var ps [4]common.Poly var p common.Poly - var seed [32]byte + var seed [CTildeSize]byte PolyDeriveUniformBallX4( [4]*common.Poly{&ps[0], &ps[1], &ps[2], &ps[3]}, seed[:], diff --git a/sign/dilithium/mode2aes.go b/sign/dilithium/mode2aes.go deleted file mode 100644 index 6985ccf84..000000000 --- a/sign/dilithium/mode2aes.go +++ /dev/null @@ -1,90 +0,0 @@ -// Code generated from mode.templ.go. DO NOT EDIT. - -package dilithium - -import ( - "fmt" - "io" - - "github.com/cloudflare/circl/sign/dilithium/mode2aes" - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// implMode2AES implements the mode.Mode interface for Dilithium2-AES. -type implMode2AES struct{} - -// Mode2AES is Dilithium in mode "Dilithium2-AES". -var Mode2AES Mode = &implMode2AES{} - -func (m *implMode2AES) GenerateKey(rand io.Reader) ( - PublicKey, PrivateKey, error) { - return mode2aes.GenerateKey(rand) -} - -func (m *implMode2AES) NewKeyFromSeed(seed []byte) (PublicKey, - PrivateKey) { - if len(seed) != common.SeedSize { - panic(fmt.Sprintf("seed must be of length %d", common.SeedSize)) - } - seedBuf := [common.SeedSize]byte{} - copy(seedBuf[:], seed) - return mode2aes.NewKeyFromSeed(&seedBuf) -} - -func (m *implMode2AES) Sign(sk PrivateKey, msg []byte) []byte { - isk := sk.(*mode2aes.PrivateKey) - ret := [mode2aes.SignatureSize]byte{} - mode2aes.SignTo(isk, msg, ret[:]) - return ret[:] -} - -func (m *implMode2AES) Verify(pk PublicKey, msg []byte, signature []byte) bool { - ipk := pk.(*mode2aes.PublicKey) - return mode2aes.Verify(ipk, msg, signature) -} - -func (m *implMode2AES) PublicKeyFromBytes(data []byte) PublicKey { - var ret mode2aes.PublicKey - if len(data) != mode2aes.PublicKeySize { - panic("packed public key must be of mode2aes.PublicKeySize bytes") - } - var buf [mode2aes.PublicKeySize]byte - copy(buf[:], data) - ret.Unpack(&buf) - return &ret -} - -func (m *implMode2AES) PrivateKeyFromBytes(data []byte) PrivateKey { - var ret mode2aes.PrivateKey - if len(data) != mode2aes.PrivateKeySize { - panic("packed private key must be of mode2aes.PrivateKeySize bytes") - } - var buf [mode2aes.PrivateKeySize]byte - copy(buf[:], data) - ret.Unpack(&buf) - return &ret -} - -func (m *implMode2AES) SeedSize() int { - return common.SeedSize -} - -func (m *implMode2AES) PublicKeySize() int { - return mode2aes.PublicKeySize -} - -func (m *implMode2AES) PrivateKeySize() int { - return mode2aes.PrivateKeySize -} - -func (m *implMode2AES) SignatureSize() int { - return mode2aes.SignatureSize -} - -func (m *implMode2AES) Name() string { - return "Dilithium2-AES" -} - -func init() { - modes["Dilithium2-AES"] = Mode2AES -} diff --git a/sign/dilithium/mode2aes/dilithium.go b/sign/dilithium/mode2aes/dilithium.go deleted file mode 100644 index 93e5058d5..000000000 --- a/sign/dilithium/mode2aes/dilithium.go +++ /dev/null @@ -1,185 +0,0 @@ -// Code generated from modePkg.templ.go. DO NOT EDIT. - - -// mode2aes implements the CRYSTALS-Dilithium signature scheme Dilithium2-AES -// as submitted to round3 of the NIST PQC competition and described in -// -// https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf - -package mode2aes - -import ( - "crypto" - "errors" - "io" - - common "github.com/cloudflare/circl/sign/internal/dilithium" - - "github.com/cloudflare/circl/sign/dilithium/mode2aes/internal" - -) - -const ( - // Size of seed for NewKeyFromSeed - SeedSize = common.SeedSize - - // Size of a packed PublicKey - PublicKeySize = internal.PublicKeySize - - // Size of a packed PrivateKey - PrivateKeySize = internal.PrivateKeySize - - // Size of a signature - SignatureSize = internal.SignatureSize -) - -// PublicKey is the type of Dilithium2-AES public key -type PublicKey internal.PublicKey - -// PrivateKey is the type of Dilithium2-AES private key -type PrivateKey internal.PrivateKey - -// GenerateKey generates a public/private key pair using entropy from rand. -// If rand is nil, crypto/rand.Reader will be used. -func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { - pk, sk, err := internal.GenerateKey(rand) - return (*PublicKey)(pk), (*PrivateKey)(sk), err -} - -// NewKeyFromSeed derives a public/private key pair using the given seed. -func NewKeyFromSeed(seed *[SeedSize]byte) (*PublicKey, *PrivateKey) { - pk, sk := internal.NewKeyFromSeed(seed) - return (*PublicKey)(pk), (*PrivateKey)(sk) -} - -// SignTo signs the given message and writes the signature into signature. -// It will panic if signature is not of length at least SignatureSize. -func SignTo(sk *PrivateKey, msg []byte, signature []byte) { - internal.SignTo( - (*internal.PrivateKey)(sk), - msg, - signature, - ) -} - -// Verify checks whether the given signature by pk on msg is valid. -func Verify(pk *PublicKey, msg []byte, signature []byte) bool { - return internal.Verify( - (*internal.PublicKey)(pk), - msg, - signature, - ) -} - -// Sets pk to the public key encoded in buf. -func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { - (*internal.PublicKey)(pk).Unpack(buf) -} - -// Sets sk to the private key encoded in buf. -func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { - (*internal.PrivateKey)(sk).Unpack(buf) -} - -// Packs the public key into buf. -func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) { - (*internal.PublicKey)(pk).Pack(buf) -} - -// Packs the private key into buf. -func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { - (*internal.PrivateKey)(sk).Pack(buf) -} - -// Packs the public key. -func (pk *PublicKey) Bytes() []byte { - var buf [PublicKeySize]byte - pk.Pack(&buf) - return buf[:] -} - -// Packs the private key. -func (sk *PrivateKey) Bytes() []byte { - var buf [PrivateKeySize]byte - sk.Pack(&buf) - return buf[:] -} - -// Packs the public key. -func (pk *PublicKey) MarshalBinary() ([]byte, error) { - return pk.Bytes(), nil -} - -// Packs the private key. -func (sk *PrivateKey) MarshalBinary() ([]byte, error) { - return sk.Bytes(), nil -} - -// Unpacks the public key from data. -func (pk *PublicKey) UnmarshalBinary(data []byte) error { - if len(data) != PublicKeySize { - return errors.New("packed public key must be of mode2aes.PublicKeySize bytes") - } - var buf [PublicKeySize]byte - copy(buf[:], data) - pk.Unpack(&buf) - return nil -} - -// Unpacks the private key from data. -func (sk *PrivateKey) UnmarshalBinary(data []byte) error { - if len(data) != PrivateKeySize { - return errors.New("packed private key must be of mode2aes.PrivateKeySize bytes") - } - var buf [PrivateKeySize]byte - copy(buf[:], data) - sk.Unpack(&buf) - return nil -} - -// Sign signs the given message. -// -// opts.HashFunc() must return zero, which can be achieved by passing -// crypto.Hash(0) for opts. rand is ignored. Will only return an error -// if opts.HashFunc() is non-zero. -// -// This function is used to make PrivateKey implement the crypto.Signer -// interface. The package-level SignTo function might be more convenient -// to use. -func (sk *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ( - signature []byte, err error) { - var sig [SignatureSize]byte - - if opts.HashFunc() != crypto.Hash(0) { - return nil, errors.New("dilithium: cannot sign hashed message") - } - - SignTo(sk, msg, sig[:]) - return sig[:], nil -} - -// Computes the public key corresponding to this private key. -// -// Returns a *PublicKey. The type crypto.PublicKey is used to make -// PrivateKey implement the crypto.Signer interface. -func (sk *PrivateKey) Public() crypto.PublicKey { - return (*PublicKey)((*internal.PrivateKey)(sk).Public()) -} - -// Equal returns whether the two private keys equal. -func (sk *PrivateKey) Equal(other crypto.PrivateKey) bool { - castOther, ok := other.(*PrivateKey) - if !ok { - return false - } - return (*internal.PrivateKey)(sk).Equal((*internal.PrivateKey)(castOther)) -} - -// Equal returns whether the two public keys equal. -func (pk *PublicKey) Equal(other crypto.PublicKey) bool { - castOther, ok := other.(*PublicKey) - if !ok { - return false - } - return (*internal.PublicKey)(pk).Equal((*internal.PublicKey)(castOther)) -} diff --git a/sign/dilithium/mode2aes/internal/dilithium.go b/sign/dilithium/mode2aes/internal/dilithium.go deleted file mode 100644 index 7869d0475..000000000 --- a/sign/dilithium/mode2aes/internal/dilithium.go +++ /dev/null @@ -1,482 +0,0 @@ -// Code generated from mode3/internal/dilithium.go by gen.go - -package internal - -import ( - cryptoRand "crypto/rand" - "crypto/subtle" - "io" - - "github.com/cloudflare/circl/internal/sha3" - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -const ( - // Size of a packed polynomial of norm ≤η. - // (Note that the formula is not valid in general.) - PolyLeqEtaSize = (common.N * DoubleEtaBits) / 8 - - // β = τη, the maximum size of c s₂. - Beta = Tau * Eta - - // γ₁ range of y - Gamma1 = 1 << Gamma1Bits - - // Size of packed polynomial of norm <γ₁ such as z - PolyLeGamma1Size = (Gamma1Bits + 1) * common.N / 8 - - // α = 2γ₂ parameter for decompose - Alpha = 2 * Gamma2 - - // Size of a packed private key - PrivateKeySize = 32 + 32 + TRSize + PolyLeqEtaSize*(L+K) + common.PolyT0Size*K - - // Size of a packed public key - PublicKeySize = 32 + common.PolyT1Size*K - - // Size of a packed signature - SignatureSize = L*PolyLeGamma1Size + Omega + K + CTildeSize - - // Size of packed w₁ - PolyW1Size = (common.N * (common.QBits - Gamma1Bits)) / 8 -) - -// PublicKey is the type of Dilithium public keys. -type PublicKey struct { - rho [32]byte - t1 VecK - - // Cached values - t1p [common.PolyT1Size * K]byte - A *Mat - tr *[TRSize]byte -} - -// PrivateKey is the type of Dilithium private keys. -type PrivateKey struct { - rho [32]byte - key [32]byte - s1 VecL - s2 VecK - t0 VecK - tr [TRSize]byte - - // Cached values - A Mat // ExpandA(ρ) - s1h VecL // NTT(s₁) - s2h VecK // NTT(s₂) - t0h VecK // NTT(t₀) -} - -type unpackedSignature struct { - z VecL - hint VecK - c [CTildeSize]byte -} - -// Packs the signature into buf. -func (sig *unpackedSignature) Pack(buf []byte) { - copy(buf[:], sig.c[:]) - sig.z.PackLeGamma1(buf[CTildeSize:]) - sig.hint.PackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) -} - -// Sets sig to the signature encoded in the buffer. -// -// Returns whether buf contains a properly packed signature. -func (sig *unpackedSignature) Unpack(buf []byte) bool { - if len(buf) < SignatureSize { - return false - } - copy(sig.c[:], buf[:]) - sig.z.UnpackLeGamma1(buf[CTildeSize:]) - if sig.z.Exceeds(Gamma1 - Beta) { - return false - } - if !sig.hint.UnpackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) { - return false - } - return true -} - -// Packs the public key into buf. -func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) { - copy(buf[:32], pk.rho[:]) - copy(buf[32:], pk.t1p[:]) -} - -// Sets pk to the public key encoded in buf. -func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { - copy(pk.rho[:], buf[:32]) - copy(pk.t1p[:], buf[32:]) - - pk.t1.UnpackT1(pk.t1p[:]) - pk.A = new(Mat) - pk.A.Derive(&pk.rho) - - // tr = CRH(ρ ‖ t1) = CRH(pk) - pk.tr = new([TRSize]byte) - h := sha3.NewShake256() - _, _ = h.Write(buf[:]) - _, _ = h.Read(pk.tr[:]) -} - -// Packs the private key into buf. -func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { - copy(buf[:32], sk.rho[:]) - copy(buf[32:64], sk.key[:]) - copy(buf[64:64+TRSize], sk.tr[:]) - offset := 64 + TRSize - sk.s1.PackLeqEta(buf[offset:]) - offset += PolyLeqEtaSize * L - sk.s2.PackLeqEta(buf[offset:]) - offset += PolyLeqEtaSize * K - sk.t0.PackT0(buf[offset:]) -} - -// Sets sk to the private key encoded in buf. -func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { - copy(sk.rho[:], buf[:32]) - copy(sk.key[:], buf[32:64]) - copy(sk.tr[:], buf[64:64+TRSize]) - offset := 64 + TRSize - sk.s1.UnpackLeqEta(buf[offset:]) - offset += PolyLeqEtaSize * L - sk.s2.UnpackLeqEta(buf[offset:]) - offset += PolyLeqEtaSize * K - sk.t0.UnpackT0(buf[offset:]) - - // Cached values - sk.A.Derive(&sk.rho) - sk.t0h = sk.t0 - sk.t0h.NTT() - sk.s1h = sk.s1 - sk.s1h.NTT() - sk.s2h = sk.s2 - sk.s2h.NTT() -} - -// GenerateKey generates a public/private key pair using entropy from rand. -// If rand is nil, crypto/rand.Reader will be used. -func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { - var seed [32]byte - if rand == nil { - rand = cryptoRand.Reader - } - _, err := io.ReadFull(rand, seed[:]) - if err != nil { - return nil, nil, err - } - pk, sk := NewKeyFromSeed(&seed) - return pk, sk, nil -} - -// NewKeyFromSeed derives a public/private key pair using the given seed. -func NewKeyFromSeed(seed *[common.SeedSize]byte) (*PublicKey, *PrivateKey) { - var eSeed [128]byte // expanded seed - var pk PublicKey - var sk PrivateKey - var sSeed [64]byte - - h := sha3.NewShake256() - _, _ = h.Write(seed[:]) - _, _ = h.Read(eSeed[:]) - - copy(pk.rho[:], eSeed[:32]) - copy(sSeed[:], eSeed[32:96]) - copy(sk.key[:], eSeed[96:]) - copy(sk.rho[:], pk.rho[:]) - - sk.A.Derive(&pk.rho) - - for i := uint16(0); i < L; i++ { - PolyDeriveUniformLeqEta(&sk.s1[i], &sSeed, i) - } - - for i := uint16(0); i < K; i++ { - PolyDeriveUniformLeqEta(&sk.s2[i], &sSeed, i+L) - } - - sk.s1h = sk.s1 - sk.s1h.NTT() - sk.s2h = sk.s2 - sk.s2h.NTT() - - sk.computeT0andT1(&sk.t0, &pk.t1) - - sk.t0h = sk.t0 - sk.t0h.NTT() - - // Complete public key far enough to be packed - pk.t1.PackT1(pk.t1p[:]) - pk.A = &sk.A - - // Finish private key - var packedPk [PublicKeySize]byte - pk.Pack(&packedPk) - - // tr = CRH(ρ ‖ t1) = CRH(pk) - h.Reset() - _, _ = h.Write(packedPk[:]) - _, _ = h.Read(sk.tr[:]) - - // Finish cache of public key - pk.tr = &sk.tr - - return &pk, &sk -} - -// Computes t0 and t1 from sk.s1h, sk.s2 and sk.A. -func (sk *PrivateKey) computeT0andT1(t0, t1 *VecK) { - var t VecK - - // Set t to A s₁ + s₂ - for i := 0; i < K; i++ { - PolyDotHat(&t[i], &sk.A[i], &sk.s1h) - t[i].ReduceLe2Q() - t[i].InvNTT() - } - t.Add(&t, &sk.s2) - t.Normalize() - - // Compute t₀, t₁ = Power2Round(t) - t.Power2Round(t0, t1) -} - -// Verify checks whether the given signature by pk on msg is valid. -func Verify(pk *PublicKey, msg []byte, signature []byte) bool { - var sig unpackedSignature - var mu [64]byte - var zh VecL - var Az, Az2dct1, w1 VecK - var ch common.Poly - var cp [CTildeSize]byte - var w1Packed [PolyW1Size * K]byte - - // Note that Unpack() checked whether ‖z‖_∞ < γ₁ - β - // and ensured that there at most ω ones in pk.hint. - if !sig.Unpack(signature) { - return false - } - - // μ = CRH(tr ‖ msg) - h := sha3.NewShake256() - _, _ = h.Write(pk.tr[:]) - _, _ = h.Write(msg) - _, _ = h.Read(mu[:]) - - // Compute Az - zh = sig.z - zh.NTT() - - for i := 0; i < K; i++ { - PolyDotHat(&Az[i], &pk.A[i], &zh) - } - - // Next, we compute Az - 2ᵈ·c·t₁. - // Note that the coefficients of t₁ are bounded by 256 = 2⁹, - // so the coefficients of Az2dct1 will bounded by 2⁹⁺ᵈ = 2²³ < 2q, - // which is small enough for NTT(). - Az2dct1.MulBy2toD(&pk.t1) - Az2dct1.NTT() - PolyDeriveUniformBall(&ch, sig.c[:32]) - ch.NTT() - for i := 0; i < K; i++ { - Az2dct1[i].MulHat(&Az2dct1[i], &ch) - } - Az2dct1.Sub(&Az, &Az2dct1) - Az2dct1.ReduceLe2Q() - Az2dct1.InvNTT() - Az2dct1.NormalizeAssumingLe2Q() - - // UseHint(pk.hint, Az - 2ᵈ·c·t₁) - // = UseHint(pk.hint, w - c·s₂ + c·t₀) - // = UseHint(pk.hint, r + c·t₀) - // = r₁ = w₁. - w1.UseHint(&Az2dct1, &sig.hint) - w1.PackW1(w1Packed[:]) - - // c' = H(μ, w₁) - h.Reset() - _, _ = h.Write(mu[:]) - _, _ = h.Write(w1Packed[:]) - _, _ = h.Read(cp[:]) - - return sig.c == cp -} - -// SignTo signs the given message and writes the signature into signature. -// -//nolint:funlen -func SignTo(sk *PrivateKey, msg []byte, signature []byte) { - var mu, rhop [64]byte - var w1Packed [PolyW1Size * K]byte - var y, yh VecL - var w, w0, w1, w0mcs2, ct0, w0mcs2pct0 VecK - var ch common.Poly - var yNonce uint16 - var sig unpackedSignature - - if len(signature) < SignatureSize { - panic("Signature does not fit in that byteslice") - } - - // μ = CRH(tr ‖ msg) - h := sha3.NewShake256() - _, _ = h.Write(sk.tr[:]) - _, _ = h.Write(msg) - _, _ = h.Read(mu[:]) - - // ρ' = CRH(key ‖ μ) - h.Reset() - _, _ = h.Write(sk.key[:]) - if NIST { - // We implement the deterministic variant where rnd is all zeroes. - // TODO expose randomized variant? - _, _ = h.Write(make([]byte, 32)) - } - _, _ = h.Write(mu[:]) - _, _ = h.Read(rhop[:]) - - // Main rejection loop - attempt := 0 - for { - attempt++ - if attempt >= 576 { - // Depending on the mode, one try has a chance between 1/7 and 1/4 - // of succeeding. Thus it is safe to say that 576 iterations - // are enough as (6/7)⁵⁷⁶ < 2⁻¹²⁸. - panic("This should only happen 1 in 2^{128}: something is wrong.") - } - - // y = ExpandMask(ρ', key) - VecLDeriveUniformLeGamma1(&y, &rhop, yNonce) - yNonce += uint16(L) - - // Set w to A y - yh = y - yh.NTT() - for i := 0; i < K; i++ { - PolyDotHat(&w[i], &sk.A[i], &yh) - w[i].ReduceLe2Q() - w[i].InvNTT() - } - - // Decompose w into w₀ and w₁ - w.NormalizeAssumingLe2Q() - w.Decompose(&w0, &w1) - - // c~ = H(μ ‖ w₁) - w1.PackW1(w1Packed[:]) - h.Reset() - _, _ = h.Write(mu[:]) - _, _ = h.Write(w1Packed[:]) - _, _ = h.Read(sig.c[:]) - - PolyDeriveUniformBall(&ch, sig.c[:32]) - ch.NTT() - - // Ensure ‖ w₀ - c·s2 ‖_∞ < γ₂ - β. - // - // By Lemma 3 of the specification this is equivalent to checking that - // both ‖ r₀ ‖_∞ < γ₂ - β and r₁ = w₁, for the decomposition - // w - c·s₂ = r₁ α + r₀ as computed by decompose(). - // See also §4.1 of the specification. - for i := 0; i < K; i++ { - w0mcs2[i].MulHat(&ch, &sk.s2h[i]) - w0mcs2[i].InvNTT() - } - w0mcs2.Sub(&w0, &w0mcs2) - w0mcs2.Normalize() - - if w0mcs2.Exceeds(Gamma2 - Beta) { - continue - } - - // z = y + c·s₁ - for i := 0; i < L; i++ { - sig.z[i].MulHat(&ch, &sk.s1h[i]) - sig.z[i].InvNTT() - } - sig.z.Add(&sig.z, &y) - sig.z.Normalize() - - // Ensure ‖z‖_∞ < γ₁ - β - if sig.z.Exceeds(Gamma1 - Beta) { - continue - } - - // Compute c·t₀ - for i := 0; i < K; i++ { - ct0[i].MulHat(&ch, &sk.t0h[i]) - ct0[i].InvNTT() - } - ct0.NormalizeAssumingLe2Q() - - // Ensure ‖c·t₀‖_∞ < γ₂. - if ct0.Exceeds(Gamma2) { - continue - } - - // Create the hint to be able to reconstruct w₁ from w - c·s₂ + c·t0. - // Note that we're not using makeHint() in the obvious way as we - // do not know whether ‖ sc·s₂ - c·t₀ ‖_∞ < γ₂. Instead we note - // that our makeHint() is actually the same as a makeHint for a - // different decomposition: - // - // Earlier we ensured indirectly with a check that r₁ = w₁ where - // r = w - c·s₂. Hence r₀ = r - r₁ α = w - c·s₂ - w₁ α = w₀ - c·s₂. - // Thus MakeHint(w₀ - c·s₂ + c·t₀, w₁) = MakeHint(r0 + c·t₀, r₁) - // and UseHint(w - c·s₂ + c·t₀, w₁) = UseHint(r + c·t₀, r₁). - // As we just ensured that ‖ c·t₀ ‖_∞ < γ₂ our usage is correct. - w0mcs2pct0.Add(&w0mcs2, &ct0) - w0mcs2pct0.NormalizeAssumingLe2Q() - hintPop := sig.hint.MakeHint(&w0mcs2pct0, &w1) - if hintPop > Omega { - continue - } - - break - } - - sig.Pack(signature[:]) -} - -// Computes the public key corresponding to this private key. -func (sk *PrivateKey) Public() *PublicKey { - var t0 VecK - pk := &PublicKey{ - rho: sk.rho, - A: &sk.A, - tr: &sk.tr, - } - sk.computeT0andT1(&t0, &pk.t1) - pk.t1.PackT1(pk.t1p[:]) - return pk -} - -// Equal returns whether the two public keys are equal -func (pk *PublicKey) Equal(other *PublicKey) bool { - return pk.rho == other.rho && pk.t1 == other.t1 -} - -// Equal returns whether the two private keys are equal -func (sk *PrivateKey) Equal(other *PrivateKey) bool { - ret := (subtle.ConstantTimeCompare(sk.rho[:], other.rho[:]) & - subtle.ConstantTimeCompare(sk.key[:], other.key[:]) & - subtle.ConstantTimeCompare(sk.tr[:], other.tr[:])) - - acc := uint32(0) - for i := 0; i < L; i++ { - for j := 0; j < common.N; j++ { - acc |= sk.s1[i][j] ^ other.s1[i][j] - } - } - for i := 0; i < K; i++ { - for j := 0; j < common.N; j++ { - acc |= sk.s2[i][j] ^ other.s2[i][j] - acc |= sk.t0[i][j] ^ other.t0[i][j] - } - } - return (ret & subtle.ConstantTimeEq(int32(acc), 0)) == 1 -} diff --git a/sign/dilithium/mode2aes/internal/dilithium_test.go b/sign/dilithium/mode2aes/internal/dilithium_test.go deleted file mode 100644 index 825e7da08..000000000 --- a/sign/dilithium/mode2aes/internal/dilithium_test.go +++ /dev/null @@ -1,144 +0,0 @@ -// Code generated from mode3/internal/dilithium_test.go by gen.go - -package internal - -import ( - "encoding/binary" - "testing" - - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// Checks whether p is normalized. Only used in tests. -func PolyNormalized(p *common.Poly) bool { - p2 := *p - p2.Normalize() - return p2 == *p -} - -func BenchmarkSkUnpack(b *testing.B) { - var buf [PrivateKeySize]byte - var sk PrivateKey - for i := 0; i < b.N; i++ { - sk.Unpack(&buf) - } -} - -func BenchmarkPkUnpack(b *testing.B) { - var buf [PublicKeySize]byte - var pk PublicKey - for i := 0; i < b.N; i++ { - pk.Unpack(&buf) - } -} - -func BenchmarkVerify(b *testing.B) { - // Note that the expansion of the matrix A is done at Unpacking/Keygen - // instead of at the moment of verification (as in the reference - // implementation.) - var seed [32]byte - var msg [8]byte - var sig [SignatureSize]byte - pk, sk := NewKeyFromSeed(&seed) - SignTo(sk, msg[:], sig[:]) - b.ResetTimer() - for i := 0; i < b.N; i++ { - // We should generate a new signature for every verify attempt, - // as this influences the time a little bit. This difference, however, - // is small and generating a new signature in between creates a lot - // pressure on the allocator which makes an accurate measurement hard. - Verify(pk, msg[:], sig[:]) - } -} - -func BenchmarkSign(b *testing.B) { - // Note that the expansion of the matrix A is done at Unpacking/Keygen - // instead of at the moment of signing (as in the reference implementation.) - var seed [32]byte - var msg [8]byte - var sig [SignatureSize]byte - _, sk := NewKeyFromSeed(&seed) - b.ResetTimer() - for i := 0; i < b.N; i++ { - binary.LittleEndian.PutUint64(msg[:], uint64(i)) - SignTo(sk, msg[:], sig[:]) - } -} - -func BenchmarkGenerateKey(b *testing.B) { - var seed [32]byte - for i := 0; i < b.N; i++ { - binary.LittleEndian.PutUint64(seed[:], uint64(i)) - NewKeyFromSeed(&seed) - } -} - -func BenchmarkPublicFromPrivate(b *testing.B) { - var seed [32]byte - for i := 0; i < b.N; i++ { - b.StopTimer() - binary.LittleEndian.PutUint64(seed[:], uint64(i)) - _, sk := NewKeyFromSeed(&seed) - b.StartTimer() - sk.Public() - } -} - -func TestSignThenVerifyAndPkSkPacking(t *testing.T) { - var seed [common.SeedSize]byte - var sig [SignatureSize]byte - var msg [8]byte - var pkb [PublicKeySize]byte - var skb [PrivateKeySize]byte - var pk2 PublicKey - var sk2 PrivateKey - for i := uint64(0); i < 100; i++ { - binary.LittleEndian.PutUint64(seed[:], i) - pk, sk := NewKeyFromSeed(&seed) - if !sk.Equal(sk) { - t.Fatal() - } - for j := uint64(0); j < 10; j++ { - binary.LittleEndian.PutUint64(msg[:], j) - SignTo(sk, msg[:], sig[:]) - if !Verify(pk, msg[:], sig[:]) { - t.Fatal() - } - } - pk.Pack(&pkb) - pk2.Unpack(&pkb) - if !pk.Equal(&pk2) { - t.Fatal() - } - sk.Pack(&skb) - sk2.Unpack(&skb) - if !sk.Equal(&sk2) { - t.Fatal() - } - } -} - -func TestPublicFromPrivate(t *testing.T) { - var seed [common.SeedSize]byte - for i := uint64(0); i < 100; i++ { - binary.LittleEndian.PutUint64(seed[:], i) - pk, sk := NewKeyFromSeed(&seed) - pk2 := sk.Public() - if !pk.Equal(pk2) { - t.Fatal() - } - } -} - -func TestGamma1Size(t *testing.T) { - var expected int - switch Gamma1Bits { - case 17: - expected = 576 - case 19: - expected = 640 - } - if expected != PolyLeGamma1Size { - t.Fatal() - } -} diff --git a/sign/dilithium/mode2aes/internal/mat.go b/sign/dilithium/mode2aes/internal/mat.go deleted file mode 100644 index ceaf634fa..000000000 --- a/sign/dilithium/mode2aes/internal/mat.go +++ /dev/null @@ -1,59 +0,0 @@ -// Code generated from mode3/internal/mat.go by gen.go - -package internal - -import ( - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// A k by l matrix of polynomials. -type Mat [K]VecL - -// Expands the given seed to a complete matrix. -// -// This function is called ExpandA in the specification. -func (m *Mat) Derive(seed *[32]byte) { - if !DeriveX4Available { - for i := uint16(0); i < K; i++ { - for j := uint16(0); j < L; j++ { - PolyDeriveUniform(&m[i][j], seed, (i<<8)+j) - } - } - return - } - - idx := 0 - var nonces [4]uint16 - var ps [4]*common.Poly - for i := uint16(0); i < K; i++ { - for j := uint16(0); j < L; j++ { - nonces[idx] = (i << 8) + j - ps[idx] = &m[i][j] - idx++ - if idx == 4 { - idx = 0 - PolyDeriveUniformX4(ps, seed, nonces) - } - } - } - if idx != 0 { - for i := idx; i < 4; i++ { - ps[i] = nil - } - PolyDeriveUniformX4(ps, seed, nonces) - } -} - -// Set p to the inner product of a and b using pointwise multiplication. -// -// Assumes a and b are in Montgomery form and their coefficients are -// pairwise sufficiently small to multiply, see Poly.MulHat(). Resulting -// coefficients are bounded by 2Lq. -func PolyDotHat(p *common.Poly, a, b *VecL) { - var t common.Poly - *p = common.Poly{} // zero p - for i := 0; i < L; i++ { - t.MulHat(&a[i], &b[i]) - p.Add(&t, p) - } -} diff --git a/sign/dilithium/mode2aes/internal/pack.go b/sign/dilithium/mode2aes/internal/pack.go deleted file mode 100644 index 1854b4197..000000000 --- a/sign/dilithium/mode2aes/internal/pack.go +++ /dev/null @@ -1,270 +0,0 @@ -// Code generated from mode3/internal/pack.go by gen.go - -package internal - -import ( - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// Writes p with norm less than or equal η into buf, which must be of -// size PolyLeqEtaSize. -// -// Assumes coefficients of p are not normalized, but in [q-η,q+η]. -func PolyPackLeqEta(p *common.Poly, buf []byte) { - if DoubleEtaBits == 4 { // compiler eliminates branch - j := 0 - for i := 0; i < PolyLeqEtaSize; i++ { - buf[i] = (byte(common.Q+Eta-p[j]) | - byte(common.Q+Eta-p[j+1])<<4) - j += 2 - } - } else if DoubleEtaBits == 3 { - j := 0 - for i := 0; i < PolyLeqEtaSize; i += 3 { - buf[i] = (byte(common.Q+Eta-p[j]) | - (byte(common.Q+Eta-p[j+1]) << 3) | - (byte(common.Q+Eta-p[j+2]) << 6)) - buf[i+1] = ((byte(common.Q+Eta-p[j+2]) >> 2) | - (byte(common.Q+Eta-p[j+3]) << 1) | - (byte(common.Q+Eta-p[j+4]) << 4) | - (byte(common.Q+Eta-p[j+5]) << 7)) - buf[i+2] = ((byte(common.Q+Eta-p[j+5]) >> 1) | - (byte(common.Q+Eta-p[j+6]) << 2) | - (byte(common.Q+Eta-p[j+7]) << 5)) - j += 8 - } - } else { - panic("eta not supported") - } -} - -// Sets p to the polynomial of norm less than or equal η encoded in the -// given buffer of size PolyLeqEtaSize. -// -// Output coefficients of p are not normalized, but in [q-η,q+η] provided -// buf was created using PackLeqEta. -// -// Beware, for arbitrary buf the coefficients of p might end up in -// the interval [q-2^b,q+2^b] where b is the least b with η≤2^b. -func PolyUnpackLeqEta(p *common.Poly, buf []byte) { - if DoubleEtaBits == 4 { // compiler eliminates branch - j := 0 - for i := 0; i < PolyLeqEtaSize; i++ { - p[j] = common.Q + Eta - uint32(buf[i]&15) - p[j+1] = common.Q + Eta - uint32(buf[i]>>4) - j += 2 - } - } else if DoubleEtaBits == 3 { - j := 0 - for i := 0; i < PolyLeqEtaSize; i += 3 { - p[j] = common.Q + Eta - uint32(buf[i]&7) - p[j+1] = common.Q + Eta - uint32((buf[i]>>3)&7) - p[j+2] = common.Q + Eta - uint32((buf[i]>>6)|((buf[i+1]<<2)&7)) - p[j+3] = common.Q + Eta - uint32((buf[i+1]>>1)&7) - p[j+4] = common.Q + Eta - uint32((buf[i+1]>>4)&7) - p[j+5] = common.Q + Eta - uint32((buf[i+1]>>7)|((buf[i+2]<<1)&7)) - p[j+6] = common.Q + Eta - uint32((buf[i+2]>>2)&7) - p[j+7] = common.Q + Eta - uint32((buf[i+2]>>5)&7) - j += 8 - } - } else { - panic("eta not supported") - } -} - -// Writes v with coefficients in {0, 1} of which at most ω non-zero -// to buf, which must have length ω+k. -func (v *VecK) PackHint(buf []byte) { - // The packed hint starts with the indices of the non-zero coefficients - // For instance: - // - // (x⁵⁶ + x¹⁰⁰, x²⁵⁵, 0, x² + x²³, x¹) - // - // Yields - // - // 56, 100, 255, 2, 23, 1 - // - // Then we pad with zeroes until we have a list of ω items: - // // 56, 100, 255, 2, 23, 1, 0, 0, ..., 0 - // - // Then we finish with a list of the switch-over-indices in this - // list between polynomials, so: - // - // 56, 100, 255, 2, 23, 1, 0, 0, ..., 0, 2, 3, 3, 5, 6 - - off := uint8(0) - for i := 0; i < K; i++ { - for j := uint16(0); j < common.N; j++ { - if v[i][j] != 0 { - buf[off] = uint8(j) - off++ - } - } - buf[Omega+i] = off - } - for ; off < Omega; off++ { - buf[off] = 0 - } -} - -// Sets v to the vector encoded using VecK.PackHint() -// -// Returns whether unpacking was successful. -func (v *VecK) UnpackHint(buf []byte) bool { - // A priori, there would be several reasonable ways to encode the same - // hint vector. We take care to only allow only one encoding, to ensure - // "strong unforgeability". - // - // See PackHint() source for description of the encoding. - *v = VecK{} // zero v - prevSOP := uint8(0) // previous switch-over-point - for i := 0; i < K; i++ { - SOP := buf[Omega+i] - if SOP < prevSOP || SOP > Omega { - return false // ensures switch-over-points are increasing - } - for j := prevSOP; j < SOP; j++ { - if j > prevSOP && buf[j] <= buf[j-1] { - return false // ensures indices are increasing (within a poly) - } - v[i][buf[j]] = 1 - } - prevSOP = SOP - } - for j := prevSOP; j < Omega; j++ { - if buf[j] != 0 { - return false // ensures padding indices are zero - } - } - - return true -} - -// Sets p to the polynomial packed into buf by PolyPackLeGamma1. -// -// p will be normalized. -func PolyUnpackLeGamma1(p *common.Poly, buf []byte) { - if Gamma1Bits == 17 { - j := 0 - for i := 0; i < PolyLeGamma1Size; i += 9 { - p0 := uint32(buf[i]) | (uint32(buf[i+1]) << 8) | - (uint32(buf[i+2]&0x3) << 16) - p1 := uint32(buf[i+2]>>2) | (uint32(buf[i+3]) << 6) | - (uint32(buf[i+4]&0xf) << 14) - p2 := uint32(buf[i+4]>>4) | (uint32(buf[i+5]) << 4) | - (uint32(buf[i+6]&0x3f) << 12) - p3 := uint32(buf[i+6]>>6) | (uint32(buf[i+7]) << 2) | - (uint32(buf[i+8]) << 10) - - // coefficients in [0,…,2γ₁) - p0 = Gamma1 - p0 // (-γ₁,…,γ₁] - p1 = Gamma1 - p1 - p2 = Gamma1 - p2 - p3 = Gamma1 - p3 - - p0 += uint32(int32(p0)>>31) & common.Q // normalize - p1 += uint32(int32(p1)>>31) & common.Q - p2 += uint32(int32(p2)>>31) & common.Q - p3 += uint32(int32(p3)>>31) & common.Q - - p[j] = p0 - p[j+1] = p1 - p[j+2] = p2 - p[j+3] = p3 - - j += 4 - } - } else if Gamma1Bits == 19 { - j := 0 - for i := 0; i < PolyLeGamma1Size; i += 5 { - p0 := uint32(buf[i]) | (uint32(buf[i+1]) << 8) | - (uint32(buf[i+2]&0xf) << 16) - p1 := uint32(buf[i+2]>>4) | (uint32(buf[i+3]) << 4) | - (uint32(buf[i+4]) << 12) - - p0 = Gamma1 - p0 - p1 = Gamma1 - p1 - - p0 += uint32(int32(p0)>>31) & common.Q - p1 += uint32(int32(p1)>>31) & common.Q - - p[j] = p0 - p[j+1] = p1 - - j += 2 - } - } else { - panic("γ₁ not supported") - } -} - -// Writes p whose coefficients are in (-γ₁,γ₁] into buf -// which has to be of length PolyLeGamma1Size. -// -// Assumes p is normalized. -func PolyPackLeGamma1(p *common.Poly, buf []byte) { - if Gamma1Bits == 17 { - j := 0 - // coefficients in [0,…,γ₁] ∪ (q-γ₁,…,q) - for i := 0; i < PolyLeGamma1Size; i += 9 { - p0 := Gamma1 - p[j] // [0,…,γ₁] ∪ (γ₁-q,…,2γ₁-q) - p0 += uint32(int32(p0)>>31) & common.Q // [0,…,2γ₁) - p1 := Gamma1 - p[j+1] - p1 += uint32(int32(p1)>>31) & common.Q - p2 := Gamma1 - p[j+2] - p2 += uint32(int32(p2)>>31) & common.Q - p3 := Gamma1 - p[j+3] - p3 += uint32(int32(p3)>>31) & common.Q - - buf[i+0] = byte(p0) - buf[i+1] = byte(p0 >> 8) - buf[i+2] = byte(p0>>16) | byte(p1<<2) - buf[i+3] = byte(p1 >> 6) - buf[i+4] = byte(p1>>14) | byte(p2<<4) - buf[i+5] = byte(p2 >> 4) - buf[i+6] = byte(p2>>12) | byte(p3<<6) - buf[i+7] = byte(p3 >> 2) - buf[i+8] = byte(p3 >> 10) - - j += 4 - } - } else if Gamma1Bits == 19 { - j := 0 - for i := 0; i < PolyLeGamma1Size; i += 5 { - // Coefficients are in [0, γ₁] ∪ (Q-γ₁, Q) - p0 := Gamma1 - p[j] - p0 += uint32(int32(p0)>>31) & common.Q - p1 := Gamma1 - p[j+1] - p1 += uint32(int32(p1)>>31) & common.Q - - buf[i+0] = byte(p0) - buf[i+1] = byte(p0 >> 8) - buf[i+2] = byte(p0>>16) | byte(p1<<4) - buf[i+3] = byte(p1 >> 4) - buf[i+4] = byte(p1 >> 12) - - j += 2 - } - } else { - panic("γ₁ not supported") - } -} - -// Pack w₁ into buf, which must be of length PolyW1Size. -// -// Assumes w₁ is normalized. -func PolyPackW1(p *common.Poly, buf []byte) { - if Gamma1Bits == 19 { - p.PackLe16(buf) - } else if Gamma1Bits == 17 { - j := 0 - for i := 0; i < PolyW1Size; i += 3 { - buf[i] = byte(p[j]) | byte(p[j+1]<<6) - buf[i+1] = byte(p[j+1]>>2) | byte(p[j+2]<<4) - buf[i+2] = byte(p[j+2]>>4) | byte(p[j+3]<<2) - j += 4 - } - } else { - panic("unsupported γ₁") - } -} diff --git a/sign/dilithium/mode2aes/internal/pack_test.go b/sign/dilithium/mode2aes/internal/pack_test.go deleted file mode 100644 index f952c6a09..000000000 --- a/sign/dilithium/mode2aes/internal/pack_test.go +++ /dev/null @@ -1,93 +0,0 @@ -// Code generated from mode3/internal/pack_test.go by gen.go - -package internal - -import ( - "testing" - - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -func TestPolyPackLeqEta(t *testing.T) { - var p1, p2 common.Poly - var seed [64]byte - var buf [PolyLeqEtaSize]byte - - for i := uint16(0); i < 100; i++ { - // Note that DeriveUniformLeqEta sets p to the right kind of - // unnormalized vector. - PolyDeriveUniformLeqEta(&p1, &seed, i) - for j := 0; j < PolyLeqEtaSize; j++ { - if p1[j] < common.Q-Eta || p1[j] > common.Q+Eta { - t.Fatalf("DerveUniformLeqEta out of bounds") - } - } - PolyPackLeqEta(&p1, buf[:]) - PolyUnpackLeqEta(&p2, buf[:]) - if p1 != p2 { - t.Fatalf("%v != %v", p1, p2) - } - } -} - -func TestPolyPackT1(t *testing.T) { - var p1, p2 common.Poly - var seed [32]byte - var buf [common.PolyT1Size]byte - - for i := uint16(0); i < 100; i++ { - PolyDeriveUniform(&p1, &seed, i) - p1.Normalize() - for j := 0; j < common.N; j++ { - p1[j] &= 0x1ff - } - p1.PackT1(buf[:]) - p2.UnpackT1(buf[:]) - if p1 != p2 { - t.Fatalf("%v != %v", p1, p2) - } - } -} - -func TestPolyPackT0(t *testing.T) { - var p, p0, p1, p2 common.Poly - var seed [32]byte - var buf [common.PolyT0Size]byte - - for i := uint16(0); i < 100; i++ { - PolyDeriveUniform(&p, &seed, i) - p.Normalize() - p.Power2Round(&p0, &p1) - - p0.PackT0(buf[:]) - p2.UnpackT0(buf[:]) - if p0 != p2 { - t.Fatalf("%v !=\n%v", p0, p2) - } - } -} - -func BenchmarkUnpackLeGamma1(b *testing.B) { - var p common.Poly - var buf [PolyLeGamma1Size]byte - for i := 0; i < b.N; i++ { - PolyUnpackLeGamma1(&p, buf[:]) - } -} - -func TestPolyPackLeGamma1(t *testing.T) { - var p0, p1 common.Poly - var seed [64]byte - var buf [PolyLeGamma1Size]byte - - for i := uint16(0); i < 100; i++ { - PolyDeriveUniformLeGamma1(&p0, &seed, i) - p0.Normalize() - - PolyPackLeGamma1(&p0, buf[:]) - PolyUnpackLeGamma1(&p1, buf[:]) - if p0 != p1 { - t.Fatalf("%v != %v", p0, p1) - } - } -} diff --git a/sign/dilithium/mode2aes/internal/params.go b/sign/dilithium/mode2aes/internal/params.go deleted file mode 100644 index 77305b51b..000000000 --- a/sign/dilithium/mode2aes/internal/params.go +++ /dev/null @@ -1,19 +0,0 @@ -// Code generated from params.templ.go. DO NOT EDIT. - -package internal - -const ( - Name = "Dilithium2-AES" - UseAES = true - K = 4 - L = 4 - Eta = 2 - DoubleEtaBits = 3 - Omega = 80 - Tau = 39 - Gamma1Bits = 17 - Gamma2 = 95232 - NIST = false - TRSize = 32 - CTildeSize = 32 -) diff --git a/sign/dilithium/mode2aes/internal/params_test.go b/sign/dilithium/mode2aes/internal/params_test.go deleted file mode 100644 index 14d70d1a7..000000000 --- a/sign/dilithium/mode2aes/internal/params_test.go +++ /dev/null @@ -1,99 +0,0 @@ -package internal - -import ( - "testing" - - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// Tests specific to the current mode - -func TestVectorDeriveUniformLeqEta(t *testing.T) { - var p common.Poly - var seed [64]byte - p2 := common.Poly{ - 8380416, 0, 2, 8380415, 1, 1, 0, 1, 0, 1, 8380415, 2, - 8380415, 8380415, 2, 2, 2, 1, 0, 2, 8380416, 1, 8380415, - 8380415, 8380416, 8380415, 8380416, 8380415, 1, 1, 0, 1, - 0, 1, 2, 8380416, 2, 1, 8380416, 1, 1, 2, 0, 8380416, - 8380416, 2, 0, 2, 8380415, 0, 1, 2, 1, 1, 1, 0, 8380415, - 1, 2, 8380415, 8380416, 1, 8380415, 0, 1, 8380416, 8380416, - 8380415, 0, 2, 8380415, 1, 8380416, 0, 8380416, 8380416, - 8380416, 2, 2, 1, 2, 8380415, 2, 0, 8380415, 8380415, 0, - 2, 8380415, 8380415, 1, 8380415, 2, 8380415, 0, 1, 2, - 8380415, 8380416, 8380415, 0, 8380416, 1, 0, 2, 0, 2, - 8380415, 8380416, 2, 1, 8380415, 1, 8380416, 1, 8380415, - 8380415, 0, 8380416, 0, 0, 0, 0, 0, 2, 1, 2, 0, 0, 8380415, - 8380416, 2, 0, 1, 8380416, 2, 1, 8380416, 2, 1, 8380416, - 0, 2, 8380416, 2, 0, 8380415, 0, 2, 0, 8380415, 1, 0, - 8380415, 2, 8380416, 8380416, 8380415, 0, 0, 8380416, 2, - 2, 1, 8380416, 2, 1, 2, 0, 8380415, 1, 0, 2, 2, 1, 0, 0, - 1, 2, 0, 2, 0, 2, 2, 0, 0, 2, 2, 8380416, 2, 2, 0, 8380415, - 1, 2, 2, 1, 1, 8380415, 8380415, 2, 2, 1, 8380416, 8380415, - 2, 1, 0, 8380416, 8380415, 8380415, 0, 1, 0, 8380416, - 8380416, 8380416, 8380416, 2, 8380415, 1, 8380415, 0, 1, - 0, 8380416, 2, 8380415, 2, 1, 2, 1, 1, 0, 8380415, 2, - 8380416, 8380416, 8380415, 8380415, 0, 2, 8380416, 1, - 8380416, 8380415, 8380416, 8380415, 2, 8380416, 2, 8380415, - 2, 2, 1, 8380415, - } - for i := 0; i < 64; i++ { - seed[i] = byte(i) - } - PolyDeriveUniformLeqEta(&p, &seed, 30000) - p.Normalize() - if p != p2 { - t.Fatalf("%v != %v", p, p2) - } -} - -func TestVectorDeriveUniformLeGamma1(t *testing.T) { - var p, p2 common.Poly - var seed [64]byte - p2 = common.Poly{ - 8340798, 8313384, 49077, 22486, 123481, 8288752, 36503, - 8340997, 8302174, 8258535, 13603, 17223, 8335009, 8345989, - 91340, 8349862, 83710, 72846, 89691, 8272088, 26276, 6832, - 29103, 8313655, 72326, 8321983, 113475, 95773, 17886, - 8365924, 8279095, 8343830, 8273195, 8310637, 8253500, - 8374711, 8262430, 17388, 8294137, 8262960, 8290290, 47349, - 44452, 128195, 8377719, 130632, 8256416, 8287230, 120060, - 8323823, 115401, 8351851, 97604, 47772, 8363419, 8353971, - 1956, 8267893, 8362705, 17686, 122170, 101229, 3317, 14205, - 8368014, 97101, 8360617, 111843, 8357331, 16215, 8346959, - 8313944, 8309613, 8348252, 64256, 8294208, 8318089, 8335255, - 8324894, 8273750, 27850, 8260308, 8258591, 80542, 8320495, - 36517, 8340794, 8304320, 8320157, 625, 8292418, 8317653, - 8275617, 8352781, 109921, 121642, 8291715, 129643, 111667, - 8325995, 8368715, 8283849, 8281348, 1417, 8336033, 100081, - 30984, 22277, 8307048, 55908, 50909, 8326533, 34891, 98542, - 121511, 2614, 125602, 59900, 120456, 8351260, 30124, 52065, - 124214, 48354, 8281081, 116665, 17218, 74568, 4798, 8274275, - 8328948, 8269139, 8908, 8276509, 8270063, 8370525, 8257669, - 36128, 8313115, 8325113, 8257382, 77895, 8288147, 8294769, - 8273027, 8370871, 57085, 59514, 82308, 71173, 6475, 8313311, - 27188, 35803, 8296637, 100553, 8333397, 19553, 8373991, - 8361935, 62433, 8300, 8371479, 8297954, 8352934, 8286, - 8355336, 8335507, 8370548, 8301039, 8270317, 26478, 113694, - 8296283, 8271234, 8250245, 8372668, 8284012, 8264500, 85893, - 8322354, 8358407, 130156, 52458, 8291251, 122476, 8308146, - 4252, 118400, 74123, 8333546, 70542, 8325370, 60510, 1874, - 8377673, 50805, 78992, 66936, 8266050, 8367830, 8342582, - 8268085, 65238, 61045, 8312728, 70547, 8309034, 5696, 118654, - 8330845, 29553, 68995, 70518, 8351920, 8269399, 128395, - 122804, 10848, 8291860, 8324935, 3842, 8265342, 8266117, - 8368377, 8311281, 24039, 8343875, 97893, 12670, 8370577, - 92482, 8288562, 8269568, 8371831, 8324316, 76758, 8327193, - 46615, 10323, 8337373, 101795, 88456, 25023, 8351520, 94650, - 8264851, 14881, 104171, 22607, 8379204, 8310533, 8324603, - 8299017, 128723, 8291421, - } - for i := 0; i < 64; i++ { - seed[i] = byte(i) - } - PolyDeriveUniformLeGamma1(&p, &seed, 30000) - p.Normalize() - if p != p2 { - t.Fatalf("%v != %v", p, p2) - } -} diff --git a/sign/dilithium/mode2aes/internal/rounding.go b/sign/dilithium/mode2aes/internal/rounding.go deleted file mode 100644 index 58123c090..000000000 --- a/sign/dilithium/mode2aes/internal/rounding.go +++ /dev/null @@ -1,142 +0,0 @@ -// Code generated from mode3/internal/rounding.go by gen.go - -package internal - -import ( - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// Splits 0 ≤ a < q into a₀ and a₁ with a = a₁*α + a₀ with -α/2 < a₀ ≤ α/2, -// except for when we would have a₁ = (q-1)/α in which case a₁=0 is taken -// and -α/2 ≤ a₀ < 0. Returns a₀ + q. Note 0 ≤ a₁ < (q-1)/α. -// Recall α = 2γ₂. -func decompose(a uint32) (a0plusQ, a1 uint32) { - // a₁ = ⌈a / 128⌉ - a1 = (a + 127) >> 7 - - if Alpha == 523776 { - // 1025/2²² is close enough to 1/4092 so that a₁ - // becomes a/α rounded down. - a1 = ((a1*1025 + (1 << 21)) >> 22) - - // For the corner-case a₁ = (q-1)/α = 16, we have to set a₁=0. - a1 &= 15 - } else if Alpha == 190464 { - // 1488/2²⁴ is close enough to 1/1488 so that a₁ - // becomes a/α rounded down. - a1 = ((a1 * 11275) + (1 << 23)) >> 24 - - // For the corner-case a₁ = (q-1)/α = 44, we have to set a₁=0. - a1 ^= uint32(int32(43-a1)>>31) & a1 - } else { - panic("unsupported α") - } - - a0plusQ = a - a1*Alpha - - // In the corner-case, when we set a₁=0, we will incorrectly - // have a₀ > (q-1)/2 and we'll need to subtract q. As we - // return a₀ + q, that comes down to adding q if a₀ < (q-1)/2. - a0plusQ += uint32(int32(a0plusQ-(common.Q-1)/2)>>31) & common.Q - - return -} - -// Assume 0 ≤ r, f < Q with ‖f‖_∞ ≤ α/2. Decompose r as r = r1*α + r0 as -// computed by decompose(). Write r' := r - f (mod Q). Now, decompose -// r'=r-f again as r' = r'1*α + r'0 using decompose(). As f is small, we -// have r'1 = r1 + h, where h ∈ {-1, 0, 1}. makeHint() computes |h| -// given z0 := r0 - f (mod Q) and r1. With |h|, which is called the hint, -// we can reconstruct r1 using only r' = r - f, which is done by useHint(). -// To wit: -// -// useHint( r - f, makeHint( r0 - f, r1 ) ) = r1. -// -// Assumes 0 ≤ z0 < Q. -func makeHint(z0, r1 uint32) uint32 { - // If -α/2 < r0 - f ≤ α/2, then r1*α + r0 - f is a valid decomposition of r' - // with the restrictions of decompose() and so r'1 = r1. So the hint - // should be 0. This is covered by the first two inequalities. - // There is one other case: if r0 - f = -α/2, then r1*α + r0 - f is also - // a valid decomposition if r1 = 0. In the other cases a one is carried - // and the hint should be 1. - if z0 <= Gamma2 || z0 > common.Q-Gamma2 || (z0 == common.Q-Gamma2 && r1 == 0) { - return 0 - } - return 1 -} - -// Uses the hint created by makeHint() to reconstruct r1 from r'=r-f; see -// documentation of makeHint() for context. -// Assumes 0 ≤ r' < Q. -func useHint(rp uint32, hint uint32) uint32 { - rp0plusQ, rp1 := decompose(rp) - if hint == 0 { - return rp1 - } - if rp0plusQ > common.Q { - return (rp1 + 1) & 15 - } - return (rp1 - 1) & 15 -} - -// Sets p to the hint polynomial for p0 the modified low bits and p1 -// the unmodified high bits --- see makeHint(). -// -// Returns the number of ones in the hint polynomial. -func PolyMakeHint(p, p0, p1 *common.Poly) (pop uint32) { - for i := 0; i < common.N; i++ { - h := makeHint(p0[i], p1[i]) - pop += h - p[i] = h - } - return -} - -// Computes corrections to the high bits of the polynomial q according -// to the hints in h and sets p to the corrected high bits. Returns p. -func PolyUseHint(p, q, hint *common.Poly) { - var q0PlusQ common.Poly - - // See useHint() and makeHint() for an explanation. We reimplement it - // here so that we can call Poly.Decompose(), which might be way faster - // than calling decompose() in a loop (for instance when having AVX2.) - - PolyDecompose(q, &q0PlusQ, p) - - for i := 0; i < common.N; i++ { - if hint[i] == 0 { - continue - } - if Gamma2 == 261888 { - if q0PlusQ[i] > common.Q { - p[i] = (p[i] + 1) & 15 - } else { - p[i] = (p[i] - 1) & 15 - } - } else if Gamma2 == 95232 { - if q0PlusQ[i] > common.Q { - if p[i] == 43 { - p[i] = 0 - } else { - p[i]++ - } - } else { - if p[i] == 0 { - p[i] = 43 - } else { - p[i]-- - } - } - } else { - panic("unsupported γ₂") - } - } -} - -// Splits each of the coefficients of p using decompose. -func PolyDecompose(p, p0PlusQ, p1 *common.Poly) { - for i := 0; i < common.N; i++ { - p0PlusQ[i], p1[i] = decompose(p[i]) - } -} diff --git a/sign/dilithium/mode2aes/internal/rounding_test.go b/sign/dilithium/mode2aes/internal/rounding_test.go deleted file mode 100644 index ad653ca3f..000000000 --- a/sign/dilithium/mode2aes/internal/rounding_test.go +++ /dev/null @@ -1,81 +0,0 @@ -// Code generated from mode3/internal/rounding_test.go by gen.go - -package internal - -import ( - "flag" - "testing" - - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -var runVeryLongTest = flag.Bool("very-long", false, "runs very long tests") - -func TestDecompose(t *testing.T) { - for a := uint32(0); a < common.Q; a++ { - a0PlusQ, a1 := decompose(a) - a0 := int32(a0PlusQ) - int32(common.Q) - recombined := a0 + int32(Alpha*a1) - if a1 == 0 && recombined < 0 { - recombined += common.Q - if -(Alpha/2) > a0 || a0 >= 0 { - t.Fatalf("decompose(%v): a0 out of bounds", a) - } - } else { - if (-(Alpha / 2) >= a0) || (a0 > Alpha/2) { - t.Fatalf("decompose(%v): a0 out of bounds", a) - } - } - if int32(a) != recombined { - t.Fatalf("decompose(%v) doesn't recombine %v %v", a, a0, a1) - } - } -} - -func TestMakeHint(t *testing.T) { - if !*runVeryLongTest { - t.SkipNow() - } - for w := uint32(0); w < common.Q; w++ { - w0, w1 := decompose(w) - for fn := uint32(0); fn <= Gamma2; fn++ { - fsign := false - for { - var f uint32 - if fsign { - if fn == 0 { - break - } - f = common.Q - fn - } else { - f = fn - } - - hint := makeHint(common.ReduceLe2Q(w0+common.Q-f), w1) - w1p := useHint(common.ReduceLe2Q(w+common.Q-f), hint) - if w1p != w1 { - t.Fatal() - } - - if fsign { - break - } - fsign = true - } - } - } -} - -func BenchmarkDecompose(b *testing.B) { - var p, p0, p1 common.Poly - for i := 0; i < b.N; i++ { - PolyDecompose(&p, &p0, &p1) - } -} - -func BenchmarkMakeHint(b *testing.B) { - var p, p0, p1 common.Poly - for i := 0; i < b.N; i++ { - PolyMakeHint(&p, &p0, &p1) - } -} diff --git a/sign/dilithium/mode2aes/internal/sample.go b/sign/dilithium/mode2aes/internal/sample.go deleted file mode 100644 index 62c261332..000000000 --- a/sign/dilithium/mode2aes/internal/sample.go +++ /dev/null @@ -1,370 +0,0 @@ -// Code generated from mode3/internal/sample.go by gen.go - -package internal - -import ( - "encoding/binary" - - "github.com/cloudflare/circl/internal/sha3" - common "github.com/cloudflare/circl/sign/internal/dilithium" - "github.com/cloudflare/circl/simd/keccakf1600" -) - -// DeriveX4Available indicates whether the system supports the quick fourway -// sampling variants like PolyDeriveUniformX4. -var DeriveX4Available = keccakf1600.IsEnabledX4() && !UseAES - -// For each i, sample ps[i] uniformly from the given seed and nonces[i]. -// ps[i] may be nil and is ignored in that case. -// -// Can only be called when DeriveX4Available is true. -func PolyDeriveUniformX4(ps [4]*common.Poly, seed *[32]byte, nonces [4]uint16) { - var perm keccakf1600.StateX4 - state := perm.Initialize(false) - - // Absorb the seed in the four states - for i := 0; i < 4; i++ { - v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) - for j := 0; j < 4; j++ { - state[i*4+j] = v - } - } - - // Absorb the nonces, the SHAKE128 domain separator (0b1111), the - // start of the padding (0b...001) and the end of the padding 0b100... - // Recall that the rate of SHAKE128 is 168 --- i.e. 21 uint64s. - for j := 0; j < 4; j++ { - state[4*4+j] = uint64(nonces[j]) | (0x1f << 16) - state[20*4+j] = 0x80 << 56 - } - - var idx [4]int // indices into ps - for j := 0; j < 4; j++ { - if ps[j] == nil { - idx[j] = common.N // mark nil polynomial as completed - } - } - - done := false - for !done { - // Applies KeccaK-f[1600] to state to get the next 21 uint64s of each - // of the four SHAKE128 streams. - perm.Permute() - - done = true - - PolyLoop: - for j := 0; j < 4; j++ { - if idx[j] == common.N { - continue - } - for i := 0; i < 7; i++ { - var t [8]uint32 - t[0] = uint32(state[i*3*4+j] & 0x7fffff) - t[1] = uint32((state[i*3*4+j] >> 24) & 0x7fffff) - t[2] = uint32((state[i*3*4+j] >> 48) | - ((state[(i*3+1)*4+j] & 0x7f) << 16)) - t[3] = uint32((state[(i*3+1)*4+j] >> 8) & 0x7fffff) - t[4] = uint32((state[(i*3+1)*4+j] >> 32) & 0x7fffff) - t[5] = uint32((state[(i*3+1)*4+j] >> 56) | - ((state[(i*3+2)*4+j] & 0x7fff) << 8)) - t[6] = uint32((state[(i*3+2)*4+j] >> 16) & 0x7fffff) - t[7] = uint32((state[(i*3+2)*4+j] >> 40) & 0x7fffff) - - for k := 0; k < 8; k++ { - if t[k] < common.Q { - ps[j][idx[j]] = t[k] - idx[j]++ - if idx[j] == common.N { - continue PolyLoop - } - } - } - } - done = false - } - } -} - -// Sample p uniformly from the given seed and nonce. -// -// p will be normalized. -func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { - var i, length int - var buf [12 * 16]byte // fits 168B SHAKE-128 rate and 12 16B AES blocks - - if UseAES { - length = 12 * 16 - } else { - length = 168 - } - - sample := func() { - // Note that 3 divides into 168 and 12*16, so we use up buf completely. - for j := 0; j < length && i < common.N; j += 3 { - t := (uint32(buf[j]) | (uint32(buf[j+1]) << 8) | - (uint32(buf[j+2]) << 16)) & 0x7fffff - - // We use rejection sampling - if t < common.Q { - p[i] = t - i++ - } - } - } - - if UseAES { - h := common.NewAesStream128(seed, nonce) - - for i < common.N { - h.SqueezeInto(buf[:length]) - sample() - } - } else { - var iv [32 + 2]byte // 32 byte seed + uint16 nonce - h := sha3.NewShake128() - copy(iv[:32], seed[:]) - iv[32] = uint8(nonce) - iv[33] = uint8(nonce >> 8) - _, _ = h.Write(iv[:]) - - for i < common.N { - _, _ = h.Read(buf[:168]) - sample() - } - } -} - -// Sample p uniformly with coefficients of norm less than or equal η, -// using the given seed and nonce. -// -// p will not be normalized, but will have coefficients in [q-η,q+η]. -func PolyDeriveUniformLeqEta(p *common.Poly, seed *[64]byte, nonce uint16) { - // Assumes 2 < η < 8. - var i, length int - var buf [9 * 16]byte // fits 136B SHAKE-256 rate and 9 16B AES blocks - - if UseAES { - length = 9 * 16 - } else { - length = 136 - } - - sample := func() { - // We use rejection sampling - for j := 0; j < length && i < common.N; j++ { - t1 := uint32(buf[j]) & 15 - t2 := uint32(buf[j]) >> 4 - if Eta == 2 { // branch is eliminated by compiler - if t1 <= 14 { - t1 -= ((205 * t1) >> 10) * 5 // reduce mod 5 - p[i] = common.Q + Eta - t1 - i++ - } - if t2 <= 14 && i < common.N { - t2 -= ((205 * t2) >> 10) * 5 // reduce mod 5 - p[i] = common.Q + Eta - t2 - i++ - } - } else if Eta == 4 { - if t1 <= 2*Eta { - p[i] = common.Q + Eta - t1 - i++ - } - if t2 <= 2*Eta && i < common.N { - p[i] = common.Q + Eta - t2 - i++ - } - } else { - panic("unsupported η") - } - } - } - - if UseAES { - h := common.NewAesStream256(seed, nonce) - - for i < common.N { - h.SqueezeInto(buf[:length]) - sample() - } - } else { - var iv [64 + 2]byte // 64 byte seed + uint16 nonce - - h := sha3.NewShake256() - copy(iv[:64], seed[:]) - iv[64] = uint8(nonce) - iv[65] = uint8(nonce >> 8) - - // 136 is SHAKE-256 rate - _, _ = h.Write(iv[:]) - - for i < common.N { - _, _ = h.Read(buf[:136]) - sample() - } - } -} - -// Sample v[i] uniformly with coefficients in (-γ₁,…,γ₁] using the -// given seed and nonce+i -// -// p will be normalized. -func VecLDeriveUniformLeGamma1(v *VecL, seed *[64]byte, nonce uint16) { - for i := 0; i < L; i++ { - PolyDeriveUniformLeGamma1(&v[i], seed, nonce+uint16(i)) - } -} - -// Sample p uniformly with coefficients in (-γ₁,…,γK1s] using the -// given seed and nonce. -// -// p will be normalized. -func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { - var buf [PolyLeGamma1Size]byte - - if UseAES { - h := common.NewAesStream256(seed, nonce) - h.SqueezeInto(buf[:]) - } else { - var iv [66]byte - h := sha3.NewShake256() - copy(iv[:64], seed[:]) - iv[64] = uint8(nonce) - iv[65] = uint8(nonce >> 8) - _, _ = h.Write(iv[:]) - _, _ = h.Read(buf[:]) - } - - PolyUnpackLeGamma1(p, buf[:]) -} - -// For each i, sample ps[i] uniformly with τ non-zero coefficients in {q-1,1} -// using the given seed and w1[i]. ps[i] may be nil and is ignored -// in that case. ps[i] will be normalized. -// -// Can only be called when DeriveX4Available is true. -// -// This function is currently not used (yet). -func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed []byte) { - var perm keccakf1600.StateX4 - state := perm.Initialize(false) - - // Absorb the seed in the four states - for i := 0; i < 32/8; i++ { - v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) - for j := 0; j < 4; j++ { - state[i*4+j] = v - } - } - - // SHAKE256 domain separator and padding - for j := 0; j < 4; j++ { - state[(32/8)*4+j] ^= 0x1f - state[16*4+j] ^= 0x80 << 56 - } - perm.Permute() - - var signs [4]uint64 - var idx [4]uint16 // indices into ps - - for j := 0; j < 4; j++ { - if ps[j] != nil { - signs[j] = state[j] - *ps[j] = common.Poly{} // zero ps[j] - idx[j] = common.N - Tau - } else { - idx[j] = common.N // mark as completed - } - } - - stateOffset := 1 - for { - done := true - - PolyLoop: - for j := 0; j < 4; j++ { - if idx[j] == common.N { - continue - } - - for i := stateOffset; i < 17; i++ { - var bs [8]byte - binary.LittleEndian.PutUint64(bs[:], state[4*i+j]) - for k := 0; k < 8; k++ { - b := uint16(bs[k]) - - if b > idx[j] { - continue - } - - ps[j][idx[j]] = ps[j][b] - ps[j][b] = 1 - // Takes least significant bit of signs and uses it for the sign. - // Note 1 ^ (1 | (Q-1)) = Q-1. - ps[j][b] ^= uint32((-(signs[j] & 1)) & (1 | (common.Q - 1))) - signs[j] >>= 1 - - idx[j]++ - if idx[j] == common.N { - continue PolyLoop - } - } - } - - done = false - } - - if done { - break - } - - perm.Permute() - stateOffset = 0 - } -} - -// Samples p uniformly with τ non-zero coefficients in {q-1,1}. -// -// The polynomial p will be normalized. -func PolyDeriveUniformBall(p *common.Poly, seed []byte) { - var buf [136]byte // SHAKE-256 rate is 136 - - h := sha3.NewShake256() - _, _ = h.Write(seed[:]) - _, _ = h.Read(buf[:]) - - // Essentially we generate a sequence of τ ones or minus ones, - // prepend 196 zeroes and shuffle the concatenation using the - // usual algorithm (Fisher--Yates.) - signs := binary.LittleEndian.Uint64(buf[:]) - bufOff := 8 // offset into buf - - *p = common.Poly{} // zero p - for i := uint16(common.N - Tau); i < common.N; i++ { - var b uint16 - - // Find location of where to move the new coefficient to using - // rejection sampling. - for { - if bufOff >= 136 { - _, _ = h.Read(buf[:]) - bufOff = 0 - } - - b = uint16(buf[bufOff]) - bufOff++ - - if b <= i { - break - } - } - - p[i] = p[b] - p[b] = 1 - // Takes least significant bit of signs and uses it for the sign. - // Note 1 ^ (1 | (Q-1)) = Q-1. - p[b] ^= uint32((-(signs & 1)) & (1 | (common.Q - 1))) - signs >>= 1 - } -} diff --git a/sign/dilithium/mode2aes/internal/sample_test.go b/sign/dilithium/mode2aes/internal/sample_test.go deleted file mode 100644 index 2059599eb..000000000 --- a/sign/dilithium/mode2aes/internal/sample_test.go +++ /dev/null @@ -1,266 +0,0 @@ -// Code generated from mode3/internal/sample_test.go by gen.go - -package internal - -import ( - "encoding/binary" - "testing" - - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -func TestVectorDeriveUniform(t *testing.T) { - var p, p2 common.Poly - var seed [32]byte - if UseAES { - p2 = common.Poly{ - 6724291, 310295, 6949524, 4464039, 1482136, 2522903, - 7025059, 3006320, 7286364, 7516512, 3361305, 1955529, - 4765954, 1725325, 6933066, 4299100, 6625173, 4272792, - 583034, 4971409, 2259140, 7715362, 3975394, 2341624, - 5481174, 8150082, 365246, 5491939, 1083120, 7517301, - 3104783, 2475292, 184149, 6425226, 4591622, 5964030, - 4729604, 5471092, 1828227, 1082044, 2516245, 1692580, - 3274844, 5443294, 7256740, 4989638, 3191250, 7479519, - 5124211, 5603858, 1230692, 2513454, 2828034, 4254312, - 1512596, 5245430, 5517392, 2814840, 932545, 6826733, - 3511094, 4075348, 3233981, 7268882, 2913733, 4870249, - 4123492, 8124406, 4016949, 5478752, 2750895, 603525, - 5724798, 3985430, 3483012, 6434230, 3136996, 8297976, - 4107616, 7307748, 6962904, 7544473, 1193110, 3448595, - 4814773, 5607932, 8221314, 1054046, 1541208, 1866050, - 8227412, 2925778, 5293953, 2065416, 4972769, 3616283, - 7990594, 1105530, 7121836, 1170740, 7417431, 633146, - 253820, 7235019, 3539504, 6807707, 451390, 5481526, - 2859902, 1063061, 4579730, 7126652, 7033767, 4294814, - 1414604, 7620048, 1953268, 8304556, 1156814, 1182881, - 5311519, 3057534, 5277666, 682843, 2070398, 2874278, - 4859533, 6376664, 6694074, 1590242, 2620706, 8331066, - 5643845, 5037538, 2891516, 7004879, 3754327, 5031296, - 5463118, 2420870, 8116529, 5517696, 7435129, 3873963, - 710407, 713806, 175647, 4274571, 2655021, 7319503, - 3027243, 7129679, 4213435, 2429323, 4643873, 4568526, - 649664, 1720514, 6497260, 2683517, 7672754, 7105190, - 3148405, 5898369, 5667677, 8050874, 1587139, 7315260, - 4337416, 2202680, 2338714, 557467, 6752058, 2469794, - 485071, 1617604, 3590498, 2151466, 2005823, 7727956, - 7776292, 6783433, 6787146, 1732833, 3596857, 7436284, - 4483349, 4970142, 4472608, 6478342, 1236215, 5695744, - 2280717, 2889355, 3233946, 5187812, 978685, 5177364, - 2922353, 4824807, 5302883, 6739803, 8092453, 5883903, - 816553, 6041174, 8317591, 1459178, 5332455, 1835058, - 1368601, 2820950, 3479224, 2589540, 7992934, 3421045, - 4657128, 8292902, 4153567, 3553988, 7830320, 6722913, - 2555309, 4149801, 8328975, 1560545, 7757473, 3106458, - 4310856, 7135453, 3481032, 652626, 1841361, 8126828, - 6250018, 300536, 7380070, 8174419, 1418793, 6208185, - 3906256, 6679016, 1605701, 3561489, 5819724, 5746996, - 8044214, 7087187, 7102330, 4962927, 4253983, 7108567, - 4119736, 6584065, 441634, 6941656, - } - } else { - p2 = common.Poly{ - 2901364, 562527, 5258502, 3885002, 4190126, 4460268, 6884052, - 3514511, 5383040, 213206, 2155865, 5179607, 3551954, 2312357, - 6066350, 8126097, 1179080, 4787182, 6552182, 6713644, - 1561067, 7626063, 7859743, 5052321, 7032876, 7815031, 157938, - 1865184, 490802, 5717642, 3451902, 7000218, 3743250, 1677431, - 1875427, 5596150, 671623, 3819041, 6247594, 1014875, 4933545, - 7122446, 6682963, 3388398, 3335295, 943002, 1145083, 3113071, - 105967, 1916675, 7474561, 1107006, 700548, 2147909, 1603855, - 5049181, 437882, 6118899, 5656914, 6731065, 3066622, 865453, - 5427634, 981549, 4650873, 861291, 4003872, 5104220, 6171453, - 3723302, 7426315, 6137283, 4874820, 6052561, 53441, 5032874, - 5614778, 2248550, 1756499, 8280764, 8263880, 7600081, - 5118374, 795344, 7543392, 6869925, 1841187, 4181568, 584562, - 7483939, 4938664, 6863397, 5126354, 5218129, 6236086, - 4149293, 379169, 4368487, 7490569, 3409215, 1580463, 3081737, - 1278732, 7109719, 7371700, 2097931, 399836, 1700274, 7188595, - 6830029, 1548850, 6593138, 6849097, 1518037, 2859442, - 7772265, 7325153, 3281191, 7856131, 4995056, 4684325, - 1351194, 8223904, 6817307, 2484146, 131782, 397032, 7436778, - 7973479, 3171829, 5624626, 3540123, 7150120, 8313283, - 3604714, 1043574, 117692, 7797783, 7909392, 903315, 7335342, - 7501562, 5826142, 2709813, 8245473, 2369045, 2782257, - 5762833, 6474114, 6862031, 424522, 594248, 2626630, 7659983, - 5642869, 4075194, 1592129, 245547, 5271031, 3205046, 982375, - 267873, 1286496, 7230481, 3208972, 7485411, 676111, 4944500, - 2959742, 5934456, 1414847, 6067948, 1709895, 4648315, 126008, - 8258986, 2183134, 2302072, 4674924, 4306056, 7465311, - 6500270, 4247428, 4016815, 4973426, 294287, 2456847, 3289700, - 2732169, 1159447, 5569724, 140001, 3237977, 8007761, 5874533, - 255652, 3119586, 2102434, 6248250, 8152822, 8006066, 7708625, - 6997719, 6260212, 6186962, 6636650, 7836834, 7998017, - 2061516, 1197591, 1706544, 733027, 2392907, 2700000, 8254598, - 4488002, 160495, 2985325, 2036837, 2703633, 6406550, 3579947, - 6195178, 5552390, 6804584, 6305468, 5731980, 6095195, - 3323409, 1322661, 6690942, 3374630, 5615167, 479044, 3136054, - 4380418, 2833144, 7829577, 1770522, 6056687, 240415, 14780, - 3740517, 5224226, 3547288, 2083124, 4699398, 3654239, - 5624978, 585593, 3655369, 2281739, 3338565, 1908093, 7784706, - 4352830, - } - } - for i := 0; i < 32; i++ { - seed[i] = byte(i) - } - PolyDeriveUniform(&p, &seed, 30000) - if p != p2 { - t.Fatalf("%v != %v", p, p2) - } -} - -func TestDeriveUniform(t *testing.T) { - var p common.Poly - var seed [32]byte - for i := 0; i < 100; i++ { - binary.LittleEndian.PutUint64(seed[:], uint64(i)) - PolyDeriveUniform(&p, &seed, uint16(i)) - if !PolyNormalized(&p) { - t.Fatal() - } - } -} - -func TestDeriveUniformLeqEta(t *testing.T) { - var p common.Poly - var seed [64]byte - for i := 0; i < 100; i++ { - binary.LittleEndian.PutUint64(seed[:], uint64(i)) - PolyDeriveUniformLeqEta(&p, &seed, uint16(i)) - for j := 0; j < common.N; j++ { - if p[j] < common.Q-Eta || p[j] > common.Q+Eta { - t.Fatal() - } - } - } -} - -func TestDeriveUniformLeGamma1(t *testing.T) { - var p common.Poly - var seed [64]byte - for i := 0; i < 100; i++ { - binary.LittleEndian.PutUint64(seed[:], uint64(i)) - PolyDeriveUniformLeGamma1(&p, &seed, uint16(i)) - for j := 0; j < common.N; j++ { - if (p[j] > Gamma1 && p[j] <= common.Q-Gamma1) || p[j] >= common.Q { - t.Fatal() - } - } - } -} - -func TestDeriveUniformBall(t *testing.T) { - var p common.Poly - var seed [32]byte - for i := 0; i < 100; i++ { - binary.LittleEndian.PutUint64(seed[:], uint64(i)) - PolyDeriveUniformBall(&p, seed[:]) - nonzero := 0 - for j := 0; j < common.N; j++ { - if p[j] != 0 { - if p[j] != 1 && p[j] != common.Q-1 { - t.Fatal() - } - nonzero++ - } - } - if nonzero != Tau { - t.Fatal() - } - } -} - -func TestDeriveUniformX4(t *testing.T) { - if !DeriveX4Available { - t.SkipNow() - } - var ps [4]common.Poly - var p common.Poly - var seed [32]byte - nonces := [4]uint16{12345, 54321, 13532, 37377} - - for i := 0; i < len(seed); i++ { - seed[i] = byte(i) - } - - PolyDeriveUniformX4([4]*common.Poly{&ps[0], &ps[1], &ps[2], &ps[3]}, &seed, - nonces) - for i := 0; i < 4; i++ { - PolyDeriveUniform(&p, &seed, nonces[i]) - if ps[i] != p { - t.Fatal() - } - } -} - -func TestDeriveUniformBallX4(t *testing.T) { - if !DeriveX4Available { - t.SkipNow() - } - var ps [4]common.Poly - var p common.Poly - var seed [32]byte - PolyDeriveUniformBallX4( - [4]*common.Poly{&ps[0], &ps[1], &ps[2], &ps[3]}, - seed[:], - ) - for j := 0; j < 4; j++ { - PolyDeriveUniformBall(&p, seed[:]) - if ps[j] != p { - t.Fatalf("%d\n%v\n%v", j, ps[j], p) - } - } -} - -func BenchmarkPolyDeriveUniformBall(b *testing.B) { - var seed [32]byte - var p common.Poly - var w1 VecK - for i := 0; i < b.N; i++ { - w1[0][0] = uint32(i) - PolyDeriveUniformBall(&p, seed[:]) - } -} - -func BenchmarkPolyDeriveUniformBallX4(b *testing.B) { - var seed [32]byte - var p common.Poly - var w1 VecK - for i := 0; i < b.N; i++ { - w1[0][0] = uint32(i) - PolyDeriveUniformBallX4( - [4]*common.Poly{&p, &p, &p, &p}, - seed[:], - ) - } -} - -func BenchmarkPolyDeriveUniform(b *testing.B) { - var seed [32]byte - var p common.Poly - for i := 0; i < b.N; i++ { - PolyDeriveUniform(&p, &seed, uint16(i)) - } -} - -func BenchmarkPolyDeriveUniformX4(b *testing.B) { - if !DeriveX4Available { - b.SkipNow() - } - var seed [32]byte - var p [4]common.Poly - for i := 0; i < b.N; i++ { - nonce := uint16(4 * i) - PolyDeriveUniformX4([4]*common.Poly{&p[0], &p[1], &p[2], &p[3]}, - &seed, [4]uint16{nonce, nonce + 1, nonce + 2, nonce + 3}) - } -} - -func BenchmarkPolyDeriveUniformLeGamma1(b *testing.B) { - var seed [64]byte - var p common.Poly - for i := 0; i < b.N; i++ { - PolyDeriveUniformLeGamma1(&p, &seed, uint16(i)) - } -} diff --git a/sign/dilithium/mode2aes/internal/vec.go b/sign/dilithium/mode2aes/internal/vec.go deleted file mode 100644 index d07d3b245..000000000 --- a/sign/dilithium/mode2aes/internal/vec.go +++ /dev/null @@ -1,281 +0,0 @@ -// Code generated from mode3/internal/vec.go by gen.go - -package internal - -import ( - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// A vector of L polynomials. -type VecL [L]common.Poly - -// A vector of K polynomials. -type VecK [K]common.Poly - -// Normalize the polynomials in this vector. -func (v *VecL) Normalize() { - for i := 0; i < L; i++ { - v[i].Normalize() - } -} - -// Normalize the polynomials in this vector assuming their coefficients -// are already bounded by 2q. -func (v *VecL) NormalizeAssumingLe2Q() { - for i := 0; i < L; i++ { - v[i].NormalizeAssumingLe2Q() - } -} - -// Sets v to w + u. Does not normalize. -func (v *VecL) Add(w, u *VecL) { - for i := 0; i < L; i++ { - v[i].Add(&w[i], &u[i]) - } -} - -// Applies NTT componentwise. See Poly.NTT() for details. -func (v *VecL) NTT() { - for i := 0; i < L; i++ { - v[i].NTT() - } -} - -// Checks whether any of the coefficients exceeds the given bound in supnorm -// -// Requires the vector to be normalized. -func (v *VecL) Exceeds(bound uint32) bool { - for i := 0; i < L; i++ { - if v[i].Exceeds(bound) { - return true - } - } - return false -} - -// Applies Poly.Power2Round componentwise. -// -// Requires the vector to be normalized. -func (v *VecL) Power2Round(v0PlusQ, v1 *VecL) { - for i := 0; i < L; i++ { - v[i].Power2Round(&v0PlusQ[i], &v1[i]) - } -} - -// Applies Poly.Decompose componentwise. -// -// Requires the vector to be normalized. -func (v *VecL) Decompose(v0PlusQ, v1 *VecL) { - for i := 0; i < L; i++ { - PolyDecompose(&v[i], &v0PlusQ[i], &v1[i]) - } -} - -// Sequentially packs each polynomial using Poly.PackLeqEta(). -func (v *VecL) PackLeqEta(buf []byte) { - offset := 0 - for i := 0; i < L; i++ { - PolyPackLeqEta(&v[i], buf[offset:]) - offset += PolyLeqEtaSize - } -} - -// Sets v to the polynomials packed in buf using VecL.PackLeqEta(). -func (v *VecL) UnpackLeqEta(buf []byte) { - offset := 0 - for i := 0; i < L; i++ { - PolyUnpackLeqEta(&v[i], buf[offset:]) - offset += PolyLeqEtaSize - } -} - -// Sequentially packs each polynomial using PolyPackLeGamma1(). -func (v *VecL) PackLeGamma1(buf []byte) { - offset := 0 - for i := 0; i < L; i++ { - PolyPackLeGamma1(&v[i], buf[offset:]) - offset += PolyLeGamma1Size - } -} - -// Sets v to the polynomials packed in buf using VecL.PackLeGamma1(). -func (v *VecL) UnpackLeGamma1(buf []byte) { - offset := 0 - for i := 0; i < L; i++ { - PolyUnpackLeGamma1(&v[i], buf[offset:]) - offset += PolyLeGamma1Size - } -} - -// Normalize the polynomials in this vector. -func (v *VecK) Normalize() { - for i := 0; i < K; i++ { - v[i].Normalize() - } -} - -// Normalize the polynomials in this vector assuming their coefficients -// are already bounded by 2q. -func (v *VecK) NormalizeAssumingLe2Q() { - for i := 0; i < K; i++ { - v[i].NormalizeAssumingLe2Q() - } -} - -// Sets v to w + u. Does not normalize. -func (v *VecK) Add(w, u *VecK) { - for i := 0; i < K; i++ { - v[i].Add(&w[i], &u[i]) - } -} - -// Checks whether any of the coefficients exceeds the given bound in supnorm -// -// Requires the vector to be normalized. -func (v *VecK) Exceeds(bound uint32) bool { - for i := 0; i < K; i++ { - if v[i].Exceeds(bound) { - return true - } - } - return false -} - -// Applies Poly.Power2Round componentwise. -// -// Requires the vector to be normalized. -func (v *VecK) Power2Round(v0PlusQ, v1 *VecK) { - for i := 0; i < K; i++ { - v[i].Power2Round(&v0PlusQ[i], &v1[i]) - } -} - -// Applies Poly.Decompose componentwise. -// -// Requires the vector to be normalized. -func (v *VecK) Decompose(v0PlusQ, v1 *VecK) { - for i := 0; i < K; i++ { - PolyDecompose(&v[i], &v0PlusQ[i], &v1[i]) - } -} - -// Sets v to the hint vector for v0 the modified low bits and v1 -// the unmodified high bits --- see makeHint(). -// -// Returns the number of ones in the hint vector. -func (v *VecK) MakeHint(v0, v1 *VecK) (pop uint32) { - for i := 0; i < K; i++ { - pop += PolyMakeHint(&v[i], &v0[i], &v1[i]) - } - return -} - -// Computes corrections to the high bits of the polynomials in the vector -// w using the hints in h and sets v to the corrected high bits. Returns v. -// See useHint(). -func (v *VecK) UseHint(q, hint *VecK) *VecK { - for i := 0; i < K; i++ { - PolyUseHint(&v[i], &q[i], &hint[i]) - } - return v -} - -// Sequentially packs each polynomial using Poly.PackT1(). -func (v *VecK) PackT1(buf []byte) { - offset := 0 - for i := 0; i < K; i++ { - v[i].PackT1(buf[offset:]) - offset += common.PolyT1Size - } -} - -// Sets v to the vector packed into buf by PackT1(). -func (v *VecK) UnpackT1(buf []byte) { - offset := 0 - for i := 0; i < K; i++ { - v[i].UnpackT1(buf[offset:]) - offset += common.PolyT1Size - } -} - -// Sequentially packs each polynomial using Poly.PackT0(). -func (v *VecK) PackT0(buf []byte) { - offset := 0 - for i := 0; i < K; i++ { - v[i].PackT0(buf[offset:]) - offset += common.PolyT0Size - } -} - -// Sets v to the vector packed into buf by PackT0(). -func (v *VecK) UnpackT0(buf []byte) { - offset := 0 - for i := 0; i < K; i++ { - v[i].UnpackT0(buf[offset:]) - offset += common.PolyT0Size - } -} - -// Sequentially packs each polynomial using Poly.PackLeqEta(). -func (v *VecK) PackLeqEta(buf []byte) { - offset := 0 - for i := 0; i < K; i++ { - PolyPackLeqEta(&v[i], buf[offset:]) - offset += PolyLeqEtaSize - } -} - -// Sets v to the polynomials packed in buf using VecK.PackLeqEta(). -func (v *VecK) UnpackLeqEta(buf []byte) { - offset := 0 - for i := 0; i < K; i++ { - PolyUnpackLeqEta(&v[i], buf[offset:]) - offset += PolyLeqEtaSize - } -} - -// Applies NTT componentwise. See Poly.NTT() for details. -func (v *VecK) NTT() { - for i := 0; i < K; i++ { - v[i].NTT() - } -} - -// Sequentially packs each polynomial using PolyPackW1(). -func (v *VecK) PackW1(buf []byte) { - offset := 0 - for i := 0; i < K; i++ { - PolyPackW1(&v[i], buf[offset:]) - offset += PolyW1Size - } -} - -// Sets v to a - b. -// -// Warning: assumes coefficients of the polynomials of b are less than 2q. -func (v *VecK) Sub(a, b *VecK) { - for i := 0; i < K; i++ { - v[i].Sub(&a[i], &b[i]) - } -} - -// Sets v to 2ᵈ w without reducing. -func (v *VecK) MulBy2toD(w *VecK) { - for i := 0; i < K; i++ { - v[i].MulBy2toD(&w[i]) - } -} - -// Applies InvNTT componentwise. See Poly.InvNTT() for details. -func (v *VecK) InvNTT() { - for i := 0; i < K; i++ { - v[i].InvNTT() - } -} - -// Applies Poly.ReduceLe2Q() componentwise. -func (v *VecK) ReduceLe2Q() { - for i := 0; i < K; i++ { - v[i].ReduceLe2Q() - } -} diff --git a/sign/dilithium/mode3.go b/sign/dilithium/mode3.go deleted file mode 100644 index 7726023f2..000000000 --- a/sign/dilithium/mode3.go +++ /dev/null @@ -1,90 +0,0 @@ -// Code generated from mode.templ.go. DO NOT EDIT. - -package dilithium - -import ( - "fmt" - "io" - - "github.com/cloudflare/circl/sign/dilithium/mode3" - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// implMode3 implements the mode.Mode interface for Dilithium3. -type implMode3 struct{} - -// Mode3 is Dilithium in mode "Dilithium3". -var Mode3 Mode = &implMode3{} - -func (m *implMode3) GenerateKey(rand io.Reader) ( - PublicKey, PrivateKey, error) { - return mode3.GenerateKey(rand) -} - -func (m *implMode3) NewKeyFromSeed(seed []byte) (PublicKey, - PrivateKey) { - if len(seed) != common.SeedSize { - panic(fmt.Sprintf("seed must be of length %d", common.SeedSize)) - } - seedBuf := [common.SeedSize]byte{} - copy(seedBuf[:], seed) - return mode3.NewKeyFromSeed(&seedBuf) -} - -func (m *implMode3) Sign(sk PrivateKey, msg []byte) []byte { - isk := sk.(*mode3.PrivateKey) - ret := [mode3.SignatureSize]byte{} - mode3.SignTo(isk, msg, ret[:]) - return ret[:] -} - -func (m *implMode3) Verify(pk PublicKey, msg []byte, signature []byte) bool { - ipk := pk.(*mode3.PublicKey) - return mode3.Verify(ipk, msg, signature) -} - -func (m *implMode3) PublicKeyFromBytes(data []byte) PublicKey { - var ret mode3.PublicKey - if len(data) != mode3.PublicKeySize { - panic("packed public key must be of mode3.PublicKeySize bytes") - } - var buf [mode3.PublicKeySize]byte - copy(buf[:], data) - ret.Unpack(&buf) - return &ret -} - -func (m *implMode3) PrivateKeyFromBytes(data []byte) PrivateKey { - var ret mode3.PrivateKey - if len(data) != mode3.PrivateKeySize { - panic("packed private key must be of mode3.PrivateKeySize bytes") - } - var buf [mode3.PrivateKeySize]byte - copy(buf[:], data) - ret.Unpack(&buf) - return &ret -} - -func (m *implMode3) SeedSize() int { - return common.SeedSize -} - -func (m *implMode3) PublicKeySize() int { - return mode3.PublicKeySize -} - -func (m *implMode3) PrivateKeySize() int { - return mode3.PrivateKeySize -} - -func (m *implMode3) SignatureSize() int { - return mode3.SignatureSize -} - -func (m *implMode3) Name() string { - return "Dilithium3" -} - -func init() { - modes["Dilithium3"] = Mode3 -} diff --git a/sign/dilithium/mode3/dilithium.go b/sign/dilithium/mode3/dilithium.go index de98b5dd2..2e93e9c50 100644 --- a/sign/dilithium/mode3/dilithium.go +++ b/sign/dilithium/mode3/dilithium.go @@ -1,11 +1,9 @@ -// Code generated from modePkg.templ.go. DO NOT EDIT. - +// Code generated from pkg.templ.go. DO NOT EDIT. // mode3 implements the CRYSTALS-Dilithium signature scheme Dilithium3 // as submitted to round3 of the NIST PQC competition and described in // // https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf - package mode3 import ( @@ -13,10 +11,9 @@ import ( "errors" "io" - common "github.com/cloudflare/circl/sign/internal/dilithium" - + "github.com/cloudflare/circl/sign" "github.com/cloudflare/circl/sign/dilithium/mode3/internal" - + common "github.com/cloudflare/circl/sign/internal/dilithium" ) const ( @@ -54,20 +51,27 @@ func NewKeyFromSeed(seed *[SeedSize]byte) (*PublicKey, *PrivateKey) { // SignTo signs the given message and writes the signature into signature. // It will panic if signature is not of length at least SignatureSize. -func SignTo(sk *PrivateKey, msg []byte, signature []byte) { +func SignTo(sk *PrivateKey, msg, sig []byte) { + var rnd [32]byte + internal.SignTo( (*internal.PrivateKey)(sk), - msg, - signature, + func(w io.Writer) { + w.Write(msg) + }, + rnd, + sig, ) } // Verify checks whether the given signature by pk on msg is valid. -func Verify(pk *PublicKey, msg []byte, signature []byte) bool { +func Verify(pk *PublicKey, msg, sig []byte) bool { return internal.Verify( (*internal.PublicKey)(pk), - msg, - signature, + func(w io.Writer) { + _, _ = w.Write(msg) + }, + sig, ) } @@ -147,15 +151,15 @@ func (sk *PrivateKey) UnmarshalBinary(data []byte) error { // interface. The package-level SignTo function might be more convenient // to use. func (sk *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ( - signature []byte, err error) { - var sig [SignatureSize]byte + sig []byte, err error) { + var ret [SignatureSize]byte if opts.HashFunc() != crypto.Hash(0) { return nil, errors.New("dilithium: cannot sign hashed message") } + SignTo(sk, msg, ret[:]) - SignTo(sk, msg, sig[:]) - return sig[:], nil + return ret[:], nil } // Computes the public key corresponding to this private key. @@ -183,3 +187,109 @@ func (pk *PublicKey) Equal(other crypto.PublicKey) bool { } return (*internal.PublicKey)(pk).Equal((*internal.PublicKey)(castOther)) } + +// Boilerplate for generic signatures API + +type scheme struct{} + +var sch sign.Scheme = &scheme{} + +// Scheme returns a generic signature interface for Dilithium3. +func Scheme() sign.Scheme { return sch } + +func (*scheme) Name() string { return "Dilithium3" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SignatureSize() int { return SignatureSize } +func (*scheme) SeedSize() int { return SeedSize } + +// TODO TLSIdentifier() and OID() + +func (*scheme) SupportsContext() bool { + return false +} + +func (*scheme) GenerateKey() (sign.PublicKey, sign.PrivateKey, error) { + return GenerateKey(nil) +} + +func (*scheme) Sign( + sk sign.PrivateKey, + msg []byte, + opts *sign.SignatureOpts, +) []byte { + sig := make([]byte, SignatureSize) + + priv, ok := sk.(*PrivateKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + panic(sign.ErrContextNotSupported) + } + SignTo(priv, msg, sig) + + return sig +} + +func (*scheme) Verify( + pk sign.PublicKey, + msg, sig []byte, + opts *sign.SignatureOpts, +) bool { + pub, ok := pk.(*PublicKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + panic(sign.ErrContextNotSupported) + } + return Verify(pub, msg, sig) +} + +func (*scheme) DeriveKey(seed []byte) (sign.PublicKey, sign.PrivateKey) { + if len(seed) != SeedSize { + panic(sign.ErrSeedSize) + } + var seed2 [SeedSize]byte + copy(seed2[:], seed) + return NewKeyFromSeed(&seed2) +} + +func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (sign.PublicKey, error) { + if len(buf) != PublicKeySize { + return nil, sign.ErrPubKeySize + } + + var ( + buf2 [PublicKeySize]byte + ret PublicKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (sign.PrivateKey, error) { + if len(buf) != PrivateKeySize { + return nil, sign.ErrPrivKeySize + } + + var ( + buf2 [PrivateKeySize]byte + ret PrivateKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (sk *PrivateKey) Scheme() sign.Scheme { + return sch +} + +func (sk *PublicKey) Scheme() sign.Scheme { + return sch +} diff --git a/sign/dilithium/mode3/internal/dilithium.go b/sign/dilithium/mode3/internal/dilithium.go index da4ec6262..63f53a966 100644 --- a/sign/dilithium/mode3/internal/dilithium.go +++ b/sign/dilithium/mode3/internal/dilithium.go @@ -242,7 +242,10 @@ func (sk *PrivateKey) computeT0andT1(t0, t1 *VecK) { } // Verify checks whether the given signature by pk on msg is valid. -func Verify(pk *PublicKey, msg []byte, signature []byte) bool { +// +// For Dilithium this is the top-level verification function. +// In ML-DSA, this is ML-DSA.Verify_internal. +func Verify(pk *PublicKey, msg func(io.Writer), signature []byte) bool { var sig unpackedSignature var mu [64]byte var zh VecL @@ -260,7 +263,7 @@ func Verify(pk *PublicKey, msg []byte, signature []byte) bool { // μ = CRH(tr ‖ msg) h := sha3.NewShake256() _, _ = h.Write(pk.tr[:]) - _, _ = h.Write(msg) + msg(&h) _, _ = h.Read(mu[:]) // Compute Az @@ -277,7 +280,7 @@ func Verify(pk *PublicKey, msg []byte, signature []byte) bool { // which is small enough for NTT(). Az2dct1.MulBy2toD(&pk.t1) Az2dct1.NTT() - PolyDeriveUniformBall(&ch, sig.c[:32]) + PolyDeriveUniformBall(&ch, sig.c[:]) ch.NTT() for i := 0; i < K; i++ { Az2dct1[i].MulHat(&Az2dct1[i], &ch) @@ -305,8 +308,11 @@ func Verify(pk *PublicKey, msg []byte, signature []byte) bool { // SignTo signs the given message and writes the signature into signature. // +// For Dilithium this is the top-level signing function. For ML-DSA +// this is ML-DSA.Sign_internal. +// //nolint:funlen -func SignTo(sk *PrivateKey, msg []byte, signature []byte) { +func SignTo(sk *PrivateKey, msg func(io.Writer), rnd [32]byte, signature []byte) { var mu, rhop [64]byte var w1Packed [PolyW1Size * K]byte var y, yh VecL @@ -322,16 +328,14 @@ func SignTo(sk *PrivateKey, msg []byte, signature []byte) { // μ = CRH(tr ‖ msg) h := sha3.NewShake256() _, _ = h.Write(sk.tr[:]) - _, _ = h.Write(msg) + msg(&h) _, _ = h.Read(mu[:]) // ρ' = CRH(key ‖ μ) h.Reset() _, _ = h.Write(sk.key[:]) if NIST { - // We implement the deterministic variant where rnd is all zeroes. - // TODO expose randomized variant? - _, _ = h.Write(make([]byte, 32)) + _, _ = h.Write(rnd[:]) } _, _ = h.Write(mu[:]) _, _ = h.Read(rhop[:]) @@ -371,7 +375,7 @@ func SignTo(sk *PrivateKey, msg []byte, signature []byte) { _, _ = h.Write(w1Packed[:]) _, _ = h.Read(sig.c[:]) - PolyDeriveUniformBall(&ch, sig.c[:32]) + PolyDeriveUniformBall(&ch, sig.c[:]) ch.NTT() // Ensure ‖ w₀ - c·s2 ‖_∞ < γ₂ - β. diff --git a/sign/dilithium/mode3/internal/dilithium_test.go b/sign/dilithium/mode3/internal/dilithium_test.go index 9707772be..a3f1126dd 100644 --- a/sign/dilithium/mode3/internal/dilithium_test.go +++ b/sign/dilithium/mode3/internal/dilithium_test.go @@ -2,6 +2,7 @@ package internal import ( "encoding/binary" + "io" "testing" common "github.com/cloudflare/circl/sign/internal/dilithium" @@ -34,32 +35,38 @@ func BenchmarkVerify(b *testing.B) { // Note that the expansion of the matrix A is done at Unpacking/Keygen // instead of at the moment of verification (as in the reference // implementation.) - var seed [32]byte - var msg [8]byte - var sig [SignatureSize]byte + var ( + seed [32]byte + msg [8]byte + sig [SignatureSize]byte + rnd [32]byte + ) pk, sk := NewKeyFromSeed(&seed) - SignTo(sk, msg[:], sig[:]) + SignTo(sk, func(w io.Writer) { _, _ = w.Write(msg[:]) }, rnd, sig[:]) b.ResetTimer() for i := 0; i < b.N; i++ { // We should generate a new signature for every verify attempt, // as this influences the time a little bit. This difference, however, // is small and generating a new signature in between creates a lot // pressure on the allocator which makes an accurate measurement hard. - Verify(pk, msg[:], sig[:]) + Verify(pk, func(w io.Writer) { _, _ = w.Write(msg[:]) }, sig[:]) } } func BenchmarkSign(b *testing.B) { // Note that the expansion of the matrix A is done at Unpacking/Keygen // instead of at the moment of signing (as in the reference implementation.) - var seed [32]byte - var msg [8]byte - var sig [SignatureSize]byte + var ( + seed [32]byte + msg [8]byte + sig [SignatureSize]byte + rnd [32]byte + ) _, sk := NewKeyFromSeed(&seed) b.ResetTimer() for i := 0; i < b.N; i++ { binary.LittleEndian.PutUint64(msg[:], uint64(i)) - SignTo(sk, msg[:], sig[:]) + SignTo(sk, func(w io.Writer) { _, _ = w.Write(msg[:]) }, rnd, sig[:]) } } @@ -83,13 +90,16 @@ func BenchmarkPublicFromPrivate(b *testing.B) { } func TestSignThenVerifyAndPkSkPacking(t *testing.T) { - var seed [common.SeedSize]byte - var sig [SignatureSize]byte - var msg [8]byte - var pkb [PublicKeySize]byte - var skb [PrivateKeySize]byte - var pk2 PublicKey - var sk2 PrivateKey + var ( + seed [common.SeedSize]byte + sig [SignatureSize]byte + msg [8]byte + pkb [PublicKeySize]byte + skb [PrivateKeySize]byte + pk2 PublicKey + sk2 PrivateKey + rnd [32]byte + ) for i := uint64(0); i < 100; i++ { binary.LittleEndian.PutUint64(seed[:], i) pk, sk := NewKeyFromSeed(&seed) @@ -98,8 +108,8 @@ func TestSignThenVerifyAndPkSkPacking(t *testing.T) { } for j := uint64(0); j < 10; j++ { binary.LittleEndian.PutUint64(msg[:], j) - SignTo(sk, msg[:], sig[:]) - if !Verify(pk, msg[:], sig[:]) { + SignTo(sk, func(w io.Writer) { _, _ = w.Write(msg[:]) }, rnd, sig[:]) + if !Verify(pk, func(w io.Writer) { _, _ = w.Write(msg[:]) }, sig[:]) { t.Fatal() } } diff --git a/sign/dilithium/mode3/internal/params.go b/sign/dilithium/mode3/internal/params.go index 77452958f..5aa596d15 100644 --- a/sign/dilithium/mode3/internal/params.go +++ b/sign/dilithium/mode3/internal/params.go @@ -4,7 +4,6 @@ package internal const ( Name = "Dilithium3" - UseAES = false K = 6 L = 5 Eta = 4 diff --git a/sign/dilithium/mode3/internal/sample.go b/sign/dilithium/mode3/internal/sample.go index b2b0bbe13..f90d211d8 100644 --- a/sign/dilithium/mode3/internal/sample.go +++ b/sign/dilithium/mode3/internal/sample.go @@ -10,7 +10,7 @@ import ( // DeriveX4Available indicates whether the system supports the quick fourway // sampling variants like PolyDeriveUniformX4. -var DeriveX4Available = keccakf1600.IsEnabledX4() && !UseAES +var DeriveX4Available = keccakf1600.IsEnabledX4() // For each i, sample ps[i] uniformly from the given seed and nonces[i]. // ps[i] may be nil and is ignored in that case. @@ -89,13 +89,9 @@ func PolyDeriveUniformX4(ps [4]*common.Poly, seed *[32]byte, nonces [4]uint16) { // p will be normalized. func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { var i, length int - var buf [12 * 16]byte // fits 168B SHAKE-128 rate and 12 16B AES blocks + var buf [12 * 16]byte // fits 168B SHAKE-128 rate - if UseAES { - length = 12 * 16 - } else { - length = 168 - } + length = 168 sample := func() { // Note that 3 divides into 168 and 12*16, so we use up buf completely. @@ -111,25 +107,16 @@ func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { } } - if UseAES { - h := common.NewAesStream128(seed, nonce) + var iv [32 + 2]byte // 32 byte seed + uint16 nonce + h := sha3.NewShake128() + copy(iv[:32], seed[:]) + iv[32] = uint8(nonce) + iv[33] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) - for i < common.N { - h.SqueezeInto(buf[:length]) - sample() - } - } else { - var iv [32 + 2]byte // 32 byte seed + uint16 nonce - h := sha3.NewShake128() - copy(iv[:32], seed[:]) - iv[32] = uint8(nonce) - iv[33] = uint8(nonce >> 8) - _, _ = h.Write(iv[:]) - - for i < common.N { - _, _ = h.Read(buf[:168]) - sample() - } + for i < common.N { + _, _ = h.Read(buf[:168]) + sample() } } @@ -140,13 +127,9 @@ func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { func PolyDeriveUniformLeqEta(p *common.Poly, seed *[64]byte, nonce uint16) { // Assumes 2 < η < 8. var i, length int - var buf [9 * 16]byte // fits 136B SHAKE-256 rate and 9 16B AES blocks + var buf [9 * 16]byte // fits 136B SHAKE-256 rate - if UseAES { - length = 9 * 16 - } else { - length = 136 - } + length = 136 sample := func() { // We use rejection sampling @@ -179,28 +162,19 @@ func PolyDeriveUniformLeqEta(p *common.Poly, seed *[64]byte, nonce uint16) { } } - if UseAES { - h := common.NewAesStream256(seed, nonce) - - for i < common.N { - h.SqueezeInto(buf[:length]) - sample() - } - } else { - var iv [64 + 2]byte // 64 byte seed + uint16 nonce + var iv [64 + 2]byte // 64 byte seed + uint16 nonce - h := sha3.NewShake256() - copy(iv[:64], seed[:]) - iv[64] = uint8(nonce) - iv[65] = uint8(nonce >> 8) + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) - // 136 is SHAKE-256 rate - _, _ = h.Write(iv[:]) + // 136 is SHAKE-256 rate + _, _ = h.Write(iv[:]) - for i < common.N { - _, _ = h.Read(buf[:136]) - sample() - } + for i < common.N { + _, _ = h.Read(buf[:136]) + sample() } } @@ -221,18 +195,13 @@ func VecLDeriveUniformLeGamma1(v *VecL, seed *[64]byte, nonce uint16) { func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { var buf [PolyLeGamma1Size]byte - if UseAES { - h := common.NewAesStream256(seed, nonce) - h.SqueezeInto(buf[:]) - } else { - var iv [66]byte - h := sha3.NewShake256() - copy(iv[:64], seed[:]) - iv[64] = uint8(nonce) - iv[65] = uint8(nonce >> 8) - _, _ = h.Write(iv[:]) - _, _ = h.Read(buf[:]) - } + var iv [66]byte + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) + _, _ = h.Read(buf[:]) PolyUnpackLeGamma1(p, buf[:]) } @@ -249,7 +218,7 @@ func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed []byte) { state := perm.Initialize(false) // Absorb the seed in the four states - for i := 0; i < 32/8; i++ { + for i := 0; i < CTildeSize/8; i++ { v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) for j := 0; j < 4; j++ { state[i*4+j] = v @@ -258,7 +227,7 @@ func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed []byte) { // SHAKE256 domain separator and padding for j := 0; j < 4; j++ { - state[(32/8)*4+j] ^= 0x1f + state[(CTildeSize/8)*4+j] ^= 0x1f state[16*4+j] ^= 0x80 << 56 } perm.Permute() diff --git a/sign/dilithium/mode3/internal/sample_test.go b/sign/dilithium/mode3/internal/sample_test.go index 1adfaf535..69e56d31a 100644 --- a/sign/dilithium/mode3/internal/sample_test.go +++ b/sign/dilithium/mode3/internal/sample_test.go @@ -10,94 +10,46 @@ import ( func TestVectorDeriveUniform(t *testing.T) { var p, p2 common.Poly var seed [32]byte - if UseAES { - p2 = common.Poly{ - 6724291, 310295, 6949524, 4464039, 1482136, 2522903, - 7025059, 3006320, 7286364, 7516512, 3361305, 1955529, - 4765954, 1725325, 6933066, 4299100, 6625173, 4272792, - 583034, 4971409, 2259140, 7715362, 3975394, 2341624, - 5481174, 8150082, 365246, 5491939, 1083120, 7517301, - 3104783, 2475292, 184149, 6425226, 4591622, 5964030, - 4729604, 5471092, 1828227, 1082044, 2516245, 1692580, - 3274844, 5443294, 7256740, 4989638, 3191250, 7479519, - 5124211, 5603858, 1230692, 2513454, 2828034, 4254312, - 1512596, 5245430, 5517392, 2814840, 932545, 6826733, - 3511094, 4075348, 3233981, 7268882, 2913733, 4870249, - 4123492, 8124406, 4016949, 5478752, 2750895, 603525, - 5724798, 3985430, 3483012, 6434230, 3136996, 8297976, - 4107616, 7307748, 6962904, 7544473, 1193110, 3448595, - 4814773, 5607932, 8221314, 1054046, 1541208, 1866050, - 8227412, 2925778, 5293953, 2065416, 4972769, 3616283, - 7990594, 1105530, 7121836, 1170740, 7417431, 633146, - 253820, 7235019, 3539504, 6807707, 451390, 5481526, - 2859902, 1063061, 4579730, 7126652, 7033767, 4294814, - 1414604, 7620048, 1953268, 8304556, 1156814, 1182881, - 5311519, 3057534, 5277666, 682843, 2070398, 2874278, - 4859533, 6376664, 6694074, 1590242, 2620706, 8331066, - 5643845, 5037538, 2891516, 7004879, 3754327, 5031296, - 5463118, 2420870, 8116529, 5517696, 7435129, 3873963, - 710407, 713806, 175647, 4274571, 2655021, 7319503, - 3027243, 7129679, 4213435, 2429323, 4643873, 4568526, - 649664, 1720514, 6497260, 2683517, 7672754, 7105190, - 3148405, 5898369, 5667677, 8050874, 1587139, 7315260, - 4337416, 2202680, 2338714, 557467, 6752058, 2469794, - 485071, 1617604, 3590498, 2151466, 2005823, 7727956, - 7776292, 6783433, 6787146, 1732833, 3596857, 7436284, - 4483349, 4970142, 4472608, 6478342, 1236215, 5695744, - 2280717, 2889355, 3233946, 5187812, 978685, 5177364, - 2922353, 4824807, 5302883, 6739803, 8092453, 5883903, - 816553, 6041174, 8317591, 1459178, 5332455, 1835058, - 1368601, 2820950, 3479224, 2589540, 7992934, 3421045, - 4657128, 8292902, 4153567, 3553988, 7830320, 6722913, - 2555309, 4149801, 8328975, 1560545, 7757473, 3106458, - 4310856, 7135453, 3481032, 652626, 1841361, 8126828, - 6250018, 300536, 7380070, 8174419, 1418793, 6208185, - 3906256, 6679016, 1605701, 3561489, 5819724, 5746996, - 8044214, 7087187, 7102330, 4962927, 4253983, 7108567, - 4119736, 6584065, 441634, 6941656, - } - } else { - p2 = common.Poly{ - 2901364, 562527, 5258502, 3885002, 4190126, 4460268, 6884052, - 3514511, 5383040, 213206, 2155865, 5179607, 3551954, 2312357, - 6066350, 8126097, 1179080, 4787182, 6552182, 6713644, - 1561067, 7626063, 7859743, 5052321, 7032876, 7815031, 157938, - 1865184, 490802, 5717642, 3451902, 7000218, 3743250, 1677431, - 1875427, 5596150, 671623, 3819041, 6247594, 1014875, 4933545, - 7122446, 6682963, 3388398, 3335295, 943002, 1145083, 3113071, - 105967, 1916675, 7474561, 1107006, 700548, 2147909, 1603855, - 5049181, 437882, 6118899, 5656914, 6731065, 3066622, 865453, - 5427634, 981549, 4650873, 861291, 4003872, 5104220, 6171453, - 3723302, 7426315, 6137283, 4874820, 6052561, 53441, 5032874, - 5614778, 2248550, 1756499, 8280764, 8263880, 7600081, - 5118374, 795344, 7543392, 6869925, 1841187, 4181568, 584562, - 7483939, 4938664, 6863397, 5126354, 5218129, 6236086, - 4149293, 379169, 4368487, 7490569, 3409215, 1580463, 3081737, - 1278732, 7109719, 7371700, 2097931, 399836, 1700274, 7188595, - 6830029, 1548850, 6593138, 6849097, 1518037, 2859442, - 7772265, 7325153, 3281191, 7856131, 4995056, 4684325, - 1351194, 8223904, 6817307, 2484146, 131782, 397032, 7436778, - 7973479, 3171829, 5624626, 3540123, 7150120, 8313283, - 3604714, 1043574, 117692, 7797783, 7909392, 903315, 7335342, - 7501562, 5826142, 2709813, 8245473, 2369045, 2782257, - 5762833, 6474114, 6862031, 424522, 594248, 2626630, 7659983, - 5642869, 4075194, 1592129, 245547, 5271031, 3205046, 982375, - 267873, 1286496, 7230481, 3208972, 7485411, 676111, 4944500, - 2959742, 5934456, 1414847, 6067948, 1709895, 4648315, 126008, - 8258986, 2183134, 2302072, 4674924, 4306056, 7465311, - 6500270, 4247428, 4016815, 4973426, 294287, 2456847, 3289700, - 2732169, 1159447, 5569724, 140001, 3237977, 8007761, 5874533, - 255652, 3119586, 2102434, 6248250, 8152822, 8006066, 7708625, - 6997719, 6260212, 6186962, 6636650, 7836834, 7998017, - 2061516, 1197591, 1706544, 733027, 2392907, 2700000, 8254598, - 4488002, 160495, 2985325, 2036837, 2703633, 6406550, 3579947, - 6195178, 5552390, 6804584, 6305468, 5731980, 6095195, - 3323409, 1322661, 6690942, 3374630, 5615167, 479044, 3136054, - 4380418, 2833144, 7829577, 1770522, 6056687, 240415, 14780, - 3740517, 5224226, 3547288, 2083124, 4699398, 3654239, - 5624978, 585593, 3655369, 2281739, 3338565, 1908093, 7784706, - 4352830, - } + p2 = common.Poly{ + 2901364, 562527, 5258502, 3885002, 4190126, 4460268, 6884052, + 3514511, 5383040, 213206, 2155865, 5179607, 3551954, 2312357, + 6066350, 8126097, 1179080, 4787182, 6552182, 6713644, + 1561067, 7626063, 7859743, 5052321, 7032876, 7815031, 157938, + 1865184, 490802, 5717642, 3451902, 7000218, 3743250, 1677431, + 1875427, 5596150, 671623, 3819041, 6247594, 1014875, 4933545, + 7122446, 6682963, 3388398, 3335295, 943002, 1145083, 3113071, + 105967, 1916675, 7474561, 1107006, 700548, 2147909, 1603855, + 5049181, 437882, 6118899, 5656914, 6731065, 3066622, 865453, + 5427634, 981549, 4650873, 861291, 4003872, 5104220, 6171453, + 3723302, 7426315, 6137283, 4874820, 6052561, 53441, 5032874, + 5614778, 2248550, 1756499, 8280764, 8263880, 7600081, + 5118374, 795344, 7543392, 6869925, 1841187, 4181568, 584562, + 7483939, 4938664, 6863397, 5126354, 5218129, 6236086, + 4149293, 379169, 4368487, 7490569, 3409215, 1580463, 3081737, + 1278732, 7109719, 7371700, 2097931, 399836, 1700274, 7188595, + 6830029, 1548850, 6593138, 6849097, 1518037, 2859442, + 7772265, 7325153, 3281191, 7856131, 4995056, 4684325, + 1351194, 8223904, 6817307, 2484146, 131782, 397032, 7436778, + 7973479, 3171829, 5624626, 3540123, 7150120, 8313283, + 3604714, 1043574, 117692, 7797783, 7909392, 903315, 7335342, + 7501562, 5826142, 2709813, 8245473, 2369045, 2782257, + 5762833, 6474114, 6862031, 424522, 594248, 2626630, 7659983, + 5642869, 4075194, 1592129, 245547, 5271031, 3205046, 982375, + 267873, 1286496, 7230481, 3208972, 7485411, 676111, 4944500, + 2959742, 5934456, 1414847, 6067948, 1709895, 4648315, 126008, + 8258986, 2183134, 2302072, 4674924, 4306056, 7465311, + 6500270, 4247428, 4016815, 4973426, 294287, 2456847, 3289700, + 2732169, 1159447, 5569724, 140001, 3237977, 8007761, 5874533, + 255652, 3119586, 2102434, 6248250, 8152822, 8006066, 7708625, + 6997719, 6260212, 6186962, 6636650, 7836834, 7998017, + 2061516, 1197591, 1706544, 733027, 2392907, 2700000, 8254598, + 4488002, 160495, 2985325, 2036837, 2703633, 6406550, 3579947, + 6195178, 5552390, 6804584, 6305468, 5731980, 6095195, + 3323409, 1322661, 6690942, 3374630, 5615167, 479044, 3136054, + 4380418, 2833144, 7829577, 1770522, 6056687, 240415, 14780, + 3740517, 5224226, 3547288, 2083124, 4699398, 3654239, + 5624978, 585593, 3655369, 2281739, 3338565, 1908093, 7784706, + 4352830, } for i := 0; i < 32; i++ { seed[i] = byte(i) @@ -150,7 +102,7 @@ func TestDeriveUniformLeGamma1(t *testing.T) { func TestDeriveUniformBall(t *testing.T) { var p common.Poly - var seed [32]byte + var seed [CTildeSize]byte for i := 0; i < 100; i++ { binary.LittleEndian.PutUint64(seed[:], uint64(i)) PolyDeriveUniformBall(&p, seed[:]) @@ -198,7 +150,7 @@ func TestDeriveUniformBallX4(t *testing.T) { } var ps [4]common.Poly var p common.Poly - var seed [32]byte + var seed [CTildeSize]byte PolyDeriveUniformBallX4( [4]*common.Poly{&ps[0], &ps[1], &ps[2], &ps[3]}, seed[:], diff --git a/sign/dilithium/mode3aes.go b/sign/dilithium/mode3aes.go deleted file mode 100644 index f7414f15b..000000000 --- a/sign/dilithium/mode3aes.go +++ /dev/null @@ -1,90 +0,0 @@ -// Code generated from mode.templ.go. DO NOT EDIT. - -package dilithium - -import ( - "fmt" - "io" - - "github.com/cloudflare/circl/sign/dilithium/mode3aes" - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// implMode3AES implements the mode.Mode interface for Dilithium3-AES. -type implMode3AES struct{} - -// Mode3AES is Dilithium in mode "Dilithium3-AES". -var Mode3AES Mode = &implMode3AES{} - -func (m *implMode3AES) GenerateKey(rand io.Reader) ( - PublicKey, PrivateKey, error) { - return mode3aes.GenerateKey(rand) -} - -func (m *implMode3AES) NewKeyFromSeed(seed []byte) (PublicKey, - PrivateKey) { - if len(seed) != common.SeedSize { - panic(fmt.Sprintf("seed must be of length %d", common.SeedSize)) - } - seedBuf := [common.SeedSize]byte{} - copy(seedBuf[:], seed) - return mode3aes.NewKeyFromSeed(&seedBuf) -} - -func (m *implMode3AES) Sign(sk PrivateKey, msg []byte) []byte { - isk := sk.(*mode3aes.PrivateKey) - ret := [mode3aes.SignatureSize]byte{} - mode3aes.SignTo(isk, msg, ret[:]) - return ret[:] -} - -func (m *implMode3AES) Verify(pk PublicKey, msg []byte, signature []byte) bool { - ipk := pk.(*mode3aes.PublicKey) - return mode3aes.Verify(ipk, msg, signature) -} - -func (m *implMode3AES) PublicKeyFromBytes(data []byte) PublicKey { - var ret mode3aes.PublicKey - if len(data) != mode3aes.PublicKeySize { - panic("packed public key must be of mode3aes.PublicKeySize bytes") - } - var buf [mode3aes.PublicKeySize]byte - copy(buf[:], data) - ret.Unpack(&buf) - return &ret -} - -func (m *implMode3AES) PrivateKeyFromBytes(data []byte) PrivateKey { - var ret mode3aes.PrivateKey - if len(data) != mode3aes.PrivateKeySize { - panic("packed private key must be of mode3aes.PrivateKeySize bytes") - } - var buf [mode3aes.PrivateKeySize]byte - copy(buf[:], data) - ret.Unpack(&buf) - return &ret -} - -func (m *implMode3AES) SeedSize() int { - return common.SeedSize -} - -func (m *implMode3AES) PublicKeySize() int { - return mode3aes.PublicKeySize -} - -func (m *implMode3AES) PrivateKeySize() int { - return mode3aes.PrivateKeySize -} - -func (m *implMode3AES) SignatureSize() int { - return mode3aes.SignatureSize -} - -func (m *implMode3AES) Name() string { - return "Dilithium3-AES" -} - -func init() { - modes["Dilithium3-AES"] = Mode3AES -} diff --git a/sign/dilithium/mode3aes/dilithium.go b/sign/dilithium/mode3aes/dilithium.go deleted file mode 100644 index 0503f7673..000000000 --- a/sign/dilithium/mode3aes/dilithium.go +++ /dev/null @@ -1,185 +0,0 @@ -// Code generated from modePkg.templ.go. DO NOT EDIT. - - -// mode3aes implements the CRYSTALS-Dilithium signature scheme Dilithium3-AES -// as submitted to round3 of the NIST PQC competition and described in -// -// https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf - -package mode3aes - -import ( - "crypto" - "errors" - "io" - - common "github.com/cloudflare/circl/sign/internal/dilithium" - - "github.com/cloudflare/circl/sign/dilithium/mode3aes/internal" - -) - -const ( - // Size of seed for NewKeyFromSeed - SeedSize = common.SeedSize - - // Size of a packed PublicKey - PublicKeySize = internal.PublicKeySize - - // Size of a packed PrivateKey - PrivateKeySize = internal.PrivateKeySize - - // Size of a signature - SignatureSize = internal.SignatureSize -) - -// PublicKey is the type of Dilithium3-AES public key -type PublicKey internal.PublicKey - -// PrivateKey is the type of Dilithium3-AES private key -type PrivateKey internal.PrivateKey - -// GenerateKey generates a public/private key pair using entropy from rand. -// If rand is nil, crypto/rand.Reader will be used. -func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { - pk, sk, err := internal.GenerateKey(rand) - return (*PublicKey)(pk), (*PrivateKey)(sk), err -} - -// NewKeyFromSeed derives a public/private key pair using the given seed. -func NewKeyFromSeed(seed *[SeedSize]byte) (*PublicKey, *PrivateKey) { - pk, sk := internal.NewKeyFromSeed(seed) - return (*PublicKey)(pk), (*PrivateKey)(sk) -} - -// SignTo signs the given message and writes the signature into signature. -// It will panic if signature is not of length at least SignatureSize. -func SignTo(sk *PrivateKey, msg []byte, signature []byte) { - internal.SignTo( - (*internal.PrivateKey)(sk), - msg, - signature, - ) -} - -// Verify checks whether the given signature by pk on msg is valid. -func Verify(pk *PublicKey, msg []byte, signature []byte) bool { - return internal.Verify( - (*internal.PublicKey)(pk), - msg, - signature, - ) -} - -// Sets pk to the public key encoded in buf. -func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { - (*internal.PublicKey)(pk).Unpack(buf) -} - -// Sets sk to the private key encoded in buf. -func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { - (*internal.PrivateKey)(sk).Unpack(buf) -} - -// Packs the public key into buf. -func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) { - (*internal.PublicKey)(pk).Pack(buf) -} - -// Packs the private key into buf. -func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { - (*internal.PrivateKey)(sk).Pack(buf) -} - -// Packs the public key. -func (pk *PublicKey) Bytes() []byte { - var buf [PublicKeySize]byte - pk.Pack(&buf) - return buf[:] -} - -// Packs the private key. -func (sk *PrivateKey) Bytes() []byte { - var buf [PrivateKeySize]byte - sk.Pack(&buf) - return buf[:] -} - -// Packs the public key. -func (pk *PublicKey) MarshalBinary() ([]byte, error) { - return pk.Bytes(), nil -} - -// Packs the private key. -func (sk *PrivateKey) MarshalBinary() ([]byte, error) { - return sk.Bytes(), nil -} - -// Unpacks the public key from data. -func (pk *PublicKey) UnmarshalBinary(data []byte) error { - if len(data) != PublicKeySize { - return errors.New("packed public key must be of mode3aes.PublicKeySize bytes") - } - var buf [PublicKeySize]byte - copy(buf[:], data) - pk.Unpack(&buf) - return nil -} - -// Unpacks the private key from data. -func (sk *PrivateKey) UnmarshalBinary(data []byte) error { - if len(data) != PrivateKeySize { - return errors.New("packed private key must be of mode3aes.PrivateKeySize bytes") - } - var buf [PrivateKeySize]byte - copy(buf[:], data) - sk.Unpack(&buf) - return nil -} - -// Sign signs the given message. -// -// opts.HashFunc() must return zero, which can be achieved by passing -// crypto.Hash(0) for opts. rand is ignored. Will only return an error -// if opts.HashFunc() is non-zero. -// -// This function is used to make PrivateKey implement the crypto.Signer -// interface. The package-level SignTo function might be more convenient -// to use. -func (sk *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ( - signature []byte, err error) { - var sig [SignatureSize]byte - - if opts.HashFunc() != crypto.Hash(0) { - return nil, errors.New("dilithium: cannot sign hashed message") - } - - SignTo(sk, msg, sig[:]) - return sig[:], nil -} - -// Computes the public key corresponding to this private key. -// -// Returns a *PublicKey. The type crypto.PublicKey is used to make -// PrivateKey implement the crypto.Signer interface. -func (sk *PrivateKey) Public() crypto.PublicKey { - return (*PublicKey)((*internal.PrivateKey)(sk).Public()) -} - -// Equal returns whether the two private keys equal. -func (sk *PrivateKey) Equal(other crypto.PrivateKey) bool { - castOther, ok := other.(*PrivateKey) - if !ok { - return false - } - return (*internal.PrivateKey)(sk).Equal((*internal.PrivateKey)(castOther)) -} - -// Equal returns whether the two public keys equal. -func (pk *PublicKey) Equal(other crypto.PublicKey) bool { - castOther, ok := other.(*PublicKey) - if !ok { - return false - } - return (*internal.PublicKey)(pk).Equal((*internal.PublicKey)(castOther)) -} diff --git a/sign/dilithium/mode3aes/internal/dilithium.go b/sign/dilithium/mode3aes/internal/dilithium.go deleted file mode 100644 index 7869d0475..000000000 --- a/sign/dilithium/mode3aes/internal/dilithium.go +++ /dev/null @@ -1,482 +0,0 @@ -// Code generated from mode3/internal/dilithium.go by gen.go - -package internal - -import ( - cryptoRand "crypto/rand" - "crypto/subtle" - "io" - - "github.com/cloudflare/circl/internal/sha3" - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -const ( - // Size of a packed polynomial of norm ≤η. - // (Note that the formula is not valid in general.) - PolyLeqEtaSize = (common.N * DoubleEtaBits) / 8 - - // β = τη, the maximum size of c s₂. - Beta = Tau * Eta - - // γ₁ range of y - Gamma1 = 1 << Gamma1Bits - - // Size of packed polynomial of norm <γ₁ such as z - PolyLeGamma1Size = (Gamma1Bits + 1) * common.N / 8 - - // α = 2γ₂ parameter for decompose - Alpha = 2 * Gamma2 - - // Size of a packed private key - PrivateKeySize = 32 + 32 + TRSize + PolyLeqEtaSize*(L+K) + common.PolyT0Size*K - - // Size of a packed public key - PublicKeySize = 32 + common.PolyT1Size*K - - // Size of a packed signature - SignatureSize = L*PolyLeGamma1Size + Omega + K + CTildeSize - - // Size of packed w₁ - PolyW1Size = (common.N * (common.QBits - Gamma1Bits)) / 8 -) - -// PublicKey is the type of Dilithium public keys. -type PublicKey struct { - rho [32]byte - t1 VecK - - // Cached values - t1p [common.PolyT1Size * K]byte - A *Mat - tr *[TRSize]byte -} - -// PrivateKey is the type of Dilithium private keys. -type PrivateKey struct { - rho [32]byte - key [32]byte - s1 VecL - s2 VecK - t0 VecK - tr [TRSize]byte - - // Cached values - A Mat // ExpandA(ρ) - s1h VecL // NTT(s₁) - s2h VecK // NTT(s₂) - t0h VecK // NTT(t₀) -} - -type unpackedSignature struct { - z VecL - hint VecK - c [CTildeSize]byte -} - -// Packs the signature into buf. -func (sig *unpackedSignature) Pack(buf []byte) { - copy(buf[:], sig.c[:]) - sig.z.PackLeGamma1(buf[CTildeSize:]) - sig.hint.PackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) -} - -// Sets sig to the signature encoded in the buffer. -// -// Returns whether buf contains a properly packed signature. -func (sig *unpackedSignature) Unpack(buf []byte) bool { - if len(buf) < SignatureSize { - return false - } - copy(sig.c[:], buf[:]) - sig.z.UnpackLeGamma1(buf[CTildeSize:]) - if sig.z.Exceeds(Gamma1 - Beta) { - return false - } - if !sig.hint.UnpackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) { - return false - } - return true -} - -// Packs the public key into buf. -func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) { - copy(buf[:32], pk.rho[:]) - copy(buf[32:], pk.t1p[:]) -} - -// Sets pk to the public key encoded in buf. -func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { - copy(pk.rho[:], buf[:32]) - copy(pk.t1p[:], buf[32:]) - - pk.t1.UnpackT1(pk.t1p[:]) - pk.A = new(Mat) - pk.A.Derive(&pk.rho) - - // tr = CRH(ρ ‖ t1) = CRH(pk) - pk.tr = new([TRSize]byte) - h := sha3.NewShake256() - _, _ = h.Write(buf[:]) - _, _ = h.Read(pk.tr[:]) -} - -// Packs the private key into buf. -func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { - copy(buf[:32], sk.rho[:]) - copy(buf[32:64], sk.key[:]) - copy(buf[64:64+TRSize], sk.tr[:]) - offset := 64 + TRSize - sk.s1.PackLeqEta(buf[offset:]) - offset += PolyLeqEtaSize * L - sk.s2.PackLeqEta(buf[offset:]) - offset += PolyLeqEtaSize * K - sk.t0.PackT0(buf[offset:]) -} - -// Sets sk to the private key encoded in buf. -func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { - copy(sk.rho[:], buf[:32]) - copy(sk.key[:], buf[32:64]) - copy(sk.tr[:], buf[64:64+TRSize]) - offset := 64 + TRSize - sk.s1.UnpackLeqEta(buf[offset:]) - offset += PolyLeqEtaSize * L - sk.s2.UnpackLeqEta(buf[offset:]) - offset += PolyLeqEtaSize * K - sk.t0.UnpackT0(buf[offset:]) - - // Cached values - sk.A.Derive(&sk.rho) - sk.t0h = sk.t0 - sk.t0h.NTT() - sk.s1h = sk.s1 - sk.s1h.NTT() - sk.s2h = sk.s2 - sk.s2h.NTT() -} - -// GenerateKey generates a public/private key pair using entropy from rand. -// If rand is nil, crypto/rand.Reader will be used. -func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { - var seed [32]byte - if rand == nil { - rand = cryptoRand.Reader - } - _, err := io.ReadFull(rand, seed[:]) - if err != nil { - return nil, nil, err - } - pk, sk := NewKeyFromSeed(&seed) - return pk, sk, nil -} - -// NewKeyFromSeed derives a public/private key pair using the given seed. -func NewKeyFromSeed(seed *[common.SeedSize]byte) (*PublicKey, *PrivateKey) { - var eSeed [128]byte // expanded seed - var pk PublicKey - var sk PrivateKey - var sSeed [64]byte - - h := sha3.NewShake256() - _, _ = h.Write(seed[:]) - _, _ = h.Read(eSeed[:]) - - copy(pk.rho[:], eSeed[:32]) - copy(sSeed[:], eSeed[32:96]) - copy(sk.key[:], eSeed[96:]) - copy(sk.rho[:], pk.rho[:]) - - sk.A.Derive(&pk.rho) - - for i := uint16(0); i < L; i++ { - PolyDeriveUniformLeqEta(&sk.s1[i], &sSeed, i) - } - - for i := uint16(0); i < K; i++ { - PolyDeriveUniformLeqEta(&sk.s2[i], &sSeed, i+L) - } - - sk.s1h = sk.s1 - sk.s1h.NTT() - sk.s2h = sk.s2 - sk.s2h.NTT() - - sk.computeT0andT1(&sk.t0, &pk.t1) - - sk.t0h = sk.t0 - sk.t0h.NTT() - - // Complete public key far enough to be packed - pk.t1.PackT1(pk.t1p[:]) - pk.A = &sk.A - - // Finish private key - var packedPk [PublicKeySize]byte - pk.Pack(&packedPk) - - // tr = CRH(ρ ‖ t1) = CRH(pk) - h.Reset() - _, _ = h.Write(packedPk[:]) - _, _ = h.Read(sk.tr[:]) - - // Finish cache of public key - pk.tr = &sk.tr - - return &pk, &sk -} - -// Computes t0 and t1 from sk.s1h, sk.s2 and sk.A. -func (sk *PrivateKey) computeT0andT1(t0, t1 *VecK) { - var t VecK - - // Set t to A s₁ + s₂ - for i := 0; i < K; i++ { - PolyDotHat(&t[i], &sk.A[i], &sk.s1h) - t[i].ReduceLe2Q() - t[i].InvNTT() - } - t.Add(&t, &sk.s2) - t.Normalize() - - // Compute t₀, t₁ = Power2Round(t) - t.Power2Round(t0, t1) -} - -// Verify checks whether the given signature by pk on msg is valid. -func Verify(pk *PublicKey, msg []byte, signature []byte) bool { - var sig unpackedSignature - var mu [64]byte - var zh VecL - var Az, Az2dct1, w1 VecK - var ch common.Poly - var cp [CTildeSize]byte - var w1Packed [PolyW1Size * K]byte - - // Note that Unpack() checked whether ‖z‖_∞ < γ₁ - β - // and ensured that there at most ω ones in pk.hint. - if !sig.Unpack(signature) { - return false - } - - // μ = CRH(tr ‖ msg) - h := sha3.NewShake256() - _, _ = h.Write(pk.tr[:]) - _, _ = h.Write(msg) - _, _ = h.Read(mu[:]) - - // Compute Az - zh = sig.z - zh.NTT() - - for i := 0; i < K; i++ { - PolyDotHat(&Az[i], &pk.A[i], &zh) - } - - // Next, we compute Az - 2ᵈ·c·t₁. - // Note that the coefficients of t₁ are bounded by 256 = 2⁹, - // so the coefficients of Az2dct1 will bounded by 2⁹⁺ᵈ = 2²³ < 2q, - // which is small enough for NTT(). - Az2dct1.MulBy2toD(&pk.t1) - Az2dct1.NTT() - PolyDeriveUniformBall(&ch, sig.c[:32]) - ch.NTT() - for i := 0; i < K; i++ { - Az2dct1[i].MulHat(&Az2dct1[i], &ch) - } - Az2dct1.Sub(&Az, &Az2dct1) - Az2dct1.ReduceLe2Q() - Az2dct1.InvNTT() - Az2dct1.NormalizeAssumingLe2Q() - - // UseHint(pk.hint, Az - 2ᵈ·c·t₁) - // = UseHint(pk.hint, w - c·s₂ + c·t₀) - // = UseHint(pk.hint, r + c·t₀) - // = r₁ = w₁. - w1.UseHint(&Az2dct1, &sig.hint) - w1.PackW1(w1Packed[:]) - - // c' = H(μ, w₁) - h.Reset() - _, _ = h.Write(mu[:]) - _, _ = h.Write(w1Packed[:]) - _, _ = h.Read(cp[:]) - - return sig.c == cp -} - -// SignTo signs the given message and writes the signature into signature. -// -//nolint:funlen -func SignTo(sk *PrivateKey, msg []byte, signature []byte) { - var mu, rhop [64]byte - var w1Packed [PolyW1Size * K]byte - var y, yh VecL - var w, w0, w1, w0mcs2, ct0, w0mcs2pct0 VecK - var ch common.Poly - var yNonce uint16 - var sig unpackedSignature - - if len(signature) < SignatureSize { - panic("Signature does not fit in that byteslice") - } - - // μ = CRH(tr ‖ msg) - h := sha3.NewShake256() - _, _ = h.Write(sk.tr[:]) - _, _ = h.Write(msg) - _, _ = h.Read(mu[:]) - - // ρ' = CRH(key ‖ μ) - h.Reset() - _, _ = h.Write(sk.key[:]) - if NIST { - // We implement the deterministic variant where rnd is all zeroes. - // TODO expose randomized variant? - _, _ = h.Write(make([]byte, 32)) - } - _, _ = h.Write(mu[:]) - _, _ = h.Read(rhop[:]) - - // Main rejection loop - attempt := 0 - for { - attempt++ - if attempt >= 576 { - // Depending on the mode, one try has a chance between 1/7 and 1/4 - // of succeeding. Thus it is safe to say that 576 iterations - // are enough as (6/7)⁵⁷⁶ < 2⁻¹²⁸. - panic("This should only happen 1 in 2^{128}: something is wrong.") - } - - // y = ExpandMask(ρ', key) - VecLDeriveUniformLeGamma1(&y, &rhop, yNonce) - yNonce += uint16(L) - - // Set w to A y - yh = y - yh.NTT() - for i := 0; i < K; i++ { - PolyDotHat(&w[i], &sk.A[i], &yh) - w[i].ReduceLe2Q() - w[i].InvNTT() - } - - // Decompose w into w₀ and w₁ - w.NormalizeAssumingLe2Q() - w.Decompose(&w0, &w1) - - // c~ = H(μ ‖ w₁) - w1.PackW1(w1Packed[:]) - h.Reset() - _, _ = h.Write(mu[:]) - _, _ = h.Write(w1Packed[:]) - _, _ = h.Read(sig.c[:]) - - PolyDeriveUniformBall(&ch, sig.c[:32]) - ch.NTT() - - // Ensure ‖ w₀ - c·s2 ‖_∞ < γ₂ - β. - // - // By Lemma 3 of the specification this is equivalent to checking that - // both ‖ r₀ ‖_∞ < γ₂ - β and r₁ = w₁, for the decomposition - // w - c·s₂ = r₁ α + r₀ as computed by decompose(). - // See also §4.1 of the specification. - for i := 0; i < K; i++ { - w0mcs2[i].MulHat(&ch, &sk.s2h[i]) - w0mcs2[i].InvNTT() - } - w0mcs2.Sub(&w0, &w0mcs2) - w0mcs2.Normalize() - - if w0mcs2.Exceeds(Gamma2 - Beta) { - continue - } - - // z = y + c·s₁ - for i := 0; i < L; i++ { - sig.z[i].MulHat(&ch, &sk.s1h[i]) - sig.z[i].InvNTT() - } - sig.z.Add(&sig.z, &y) - sig.z.Normalize() - - // Ensure ‖z‖_∞ < γ₁ - β - if sig.z.Exceeds(Gamma1 - Beta) { - continue - } - - // Compute c·t₀ - for i := 0; i < K; i++ { - ct0[i].MulHat(&ch, &sk.t0h[i]) - ct0[i].InvNTT() - } - ct0.NormalizeAssumingLe2Q() - - // Ensure ‖c·t₀‖_∞ < γ₂. - if ct0.Exceeds(Gamma2) { - continue - } - - // Create the hint to be able to reconstruct w₁ from w - c·s₂ + c·t0. - // Note that we're not using makeHint() in the obvious way as we - // do not know whether ‖ sc·s₂ - c·t₀ ‖_∞ < γ₂. Instead we note - // that our makeHint() is actually the same as a makeHint for a - // different decomposition: - // - // Earlier we ensured indirectly with a check that r₁ = w₁ where - // r = w - c·s₂. Hence r₀ = r - r₁ α = w - c·s₂ - w₁ α = w₀ - c·s₂. - // Thus MakeHint(w₀ - c·s₂ + c·t₀, w₁) = MakeHint(r0 + c·t₀, r₁) - // and UseHint(w - c·s₂ + c·t₀, w₁) = UseHint(r + c·t₀, r₁). - // As we just ensured that ‖ c·t₀ ‖_∞ < γ₂ our usage is correct. - w0mcs2pct0.Add(&w0mcs2, &ct0) - w0mcs2pct0.NormalizeAssumingLe2Q() - hintPop := sig.hint.MakeHint(&w0mcs2pct0, &w1) - if hintPop > Omega { - continue - } - - break - } - - sig.Pack(signature[:]) -} - -// Computes the public key corresponding to this private key. -func (sk *PrivateKey) Public() *PublicKey { - var t0 VecK - pk := &PublicKey{ - rho: sk.rho, - A: &sk.A, - tr: &sk.tr, - } - sk.computeT0andT1(&t0, &pk.t1) - pk.t1.PackT1(pk.t1p[:]) - return pk -} - -// Equal returns whether the two public keys are equal -func (pk *PublicKey) Equal(other *PublicKey) bool { - return pk.rho == other.rho && pk.t1 == other.t1 -} - -// Equal returns whether the two private keys are equal -func (sk *PrivateKey) Equal(other *PrivateKey) bool { - ret := (subtle.ConstantTimeCompare(sk.rho[:], other.rho[:]) & - subtle.ConstantTimeCompare(sk.key[:], other.key[:]) & - subtle.ConstantTimeCompare(sk.tr[:], other.tr[:])) - - acc := uint32(0) - for i := 0; i < L; i++ { - for j := 0; j < common.N; j++ { - acc |= sk.s1[i][j] ^ other.s1[i][j] - } - } - for i := 0; i < K; i++ { - for j := 0; j < common.N; j++ { - acc |= sk.s2[i][j] ^ other.s2[i][j] - acc |= sk.t0[i][j] ^ other.t0[i][j] - } - } - return (ret & subtle.ConstantTimeEq(int32(acc), 0)) == 1 -} diff --git a/sign/dilithium/mode3aes/internal/dilithium_test.go b/sign/dilithium/mode3aes/internal/dilithium_test.go deleted file mode 100644 index 825e7da08..000000000 --- a/sign/dilithium/mode3aes/internal/dilithium_test.go +++ /dev/null @@ -1,144 +0,0 @@ -// Code generated from mode3/internal/dilithium_test.go by gen.go - -package internal - -import ( - "encoding/binary" - "testing" - - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// Checks whether p is normalized. Only used in tests. -func PolyNormalized(p *common.Poly) bool { - p2 := *p - p2.Normalize() - return p2 == *p -} - -func BenchmarkSkUnpack(b *testing.B) { - var buf [PrivateKeySize]byte - var sk PrivateKey - for i := 0; i < b.N; i++ { - sk.Unpack(&buf) - } -} - -func BenchmarkPkUnpack(b *testing.B) { - var buf [PublicKeySize]byte - var pk PublicKey - for i := 0; i < b.N; i++ { - pk.Unpack(&buf) - } -} - -func BenchmarkVerify(b *testing.B) { - // Note that the expansion of the matrix A is done at Unpacking/Keygen - // instead of at the moment of verification (as in the reference - // implementation.) - var seed [32]byte - var msg [8]byte - var sig [SignatureSize]byte - pk, sk := NewKeyFromSeed(&seed) - SignTo(sk, msg[:], sig[:]) - b.ResetTimer() - for i := 0; i < b.N; i++ { - // We should generate a new signature for every verify attempt, - // as this influences the time a little bit. This difference, however, - // is small and generating a new signature in between creates a lot - // pressure on the allocator which makes an accurate measurement hard. - Verify(pk, msg[:], sig[:]) - } -} - -func BenchmarkSign(b *testing.B) { - // Note that the expansion of the matrix A is done at Unpacking/Keygen - // instead of at the moment of signing (as in the reference implementation.) - var seed [32]byte - var msg [8]byte - var sig [SignatureSize]byte - _, sk := NewKeyFromSeed(&seed) - b.ResetTimer() - for i := 0; i < b.N; i++ { - binary.LittleEndian.PutUint64(msg[:], uint64(i)) - SignTo(sk, msg[:], sig[:]) - } -} - -func BenchmarkGenerateKey(b *testing.B) { - var seed [32]byte - for i := 0; i < b.N; i++ { - binary.LittleEndian.PutUint64(seed[:], uint64(i)) - NewKeyFromSeed(&seed) - } -} - -func BenchmarkPublicFromPrivate(b *testing.B) { - var seed [32]byte - for i := 0; i < b.N; i++ { - b.StopTimer() - binary.LittleEndian.PutUint64(seed[:], uint64(i)) - _, sk := NewKeyFromSeed(&seed) - b.StartTimer() - sk.Public() - } -} - -func TestSignThenVerifyAndPkSkPacking(t *testing.T) { - var seed [common.SeedSize]byte - var sig [SignatureSize]byte - var msg [8]byte - var pkb [PublicKeySize]byte - var skb [PrivateKeySize]byte - var pk2 PublicKey - var sk2 PrivateKey - for i := uint64(0); i < 100; i++ { - binary.LittleEndian.PutUint64(seed[:], i) - pk, sk := NewKeyFromSeed(&seed) - if !sk.Equal(sk) { - t.Fatal() - } - for j := uint64(0); j < 10; j++ { - binary.LittleEndian.PutUint64(msg[:], j) - SignTo(sk, msg[:], sig[:]) - if !Verify(pk, msg[:], sig[:]) { - t.Fatal() - } - } - pk.Pack(&pkb) - pk2.Unpack(&pkb) - if !pk.Equal(&pk2) { - t.Fatal() - } - sk.Pack(&skb) - sk2.Unpack(&skb) - if !sk.Equal(&sk2) { - t.Fatal() - } - } -} - -func TestPublicFromPrivate(t *testing.T) { - var seed [common.SeedSize]byte - for i := uint64(0); i < 100; i++ { - binary.LittleEndian.PutUint64(seed[:], i) - pk, sk := NewKeyFromSeed(&seed) - pk2 := sk.Public() - if !pk.Equal(pk2) { - t.Fatal() - } - } -} - -func TestGamma1Size(t *testing.T) { - var expected int - switch Gamma1Bits { - case 17: - expected = 576 - case 19: - expected = 640 - } - if expected != PolyLeGamma1Size { - t.Fatal() - } -} diff --git a/sign/dilithium/mode3aes/internal/mat.go b/sign/dilithium/mode3aes/internal/mat.go deleted file mode 100644 index ceaf634fa..000000000 --- a/sign/dilithium/mode3aes/internal/mat.go +++ /dev/null @@ -1,59 +0,0 @@ -// Code generated from mode3/internal/mat.go by gen.go - -package internal - -import ( - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// A k by l matrix of polynomials. -type Mat [K]VecL - -// Expands the given seed to a complete matrix. -// -// This function is called ExpandA in the specification. -func (m *Mat) Derive(seed *[32]byte) { - if !DeriveX4Available { - for i := uint16(0); i < K; i++ { - for j := uint16(0); j < L; j++ { - PolyDeriveUniform(&m[i][j], seed, (i<<8)+j) - } - } - return - } - - idx := 0 - var nonces [4]uint16 - var ps [4]*common.Poly - for i := uint16(0); i < K; i++ { - for j := uint16(0); j < L; j++ { - nonces[idx] = (i << 8) + j - ps[idx] = &m[i][j] - idx++ - if idx == 4 { - idx = 0 - PolyDeriveUniformX4(ps, seed, nonces) - } - } - } - if idx != 0 { - for i := idx; i < 4; i++ { - ps[i] = nil - } - PolyDeriveUniformX4(ps, seed, nonces) - } -} - -// Set p to the inner product of a and b using pointwise multiplication. -// -// Assumes a and b are in Montgomery form and their coefficients are -// pairwise sufficiently small to multiply, see Poly.MulHat(). Resulting -// coefficients are bounded by 2Lq. -func PolyDotHat(p *common.Poly, a, b *VecL) { - var t common.Poly - *p = common.Poly{} // zero p - for i := 0; i < L; i++ { - t.MulHat(&a[i], &b[i]) - p.Add(&t, p) - } -} diff --git a/sign/dilithium/mode3aes/internal/pack.go b/sign/dilithium/mode3aes/internal/pack.go deleted file mode 100644 index 1854b4197..000000000 --- a/sign/dilithium/mode3aes/internal/pack.go +++ /dev/null @@ -1,270 +0,0 @@ -// Code generated from mode3/internal/pack.go by gen.go - -package internal - -import ( - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// Writes p with norm less than or equal η into buf, which must be of -// size PolyLeqEtaSize. -// -// Assumes coefficients of p are not normalized, but in [q-η,q+η]. -func PolyPackLeqEta(p *common.Poly, buf []byte) { - if DoubleEtaBits == 4 { // compiler eliminates branch - j := 0 - for i := 0; i < PolyLeqEtaSize; i++ { - buf[i] = (byte(common.Q+Eta-p[j]) | - byte(common.Q+Eta-p[j+1])<<4) - j += 2 - } - } else if DoubleEtaBits == 3 { - j := 0 - for i := 0; i < PolyLeqEtaSize; i += 3 { - buf[i] = (byte(common.Q+Eta-p[j]) | - (byte(common.Q+Eta-p[j+1]) << 3) | - (byte(common.Q+Eta-p[j+2]) << 6)) - buf[i+1] = ((byte(common.Q+Eta-p[j+2]) >> 2) | - (byte(common.Q+Eta-p[j+3]) << 1) | - (byte(common.Q+Eta-p[j+4]) << 4) | - (byte(common.Q+Eta-p[j+5]) << 7)) - buf[i+2] = ((byte(common.Q+Eta-p[j+5]) >> 1) | - (byte(common.Q+Eta-p[j+6]) << 2) | - (byte(common.Q+Eta-p[j+7]) << 5)) - j += 8 - } - } else { - panic("eta not supported") - } -} - -// Sets p to the polynomial of norm less than or equal η encoded in the -// given buffer of size PolyLeqEtaSize. -// -// Output coefficients of p are not normalized, but in [q-η,q+η] provided -// buf was created using PackLeqEta. -// -// Beware, for arbitrary buf the coefficients of p might end up in -// the interval [q-2^b,q+2^b] where b is the least b with η≤2^b. -func PolyUnpackLeqEta(p *common.Poly, buf []byte) { - if DoubleEtaBits == 4 { // compiler eliminates branch - j := 0 - for i := 0; i < PolyLeqEtaSize; i++ { - p[j] = common.Q + Eta - uint32(buf[i]&15) - p[j+1] = common.Q + Eta - uint32(buf[i]>>4) - j += 2 - } - } else if DoubleEtaBits == 3 { - j := 0 - for i := 0; i < PolyLeqEtaSize; i += 3 { - p[j] = common.Q + Eta - uint32(buf[i]&7) - p[j+1] = common.Q + Eta - uint32((buf[i]>>3)&7) - p[j+2] = common.Q + Eta - uint32((buf[i]>>6)|((buf[i+1]<<2)&7)) - p[j+3] = common.Q + Eta - uint32((buf[i+1]>>1)&7) - p[j+4] = common.Q + Eta - uint32((buf[i+1]>>4)&7) - p[j+5] = common.Q + Eta - uint32((buf[i+1]>>7)|((buf[i+2]<<1)&7)) - p[j+6] = common.Q + Eta - uint32((buf[i+2]>>2)&7) - p[j+7] = common.Q + Eta - uint32((buf[i+2]>>5)&7) - j += 8 - } - } else { - panic("eta not supported") - } -} - -// Writes v with coefficients in {0, 1} of which at most ω non-zero -// to buf, which must have length ω+k. -func (v *VecK) PackHint(buf []byte) { - // The packed hint starts with the indices of the non-zero coefficients - // For instance: - // - // (x⁵⁶ + x¹⁰⁰, x²⁵⁵, 0, x² + x²³, x¹) - // - // Yields - // - // 56, 100, 255, 2, 23, 1 - // - // Then we pad with zeroes until we have a list of ω items: - // // 56, 100, 255, 2, 23, 1, 0, 0, ..., 0 - // - // Then we finish with a list of the switch-over-indices in this - // list between polynomials, so: - // - // 56, 100, 255, 2, 23, 1, 0, 0, ..., 0, 2, 3, 3, 5, 6 - - off := uint8(0) - for i := 0; i < K; i++ { - for j := uint16(0); j < common.N; j++ { - if v[i][j] != 0 { - buf[off] = uint8(j) - off++ - } - } - buf[Omega+i] = off - } - for ; off < Omega; off++ { - buf[off] = 0 - } -} - -// Sets v to the vector encoded using VecK.PackHint() -// -// Returns whether unpacking was successful. -func (v *VecK) UnpackHint(buf []byte) bool { - // A priori, there would be several reasonable ways to encode the same - // hint vector. We take care to only allow only one encoding, to ensure - // "strong unforgeability". - // - // See PackHint() source for description of the encoding. - *v = VecK{} // zero v - prevSOP := uint8(0) // previous switch-over-point - for i := 0; i < K; i++ { - SOP := buf[Omega+i] - if SOP < prevSOP || SOP > Omega { - return false // ensures switch-over-points are increasing - } - for j := prevSOP; j < SOP; j++ { - if j > prevSOP && buf[j] <= buf[j-1] { - return false // ensures indices are increasing (within a poly) - } - v[i][buf[j]] = 1 - } - prevSOP = SOP - } - for j := prevSOP; j < Omega; j++ { - if buf[j] != 0 { - return false // ensures padding indices are zero - } - } - - return true -} - -// Sets p to the polynomial packed into buf by PolyPackLeGamma1. -// -// p will be normalized. -func PolyUnpackLeGamma1(p *common.Poly, buf []byte) { - if Gamma1Bits == 17 { - j := 0 - for i := 0; i < PolyLeGamma1Size; i += 9 { - p0 := uint32(buf[i]) | (uint32(buf[i+1]) << 8) | - (uint32(buf[i+2]&0x3) << 16) - p1 := uint32(buf[i+2]>>2) | (uint32(buf[i+3]) << 6) | - (uint32(buf[i+4]&0xf) << 14) - p2 := uint32(buf[i+4]>>4) | (uint32(buf[i+5]) << 4) | - (uint32(buf[i+6]&0x3f) << 12) - p3 := uint32(buf[i+6]>>6) | (uint32(buf[i+7]) << 2) | - (uint32(buf[i+8]) << 10) - - // coefficients in [0,…,2γ₁) - p0 = Gamma1 - p0 // (-γ₁,…,γ₁] - p1 = Gamma1 - p1 - p2 = Gamma1 - p2 - p3 = Gamma1 - p3 - - p0 += uint32(int32(p0)>>31) & common.Q // normalize - p1 += uint32(int32(p1)>>31) & common.Q - p2 += uint32(int32(p2)>>31) & common.Q - p3 += uint32(int32(p3)>>31) & common.Q - - p[j] = p0 - p[j+1] = p1 - p[j+2] = p2 - p[j+3] = p3 - - j += 4 - } - } else if Gamma1Bits == 19 { - j := 0 - for i := 0; i < PolyLeGamma1Size; i += 5 { - p0 := uint32(buf[i]) | (uint32(buf[i+1]) << 8) | - (uint32(buf[i+2]&0xf) << 16) - p1 := uint32(buf[i+2]>>4) | (uint32(buf[i+3]) << 4) | - (uint32(buf[i+4]) << 12) - - p0 = Gamma1 - p0 - p1 = Gamma1 - p1 - - p0 += uint32(int32(p0)>>31) & common.Q - p1 += uint32(int32(p1)>>31) & common.Q - - p[j] = p0 - p[j+1] = p1 - - j += 2 - } - } else { - panic("γ₁ not supported") - } -} - -// Writes p whose coefficients are in (-γ₁,γ₁] into buf -// which has to be of length PolyLeGamma1Size. -// -// Assumes p is normalized. -func PolyPackLeGamma1(p *common.Poly, buf []byte) { - if Gamma1Bits == 17 { - j := 0 - // coefficients in [0,…,γ₁] ∪ (q-γ₁,…,q) - for i := 0; i < PolyLeGamma1Size; i += 9 { - p0 := Gamma1 - p[j] // [0,…,γ₁] ∪ (γ₁-q,…,2γ₁-q) - p0 += uint32(int32(p0)>>31) & common.Q // [0,…,2γ₁) - p1 := Gamma1 - p[j+1] - p1 += uint32(int32(p1)>>31) & common.Q - p2 := Gamma1 - p[j+2] - p2 += uint32(int32(p2)>>31) & common.Q - p3 := Gamma1 - p[j+3] - p3 += uint32(int32(p3)>>31) & common.Q - - buf[i+0] = byte(p0) - buf[i+1] = byte(p0 >> 8) - buf[i+2] = byte(p0>>16) | byte(p1<<2) - buf[i+3] = byte(p1 >> 6) - buf[i+4] = byte(p1>>14) | byte(p2<<4) - buf[i+5] = byte(p2 >> 4) - buf[i+6] = byte(p2>>12) | byte(p3<<6) - buf[i+7] = byte(p3 >> 2) - buf[i+8] = byte(p3 >> 10) - - j += 4 - } - } else if Gamma1Bits == 19 { - j := 0 - for i := 0; i < PolyLeGamma1Size; i += 5 { - // Coefficients are in [0, γ₁] ∪ (Q-γ₁, Q) - p0 := Gamma1 - p[j] - p0 += uint32(int32(p0)>>31) & common.Q - p1 := Gamma1 - p[j+1] - p1 += uint32(int32(p1)>>31) & common.Q - - buf[i+0] = byte(p0) - buf[i+1] = byte(p0 >> 8) - buf[i+2] = byte(p0>>16) | byte(p1<<4) - buf[i+3] = byte(p1 >> 4) - buf[i+4] = byte(p1 >> 12) - - j += 2 - } - } else { - panic("γ₁ not supported") - } -} - -// Pack w₁ into buf, which must be of length PolyW1Size. -// -// Assumes w₁ is normalized. -func PolyPackW1(p *common.Poly, buf []byte) { - if Gamma1Bits == 19 { - p.PackLe16(buf) - } else if Gamma1Bits == 17 { - j := 0 - for i := 0; i < PolyW1Size; i += 3 { - buf[i] = byte(p[j]) | byte(p[j+1]<<6) - buf[i+1] = byte(p[j+1]>>2) | byte(p[j+2]<<4) - buf[i+2] = byte(p[j+2]>>4) | byte(p[j+3]<<2) - j += 4 - } - } else { - panic("unsupported γ₁") - } -} diff --git a/sign/dilithium/mode3aes/internal/pack_test.go b/sign/dilithium/mode3aes/internal/pack_test.go deleted file mode 100644 index f952c6a09..000000000 --- a/sign/dilithium/mode3aes/internal/pack_test.go +++ /dev/null @@ -1,93 +0,0 @@ -// Code generated from mode3/internal/pack_test.go by gen.go - -package internal - -import ( - "testing" - - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -func TestPolyPackLeqEta(t *testing.T) { - var p1, p2 common.Poly - var seed [64]byte - var buf [PolyLeqEtaSize]byte - - for i := uint16(0); i < 100; i++ { - // Note that DeriveUniformLeqEta sets p to the right kind of - // unnormalized vector. - PolyDeriveUniformLeqEta(&p1, &seed, i) - for j := 0; j < PolyLeqEtaSize; j++ { - if p1[j] < common.Q-Eta || p1[j] > common.Q+Eta { - t.Fatalf("DerveUniformLeqEta out of bounds") - } - } - PolyPackLeqEta(&p1, buf[:]) - PolyUnpackLeqEta(&p2, buf[:]) - if p1 != p2 { - t.Fatalf("%v != %v", p1, p2) - } - } -} - -func TestPolyPackT1(t *testing.T) { - var p1, p2 common.Poly - var seed [32]byte - var buf [common.PolyT1Size]byte - - for i := uint16(0); i < 100; i++ { - PolyDeriveUniform(&p1, &seed, i) - p1.Normalize() - for j := 0; j < common.N; j++ { - p1[j] &= 0x1ff - } - p1.PackT1(buf[:]) - p2.UnpackT1(buf[:]) - if p1 != p2 { - t.Fatalf("%v != %v", p1, p2) - } - } -} - -func TestPolyPackT0(t *testing.T) { - var p, p0, p1, p2 common.Poly - var seed [32]byte - var buf [common.PolyT0Size]byte - - for i := uint16(0); i < 100; i++ { - PolyDeriveUniform(&p, &seed, i) - p.Normalize() - p.Power2Round(&p0, &p1) - - p0.PackT0(buf[:]) - p2.UnpackT0(buf[:]) - if p0 != p2 { - t.Fatalf("%v !=\n%v", p0, p2) - } - } -} - -func BenchmarkUnpackLeGamma1(b *testing.B) { - var p common.Poly - var buf [PolyLeGamma1Size]byte - for i := 0; i < b.N; i++ { - PolyUnpackLeGamma1(&p, buf[:]) - } -} - -func TestPolyPackLeGamma1(t *testing.T) { - var p0, p1 common.Poly - var seed [64]byte - var buf [PolyLeGamma1Size]byte - - for i := uint16(0); i < 100; i++ { - PolyDeriveUniformLeGamma1(&p0, &seed, i) - p0.Normalize() - - PolyPackLeGamma1(&p0, buf[:]) - PolyUnpackLeGamma1(&p1, buf[:]) - if p0 != p1 { - t.Fatalf("%v != %v", p0, p1) - } - } -} diff --git a/sign/dilithium/mode3aes/internal/params.go b/sign/dilithium/mode3aes/internal/params.go deleted file mode 100644 index 425cea3b3..000000000 --- a/sign/dilithium/mode3aes/internal/params.go +++ /dev/null @@ -1,19 +0,0 @@ -// Code generated from params.templ.go. DO NOT EDIT. - -package internal - -const ( - Name = "Dilithium3-AES" - UseAES = true - K = 6 - L = 5 - Eta = 4 - DoubleEtaBits = 4 - Omega = 55 - Tau = 49 - Gamma1Bits = 19 - Gamma2 = 261888 - NIST = false - TRSize = 32 - CTildeSize = 32 -) diff --git a/sign/dilithium/mode3aes/internal/params_test.go b/sign/dilithium/mode3aes/internal/params_test.go deleted file mode 100644 index 8e71ef60d..000000000 --- a/sign/dilithium/mode3aes/internal/params_test.go +++ /dev/null @@ -1,101 +0,0 @@ -package internal - -import ( - "testing" - - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// Tests specific to the current mode - -func TestVectorDeriveUniformLeqEta(t *testing.T) { - var p common.Poly - var seed [64]byte - p2 := common.Poly{ - 1, 8380415, 8380415, 8380414, 3, 0, 4, 0, 4, 8380415, - 8380414, 3, 0, 0, 8380413, 8380415, 3, 8380414, 3, 8380414, - 8380415, 1, 3, 1, 8380415, 4, 8380414, 8380416, 2, 8380415, - 4, 8380415, 3, 2, 3, 0, 1, 8380415, 2, 4, 8380413, 8380413, - 1, 8380416, 3, 0, 8380416, 3, 0, 8380416, 8380414, 3, - 8380416, 8380413, 2, 1, 3, 8380414, 8380416, 8380413, 4, - 3, 0, 0, 8380413, 8380414, 2, 2, 2, 2, 8380416, 8380414, - 2, 8380413, 8380413, 1, 8380415, 2, 1, 8380416, 2, 0, - 8380416, 2, 8380416, 8380413, 1, 1, 8380416, 4, 8380415, - 8380413, 4, 3, 8380416, 8380414, 0, 2, 4, 4, 8380415, 2, - 3, 8380416, 8380416, 2, 8380416, 8380416, 2, 4, 8380413, - 4, 2, 8380415, 4, 4, 3, 8380415, 0, 4, 4, 0, 4, 2, 8380413, - 0, 0, 8380414, 8380414, 1, 1, 8380413, 8380416, 2, 8380413, - 4, 8380416, 3, 8380416, 8380415, 8380415, 2, 0, 1, 8380416, - 8380413, 3, 1, 4, 1, 8380416, 0, 8380415, 8380415, 2, 2, - 0, 2, 3, 4, 1, 4, 2, 2, 8380414, 1, 8380414, 4, 1, 2, 3, - 2, 8380413, 8380416, 0, 8380415, 8380414, 2, 3, 2, 8380416, - 8380415, 2, 4, 8380414, 2, 2, 8380413, 8380415, 4, 0, 0, - 3, 8380414, 8380415, 4, 4, 8380416, 4, 8380416, 4, 1, 0, - 8380413, 8380414, 1, 3, 1, 8380413, 2, 8380413, 8380415, - 1, 1, 8380416, 0, 8380416, 2, 8380413, 8380416, 3, 1, 2, - 3, 8380415, 8380416, 8380416, 8380414, 8380415, 4, 8380416, - 0, 8380415, 1, 8380415, 8380414, 8380414, 8380416, 1, 0, - 4, 8380415, 1, 2, 8380416, 8380413, 8380416, 1, 4, 8380414, - 8380416, 8380414, 8380416, 8380415, 3, 4, - } - for i := 0; i < 64; i++ { - seed[i] = byte(i) - } - PolyDeriveUniformLeqEta(&p, &seed, 30000) - p.Normalize() - if p != p2 { - t.Fatalf("%v != %v", p, p2) - } -} - -func TestVectorDeriveUniformLeGamma1(t *testing.T) { - var p, p2 common.Poly - var seed [64]byte - p2 = common.Poly{ - 91453, 8134283, 8211453, 8218977, 8362980, 431655, 98537, - 320966, 7892886, 144675, 495826, 7910635, 308711, 8024934, - 8314212, 8323958, 8242606, 7947101, 419492, 427692, 354075, - 21485, 456475, 213575, 362300, 8142303, 8322444, 7885879, - 89158, 181715, 8094655, 8303634, 8060028, 7920325, 192378, - 7910586, 7897074, 8097343, 7899868, 8339413, 73206, 237312, - 8183555, 348083, 8154041, 8364746, 8078364, 8312790, 105195, - 8037823, 8356712, 7994594, 240882, 70742, 8109371, 8176349, - 467152, 51422, 340432, 8030176, 342172, 154911, 64858, - 97614, 212758, 8285880, 521738, 326395, 296748, 8111442, - 8016327, 7953747, 158922, 330421, 8331843, 449771, 168214, - 8198309, 8228760, 7940533, 2498, 305217, 475829, 8037995, - 8250962, 305070, 8217080, 432779, 213808, 8162729, 381514, - 7995827, 7989202, 129047, 246099, 67554, 8233257, 398954, - 223629, 444125, 150369, 223365, 159236, 55259, 172419, - 163583, 354428, 8263789, 8017325, 8229594, 32340, 490228, - 450684, 8069619, 53733, 7932894, 7955848, 8197876, 201557, - 8307246, 446889, 8211538, 7889784, 8071108, 496027, 8159198, - 8037, 7973907, 248186, 4806, 185437, 457847, 138862, 8124477, - 284692, 8255820, 8068729, 8292005, 244272, 8061114, 21475, - 8058902, 421466, 8306487, 455649, 8218652, 7634, 148216, - 7951766, 394889, 8127579, 366374, 8062903, 8139245, 367068, - 8281027, 734, 396374, 7969282, 7977632, 8098596, 343569, - 8191282, 223874, 163783, 203572, 109732, 8229113, 8128208, - 321529, 296492, 8202474, 50404, 8336017, 8190899, 8191497, - 8279167, 336877, 7878526, 7922949, 7974614, 8076047, 8201365, - 8334333, 416495, 8090175, 150066, 7947253, 474615, 7937629, - 8027358, 356569, 191566, 87441, 8219157, 8375553, 8029697, - 8026188, 8193863, 295873, 7906281, 487687, 8363474, 386621, - 282726, 8373831, 50680, 8239505, 7912018, 493972, 8335677, - 8079840, 251210, 263667, 221541, 41291, 88028, 8373098, - 505241, 7981448, 8308113, 299485, 428036, 93865, 90428, - 392003, 80833, 7975521, 336649, 7950328, 8049195, 8332757, - 8205291, 8178296, 7911197, 7925805, 519154, 60176, 54121, - 222738, 464285, 8022604, 8174235, 7856202, 8291898, 473254, - 8106411, 7943812, 267650, 7958173, 372387, 409597, 204263, - 477847, 83925, 111791, - } - for i := 0; i < 64; i++ { - seed[i] = byte(i) - } - PolyDeriveUniformLeGamma1(&p, &seed, 30000) - p.Normalize() - if p != p2 { - t.Fatalf("%v != %v", p, p2) - } -} diff --git a/sign/dilithium/mode3aes/internal/rounding.go b/sign/dilithium/mode3aes/internal/rounding.go deleted file mode 100644 index 58123c090..000000000 --- a/sign/dilithium/mode3aes/internal/rounding.go +++ /dev/null @@ -1,142 +0,0 @@ -// Code generated from mode3/internal/rounding.go by gen.go - -package internal - -import ( - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// Splits 0 ≤ a < q into a₀ and a₁ with a = a₁*α + a₀ with -α/2 < a₀ ≤ α/2, -// except for when we would have a₁ = (q-1)/α in which case a₁=0 is taken -// and -α/2 ≤ a₀ < 0. Returns a₀ + q. Note 0 ≤ a₁ < (q-1)/α. -// Recall α = 2γ₂. -func decompose(a uint32) (a0plusQ, a1 uint32) { - // a₁ = ⌈a / 128⌉ - a1 = (a + 127) >> 7 - - if Alpha == 523776 { - // 1025/2²² is close enough to 1/4092 so that a₁ - // becomes a/α rounded down. - a1 = ((a1*1025 + (1 << 21)) >> 22) - - // For the corner-case a₁ = (q-1)/α = 16, we have to set a₁=0. - a1 &= 15 - } else if Alpha == 190464 { - // 1488/2²⁴ is close enough to 1/1488 so that a₁ - // becomes a/α rounded down. - a1 = ((a1 * 11275) + (1 << 23)) >> 24 - - // For the corner-case a₁ = (q-1)/α = 44, we have to set a₁=0. - a1 ^= uint32(int32(43-a1)>>31) & a1 - } else { - panic("unsupported α") - } - - a0plusQ = a - a1*Alpha - - // In the corner-case, when we set a₁=0, we will incorrectly - // have a₀ > (q-1)/2 and we'll need to subtract q. As we - // return a₀ + q, that comes down to adding q if a₀ < (q-1)/2. - a0plusQ += uint32(int32(a0plusQ-(common.Q-1)/2)>>31) & common.Q - - return -} - -// Assume 0 ≤ r, f < Q with ‖f‖_∞ ≤ α/2. Decompose r as r = r1*α + r0 as -// computed by decompose(). Write r' := r - f (mod Q). Now, decompose -// r'=r-f again as r' = r'1*α + r'0 using decompose(). As f is small, we -// have r'1 = r1 + h, where h ∈ {-1, 0, 1}. makeHint() computes |h| -// given z0 := r0 - f (mod Q) and r1. With |h|, which is called the hint, -// we can reconstruct r1 using only r' = r - f, which is done by useHint(). -// To wit: -// -// useHint( r - f, makeHint( r0 - f, r1 ) ) = r1. -// -// Assumes 0 ≤ z0 < Q. -func makeHint(z0, r1 uint32) uint32 { - // If -α/2 < r0 - f ≤ α/2, then r1*α + r0 - f is a valid decomposition of r' - // with the restrictions of decompose() and so r'1 = r1. So the hint - // should be 0. This is covered by the first two inequalities. - // There is one other case: if r0 - f = -α/2, then r1*α + r0 - f is also - // a valid decomposition if r1 = 0. In the other cases a one is carried - // and the hint should be 1. - if z0 <= Gamma2 || z0 > common.Q-Gamma2 || (z0 == common.Q-Gamma2 && r1 == 0) { - return 0 - } - return 1 -} - -// Uses the hint created by makeHint() to reconstruct r1 from r'=r-f; see -// documentation of makeHint() for context. -// Assumes 0 ≤ r' < Q. -func useHint(rp uint32, hint uint32) uint32 { - rp0plusQ, rp1 := decompose(rp) - if hint == 0 { - return rp1 - } - if rp0plusQ > common.Q { - return (rp1 + 1) & 15 - } - return (rp1 - 1) & 15 -} - -// Sets p to the hint polynomial for p0 the modified low bits and p1 -// the unmodified high bits --- see makeHint(). -// -// Returns the number of ones in the hint polynomial. -func PolyMakeHint(p, p0, p1 *common.Poly) (pop uint32) { - for i := 0; i < common.N; i++ { - h := makeHint(p0[i], p1[i]) - pop += h - p[i] = h - } - return -} - -// Computes corrections to the high bits of the polynomial q according -// to the hints in h and sets p to the corrected high bits. Returns p. -func PolyUseHint(p, q, hint *common.Poly) { - var q0PlusQ common.Poly - - // See useHint() and makeHint() for an explanation. We reimplement it - // here so that we can call Poly.Decompose(), which might be way faster - // than calling decompose() in a loop (for instance when having AVX2.) - - PolyDecompose(q, &q0PlusQ, p) - - for i := 0; i < common.N; i++ { - if hint[i] == 0 { - continue - } - if Gamma2 == 261888 { - if q0PlusQ[i] > common.Q { - p[i] = (p[i] + 1) & 15 - } else { - p[i] = (p[i] - 1) & 15 - } - } else if Gamma2 == 95232 { - if q0PlusQ[i] > common.Q { - if p[i] == 43 { - p[i] = 0 - } else { - p[i]++ - } - } else { - if p[i] == 0 { - p[i] = 43 - } else { - p[i]-- - } - } - } else { - panic("unsupported γ₂") - } - } -} - -// Splits each of the coefficients of p using decompose. -func PolyDecompose(p, p0PlusQ, p1 *common.Poly) { - for i := 0; i < common.N; i++ { - p0PlusQ[i], p1[i] = decompose(p[i]) - } -} diff --git a/sign/dilithium/mode3aes/internal/rounding_test.go b/sign/dilithium/mode3aes/internal/rounding_test.go deleted file mode 100644 index ad653ca3f..000000000 --- a/sign/dilithium/mode3aes/internal/rounding_test.go +++ /dev/null @@ -1,81 +0,0 @@ -// Code generated from mode3/internal/rounding_test.go by gen.go - -package internal - -import ( - "flag" - "testing" - - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -var runVeryLongTest = flag.Bool("very-long", false, "runs very long tests") - -func TestDecompose(t *testing.T) { - for a := uint32(0); a < common.Q; a++ { - a0PlusQ, a1 := decompose(a) - a0 := int32(a0PlusQ) - int32(common.Q) - recombined := a0 + int32(Alpha*a1) - if a1 == 0 && recombined < 0 { - recombined += common.Q - if -(Alpha/2) > a0 || a0 >= 0 { - t.Fatalf("decompose(%v): a0 out of bounds", a) - } - } else { - if (-(Alpha / 2) >= a0) || (a0 > Alpha/2) { - t.Fatalf("decompose(%v): a0 out of bounds", a) - } - } - if int32(a) != recombined { - t.Fatalf("decompose(%v) doesn't recombine %v %v", a, a0, a1) - } - } -} - -func TestMakeHint(t *testing.T) { - if !*runVeryLongTest { - t.SkipNow() - } - for w := uint32(0); w < common.Q; w++ { - w0, w1 := decompose(w) - for fn := uint32(0); fn <= Gamma2; fn++ { - fsign := false - for { - var f uint32 - if fsign { - if fn == 0 { - break - } - f = common.Q - fn - } else { - f = fn - } - - hint := makeHint(common.ReduceLe2Q(w0+common.Q-f), w1) - w1p := useHint(common.ReduceLe2Q(w+common.Q-f), hint) - if w1p != w1 { - t.Fatal() - } - - if fsign { - break - } - fsign = true - } - } - } -} - -func BenchmarkDecompose(b *testing.B) { - var p, p0, p1 common.Poly - for i := 0; i < b.N; i++ { - PolyDecompose(&p, &p0, &p1) - } -} - -func BenchmarkMakeHint(b *testing.B) { - var p, p0, p1 common.Poly - for i := 0; i < b.N; i++ { - PolyMakeHint(&p, &p0, &p1) - } -} diff --git a/sign/dilithium/mode3aes/internal/sample.go b/sign/dilithium/mode3aes/internal/sample.go deleted file mode 100644 index 62c261332..000000000 --- a/sign/dilithium/mode3aes/internal/sample.go +++ /dev/null @@ -1,370 +0,0 @@ -// Code generated from mode3/internal/sample.go by gen.go - -package internal - -import ( - "encoding/binary" - - "github.com/cloudflare/circl/internal/sha3" - common "github.com/cloudflare/circl/sign/internal/dilithium" - "github.com/cloudflare/circl/simd/keccakf1600" -) - -// DeriveX4Available indicates whether the system supports the quick fourway -// sampling variants like PolyDeriveUniformX4. -var DeriveX4Available = keccakf1600.IsEnabledX4() && !UseAES - -// For each i, sample ps[i] uniformly from the given seed and nonces[i]. -// ps[i] may be nil and is ignored in that case. -// -// Can only be called when DeriveX4Available is true. -func PolyDeriveUniformX4(ps [4]*common.Poly, seed *[32]byte, nonces [4]uint16) { - var perm keccakf1600.StateX4 - state := perm.Initialize(false) - - // Absorb the seed in the four states - for i := 0; i < 4; i++ { - v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) - for j := 0; j < 4; j++ { - state[i*4+j] = v - } - } - - // Absorb the nonces, the SHAKE128 domain separator (0b1111), the - // start of the padding (0b...001) and the end of the padding 0b100... - // Recall that the rate of SHAKE128 is 168 --- i.e. 21 uint64s. - for j := 0; j < 4; j++ { - state[4*4+j] = uint64(nonces[j]) | (0x1f << 16) - state[20*4+j] = 0x80 << 56 - } - - var idx [4]int // indices into ps - for j := 0; j < 4; j++ { - if ps[j] == nil { - idx[j] = common.N // mark nil polynomial as completed - } - } - - done := false - for !done { - // Applies KeccaK-f[1600] to state to get the next 21 uint64s of each - // of the four SHAKE128 streams. - perm.Permute() - - done = true - - PolyLoop: - for j := 0; j < 4; j++ { - if idx[j] == common.N { - continue - } - for i := 0; i < 7; i++ { - var t [8]uint32 - t[0] = uint32(state[i*3*4+j] & 0x7fffff) - t[1] = uint32((state[i*3*4+j] >> 24) & 0x7fffff) - t[2] = uint32((state[i*3*4+j] >> 48) | - ((state[(i*3+1)*4+j] & 0x7f) << 16)) - t[3] = uint32((state[(i*3+1)*4+j] >> 8) & 0x7fffff) - t[4] = uint32((state[(i*3+1)*4+j] >> 32) & 0x7fffff) - t[5] = uint32((state[(i*3+1)*4+j] >> 56) | - ((state[(i*3+2)*4+j] & 0x7fff) << 8)) - t[6] = uint32((state[(i*3+2)*4+j] >> 16) & 0x7fffff) - t[7] = uint32((state[(i*3+2)*4+j] >> 40) & 0x7fffff) - - for k := 0; k < 8; k++ { - if t[k] < common.Q { - ps[j][idx[j]] = t[k] - idx[j]++ - if idx[j] == common.N { - continue PolyLoop - } - } - } - } - done = false - } - } -} - -// Sample p uniformly from the given seed and nonce. -// -// p will be normalized. -func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { - var i, length int - var buf [12 * 16]byte // fits 168B SHAKE-128 rate and 12 16B AES blocks - - if UseAES { - length = 12 * 16 - } else { - length = 168 - } - - sample := func() { - // Note that 3 divides into 168 and 12*16, so we use up buf completely. - for j := 0; j < length && i < common.N; j += 3 { - t := (uint32(buf[j]) | (uint32(buf[j+1]) << 8) | - (uint32(buf[j+2]) << 16)) & 0x7fffff - - // We use rejection sampling - if t < common.Q { - p[i] = t - i++ - } - } - } - - if UseAES { - h := common.NewAesStream128(seed, nonce) - - for i < common.N { - h.SqueezeInto(buf[:length]) - sample() - } - } else { - var iv [32 + 2]byte // 32 byte seed + uint16 nonce - h := sha3.NewShake128() - copy(iv[:32], seed[:]) - iv[32] = uint8(nonce) - iv[33] = uint8(nonce >> 8) - _, _ = h.Write(iv[:]) - - for i < common.N { - _, _ = h.Read(buf[:168]) - sample() - } - } -} - -// Sample p uniformly with coefficients of norm less than or equal η, -// using the given seed and nonce. -// -// p will not be normalized, but will have coefficients in [q-η,q+η]. -func PolyDeriveUniformLeqEta(p *common.Poly, seed *[64]byte, nonce uint16) { - // Assumes 2 < η < 8. - var i, length int - var buf [9 * 16]byte // fits 136B SHAKE-256 rate and 9 16B AES blocks - - if UseAES { - length = 9 * 16 - } else { - length = 136 - } - - sample := func() { - // We use rejection sampling - for j := 0; j < length && i < common.N; j++ { - t1 := uint32(buf[j]) & 15 - t2 := uint32(buf[j]) >> 4 - if Eta == 2 { // branch is eliminated by compiler - if t1 <= 14 { - t1 -= ((205 * t1) >> 10) * 5 // reduce mod 5 - p[i] = common.Q + Eta - t1 - i++ - } - if t2 <= 14 && i < common.N { - t2 -= ((205 * t2) >> 10) * 5 // reduce mod 5 - p[i] = common.Q + Eta - t2 - i++ - } - } else if Eta == 4 { - if t1 <= 2*Eta { - p[i] = common.Q + Eta - t1 - i++ - } - if t2 <= 2*Eta && i < common.N { - p[i] = common.Q + Eta - t2 - i++ - } - } else { - panic("unsupported η") - } - } - } - - if UseAES { - h := common.NewAesStream256(seed, nonce) - - for i < common.N { - h.SqueezeInto(buf[:length]) - sample() - } - } else { - var iv [64 + 2]byte // 64 byte seed + uint16 nonce - - h := sha3.NewShake256() - copy(iv[:64], seed[:]) - iv[64] = uint8(nonce) - iv[65] = uint8(nonce >> 8) - - // 136 is SHAKE-256 rate - _, _ = h.Write(iv[:]) - - for i < common.N { - _, _ = h.Read(buf[:136]) - sample() - } - } -} - -// Sample v[i] uniformly with coefficients in (-γ₁,…,γ₁] using the -// given seed and nonce+i -// -// p will be normalized. -func VecLDeriveUniformLeGamma1(v *VecL, seed *[64]byte, nonce uint16) { - for i := 0; i < L; i++ { - PolyDeriveUniformLeGamma1(&v[i], seed, nonce+uint16(i)) - } -} - -// Sample p uniformly with coefficients in (-γ₁,…,γK1s] using the -// given seed and nonce. -// -// p will be normalized. -func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { - var buf [PolyLeGamma1Size]byte - - if UseAES { - h := common.NewAesStream256(seed, nonce) - h.SqueezeInto(buf[:]) - } else { - var iv [66]byte - h := sha3.NewShake256() - copy(iv[:64], seed[:]) - iv[64] = uint8(nonce) - iv[65] = uint8(nonce >> 8) - _, _ = h.Write(iv[:]) - _, _ = h.Read(buf[:]) - } - - PolyUnpackLeGamma1(p, buf[:]) -} - -// For each i, sample ps[i] uniformly with τ non-zero coefficients in {q-1,1} -// using the given seed and w1[i]. ps[i] may be nil and is ignored -// in that case. ps[i] will be normalized. -// -// Can only be called when DeriveX4Available is true. -// -// This function is currently not used (yet). -func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed []byte) { - var perm keccakf1600.StateX4 - state := perm.Initialize(false) - - // Absorb the seed in the four states - for i := 0; i < 32/8; i++ { - v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) - for j := 0; j < 4; j++ { - state[i*4+j] = v - } - } - - // SHAKE256 domain separator and padding - for j := 0; j < 4; j++ { - state[(32/8)*4+j] ^= 0x1f - state[16*4+j] ^= 0x80 << 56 - } - perm.Permute() - - var signs [4]uint64 - var idx [4]uint16 // indices into ps - - for j := 0; j < 4; j++ { - if ps[j] != nil { - signs[j] = state[j] - *ps[j] = common.Poly{} // zero ps[j] - idx[j] = common.N - Tau - } else { - idx[j] = common.N // mark as completed - } - } - - stateOffset := 1 - for { - done := true - - PolyLoop: - for j := 0; j < 4; j++ { - if idx[j] == common.N { - continue - } - - for i := stateOffset; i < 17; i++ { - var bs [8]byte - binary.LittleEndian.PutUint64(bs[:], state[4*i+j]) - for k := 0; k < 8; k++ { - b := uint16(bs[k]) - - if b > idx[j] { - continue - } - - ps[j][idx[j]] = ps[j][b] - ps[j][b] = 1 - // Takes least significant bit of signs and uses it for the sign. - // Note 1 ^ (1 | (Q-1)) = Q-1. - ps[j][b] ^= uint32((-(signs[j] & 1)) & (1 | (common.Q - 1))) - signs[j] >>= 1 - - idx[j]++ - if idx[j] == common.N { - continue PolyLoop - } - } - } - - done = false - } - - if done { - break - } - - perm.Permute() - stateOffset = 0 - } -} - -// Samples p uniformly with τ non-zero coefficients in {q-1,1}. -// -// The polynomial p will be normalized. -func PolyDeriveUniformBall(p *common.Poly, seed []byte) { - var buf [136]byte // SHAKE-256 rate is 136 - - h := sha3.NewShake256() - _, _ = h.Write(seed[:]) - _, _ = h.Read(buf[:]) - - // Essentially we generate a sequence of τ ones or minus ones, - // prepend 196 zeroes and shuffle the concatenation using the - // usual algorithm (Fisher--Yates.) - signs := binary.LittleEndian.Uint64(buf[:]) - bufOff := 8 // offset into buf - - *p = common.Poly{} // zero p - for i := uint16(common.N - Tau); i < common.N; i++ { - var b uint16 - - // Find location of where to move the new coefficient to using - // rejection sampling. - for { - if bufOff >= 136 { - _, _ = h.Read(buf[:]) - bufOff = 0 - } - - b = uint16(buf[bufOff]) - bufOff++ - - if b <= i { - break - } - } - - p[i] = p[b] - p[b] = 1 - // Takes least significant bit of signs and uses it for the sign. - // Note 1 ^ (1 | (Q-1)) = Q-1. - p[b] ^= uint32((-(signs & 1)) & (1 | (common.Q - 1))) - signs >>= 1 - } -} diff --git a/sign/dilithium/mode3aes/internal/sample_test.go b/sign/dilithium/mode3aes/internal/sample_test.go deleted file mode 100644 index 2059599eb..000000000 --- a/sign/dilithium/mode3aes/internal/sample_test.go +++ /dev/null @@ -1,266 +0,0 @@ -// Code generated from mode3/internal/sample_test.go by gen.go - -package internal - -import ( - "encoding/binary" - "testing" - - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -func TestVectorDeriveUniform(t *testing.T) { - var p, p2 common.Poly - var seed [32]byte - if UseAES { - p2 = common.Poly{ - 6724291, 310295, 6949524, 4464039, 1482136, 2522903, - 7025059, 3006320, 7286364, 7516512, 3361305, 1955529, - 4765954, 1725325, 6933066, 4299100, 6625173, 4272792, - 583034, 4971409, 2259140, 7715362, 3975394, 2341624, - 5481174, 8150082, 365246, 5491939, 1083120, 7517301, - 3104783, 2475292, 184149, 6425226, 4591622, 5964030, - 4729604, 5471092, 1828227, 1082044, 2516245, 1692580, - 3274844, 5443294, 7256740, 4989638, 3191250, 7479519, - 5124211, 5603858, 1230692, 2513454, 2828034, 4254312, - 1512596, 5245430, 5517392, 2814840, 932545, 6826733, - 3511094, 4075348, 3233981, 7268882, 2913733, 4870249, - 4123492, 8124406, 4016949, 5478752, 2750895, 603525, - 5724798, 3985430, 3483012, 6434230, 3136996, 8297976, - 4107616, 7307748, 6962904, 7544473, 1193110, 3448595, - 4814773, 5607932, 8221314, 1054046, 1541208, 1866050, - 8227412, 2925778, 5293953, 2065416, 4972769, 3616283, - 7990594, 1105530, 7121836, 1170740, 7417431, 633146, - 253820, 7235019, 3539504, 6807707, 451390, 5481526, - 2859902, 1063061, 4579730, 7126652, 7033767, 4294814, - 1414604, 7620048, 1953268, 8304556, 1156814, 1182881, - 5311519, 3057534, 5277666, 682843, 2070398, 2874278, - 4859533, 6376664, 6694074, 1590242, 2620706, 8331066, - 5643845, 5037538, 2891516, 7004879, 3754327, 5031296, - 5463118, 2420870, 8116529, 5517696, 7435129, 3873963, - 710407, 713806, 175647, 4274571, 2655021, 7319503, - 3027243, 7129679, 4213435, 2429323, 4643873, 4568526, - 649664, 1720514, 6497260, 2683517, 7672754, 7105190, - 3148405, 5898369, 5667677, 8050874, 1587139, 7315260, - 4337416, 2202680, 2338714, 557467, 6752058, 2469794, - 485071, 1617604, 3590498, 2151466, 2005823, 7727956, - 7776292, 6783433, 6787146, 1732833, 3596857, 7436284, - 4483349, 4970142, 4472608, 6478342, 1236215, 5695744, - 2280717, 2889355, 3233946, 5187812, 978685, 5177364, - 2922353, 4824807, 5302883, 6739803, 8092453, 5883903, - 816553, 6041174, 8317591, 1459178, 5332455, 1835058, - 1368601, 2820950, 3479224, 2589540, 7992934, 3421045, - 4657128, 8292902, 4153567, 3553988, 7830320, 6722913, - 2555309, 4149801, 8328975, 1560545, 7757473, 3106458, - 4310856, 7135453, 3481032, 652626, 1841361, 8126828, - 6250018, 300536, 7380070, 8174419, 1418793, 6208185, - 3906256, 6679016, 1605701, 3561489, 5819724, 5746996, - 8044214, 7087187, 7102330, 4962927, 4253983, 7108567, - 4119736, 6584065, 441634, 6941656, - } - } else { - p2 = common.Poly{ - 2901364, 562527, 5258502, 3885002, 4190126, 4460268, 6884052, - 3514511, 5383040, 213206, 2155865, 5179607, 3551954, 2312357, - 6066350, 8126097, 1179080, 4787182, 6552182, 6713644, - 1561067, 7626063, 7859743, 5052321, 7032876, 7815031, 157938, - 1865184, 490802, 5717642, 3451902, 7000218, 3743250, 1677431, - 1875427, 5596150, 671623, 3819041, 6247594, 1014875, 4933545, - 7122446, 6682963, 3388398, 3335295, 943002, 1145083, 3113071, - 105967, 1916675, 7474561, 1107006, 700548, 2147909, 1603855, - 5049181, 437882, 6118899, 5656914, 6731065, 3066622, 865453, - 5427634, 981549, 4650873, 861291, 4003872, 5104220, 6171453, - 3723302, 7426315, 6137283, 4874820, 6052561, 53441, 5032874, - 5614778, 2248550, 1756499, 8280764, 8263880, 7600081, - 5118374, 795344, 7543392, 6869925, 1841187, 4181568, 584562, - 7483939, 4938664, 6863397, 5126354, 5218129, 6236086, - 4149293, 379169, 4368487, 7490569, 3409215, 1580463, 3081737, - 1278732, 7109719, 7371700, 2097931, 399836, 1700274, 7188595, - 6830029, 1548850, 6593138, 6849097, 1518037, 2859442, - 7772265, 7325153, 3281191, 7856131, 4995056, 4684325, - 1351194, 8223904, 6817307, 2484146, 131782, 397032, 7436778, - 7973479, 3171829, 5624626, 3540123, 7150120, 8313283, - 3604714, 1043574, 117692, 7797783, 7909392, 903315, 7335342, - 7501562, 5826142, 2709813, 8245473, 2369045, 2782257, - 5762833, 6474114, 6862031, 424522, 594248, 2626630, 7659983, - 5642869, 4075194, 1592129, 245547, 5271031, 3205046, 982375, - 267873, 1286496, 7230481, 3208972, 7485411, 676111, 4944500, - 2959742, 5934456, 1414847, 6067948, 1709895, 4648315, 126008, - 8258986, 2183134, 2302072, 4674924, 4306056, 7465311, - 6500270, 4247428, 4016815, 4973426, 294287, 2456847, 3289700, - 2732169, 1159447, 5569724, 140001, 3237977, 8007761, 5874533, - 255652, 3119586, 2102434, 6248250, 8152822, 8006066, 7708625, - 6997719, 6260212, 6186962, 6636650, 7836834, 7998017, - 2061516, 1197591, 1706544, 733027, 2392907, 2700000, 8254598, - 4488002, 160495, 2985325, 2036837, 2703633, 6406550, 3579947, - 6195178, 5552390, 6804584, 6305468, 5731980, 6095195, - 3323409, 1322661, 6690942, 3374630, 5615167, 479044, 3136054, - 4380418, 2833144, 7829577, 1770522, 6056687, 240415, 14780, - 3740517, 5224226, 3547288, 2083124, 4699398, 3654239, - 5624978, 585593, 3655369, 2281739, 3338565, 1908093, 7784706, - 4352830, - } - } - for i := 0; i < 32; i++ { - seed[i] = byte(i) - } - PolyDeriveUniform(&p, &seed, 30000) - if p != p2 { - t.Fatalf("%v != %v", p, p2) - } -} - -func TestDeriveUniform(t *testing.T) { - var p common.Poly - var seed [32]byte - for i := 0; i < 100; i++ { - binary.LittleEndian.PutUint64(seed[:], uint64(i)) - PolyDeriveUniform(&p, &seed, uint16(i)) - if !PolyNormalized(&p) { - t.Fatal() - } - } -} - -func TestDeriveUniformLeqEta(t *testing.T) { - var p common.Poly - var seed [64]byte - for i := 0; i < 100; i++ { - binary.LittleEndian.PutUint64(seed[:], uint64(i)) - PolyDeriveUniformLeqEta(&p, &seed, uint16(i)) - for j := 0; j < common.N; j++ { - if p[j] < common.Q-Eta || p[j] > common.Q+Eta { - t.Fatal() - } - } - } -} - -func TestDeriveUniformLeGamma1(t *testing.T) { - var p common.Poly - var seed [64]byte - for i := 0; i < 100; i++ { - binary.LittleEndian.PutUint64(seed[:], uint64(i)) - PolyDeriveUniformLeGamma1(&p, &seed, uint16(i)) - for j := 0; j < common.N; j++ { - if (p[j] > Gamma1 && p[j] <= common.Q-Gamma1) || p[j] >= common.Q { - t.Fatal() - } - } - } -} - -func TestDeriveUniformBall(t *testing.T) { - var p common.Poly - var seed [32]byte - for i := 0; i < 100; i++ { - binary.LittleEndian.PutUint64(seed[:], uint64(i)) - PolyDeriveUniformBall(&p, seed[:]) - nonzero := 0 - for j := 0; j < common.N; j++ { - if p[j] != 0 { - if p[j] != 1 && p[j] != common.Q-1 { - t.Fatal() - } - nonzero++ - } - } - if nonzero != Tau { - t.Fatal() - } - } -} - -func TestDeriveUniformX4(t *testing.T) { - if !DeriveX4Available { - t.SkipNow() - } - var ps [4]common.Poly - var p common.Poly - var seed [32]byte - nonces := [4]uint16{12345, 54321, 13532, 37377} - - for i := 0; i < len(seed); i++ { - seed[i] = byte(i) - } - - PolyDeriveUniformX4([4]*common.Poly{&ps[0], &ps[1], &ps[2], &ps[3]}, &seed, - nonces) - for i := 0; i < 4; i++ { - PolyDeriveUniform(&p, &seed, nonces[i]) - if ps[i] != p { - t.Fatal() - } - } -} - -func TestDeriveUniformBallX4(t *testing.T) { - if !DeriveX4Available { - t.SkipNow() - } - var ps [4]common.Poly - var p common.Poly - var seed [32]byte - PolyDeriveUniformBallX4( - [4]*common.Poly{&ps[0], &ps[1], &ps[2], &ps[3]}, - seed[:], - ) - for j := 0; j < 4; j++ { - PolyDeriveUniformBall(&p, seed[:]) - if ps[j] != p { - t.Fatalf("%d\n%v\n%v", j, ps[j], p) - } - } -} - -func BenchmarkPolyDeriveUniformBall(b *testing.B) { - var seed [32]byte - var p common.Poly - var w1 VecK - for i := 0; i < b.N; i++ { - w1[0][0] = uint32(i) - PolyDeriveUniformBall(&p, seed[:]) - } -} - -func BenchmarkPolyDeriveUniformBallX4(b *testing.B) { - var seed [32]byte - var p common.Poly - var w1 VecK - for i := 0; i < b.N; i++ { - w1[0][0] = uint32(i) - PolyDeriveUniformBallX4( - [4]*common.Poly{&p, &p, &p, &p}, - seed[:], - ) - } -} - -func BenchmarkPolyDeriveUniform(b *testing.B) { - var seed [32]byte - var p common.Poly - for i := 0; i < b.N; i++ { - PolyDeriveUniform(&p, &seed, uint16(i)) - } -} - -func BenchmarkPolyDeriveUniformX4(b *testing.B) { - if !DeriveX4Available { - b.SkipNow() - } - var seed [32]byte - var p [4]common.Poly - for i := 0; i < b.N; i++ { - nonce := uint16(4 * i) - PolyDeriveUniformX4([4]*common.Poly{&p[0], &p[1], &p[2], &p[3]}, - &seed, [4]uint16{nonce, nonce + 1, nonce + 2, nonce + 3}) - } -} - -func BenchmarkPolyDeriveUniformLeGamma1(b *testing.B) { - var seed [64]byte - var p common.Poly - for i := 0; i < b.N; i++ { - PolyDeriveUniformLeGamma1(&p, &seed, uint16(i)) - } -} diff --git a/sign/dilithium/mode3aes/internal/vec.go b/sign/dilithium/mode3aes/internal/vec.go deleted file mode 100644 index d07d3b245..000000000 --- a/sign/dilithium/mode3aes/internal/vec.go +++ /dev/null @@ -1,281 +0,0 @@ -// Code generated from mode3/internal/vec.go by gen.go - -package internal - -import ( - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// A vector of L polynomials. -type VecL [L]common.Poly - -// A vector of K polynomials. -type VecK [K]common.Poly - -// Normalize the polynomials in this vector. -func (v *VecL) Normalize() { - for i := 0; i < L; i++ { - v[i].Normalize() - } -} - -// Normalize the polynomials in this vector assuming their coefficients -// are already bounded by 2q. -func (v *VecL) NormalizeAssumingLe2Q() { - for i := 0; i < L; i++ { - v[i].NormalizeAssumingLe2Q() - } -} - -// Sets v to w + u. Does not normalize. -func (v *VecL) Add(w, u *VecL) { - for i := 0; i < L; i++ { - v[i].Add(&w[i], &u[i]) - } -} - -// Applies NTT componentwise. See Poly.NTT() for details. -func (v *VecL) NTT() { - for i := 0; i < L; i++ { - v[i].NTT() - } -} - -// Checks whether any of the coefficients exceeds the given bound in supnorm -// -// Requires the vector to be normalized. -func (v *VecL) Exceeds(bound uint32) bool { - for i := 0; i < L; i++ { - if v[i].Exceeds(bound) { - return true - } - } - return false -} - -// Applies Poly.Power2Round componentwise. -// -// Requires the vector to be normalized. -func (v *VecL) Power2Round(v0PlusQ, v1 *VecL) { - for i := 0; i < L; i++ { - v[i].Power2Round(&v0PlusQ[i], &v1[i]) - } -} - -// Applies Poly.Decompose componentwise. -// -// Requires the vector to be normalized. -func (v *VecL) Decompose(v0PlusQ, v1 *VecL) { - for i := 0; i < L; i++ { - PolyDecompose(&v[i], &v0PlusQ[i], &v1[i]) - } -} - -// Sequentially packs each polynomial using Poly.PackLeqEta(). -func (v *VecL) PackLeqEta(buf []byte) { - offset := 0 - for i := 0; i < L; i++ { - PolyPackLeqEta(&v[i], buf[offset:]) - offset += PolyLeqEtaSize - } -} - -// Sets v to the polynomials packed in buf using VecL.PackLeqEta(). -func (v *VecL) UnpackLeqEta(buf []byte) { - offset := 0 - for i := 0; i < L; i++ { - PolyUnpackLeqEta(&v[i], buf[offset:]) - offset += PolyLeqEtaSize - } -} - -// Sequentially packs each polynomial using PolyPackLeGamma1(). -func (v *VecL) PackLeGamma1(buf []byte) { - offset := 0 - for i := 0; i < L; i++ { - PolyPackLeGamma1(&v[i], buf[offset:]) - offset += PolyLeGamma1Size - } -} - -// Sets v to the polynomials packed in buf using VecL.PackLeGamma1(). -func (v *VecL) UnpackLeGamma1(buf []byte) { - offset := 0 - for i := 0; i < L; i++ { - PolyUnpackLeGamma1(&v[i], buf[offset:]) - offset += PolyLeGamma1Size - } -} - -// Normalize the polynomials in this vector. -func (v *VecK) Normalize() { - for i := 0; i < K; i++ { - v[i].Normalize() - } -} - -// Normalize the polynomials in this vector assuming their coefficients -// are already bounded by 2q. -func (v *VecK) NormalizeAssumingLe2Q() { - for i := 0; i < K; i++ { - v[i].NormalizeAssumingLe2Q() - } -} - -// Sets v to w + u. Does not normalize. -func (v *VecK) Add(w, u *VecK) { - for i := 0; i < K; i++ { - v[i].Add(&w[i], &u[i]) - } -} - -// Checks whether any of the coefficients exceeds the given bound in supnorm -// -// Requires the vector to be normalized. -func (v *VecK) Exceeds(bound uint32) bool { - for i := 0; i < K; i++ { - if v[i].Exceeds(bound) { - return true - } - } - return false -} - -// Applies Poly.Power2Round componentwise. -// -// Requires the vector to be normalized. -func (v *VecK) Power2Round(v0PlusQ, v1 *VecK) { - for i := 0; i < K; i++ { - v[i].Power2Round(&v0PlusQ[i], &v1[i]) - } -} - -// Applies Poly.Decompose componentwise. -// -// Requires the vector to be normalized. -func (v *VecK) Decompose(v0PlusQ, v1 *VecK) { - for i := 0; i < K; i++ { - PolyDecompose(&v[i], &v0PlusQ[i], &v1[i]) - } -} - -// Sets v to the hint vector for v0 the modified low bits and v1 -// the unmodified high bits --- see makeHint(). -// -// Returns the number of ones in the hint vector. -func (v *VecK) MakeHint(v0, v1 *VecK) (pop uint32) { - for i := 0; i < K; i++ { - pop += PolyMakeHint(&v[i], &v0[i], &v1[i]) - } - return -} - -// Computes corrections to the high bits of the polynomials in the vector -// w using the hints in h and sets v to the corrected high bits. Returns v. -// See useHint(). -func (v *VecK) UseHint(q, hint *VecK) *VecK { - for i := 0; i < K; i++ { - PolyUseHint(&v[i], &q[i], &hint[i]) - } - return v -} - -// Sequentially packs each polynomial using Poly.PackT1(). -func (v *VecK) PackT1(buf []byte) { - offset := 0 - for i := 0; i < K; i++ { - v[i].PackT1(buf[offset:]) - offset += common.PolyT1Size - } -} - -// Sets v to the vector packed into buf by PackT1(). -func (v *VecK) UnpackT1(buf []byte) { - offset := 0 - for i := 0; i < K; i++ { - v[i].UnpackT1(buf[offset:]) - offset += common.PolyT1Size - } -} - -// Sequentially packs each polynomial using Poly.PackT0(). -func (v *VecK) PackT0(buf []byte) { - offset := 0 - for i := 0; i < K; i++ { - v[i].PackT0(buf[offset:]) - offset += common.PolyT0Size - } -} - -// Sets v to the vector packed into buf by PackT0(). -func (v *VecK) UnpackT0(buf []byte) { - offset := 0 - for i := 0; i < K; i++ { - v[i].UnpackT0(buf[offset:]) - offset += common.PolyT0Size - } -} - -// Sequentially packs each polynomial using Poly.PackLeqEta(). -func (v *VecK) PackLeqEta(buf []byte) { - offset := 0 - for i := 0; i < K; i++ { - PolyPackLeqEta(&v[i], buf[offset:]) - offset += PolyLeqEtaSize - } -} - -// Sets v to the polynomials packed in buf using VecK.PackLeqEta(). -func (v *VecK) UnpackLeqEta(buf []byte) { - offset := 0 - for i := 0; i < K; i++ { - PolyUnpackLeqEta(&v[i], buf[offset:]) - offset += PolyLeqEtaSize - } -} - -// Applies NTT componentwise. See Poly.NTT() for details. -func (v *VecK) NTT() { - for i := 0; i < K; i++ { - v[i].NTT() - } -} - -// Sequentially packs each polynomial using PolyPackW1(). -func (v *VecK) PackW1(buf []byte) { - offset := 0 - for i := 0; i < K; i++ { - PolyPackW1(&v[i], buf[offset:]) - offset += PolyW1Size - } -} - -// Sets v to a - b. -// -// Warning: assumes coefficients of the polynomials of b are less than 2q. -func (v *VecK) Sub(a, b *VecK) { - for i := 0; i < K; i++ { - v[i].Sub(&a[i], &b[i]) - } -} - -// Sets v to 2ᵈ w without reducing. -func (v *VecK) MulBy2toD(w *VecK) { - for i := 0; i < K; i++ { - v[i].MulBy2toD(&w[i]) - } -} - -// Applies InvNTT componentwise. See Poly.InvNTT() for details. -func (v *VecK) InvNTT() { - for i := 0; i < K; i++ { - v[i].InvNTT() - } -} - -// Applies Poly.ReduceLe2Q() componentwise. -func (v *VecK) ReduceLe2Q() { - for i := 0; i < K; i++ { - v[i].ReduceLe2Q() - } -} diff --git a/sign/dilithium/mode5.go b/sign/dilithium/mode5.go deleted file mode 100644 index 2e282fe8f..000000000 --- a/sign/dilithium/mode5.go +++ /dev/null @@ -1,90 +0,0 @@ -// Code generated from mode.templ.go. DO NOT EDIT. - -package dilithium - -import ( - "fmt" - "io" - - "github.com/cloudflare/circl/sign/dilithium/mode5" - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// implMode5 implements the mode.Mode interface for Dilithium5. -type implMode5 struct{} - -// Mode5 is Dilithium in mode "Dilithium5". -var Mode5 Mode = &implMode5{} - -func (m *implMode5) GenerateKey(rand io.Reader) ( - PublicKey, PrivateKey, error) { - return mode5.GenerateKey(rand) -} - -func (m *implMode5) NewKeyFromSeed(seed []byte) (PublicKey, - PrivateKey) { - if len(seed) != common.SeedSize { - panic(fmt.Sprintf("seed must be of length %d", common.SeedSize)) - } - seedBuf := [common.SeedSize]byte{} - copy(seedBuf[:], seed) - return mode5.NewKeyFromSeed(&seedBuf) -} - -func (m *implMode5) Sign(sk PrivateKey, msg []byte) []byte { - isk := sk.(*mode5.PrivateKey) - ret := [mode5.SignatureSize]byte{} - mode5.SignTo(isk, msg, ret[:]) - return ret[:] -} - -func (m *implMode5) Verify(pk PublicKey, msg []byte, signature []byte) bool { - ipk := pk.(*mode5.PublicKey) - return mode5.Verify(ipk, msg, signature) -} - -func (m *implMode5) PublicKeyFromBytes(data []byte) PublicKey { - var ret mode5.PublicKey - if len(data) != mode5.PublicKeySize { - panic("packed public key must be of mode5.PublicKeySize bytes") - } - var buf [mode5.PublicKeySize]byte - copy(buf[:], data) - ret.Unpack(&buf) - return &ret -} - -func (m *implMode5) PrivateKeyFromBytes(data []byte) PrivateKey { - var ret mode5.PrivateKey - if len(data) != mode5.PrivateKeySize { - panic("packed private key must be of mode5.PrivateKeySize bytes") - } - var buf [mode5.PrivateKeySize]byte - copy(buf[:], data) - ret.Unpack(&buf) - return &ret -} - -func (m *implMode5) SeedSize() int { - return common.SeedSize -} - -func (m *implMode5) PublicKeySize() int { - return mode5.PublicKeySize -} - -func (m *implMode5) PrivateKeySize() int { - return mode5.PrivateKeySize -} - -func (m *implMode5) SignatureSize() int { - return mode5.SignatureSize -} - -func (m *implMode5) Name() string { - return "Dilithium5" -} - -func init() { - modes["Dilithium5"] = Mode5 -} diff --git a/sign/dilithium/mode5/dilithium.go b/sign/dilithium/mode5/dilithium.go index 7271ad17d..ce3ec7546 100644 --- a/sign/dilithium/mode5/dilithium.go +++ b/sign/dilithium/mode5/dilithium.go @@ -1,11 +1,9 @@ -// Code generated from modePkg.templ.go. DO NOT EDIT. - +// Code generated from pkg.templ.go. DO NOT EDIT. // mode5 implements the CRYSTALS-Dilithium signature scheme Dilithium5 // as submitted to round3 of the NIST PQC competition and described in // // https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf - package mode5 import ( @@ -13,10 +11,9 @@ import ( "errors" "io" - common "github.com/cloudflare/circl/sign/internal/dilithium" - + "github.com/cloudflare/circl/sign" "github.com/cloudflare/circl/sign/dilithium/mode5/internal" - + common "github.com/cloudflare/circl/sign/internal/dilithium" ) const ( @@ -54,20 +51,27 @@ func NewKeyFromSeed(seed *[SeedSize]byte) (*PublicKey, *PrivateKey) { // SignTo signs the given message and writes the signature into signature. // It will panic if signature is not of length at least SignatureSize. -func SignTo(sk *PrivateKey, msg []byte, signature []byte) { +func SignTo(sk *PrivateKey, msg, sig []byte) { + var rnd [32]byte + internal.SignTo( (*internal.PrivateKey)(sk), - msg, - signature, + func(w io.Writer) { + w.Write(msg) + }, + rnd, + sig, ) } // Verify checks whether the given signature by pk on msg is valid. -func Verify(pk *PublicKey, msg []byte, signature []byte) bool { +func Verify(pk *PublicKey, msg, sig []byte) bool { return internal.Verify( (*internal.PublicKey)(pk), - msg, - signature, + func(w io.Writer) { + _, _ = w.Write(msg) + }, + sig, ) } @@ -147,15 +151,15 @@ func (sk *PrivateKey) UnmarshalBinary(data []byte) error { // interface. The package-level SignTo function might be more convenient // to use. func (sk *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ( - signature []byte, err error) { - var sig [SignatureSize]byte + sig []byte, err error) { + var ret [SignatureSize]byte if opts.HashFunc() != crypto.Hash(0) { return nil, errors.New("dilithium: cannot sign hashed message") } + SignTo(sk, msg, ret[:]) - SignTo(sk, msg, sig[:]) - return sig[:], nil + return ret[:], nil } // Computes the public key corresponding to this private key. @@ -183,3 +187,109 @@ func (pk *PublicKey) Equal(other crypto.PublicKey) bool { } return (*internal.PublicKey)(pk).Equal((*internal.PublicKey)(castOther)) } + +// Boilerplate for generic signatures API + +type scheme struct{} + +var sch sign.Scheme = &scheme{} + +// Scheme returns a generic signature interface for Dilithium5. +func Scheme() sign.Scheme { return sch } + +func (*scheme) Name() string { return "Dilithium5" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SignatureSize() int { return SignatureSize } +func (*scheme) SeedSize() int { return SeedSize } + +// TODO TLSIdentifier() and OID() + +func (*scheme) SupportsContext() bool { + return false +} + +func (*scheme) GenerateKey() (sign.PublicKey, sign.PrivateKey, error) { + return GenerateKey(nil) +} + +func (*scheme) Sign( + sk sign.PrivateKey, + msg []byte, + opts *sign.SignatureOpts, +) []byte { + sig := make([]byte, SignatureSize) + + priv, ok := sk.(*PrivateKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + panic(sign.ErrContextNotSupported) + } + SignTo(priv, msg, sig) + + return sig +} + +func (*scheme) Verify( + pk sign.PublicKey, + msg, sig []byte, + opts *sign.SignatureOpts, +) bool { + pub, ok := pk.(*PublicKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + panic(sign.ErrContextNotSupported) + } + return Verify(pub, msg, sig) +} + +func (*scheme) DeriveKey(seed []byte) (sign.PublicKey, sign.PrivateKey) { + if len(seed) != SeedSize { + panic(sign.ErrSeedSize) + } + var seed2 [SeedSize]byte + copy(seed2[:], seed) + return NewKeyFromSeed(&seed2) +} + +func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (sign.PublicKey, error) { + if len(buf) != PublicKeySize { + return nil, sign.ErrPubKeySize + } + + var ( + buf2 [PublicKeySize]byte + ret PublicKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (sign.PrivateKey, error) { + if len(buf) != PrivateKeySize { + return nil, sign.ErrPrivKeySize + } + + var ( + buf2 [PrivateKeySize]byte + ret PrivateKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (sk *PrivateKey) Scheme() sign.Scheme { + return sch +} + +func (sk *PublicKey) Scheme() sign.Scheme { + return sch +} diff --git a/sign/dilithium/mode5/internal/dilithium.go b/sign/dilithium/mode5/internal/dilithium.go index 7869d0475..609ab3a4c 100644 --- a/sign/dilithium/mode5/internal/dilithium.go +++ b/sign/dilithium/mode5/internal/dilithium.go @@ -244,7 +244,10 @@ func (sk *PrivateKey) computeT0andT1(t0, t1 *VecK) { } // Verify checks whether the given signature by pk on msg is valid. -func Verify(pk *PublicKey, msg []byte, signature []byte) bool { +// +// For Dilithium this is the top-level verification function. +// In ML-DSA, this is ML-DSA.Verify_internal. +func Verify(pk *PublicKey, msg func(io.Writer), signature []byte) bool { var sig unpackedSignature var mu [64]byte var zh VecL @@ -262,7 +265,7 @@ func Verify(pk *PublicKey, msg []byte, signature []byte) bool { // μ = CRH(tr ‖ msg) h := sha3.NewShake256() _, _ = h.Write(pk.tr[:]) - _, _ = h.Write(msg) + msg(&h) _, _ = h.Read(mu[:]) // Compute Az @@ -279,7 +282,7 @@ func Verify(pk *PublicKey, msg []byte, signature []byte) bool { // which is small enough for NTT(). Az2dct1.MulBy2toD(&pk.t1) Az2dct1.NTT() - PolyDeriveUniformBall(&ch, sig.c[:32]) + PolyDeriveUniformBall(&ch, sig.c[:]) ch.NTT() for i := 0; i < K; i++ { Az2dct1[i].MulHat(&Az2dct1[i], &ch) @@ -307,8 +310,11 @@ func Verify(pk *PublicKey, msg []byte, signature []byte) bool { // SignTo signs the given message and writes the signature into signature. // +// For Dilithium this is the top-level signing function. For ML-DSA +// this is ML-DSA.Sign_internal. +// //nolint:funlen -func SignTo(sk *PrivateKey, msg []byte, signature []byte) { +func SignTo(sk *PrivateKey, msg func(io.Writer), rnd [32]byte, signature []byte) { var mu, rhop [64]byte var w1Packed [PolyW1Size * K]byte var y, yh VecL @@ -324,16 +330,14 @@ func SignTo(sk *PrivateKey, msg []byte, signature []byte) { // μ = CRH(tr ‖ msg) h := sha3.NewShake256() _, _ = h.Write(sk.tr[:]) - _, _ = h.Write(msg) + msg(&h) _, _ = h.Read(mu[:]) // ρ' = CRH(key ‖ μ) h.Reset() _, _ = h.Write(sk.key[:]) if NIST { - // We implement the deterministic variant where rnd is all zeroes. - // TODO expose randomized variant? - _, _ = h.Write(make([]byte, 32)) + _, _ = h.Write(rnd[:]) } _, _ = h.Write(mu[:]) _, _ = h.Read(rhop[:]) @@ -373,7 +377,7 @@ func SignTo(sk *PrivateKey, msg []byte, signature []byte) { _, _ = h.Write(w1Packed[:]) _, _ = h.Read(sig.c[:]) - PolyDeriveUniformBall(&ch, sig.c[:32]) + PolyDeriveUniformBall(&ch, sig.c[:]) ch.NTT() // Ensure ‖ w₀ - c·s2 ‖_∞ < γ₂ - β. diff --git a/sign/dilithium/mode5/internal/dilithium_test.go b/sign/dilithium/mode5/internal/dilithium_test.go index 825e7da08..91dd478e0 100644 --- a/sign/dilithium/mode5/internal/dilithium_test.go +++ b/sign/dilithium/mode5/internal/dilithium_test.go @@ -4,6 +4,7 @@ package internal import ( "encoding/binary" + "io" "testing" common "github.com/cloudflare/circl/sign/internal/dilithium" @@ -36,32 +37,38 @@ func BenchmarkVerify(b *testing.B) { // Note that the expansion of the matrix A is done at Unpacking/Keygen // instead of at the moment of verification (as in the reference // implementation.) - var seed [32]byte - var msg [8]byte - var sig [SignatureSize]byte + var ( + seed [32]byte + msg [8]byte + sig [SignatureSize]byte + rnd [32]byte + ) pk, sk := NewKeyFromSeed(&seed) - SignTo(sk, msg[:], sig[:]) + SignTo(sk, func(w io.Writer) { w.Write(msg[:]) }, rnd, sig[:]) b.ResetTimer() for i := 0; i < b.N; i++ { // We should generate a new signature for every verify attempt, // as this influences the time a little bit. This difference, however, // is small and generating a new signature in between creates a lot // pressure on the allocator which makes an accurate measurement hard. - Verify(pk, msg[:], sig[:]) + Verify(pk, func(w io.Writer) { w.Write(msg[:]) }, sig[:]) } } func BenchmarkSign(b *testing.B) { // Note that the expansion of the matrix A is done at Unpacking/Keygen // instead of at the moment of signing (as in the reference implementation.) - var seed [32]byte - var msg [8]byte - var sig [SignatureSize]byte + var ( + seed [32]byte + msg [8]byte + sig [SignatureSize]byte + rnd [32]byte + ) _, sk := NewKeyFromSeed(&seed) b.ResetTimer() for i := 0; i < b.N; i++ { binary.LittleEndian.PutUint64(msg[:], uint64(i)) - SignTo(sk, msg[:], sig[:]) + SignTo(sk, func(w io.Writer) { w.Write(msg[:]) }, rnd, sig[:]) } } @@ -85,13 +92,16 @@ func BenchmarkPublicFromPrivate(b *testing.B) { } func TestSignThenVerifyAndPkSkPacking(t *testing.T) { - var seed [common.SeedSize]byte - var sig [SignatureSize]byte - var msg [8]byte - var pkb [PublicKeySize]byte - var skb [PrivateKeySize]byte - var pk2 PublicKey - var sk2 PrivateKey + var ( + seed [common.SeedSize]byte + sig [SignatureSize]byte + msg [8]byte + pkb [PublicKeySize]byte + skb [PrivateKeySize]byte + pk2 PublicKey + sk2 PrivateKey + rnd [32]byte + ) for i := uint64(0); i < 100; i++ { binary.LittleEndian.PutUint64(seed[:], i) pk, sk := NewKeyFromSeed(&seed) @@ -100,8 +110,8 @@ func TestSignThenVerifyAndPkSkPacking(t *testing.T) { } for j := uint64(0); j < 10; j++ { binary.LittleEndian.PutUint64(msg[:], j) - SignTo(sk, msg[:], sig[:]) - if !Verify(pk, msg[:], sig[:]) { + SignTo(sk, func(w io.Writer) { w.Write(msg[:]) }, rnd, sig[:]) + if !Verify(pk, func(w io.Writer) { w.Write(msg[:]) }, sig[:]) { t.Fatal() } } diff --git a/sign/dilithium/mode5/internal/params.go b/sign/dilithium/mode5/internal/params.go index e8a2b143e..6f65f0336 100644 --- a/sign/dilithium/mode5/internal/params.go +++ b/sign/dilithium/mode5/internal/params.go @@ -4,7 +4,6 @@ package internal const ( Name = "Dilithium5" - UseAES = false K = 8 L = 7 Eta = 2 diff --git a/sign/dilithium/mode5/internal/sample.go b/sign/dilithium/mode5/internal/sample.go index 62c261332..b37370a4e 100644 --- a/sign/dilithium/mode5/internal/sample.go +++ b/sign/dilithium/mode5/internal/sample.go @@ -12,7 +12,7 @@ import ( // DeriveX4Available indicates whether the system supports the quick fourway // sampling variants like PolyDeriveUniformX4. -var DeriveX4Available = keccakf1600.IsEnabledX4() && !UseAES +var DeriveX4Available = keccakf1600.IsEnabledX4() // For each i, sample ps[i] uniformly from the given seed and nonces[i]. // ps[i] may be nil and is ignored in that case. @@ -91,13 +91,9 @@ func PolyDeriveUniformX4(ps [4]*common.Poly, seed *[32]byte, nonces [4]uint16) { // p will be normalized. func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { var i, length int - var buf [12 * 16]byte // fits 168B SHAKE-128 rate and 12 16B AES blocks + var buf [12 * 16]byte // fits 168B SHAKE-128 rate - if UseAES { - length = 12 * 16 - } else { - length = 168 - } + length = 168 sample := func() { // Note that 3 divides into 168 and 12*16, so we use up buf completely. @@ -113,25 +109,16 @@ func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { } } - if UseAES { - h := common.NewAesStream128(seed, nonce) + var iv [32 + 2]byte // 32 byte seed + uint16 nonce + h := sha3.NewShake128() + copy(iv[:32], seed[:]) + iv[32] = uint8(nonce) + iv[33] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) - for i < common.N { - h.SqueezeInto(buf[:length]) - sample() - } - } else { - var iv [32 + 2]byte // 32 byte seed + uint16 nonce - h := sha3.NewShake128() - copy(iv[:32], seed[:]) - iv[32] = uint8(nonce) - iv[33] = uint8(nonce >> 8) - _, _ = h.Write(iv[:]) - - for i < common.N { - _, _ = h.Read(buf[:168]) - sample() - } + for i < common.N { + _, _ = h.Read(buf[:168]) + sample() } } @@ -142,13 +129,9 @@ func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { func PolyDeriveUniformLeqEta(p *common.Poly, seed *[64]byte, nonce uint16) { // Assumes 2 < η < 8. var i, length int - var buf [9 * 16]byte // fits 136B SHAKE-256 rate and 9 16B AES blocks + var buf [9 * 16]byte // fits 136B SHAKE-256 rate - if UseAES { - length = 9 * 16 - } else { - length = 136 - } + length = 136 sample := func() { // We use rejection sampling @@ -181,28 +164,19 @@ func PolyDeriveUniformLeqEta(p *common.Poly, seed *[64]byte, nonce uint16) { } } - if UseAES { - h := common.NewAesStream256(seed, nonce) - - for i < common.N { - h.SqueezeInto(buf[:length]) - sample() - } - } else { - var iv [64 + 2]byte // 64 byte seed + uint16 nonce + var iv [64 + 2]byte // 64 byte seed + uint16 nonce - h := sha3.NewShake256() - copy(iv[:64], seed[:]) - iv[64] = uint8(nonce) - iv[65] = uint8(nonce >> 8) + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) - // 136 is SHAKE-256 rate - _, _ = h.Write(iv[:]) + // 136 is SHAKE-256 rate + _, _ = h.Write(iv[:]) - for i < common.N { - _, _ = h.Read(buf[:136]) - sample() - } + for i < common.N { + _, _ = h.Read(buf[:136]) + sample() } } @@ -223,18 +197,13 @@ func VecLDeriveUniformLeGamma1(v *VecL, seed *[64]byte, nonce uint16) { func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { var buf [PolyLeGamma1Size]byte - if UseAES { - h := common.NewAesStream256(seed, nonce) - h.SqueezeInto(buf[:]) - } else { - var iv [66]byte - h := sha3.NewShake256() - copy(iv[:64], seed[:]) - iv[64] = uint8(nonce) - iv[65] = uint8(nonce >> 8) - _, _ = h.Write(iv[:]) - _, _ = h.Read(buf[:]) - } + var iv [66]byte + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) + _, _ = h.Read(buf[:]) PolyUnpackLeGamma1(p, buf[:]) } @@ -251,7 +220,7 @@ func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed []byte) { state := perm.Initialize(false) // Absorb the seed in the four states - for i := 0; i < 32/8; i++ { + for i := 0; i < CTildeSize/8; i++ { v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) for j := 0; j < 4; j++ { state[i*4+j] = v @@ -260,7 +229,7 @@ func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed []byte) { // SHAKE256 domain separator and padding for j := 0; j < 4; j++ { - state[(32/8)*4+j] ^= 0x1f + state[(CTildeSize/8)*4+j] ^= 0x1f state[16*4+j] ^= 0x80 << 56 } perm.Permute() diff --git a/sign/dilithium/mode5/internal/sample_test.go b/sign/dilithium/mode5/internal/sample_test.go index 2059599eb..32931c94f 100644 --- a/sign/dilithium/mode5/internal/sample_test.go +++ b/sign/dilithium/mode5/internal/sample_test.go @@ -12,94 +12,46 @@ import ( func TestVectorDeriveUniform(t *testing.T) { var p, p2 common.Poly var seed [32]byte - if UseAES { - p2 = common.Poly{ - 6724291, 310295, 6949524, 4464039, 1482136, 2522903, - 7025059, 3006320, 7286364, 7516512, 3361305, 1955529, - 4765954, 1725325, 6933066, 4299100, 6625173, 4272792, - 583034, 4971409, 2259140, 7715362, 3975394, 2341624, - 5481174, 8150082, 365246, 5491939, 1083120, 7517301, - 3104783, 2475292, 184149, 6425226, 4591622, 5964030, - 4729604, 5471092, 1828227, 1082044, 2516245, 1692580, - 3274844, 5443294, 7256740, 4989638, 3191250, 7479519, - 5124211, 5603858, 1230692, 2513454, 2828034, 4254312, - 1512596, 5245430, 5517392, 2814840, 932545, 6826733, - 3511094, 4075348, 3233981, 7268882, 2913733, 4870249, - 4123492, 8124406, 4016949, 5478752, 2750895, 603525, - 5724798, 3985430, 3483012, 6434230, 3136996, 8297976, - 4107616, 7307748, 6962904, 7544473, 1193110, 3448595, - 4814773, 5607932, 8221314, 1054046, 1541208, 1866050, - 8227412, 2925778, 5293953, 2065416, 4972769, 3616283, - 7990594, 1105530, 7121836, 1170740, 7417431, 633146, - 253820, 7235019, 3539504, 6807707, 451390, 5481526, - 2859902, 1063061, 4579730, 7126652, 7033767, 4294814, - 1414604, 7620048, 1953268, 8304556, 1156814, 1182881, - 5311519, 3057534, 5277666, 682843, 2070398, 2874278, - 4859533, 6376664, 6694074, 1590242, 2620706, 8331066, - 5643845, 5037538, 2891516, 7004879, 3754327, 5031296, - 5463118, 2420870, 8116529, 5517696, 7435129, 3873963, - 710407, 713806, 175647, 4274571, 2655021, 7319503, - 3027243, 7129679, 4213435, 2429323, 4643873, 4568526, - 649664, 1720514, 6497260, 2683517, 7672754, 7105190, - 3148405, 5898369, 5667677, 8050874, 1587139, 7315260, - 4337416, 2202680, 2338714, 557467, 6752058, 2469794, - 485071, 1617604, 3590498, 2151466, 2005823, 7727956, - 7776292, 6783433, 6787146, 1732833, 3596857, 7436284, - 4483349, 4970142, 4472608, 6478342, 1236215, 5695744, - 2280717, 2889355, 3233946, 5187812, 978685, 5177364, - 2922353, 4824807, 5302883, 6739803, 8092453, 5883903, - 816553, 6041174, 8317591, 1459178, 5332455, 1835058, - 1368601, 2820950, 3479224, 2589540, 7992934, 3421045, - 4657128, 8292902, 4153567, 3553988, 7830320, 6722913, - 2555309, 4149801, 8328975, 1560545, 7757473, 3106458, - 4310856, 7135453, 3481032, 652626, 1841361, 8126828, - 6250018, 300536, 7380070, 8174419, 1418793, 6208185, - 3906256, 6679016, 1605701, 3561489, 5819724, 5746996, - 8044214, 7087187, 7102330, 4962927, 4253983, 7108567, - 4119736, 6584065, 441634, 6941656, - } - } else { - p2 = common.Poly{ - 2901364, 562527, 5258502, 3885002, 4190126, 4460268, 6884052, - 3514511, 5383040, 213206, 2155865, 5179607, 3551954, 2312357, - 6066350, 8126097, 1179080, 4787182, 6552182, 6713644, - 1561067, 7626063, 7859743, 5052321, 7032876, 7815031, 157938, - 1865184, 490802, 5717642, 3451902, 7000218, 3743250, 1677431, - 1875427, 5596150, 671623, 3819041, 6247594, 1014875, 4933545, - 7122446, 6682963, 3388398, 3335295, 943002, 1145083, 3113071, - 105967, 1916675, 7474561, 1107006, 700548, 2147909, 1603855, - 5049181, 437882, 6118899, 5656914, 6731065, 3066622, 865453, - 5427634, 981549, 4650873, 861291, 4003872, 5104220, 6171453, - 3723302, 7426315, 6137283, 4874820, 6052561, 53441, 5032874, - 5614778, 2248550, 1756499, 8280764, 8263880, 7600081, - 5118374, 795344, 7543392, 6869925, 1841187, 4181568, 584562, - 7483939, 4938664, 6863397, 5126354, 5218129, 6236086, - 4149293, 379169, 4368487, 7490569, 3409215, 1580463, 3081737, - 1278732, 7109719, 7371700, 2097931, 399836, 1700274, 7188595, - 6830029, 1548850, 6593138, 6849097, 1518037, 2859442, - 7772265, 7325153, 3281191, 7856131, 4995056, 4684325, - 1351194, 8223904, 6817307, 2484146, 131782, 397032, 7436778, - 7973479, 3171829, 5624626, 3540123, 7150120, 8313283, - 3604714, 1043574, 117692, 7797783, 7909392, 903315, 7335342, - 7501562, 5826142, 2709813, 8245473, 2369045, 2782257, - 5762833, 6474114, 6862031, 424522, 594248, 2626630, 7659983, - 5642869, 4075194, 1592129, 245547, 5271031, 3205046, 982375, - 267873, 1286496, 7230481, 3208972, 7485411, 676111, 4944500, - 2959742, 5934456, 1414847, 6067948, 1709895, 4648315, 126008, - 8258986, 2183134, 2302072, 4674924, 4306056, 7465311, - 6500270, 4247428, 4016815, 4973426, 294287, 2456847, 3289700, - 2732169, 1159447, 5569724, 140001, 3237977, 8007761, 5874533, - 255652, 3119586, 2102434, 6248250, 8152822, 8006066, 7708625, - 6997719, 6260212, 6186962, 6636650, 7836834, 7998017, - 2061516, 1197591, 1706544, 733027, 2392907, 2700000, 8254598, - 4488002, 160495, 2985325, 2036837, 2703633, 6406550, 3579947, - 6195178, 5552390, 6804584, 6305468, 5731980, 6095195, - 3323409, 1322661, 6690942, 3374630, 5615167, 479044, 3136054, - 4380418, 2833144, 7829577, 1770522, 6056687, 240415, 14780, - 3740517, 5224226, 3547288, 2083124, 4699398, 3654239, - 5624978, 585593, 3655369, 2281739, 3338565, 1908093, 7784706, - 4352830, - } + p2 = common.Poly{ + 2901364, 562527, 5258502, 3885002, 4190126, 4460268, 6884052, + 3514511, 5383040, 213206, 2155865, 5179607, 3551954, 2312357, + 6066350, 8126097, 1179080, 4787182, 6552182, 6713644, + 1561067, 7626063, 7859743, 5052321, 7032876, 7815031, 157938, + 1865184, 490802, 5717642, 3451902, 7000218, 3743250, 1677431, + 1875427, 5596150, 671623, 3819041, 6247594, 1014875, 4933545, + 7122446, 6682963, 3388398, 3335295, 943002, 1145083, 3113071, + 105967, 1916675, 7474561, 1107006, 700548, 2147909, 1603855, + 5049181, 437882, 6118899, 5656914, 6731065, 3066622, 865453, + 5427634, 981549, 4650873, 861291, 4003872, 5104220, 6171453, + 3723302, 7426315, 6137283, 4874820, 6052561, 53441, 5032874, + 5614778, 2248550, 1756499, 8280764, 8263880, 7600081, + 5118374, 795344, 7543392, 6869925, 1841187, 4181568, 584562, + 7483939, 4938664, 6863397, 5126354, 5218129, 6236086, + 4149293, 379169, 4368487, 7490569, 3409215, 1580463, 3081737, + 1278732, 7109719, 7371700, 2097931, 399836, 1700274, 7188595, + 6830029, 1548850, 6593138, 6849097, 1518037, 2859442, + 7772265, 7325153, 3281191, 7856131, 4995056, 4684325, + 1351194, 8223904, 6817307, 2484146, 131782, 397032, 7436778, + 7973479, 3171829, 5624626, 3540123, 7150120, 8313283, + 3604714, 1043574, 117692, 7797783, 7909392, 903315, 7335342, + 7501562, 5826142, 2709813, 8245473, 2369045, 2782257, + 5762833, 6474114, 6862031, 424522, 594248, 2626630, 7659983, + 5642869, 4075194, 1592129, 245547, 5271031, 3205046, 982375, + 267873, 1286496, 7230481, 3208972, 7485411, 676111, 4944500, + 2959742, 5934456, 1414847, 6067948, 1709895, 4648315, 126008, + 8258986, 2183134, 2302072, 4674924, 4306056, 7465311, + 6500270, 4247428, 4016815, 4973426, 294287, 2456847, 3289700, + 2732169, 1159447, 5569724, 140001, 3237977, 8007761, 5874533, + 255652, 3119586, 2102434, 6248250, 8152822, 8006066, 7708625, + 6997719, 6260212, 6186962, 6636650, 7836834, 7998017, + 2061516, 1197591, 1706544, 733027, 2392907, 2700000, 8254598, + 4488002, 160495, 2985325, 2036837, 2703633, 6406550, 3579947, + 6195178, 5552390, 6804584, 6305468, 5731980, 6095195, + 3323409, 1322661, 6690942, 3374630, 5615167, 479044, 3136054, + 4380418, 2833144, 7829577, 1770522, 6056687, 240415, 14780, + 3740517, 5224226, 3547288, 2083124, 4699398, 3654239, + 5624978, 585593, 3655369, 2281739, 3338565, 1908093, 7784706, + 4352830, } for i := 0; i < 32; i++ { seed[i] = byte(i) @@ -152,7 +104,7 @@ func TestDeriveUniformLeGamma1(t *testing.T) { func TestDeriveUniformBall(t *testing.T) { var p common.Poly - var seed [32]byte + var seed [CTildeSize]byte for i := 0; i < 100; i++ { binary.LittleEndian.PutUint64(seed[:], uint64(i)) PolyDeriveUniformBall(&p, seed[:]) @@ -200,7 +152,7 @@ func TestDeriveUniformBallX4(t *testing.T) { } var ps [4]common.Poly var p common.Poly - var seed [32]byte + var seed [CTildeSize]byte PolyDeriveUniformBallX4( [4]*common.Poly{&ps[0], &ps[1], &ps[2], &ps[3]}, seed[:], diff --git a/sign/dilithium/mode5aes.go b/sign/dilithium/mode5aes.go deleted file mode 100644 index b7f1cb485..000000000 --- a/sign/dilithium/mode5aes.go +++ /dev/null @@ -1,90 +0,0 @@ -// Code generated from mode.templ.go. DO NOT EDIT. - -package dilithium - -import ( - "fmt" - "io" - - "github.com/cloudflare/circl/sign/dilithium/mode5aes" - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// implMode5AES implements the mode.Mode interface for Dilithium5-AES. -type implMode5AES struct{} - -// Mode5AES is Dilithium in mode "Dilithium5-AES". -var Mode5AES Mode = &implMode5AES{} - -func (m *implMode5AES) GenerateKey(rand io.Reader) ( - PublicKey, PrivateKey, error) { - return mode5aes.GenerateKey(rand) -} - -func (m *implMode5AES) NewKeyFromSeed(seed []byte) (PublicKey, - PrivateKey) { - if len(seed) != common.SeedSize { - panic(fmt.Sprintf("seed must be of length %d", common.SeedSize)) - } - seedBuf := [common.SeedSize]byte{} - copy(seedBuf[:], seed) - return mode5aes.NewKeyFromSeed(&seedBuf) -} - -func (m *implMode5AES) Sign(sk PrivateKey, msg []byte) []byte { - isk := sk.(*mode5aes.PrivateKey) - ret := [mode5aes.SignatureSize]byte{} - mode5aes.SignTo(isk, msg, ret[:]) - return ret[:] -} - -func (m *implMode5AES) Verify(pk PublicKey, msg []byte, signature []byte) bool { - ipk := pk.(*mode5aes.PublicKey) - return mode5aes.Verify(ipk, msg, signature) -} - -func (m *implMode5AES) PublicKeyFromBytes(data []byte) PublicKey { - var ret mode5aes.PublicKey - if len(data) != mode5aes.PublicKeySize { - panic("packed public key must be of mode5aes.PublicKeySize bytes") - } - var buf [mode5aes.PublicKeySize]byte - copy(buf[:], data) - ret.Unpack(&buf) - return &ret -} - -func (m *implMode5AES) PrivateKeyFromBytes(data []byte) PrivateKey { - var ret mode5aes.PrivateKey - if len(data) != mode5aes.PrivateKeySize { - panic("packed private key must be of mode5aes.PrivateKeySize bytes") - } - var buf [mode5aes.PrivateKeySize]byte - copy(buf[:], data) - ret.Unpack(&buf) - return &ret -} - -func (m *implMode5AES) SeedSize() int { - return common.SeedSize -} - -func (m *implMode5AES) PublicKeySize() int { - return mode5aes.PublicKeySize -} - -func (m *implMode5AES) PrivateKeySize() int { - return mode5aes.PrivateKeySize -} - -func (m *implMode5AES) SignatureSize() int { - return mode5aes.SignatureSize -} - -func (m *implMode5AES) Name() string { - return "Dilithium5-AES" -} - -func init() { - modes["Dilithium5-AES"] = Mode5AES -} diff --git a/sign/dilithium/mode5aes/dilithium.go b/sign/dilithium/mode5aes/dilithium.go deleted file mode 100644 index c0300f2e6..000000000 --- a/sign/dilithium/mode5aes/dilithium.go +++ /dev/null @@ -1,185 +0,0 @@ -// Code generated from modePkg.templ.go. DO NOT EDIT. - - -// mode5aes implements the CRYSTALS-Dilithium signature scheme Dilithium5-AES -// as submitted to round3 of the NIST PQC competition and described in -// -// https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf - -package mode5aes - -import ( - "crypto" - "errors" - "io" - - common "github.com/cloudflare/circl/sign/internal/dilithium" - - "github.com/cloudflare/circl/sign/dilithium/mode5aes/internal" - -) - -const ( - // Size of seed for NewKeyFromSeed - SeedSize = common.SeedSize - - // Size of a packed PublicKey - PublicKeySize = internal.PublicKeySize - - // Size of a packed PrivateKey - PrivateKeySize = internal.PrivateKeySize - - // Size of a signature - SignatureSize = internal.SignatureSize -) - -// PublicKey is the type of Dilithium5-AES public key -type PublicKey internal.PublicKey - -// PrivateKey is the type of Dilithium5-AES private key -type PrivateKey internal.PrivateKey - -// GenerateKey generates a public/private key pair using entropy from rand. -// If rand is nil, crypto/rand.Reader will be used. -func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { - pk, sk, err := internal.GenerateKey(rand) - return (*PublicKey)(pk), (*PrivateKey)(sk), err -} - -// NewKeyFromSeed derives a public/private key pair using the given seed. -func NewKeyFromSeed(seed *[SeedSize]byte) (*PublicKey, *PrivateKey) { - pk, sk := internal.NewKeyFromSeed(seed) - return (*PublicKey)(pk), (*PrivateKey)(sk) -} - -// SignTo signs the given message and writes the signature into signature. -// It will panic if signature is not of length at least SignatureSize. -func SignTo(sk *PrivateKey, msg []byte, signature []byte) { - internal.SignTo( - (*internal.PrivateKey)(sk), - msg, - signature, - ) -} - -// Verify checks whether the given signature by pk on msg is valid. -func Verify(pk *PublicKey, msg []byte, signature []byte) bool { - return internal.Verify( - (*internal.PublicKey)(pk), - msg, - signature, - ) -} - -// Sets pk to the public key encoded in buf. -func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { - (*internal.PublicKey)(pk).Unpack(buf) -} - -// Sets sk to the private key encoded in buf. -func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { - (*internal.PrivateKey)(sk).Unpack(buf) -} - -// Packs the public key into buf. -func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) { - (*internal.PublicKey)(pk).Pack(buf) -} - -// Packs the private key into buf. -func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { - (*internal.PrivateKey)(sk).Pack(buf) -} - -// Packs the public key. -func (pk *PublicKey) Bytes() []byte { - var buf [PublicKeySize]byte - pk.Pack(&buf) - return buf[:] -} - -// Packs the private key. -func (sk *PrivateKey) Bytes() []byte { - var buf [PrivateKeySize]byte - sk.Pack(&buf) - return buf[:] -} - -// Packs the public key. -func (pk *PublicKey) MarshalBinary() ([]byte, error) { - return pk.Bytes(), nil -} - -// Packs the private key. -func (sk *PrivateKey) MarshalBinary() ([]byte, error) { - return sk.Bytes(), nil -} - -// Unpacks the public key from data. -func (pk *PublicKey) UnmarshalBinary(data []byte) error { - if len(data) != PublicKeySize { - return errors.New("packed public key must be of mode5aes.PublicKeySize bytes") - } - var buf [PublicKeySize]byte - copy(buf[:], data) - pk.Unpack(&buf) - return nil -} - -// Unpacks the private key from data. -func (sk *PrivateKey) UnmarshalBinary(data []byte) error { - if len(data) != PrivateKeySize { - return errors.New("packed private key must be of mode5aes.PrivateKeySize bytes") - } - var buf [PrivateKeySize]byte - copy(buf[:], data) - sk.Unpack(&buf) - return nil -} - -// Sign signs the given message. -// -// opts.HashFunc() must return zero, which can be achieved by passing -// crypto.Hash(0) for opts. rand is ignored. Will only return an error -// if opts.HashFunc() is non-zero. -// -// This function is used to make PrivateKey implement the crypto.Signer -// interface. The package-level SignTo function might be more convenient -// to use. -func (sk *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ( - signature []byte, err error) { - var sig [SignatureSize]byte - - if opts.HashFunc() != crypto.Hash(0) { - return nil, errors.New("dilithium: cannot sign hashed message") - } - - SignTo(sk, msg, sig[:]) - return sig[:], nil -} - -// Computes the public key corresponding to this private key. -// -// Returns a *PublicKey. The type crypto.PublicKey is used to make -// PrivateKey implement the crypto.Signer interface. -func (sk *PrivateKey) Public() crypto.PublicKey { - return (*PublicKey)((*internal.PrivateKey)(sk).Public()) -} - -// Equal returns whether the two private keys equal. -func (sk *PrivateKey) Equal(other crypto.PrivateKey) bool { - castOther, ok := other.(*PrivateKey) - if !ok { - return false - } - return (*internal.PrivateKey)(sk).Equal((*internal.PrivateKey)(castOther)) -} - -// Equal returns whether the two public keys equal. -func (pk *PublicKey) Equal(other crypto.PublicKey) bool { - castOther, ok := other.(*PublicKey) - if !ok { - return false - } - return (*internal.PublicKey)(pk).Equal((*internal.PublicKey)(castOther)) -} diff --git a/sign/dilithium/mode5aes/internal/dilithium.go b/sign/dilithium/mode5aes/internal/dilithium.go deleted file mode 100644 index 7869d0475..000000000 --- a/sign/dilithium/mode5aes/internal/dilithium.go +++ /dev/null @@ -1,482 +0,0 @@ -// Code generated from mode3/internal/dilithium.go by gen.go - -package internal - -import ( - cryptoRand "crypto/rand" - "crypto/subtle" - "io" - - "github.com/cloudflare/circl/internal/sha3" - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -const ( - // Size of a packed polynomial of norm ≤η. - // (Note that the formula is not valid in general.) - PolyLeqEtaSize = (common.N * DoubleEtaBits) / 8 - - // β = τη, the maximum size of c s₂. - Beta = Tau * Eta - - // γ₁ range of y - Gamma1 = 1 << Gamma1Bits - - // Size of packed polynomial of norm <γ₁ such as z - PolyLeGamma1Size = (Gamma1Bits + 1) * common.N / 8 - - // α = 2γ₂ parameter for decompose - Alpha = 2 * Gamma2 - - // Size of a packed private key - PrivateKeySize = 32 + 32 + TRSize + PolyLeqEtaSize*(L+K) + common.PolyT0Size*K - - // Size of a packed public key - PublicKeySize = 32 + common.PolyT1Size*K - - // Size of a packed signature - SignatureSize = L*PolyLeGamma1Size + Omega + K + CTildeSize - - // Size of packed w₁ - PolyW1Size = (common.N * (common.QBits - Gamma1Bits)) / 8 -) - -// PublicKey is the type of Dilithium public keys. -type PublicKey struct { - rho [32]byte - t1 VecK - - // Cached values - t1p [common.PolyT1Size * K]byte - A *Mat - tr *[TRSize]byte -} - -// PrivateKey is the type of Dilithium private keys. -type PrivateKey struct { - rho [32]byte - key [32]byte - s1 VecL - s2 VecK - t0 VecK - tr [TRSize]byte - - // Cached values - A Mat // ExpandA(ρ) - s1h VecL // NTT(s₁) - s2h VecK // NTT(s₂) - t0h VecK // NTT(t₀) -} - -type unpackedSignature struct { - z VecL - hint VecK - c [CTildeSize]byte -} - -// Packs the signature into buf. -func (sig *unpackedSignature) Pack(buf []byte) { - copy(buf[:], sig.c[:]) - sig.z.PackLeGamma1(buf[CTildeSize:]) - sig.hint.PackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) -} - -// Sets sig to the signature encoded in the buffer. -// -// Returns whether buf contains a properly packed signature. -func (sig *unpackedSignature) Unpack(buf []byte) bool { - if len(buf) < SignatureSize { - return false - } - copy(sig.c[:], buf[:]) - sig.z.UnpackLeGamma1(buf[CTildeSize:]) - if sig.z.Exceeds(Gamma1 - Beta) { - return false - } - if !sig.hint.UnpackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) { - return false - } - return true -} - -// Packs the public key into buf. -func (pk *PublicKey) Pack(buf *[PublicKeySize]byte) { - copy(buf[:32], pk.rho[:]) - copy(buf[32:], pk.t1p[:]) -} - -// Sets pk to the public key encoded in buf. -func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { - copy(pk.rho[:], buf[:32]) - copy(pk.t1p[:], buf[32:]) - - pk.t1.UnpackT1(pk.t1p[:]) - pk.A = new(Mat) - pk.A.Derive(&pk.rho) - - // tr = CRH(ρ ‖ t1) = CRH(pk) - pk.tr = new([TRSize]byte) - h := sha3.NewShake256() - _, _ = h.Write(buf[:]) - _, _ = h.Read(pk.tr[:]) -} - -// Packs the private key into buf. -func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { - copy(buf[:32], sk.rho[:]) - copy(buf[32:64], sk.key[:]) - copy(buf[64:64+TRSize], sk.tr[:]) - offset := 64 + TRSize - sk.s1.PackLeqEta(buf[offset:]) - offset += PolyLeqEtaSize * L - sk.s2.PackLeqEta(buf[offset:]) - offset += PolyLeqEtaSize * K - sk.t0.PackT0(buf[offset:]) -} - -// Sets sk to the private key encoded in buf. -func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { - copy(sk.rho[:], buf[:32]) - copy(sk.key[:], buf[32:64]) - copy(sk.tr[:], buf[64:64+TRSize]) - offset := 64 + TRSize - sk.s1.UnpackLeqEta(buf[offset:]) - offset += PolyLeqEtaSize * L - sk.s2.UnpackLeqEta(buf[offset:]) - offset += PolyLeqEtaSize * K - sk.t0.UnpackT0(buf[offset:]) - - // Cached values - sk.A.Derive(&sk.rho) - sk.t0h = sk.t0 - sk.t0h.NTT() - sk.s1h = sk.s1 - sk.s1h.NTT() - sk.s2h = sk.s2 - sk.s2h.NTT() -} - -// GenerateKey generates a public/private key pair using entropy from rand. -// If rand is nil, crypto/rand.Reader will be used. -func GenerateKey(rand io.Reader) (*PublicKey, *PrivateKey, error) { - var seed [32]byte - if rand == nil { - rand = cryptoRand.Reader - } - _, err := io.ReadFull(rand, seed[:]) - if err != nil { - return nil, nil, err - } - pk, sk := NewKeyFromSeed(&seed) - return pk, sk, nil -} - -// NewKeyFromSeed derives a public/private key pair using the given seed. -func NewKeyFromSeed(seed *[common.SeedSize]byte) (*PublicKey, *PrivateKey) { - var eSeed [128]byte // expanded seed - var pk PublicKey - var sk PrivateKey - var sSeed [64]byte - - h := sha3.NewShake256() - _, _ = h.Write(seed[:]) - _, _ = h.Read(eSeed[:]) - - copy(pk.rho[:], eSeed[:32]) - copy(sSeed[:], eSeed[32:96]) - copy(sk.key[:], eSeed[96:]) - copy(sk.rho[:], pk.rho[:]) - - sk.A.Derive(&pk.rho) - - for i := uint16(0); i < L; i++ { - PolyDeriveUniformLeqEta(&sk.s1[i], &sSeed, i) - } - - for i := uint16(0); i < K; i++ { - PolyDeriveUniformLeqEta(&sk.s2[i], &sSeed, i+L) - } - - sk.s1h = sk.s1 - sk.s1h.NTT() - sk.s2h = sk.s2 - sk.s2h.NTT() - - sk.computeT0andT1(&sk.t0, &pk.t1) - - sk.t0h = sk.t0 - sk.t0h.NTT() - - // Complete public key far enough to be packed - pk.t1.PackT1(pk.t1p[:]) - pk.A = &sk.A - - // Finish private key - var packedPk [PublicKeySize]byte - pk.Pack(&packedPk) - - // tr = CRH(ρ ‖ t1) = CRH(pk) - h.Reset() - _, _ = h.Write(packedPk[:]) - _, _ = h.Read(sk.tr[:]) - - // Finish cache of public key - pk.tr = &sk.tr - - return &pk, &sk -} - -// Computes t0 and t1 from sk.s1h, sk.s2 and sk.A. -func (sk *PrivateKey) computeT0andT1(t0, t1 *VecK) { - var t VecK - - // Set t to A s₁ + s₂ - for i := 0; i < K; i++ { - PolyDotHat(&t[i], &sk.A[i], &sk.s1h) - t[i].ReduceLe2Q() - t[i].InvNTT() - } - t.Add(&t, &sk.s2) - t.Normalize() - - // Compute t₀, t₁ = Power2Round(t) - t.Power2Round(t0, t1) -} - -// Verify checks whether the given signature by pk on msg is valid. -func Verify(pk *PublicKey, msg []byte, signature []byte) bool { - var sig unpackedSignature - var mu [64]byte - var zh VecL - var Az, Az2dct1, w1 VecK - var ch common.Poly - var cp [CTildeSize]byte - var w1Packed [PolyW1Size * K]byte - - // Note that Unpack() checked whether ‖z‖_∞ < γ₁ - β - // and ensured that there at most ω ones in pk.hint. - if !sig.Unpack(signature) { - return false - } - - // μ = CRH(tr ‖ msg) - h := sha3.NewShake256() - _, _ = h.Write(pk.tr[:]) - _, _ = h.Write(msg) - _, _ = h.Read(mu[:]) - - // Compute Az - zh = sig.z - zh.NTT() - - for i := 0; i < K; i++ { - PolyDotHat(&Az[i], &pk.A[i], &zh) - } - - // Next, we compute Az - 2ᵈ·c·t₁. - // Note that the coefficients of t₁ are bounded by 256 = 2⁹, - // so the coefficients of Az2dct1 will bounded by 2⁹⁺ᵈ = 2²³ < 2q, - // which is small enough for NTT(). - Az2dct1.MulBy2toD(&pk.t1) - Az2dct1.NTT() - PolyDeriveUniformBall(&ch, sig.c[:32]) - ch.NTT() - for i := 0; i < K; i++ { - Az2dct1[i].MulHat(&Az2dct1[i], &ch) - } - Az2dct1.Sub(&Az, &Az2dct1) - Az2dct1.ReduceLe2Q() - Az2dct1.InvNTT() - Az2dct1.NormalizeAssumingLe2Q() - - // UseHint(pk.hint, Az - 2ᵈ·c·t₁) - // = UseHint(pk.hint, w - c·s₂ + c·t₀) - // = UseHint(pk.hint, r + c·t₀) - // = r₁ = w₁. - w1.UseHint(&Az2dct1, &sig.hint) - w1.PackW1(w1Packed[:]) - - // c' = H(μ, w₁) - h.Reset() - _, _ = h.Write(mu[:]) - _, _ = h.Write(w1Packed[:]) - _, _ = h.Read(cp[:]) - - return sig.c == cp -} - -// SignTo signs the given message and writes the signature into signature. -// -//nolint:funlen -func SignTo(sk *PrivateKey, msg []byte, signature []byte) { - var mu, rhop [64]byte - var w1Packed [PolyW1Size * K]byte - var y, yh VecL - var w, w0, w1, w0mcs2, ct0, w0mcs2pct0 VecK - var ch common.Poly - var yNonce uint16 - var sig unpackedSignature - - if len(signature) < SignatureSize { - panic("Signature does not fit in that byteslice") - } - - // μ = CRH(tr ‖ msg) - h := sha3.NewShake256() - _, _ = h.Write(sk.tr[:]) - _, _ = h.Write(msg) - _, _ = h.Read(mu[:]) - - // ρ' = CRH(key ‖ μ) - h.Reset() - _, _ = h.Write(sk.key[:]) - if NIST { - // We implement the deterministic variant where rnd is all zeroes. - // TODO expose randomized variant? - _, _ = h.Write(make([]byte, 32)) - } - _, _ = h.Write(mu[:]) - _, _ = h.Read(rhop[:]) - - // Main rejection loop - attempt := 0 - for { - attempt++ - if attempt >= 576 { - // Depending on the mode, one try has a chance between 1/7 and 1/4 - // of succeeding. Thus it is safe to say that 576 iterations - // are enough as (6/7)⁵⁷⁶ < 2⁻¹²⁸. - panic("This should only happen 1 in 2^{128}: something is wrong.") - } - - // y = ExpandMask(ρ', key) - VecLDeriveUniformLeGamma1(&y, &rhop, yNonce) - yNonce += uint16(L) - - // Set w to A y - yh = y - yh.NTT() - for i := 0; i < K; i++ { - PolyDotHat(&w[i], &sk.A[i], &yh) - w[i].ReduceLe2Q() - w[i].InvNTT() - } - - // Decompose w into w₀ and w₁ - w.NormalizeAssumingLe2Q() - w.Decompose(&w0, &w1) - - // c~ = H(μ ‖ w₁) - w1.PackW1(w1Packed[:]) - h.Reset() - _, _ = h.Write(mu[:]) - _, _ = h.Write(w1Packed[:]) - _, _ = h.Read(sig.c[:]) - - PolyDeriveUniformBall(&ch, sig.c[:32]) - ch.NTT() - - // Ensure ‖ w₀ - c·s2 ‖_∞ < γ₂ - β. - // - // By Lemma 3 of the specification this is equivalent to checking that - // both ‖ r₀ ‖_∞ < γ₂ - β and r₁ = w₁, for the decomposition - // w - c·s₂ = r₁ α + r₀ as computed by decompose(). - // See also §4.1 of the specification. - for i := 0; i < K; i++ { - w0mcs2[i].MulHat(&ch, &sk.s2h[i]) - w0mcs2[i].InvNTT() - } - w0mcs2.Sub(&w0, &w0mcs2) - w0mcs2.Normalize() - - if w0mcs2.Exceeds(Gamma2 - Beta) { - continue - } - - // z = y + c·s₁ - for i := 0; i < L; i++ { - sig.z[i].MulHat(&ch, &sk.s1h[i]) - sig.z[i].InvNTT() - } - sig.z.Add(&sig.z, &y) - sig.z.Normalize() - - // Ensure ‖z‖_∞ < γ₁ - β - if sig.z.Exceeds(Gamma1 - Beta) { - continue - } - - // Compute c·t₀ - for i := 0; i < K; i++ { - ct0[i].MulHat(&ch, &sk.t0h[i]) - ct0[i].InvNTT() - } - ct0.NormalizeAssumingLe2Q() - - // Ensure ‖c·t₀‖_∞ < γ₂. - if ct0.Exceeds(Gamma2) { - continue - } - - // Create the hint to be able to reconstruct w₁ from w - c·s₂ + c·t0. - // Note that we're not using makeHint() in the obvious way as we - // do not know whether ‖ sc·s₂ - c·t₀ ‖_∞ < γ₂. Instead we note - // that our makeHint() is actually the same as a makeHint for a - // different decomposition: - // - // Earlier we ensured indirectly with a check that r₁ = w₁ where - // r = w - c·s₂. Hence r₀ = r - r₁ α = w - c·s₂ - w₁ α = w₀ - c·s₂. - // Thus MakeHint(w₀ - c·s₂ + c·t₀, w₁) = MakeHint(r0 + c·t₀, r₁) - // and UseHint(w - c·s₂ + c·t₀, w₁) = UseHint(r + c·t₀, r₁). - // As we just ensured that ‖ c·t₀ ‖_∞ < γ₂ our usage is correct. - w0mcs2pct0.Add(&w0mcs2, &ct0) - w0mcs2pct0.NormalizeAssumingLe2Q() - hintPop := sig.hint.MakeHint(&w0mcs2pct0, &w1) - if hintPop > Omega { - continue - } - - break - } - - sig.Pack(signature[:]) -} - -// Computes the public key corresponding to this private key. -func (sk *PrivateKey) Public() *PublicKey { - var t0 VecK - pk := &PublicKey{ - rho: sk.rho, - A: &sk.A, - tr: &sk.tr, - } - sk.computeT0andT1(&t0, &pk.t1) - pk.t1.PackT1(pk.t1p[:]) - return pk -} - -// Equal returns whether the two public keys are equal -func (pk *PublicKey) Equal(other *PublicKey) bool { - return pk.rho == other.rho && pk.t1 == other.t1 -} - -// Equal returns whether the two private keys are equal -func (sk *PrivateKey) Equal(other *PrivateKey) bool { - ret := (subtle.ConstantTimeCompare(sk.rho[:], other.rho[:]) & - subtle.ConstantTimeCompare(sk.key[:], other.key[:]) & - subtle.ConstantTimeCompare(sk.tr[:], other.tr[:])) - - acc := uint32(0) - for i := 0; i < L; i++ { - for j := 0; j < common.N; j++ { - acc |= sk.s1[i][j] ^ other.s1[i][j] - } - } - for i := 0; i < K; i++ { - for j := 0; j < common.N; j++ { - acc |= sk.s2[i][j] ^ other.s2[i][j] - acc |= sk.t0[i][j] ^ other.t0[i][j] - } - } - return (ret & subtle.ConstantTimeEq(int32(acc), 0)) == 1 -} diff --git a/sign/dilithium/mode5aes/internal/dilithium_test.go b/sign/dilithium/mode5aes/internal/dilithium_test.go deleted file mode 100644 index 825e7da08..000000000 --- a/sign/dilithium/mode5aes/internal/dilithium_test.go +++ /dev/null @@ -1,144 +0,0 @@ -// Code generated from mode3/internal/dilithium_test.go by gen.go - -package internal - -import ( - "encoding/binary" - "testing" - - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// Checks whether p is normalized. Only used in tests. -func PolyNormalized(p *common.Poly) bool { - p2 := *p - p2.Normalize() - return p2 == *p -} - -func BenchmarkSkUnpack(b *testing.B) { - var buf [PrivateKeySize]byte - var sk PrivateKey - for i := 0; i < b.N; i++ { - sk.Unpack(&buf) - } -} - -func BenchmarkPkUnpack(b *testing.B) { - var buf [PublicKeySize]byte - var pk PublicKey - for i := 0; i < b.N; i++ { - pk.Unpack(&buf) - } -} - -func BenchmarkVerify(b *testing.B) { - // Note that the expansion of the matrix A is done at Unpacking/Keygen - // instead of at the moment of verification (as in the reference - // implementation.) - var seed [32]byte - var msg [8]byte - var sig [SignatureSize]byte - pk, sk := NewKeyFromSeed(&seed) - SignTo(sk, msg[:], sig[:]) - b.ResetTimer() - for i := 0; i < b.N; i++ { - // We should generate a new signature for every verify attempt, - // as this influences the time a little bit. This difference, however, - // is small and generating a new signature in between creates a lot - // pressure on the allocator which makes an accurate measurement hard. - Verify(pk, msg[:], sig[:]) - } -} - -func BenchmarkSign(b *testing.B) { - // Note that the expansion of the matrix A is done at Unpacking/Keygen - // instead of at the moment of signing (as in the reference implementation.) - var seed [32]byte - var msg [8]byte - var sig [SignatureSize]byte - _, sk := NewKeyFromSeed(&seed) - b.ResetTimer() - for i := 0; i < b.N; i++ { - binary.LittleEndian.PutUint64(msg[:], uint64(i)) - SignTo(sk, msg[:], sig[:]) - } -} - -func BenchmarkGenerateKey(b *testing.B) { - var seed [32]byte - for i := 0; i < b.N; i++ { - binary.LittleEndian.PutUint64(seed[:], uint64(i)) - NewKeyFromSeed(&seed) - } -} - -func BenchmarkPublicFromPrivate(b *testing.B) { - var seed [32]byte - for i := 0; i < b.N; i++ { - b.StopTimer() - binary.LittleEndian.PutUint64(seed[:], uint64(i)) - _, sk := NewKeyFromSeed(&seed) - b.StartTimer() - sk.Public() - } -} - -func TestSignThenVerifyAndPkSkPacking(t *testing.T) { - var seed [common.SeedSize]byte - var sig [SignatureSize]byte - var msg [8]byte - var pkb [PublicKeySize]byte - var skb [PrivateKeySize]byte - var pk2 PublicKey - var sk2 PrivateKey - for i := uint64(0); i < 100; i++ { - binary.LittleEndian.PutUint64(seed[:], i) - pk, sk := NewKeyFromSeed(&seed) - if !sk.Equal(sk) { - t.Fatal() - } - for j := uint64(0); j < 10; j++ { - binary.LittleEndian.PutUint64(msg[:], j) - SignTo(sk, msg[:], sig[:]) - if !Verify(pk, msg[:], sig[:]) { - t.Fatal() - } - } - pk.Pack(&pkb) - pk2.Unpack(&pkb) - if !pk.Equal(&pk2) { - t.Fatal() - } - sk.Pack(&skb) - sk2.Unpack(&skb) - if !sk.Equal(&sk2) { - t.Fatal() - } - } -} - -func TestPublicFromPrivate(t *testing.T) { - var seed [common.SeedSize]byte - for i := uint64(0); i < 100; i++ { - binary.LittleEndian.PutUint64(seed[:], i) - pk, sk := NewKeyFromSeed(&seed) - pk2 := sk.Public() - if !pk.Equal(pk2) { - t.Fatal() - } - } -} - -func TestGamma1Size(t *testing.T) { - var expected int - switch Gamma1Bits { - case 17: - expected = 576 - case 19: - expected = 640 - } - if expected != PolyLeGamma1Size { - t.Fatal() - } -} diff --git a/sign/dilithium/mode5aes/internal/mat.go b/sign/dilithium/mode5aes/internal/mat.go deleted file mode 100644 index ceaf634fa..000000000 --- a/sign/dilithium/mode5aes/internal/mat.go +++ /dev/null @@ -1,59 +0,0 @@ -// Code generated from mode3/internal/mat.go by gen.go - -package internal - -import ( - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// A k by l matrix of polynomials. -type Mat [K]VecL - -// Expands the given seed to a complete matrix. -// -// This function is called ExpandA in the specification. -func (m *Mat) Derive(seed *[32]byte) { - if !DeriveX4Available { - for i := uint16(0); i < K; i++ { - for j := uint16(0); j < L; j++ { - PolyDeriveUniform(&m[i][j], seed, (i<<8)+j) - } - } - return - } - - idx := 0 - var nonces [4]uint16 - var ps [4]*common.Poly - for i := uint16(0); i < K; i++ { - for j := uint16(0); j < L; j++ { - nonces[idx] = (i << 8) + j - ps[idx] = &m[i][j] - idx++ - if idx == 4 { - idx = 0 - PolyDeriveUniformX4(ps, seed, nonces) - } - } - } - if idx != 0 { - for i := idx; i < 4; i++ { - ps[i] = nil - } - PolyDeriveUniformX4(ps, seed, nonces) - } -} - -// Set p to the inner product of a and b using pointwise multiplication. -// -// Assumes a and b are in Montgomery form and their coefficients are -// pairwise sufficiently small to multiply, see Poly.MulHat(). Resulting -// coefficients are bounded by 2Lq. -func PolyDotHat(p *common.Poly, a, b *VecL) { - var t common.Poly - *p = common.Poly{} // zero p - for i := 0; i < L; i++ { - t.MulHat(&a[i], &b[i]) - p.Add(&t, p) - } -} diff --git a/sign/dilithium/mode5aes/internal/pack.go b/sign/dilithium/mode5aes/internal/pack.go deleted file mode 100644 index 1854b4197..000000000 --- a/sign/dilithium/mode5aes/internal/pack.go +++ /dev/null @@ -1,270 +0,0 @@ -// Code generated from mode3/internal/pack.go by gen.go - -package internal - -import ( - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// Writes p with norm less than or equal η into buf, which must be of -// size PolyLeqEtaSize. -// -// Assumes coefficients of p are not normalized, but in [q-η,q+η]. -func PolyPackLeqEta(p *common.Poly, buf []byte) { - if DoubleEtaBits == 4 { // compiler eliminates branch - j := 0 - for i := 0; i < PolyLeqEtaSize; i++ { - buf[i] = (byte(common.Q+Eta-p[j]) | - byte(common.Q+Eta-p[j+1])<<4) - j += 2 - } - } else if DoubleEtaBits == 3 { - j := 0 - for i := 0; i < PolyLeqEtaSize; i += 3 { - buf[i] = (byte(common.Q+Eta-p[j]) | - (byte(common.Q+Eta-p[j+1]) << 3) | - (byte(common.Q+Eta-p[j+2]) << 6)) - buf[i+1] = ((byte(common.Q+Eta-p[j+2]) >> 2) | - (byte(common.Q+Eta-p[j+3]) << 1) | - (byte(common.Q+Eta-p[j+4]) << 4) | - (byte(common.Q+Eta-p[j+5]) << 7)) - buf[i+2] = ((byte(common.Q+Eta-p[j+5]) >> 1) | - (byte(common.Q+Eta-p[j+6]) << 2) | - (byte(common.Q+Eta-p[j+7]) << 5)) - j += 8 - } - } else { - panic("eta not supported") - } -} - -// Sets p to the polynomial of norm less than or equal η encoded in the -// given buffer of size PolyLeqEtaSize. -// -// Output coefficients of p are not normalized, but in [q-η,q+η] provided -// buf was created using PackLeqEta. -// -// Beware, for arbitrary buf the coefficients of p might end up in -// the interval [q-2^b,q+2^b] where b is the least b with η≤2^b. -func PolyUnpackLeqEta(p *common.Poly, buf []byte) { - if DoubleEtaBits == 4 { // compiler eliminates branch - j := 0 - for i := 0; i < PolyLeqEtaSize; i++ { - p[j] = common.Q + Eta - uint32(buf[i]&15) - p[j+1] = common.Q + Eta - uint32(buf[i]>>4) - j += 2 - } - } else if DoubleEtaBits == 3 { - j := 0 - for i := 0; i < PolyLeqEtaSize; i += 3 { - p[j] = common.Q + Eta - uint32(buf[i]&7) - p[j+1] = common.Q + Eta - uint32((buf[i]>>3)&7) - p[j+2] = common.Q + Eta - uint32((buf[i]>>6)|((buf[i+1]<<2)&7)) - p[j+3] = common.Q + Eta - uint32((buf[i+1]>>1)&7) - p[j+4] = common.Q + Eta - uint32((buf[i+1]>>4)&7) - p[j+5] = common.Q + Eta - uint32((buf[i+1]>>7)|((buf[i+2]<<1)&7)) - p[j+6] = common.Q + Eta - uint32((buf[i+2]>>2)&7) - p[j+7] = common.Q + Eta - uint32((buf[i+2]>>5)&7) - j += 8 - } - } else { - panic("eta not supported") - } -} - -// Writes v with coefficients in {0, 1} of which at most ω non-zero -// to buf, which must have length ω+k. -func (v *VecK) PackHint(buf []byte) { - // The packed hint starts with the indices of the non-zero coefficients - // For instance: - // - // (x⁵⁶ + x¹⁰⁰, x²⁵⁵, 0, x² + x²³, x¹) - // - // Yields - // - // 56, 100, 255, 2, 23, 1 - // - // Then we pad with zeroes until we have a list of ω items: - // // 56, 100, 255, 2, 23, 1, 0, 0, ..., 0 - // - // Then we finish with a list of the switch-over-indices in this - // list between polynomials, so: - // - // 56, 100, 255, 2, 23, 1, 0, 0, ..., 0, 2, 3, 3, 5, 6 - - off := uint8(0) - for i := 0; i < K; i++ { - for j := uint16(0); j < common.N; j++ { - if v[i][j] != 0 { - buf[off] = uint8(j) - off++ - } - } - buf[Omega+i] = off - } - for ; off < Omega; off++ { - buf[off] = 0 - } -} - -// Sets v to the vector encoded using VecK.PackHint() -// -// Returns whether unpacking was successful. -func (v *VecK) UnpackHint(buf []byte) bool { - // A priori, there would be several reasonable ways to encode the same - // hint vector. We take care to only allow only one encoding, to ensure - // "strong unforgeability". - // - // See PackHint() source for description of the encoding. - *v = VecK{} // zero v - prevSOP := uint8(0) // previous switch-over-point - for i := 0; i < K; i++ { - SOP := buf[Omega+i] - if SOP < prevSOP || SOP > Omega { - return false // ensures switch-over-points are increasing - } - for j := prevSOP; j < SOP; j++ { - if j > prevSOP && buf[j] <= buf[j-1] { - return false // ensures indices are increasing (within a poly) - } - v[i][buf[j]] = 1 - } - prevSOP = SOP - } - for j := prevSOP; j < Omega; j++ { - if buf[j] != 0 { - return false // ensures padding indices are zero - } - } - - return true -} - -// Sets p to the polynomial packed into buf by PolyPackLeGamma1. -// -// p will be normalized. -func PolyUnpackLeGamma1(p *common.Poly, buf []byte) { - if Gamma1Bits == 17 { - j := 0 - for i := 0; i < PolyLeGamma1Size; i += 9 { - p0 := uint32(buf[i]) | (uint32(buf[i+1]) << 8) | - (uint32(buf[i+2]&0x3) << 16) - p1 := uint32(buf[i+2]>>2) | (uint32(buf[i+3]) << 6) | - (uint32(buf[i+4]&0xf) << 14) - p2 := uint32(buf[i+4]>>4) | (uint32(buf[i+5]) << 4) | - (uint32(buf[i+6]&0x3f) << 12) - p3 := uint32(buf[i+6]>>6) | (uint32(buf[i+7]) << 2) | - (uint32(buf[i+8]) << 10) - - // coefficients in [0,…,2γ₁) - p0 = Gamma1 - p0 // (-γ₁,…,γ₁] - p1 = Gamma1 - p1 - p2 = Gamma1 - p2 - p3 = Gamma1 - p3 - - p0 += uint32(int32(p0)>>31) & common.Q // normalize - p1 += uint32(int32(p1)>>31) & common.Q - p2 += uint32(int32(p2)>>31) & common.Q - p3 += uint32(int32(p3)>>31) & common.Q - - p[j] = p0 - p[j+1] = p1 - p[j+2] = p2 - p[j+3] = p3 - - j += 4 - } - } else if Gamma1Bits == 19 { - j := 0 - for i := 0; i < PolyLeGamma1Size; i += 5 { - p0 := uint32(buf[i]) | (uint32(buf[i+1]) << 8) | - (uint32(buf[i+2]&0xf) << 16) - p1 := uint32(buf[i+2]>>4) | (uint32(buf[i+3]) << 4) | - (uint32(buf[i+4]) << 12) - - p0 = Gamma1 - p0 - p1 = Gamma1 - p1 - - p0 += uint32(int32(p0)>>31) & common.Q - p1 += uint32(int32(p1)>>31) & common.Q - - p[j] = p0 - p[j+1] = p1 - - j += 2 - } - } else { - panic("γ₁ not supported") - } -} - -// Writes p whose coefficients are in (-γ₁,γ₁] into buf -// which has to be of length PolyLeGamma1Size. -// -// Assumes p is normalized. -func PolyPackLeGamma1(p *common.Poly, buf []byte) { - if Gamma1Bits == 17 { - j := 0 - // coefficients in [0,…,γ₁] ∪ (q-γ₁,…,q) - for i := 0; i < PolyLeGamma1Size; i += 9 { - p0 := Gamma1 - p[j] // [0,…,γ₁] ∪ (γ₁-q,…,2γ₁-q) - p0 += uint32(int32(p0)>>31) & common.Q // [0,…,2γ₁) - p1 := Gamma1 - p[j+1] - p1 += uint32(int32(p1)>>31) & common.Q - p2 := Gamma1 - p[j+2] - p2 += uint32(int32(p2)>>31) & common.Q - p3 := Gamma1 - p[j+3] - p3 += uint32(int32(p3)>>31) & common.Q - - buf[i+0] = byte(p0) - buf[i+1] = byte(p0 >> 8) - buf[i+2] = byte(p0>>16) | byte(p1<<2) - buf[i+3] = byte(p1 >> 6) - buf[i+4] = byte(p1>>14) | byte(p2<<4) - buf[i+5] = byte(p2 >> 4) - buf[i+6] = byte(p2>>12) | byte(p3<<6) - buf[i+7] = byte(p3 >> 2) - buf[i+8] = byte(p3 >> 10) - - j += 4 - } - } else if Gamma1Bits == 19 { - j := 0 - for i := 0; i < PolyLeGamma1Size; i += 5 { - // Coefficients are in [0, γ₁] ∪ (Q-γ₁, Q) - p0 := Gamma1 - p[j] - p0 += uint32(int32(p0)>>31) & common.Q - p1 := Gamma1 - p[j+1] - p1 += uint32(int32(p1)>>31) & common.Q - - buf[i+0] = byte(p0) - buf[i+1] = byte(p0 >> 8) - buf[i+2] = byte(p0>>16) | byte(p1<<4) - buf[i+3] = byte(p1 >> 4) - buf[i+4] = byte(p1 >> 12) - - j += 2 - } - } else { - panic("γ₁ not supported") - } -} - -// Pack w₁ into buf, which must be of length PolyW1Size. -// -// Assumes w₁ is normalized. -func PolyPackW1(p *common.Poly, buf []byte) { - if Gamma1Bits == 19 { - p.PackLe16(buf) - } else if Gamma1Bits == 17 { - j := 0 - for i := 0; i < PolyW1Size; i += 3 { - buf[i] = byte(p[j]) | byte(p[j+1]<<6) - buf[i+1] = byte(p[j+1]>>2) | byte(p[j+2]<<4) - buf[i+2] = byte(p[j+2]>>4) | byte(p[j+3]<<2) - j += 4 - } - } else { - panic("unsupported γ₁") - } -} diff --git a/sign/dilithium/mode5aes/internal/pack_test.go b/sign/dilithium/mode5aes/internal/pack_test.go deleted file mode 100644 index f952c6a09..000000000 --- a/sign/dilithium/mode5aes/internal/pack_test.go +++ /dev/null @@ -1,93 +0,0 @@ -// Code generated from mode3/internal/pack_test.go by gen.go - -package internal - -import ( - "testing" - - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -func TestPolyPackLeqEta(t *testing.T) { - var p1, p2 common.Poly - var seed [64]byte - var buf [PolyLeqEtaSize]byte - - for i := uint16(0); i < 100; i++ { - // Note that DeriveUniformLeqEta sets p to the right kind of - // unnormalized vector. - PolyDeriveUniformLeqEta(&p1, &seed, i) - for j := 0; j < PolyLeqEtaSize; j++ { - if p1[j] < common.Q-Eta || p1[j] > common.Q+Eta { - t.Fatalf("DerveUniformLeqEta out of bounds") - } - } - PolyPackLeqEta(&p1, buf[:]) - PolyUnpackLeqEta(&p2, buf[:]) - if p1 != p2 { - t.Fatalf("%v != %v", p1, p2) - } - } -} - -func TestPolyPackT1(t *testing.T) { - var p1, p2 common.Poly - var seed [32]byte - var buf [common.PolyT1Size]byte - - for i := uint16(0); i < 100; i++ { - PolyDeriveUniform(&p1, &seed, i) - p1.Normalize() - for j := 0; j < common.N; j++ { - p1[j] &= 0x1ff - } - p1.PackT1(buf[:]) - p2.UnpackT1(buf[:]) - if p1 != p2 { - t.Fatalf("%v != %v", p1, p2) - } - } -} - -func TestPolyPackT0(t *testing.T) { - var p, p0, p1, p2 common.Poly - var seed [32]byte - var buf [common.PolyT0Size]byte - - for i := uint16(0); i < 100; i++ { - PolyDeriveUniform(&p, &seed, i) - p.Normalize() - p.Power2Round(&p0, &p1) - - p0.PackT0(buf[:]) - p2.UnpackT0(buf[:]) - if p0 != p2 { - t.Fatalf("%v !=\n%v", p0, p2) - } - } -} - -func BenchmarkUnpackLeGamma1(b *testing.B) { - var p common.Poly - var buf [PolyLeGamma1Size]byte - for i := 0; i < b.N; i++ { - PolyUnpackLeGamma1(&p, buf[:]) - } -} - -func TestPolyPackLeGamma1(t *testing.T) { - var p0, p1 common.Poly - var seed [64]byte - var buf [PolyLeGamma1Size]byte - - for i := uint16(0); i < 100; i++ { - PolyDeriveUniformLeGamma1(&p0, &seed, i) - p0.Normalize() - - PolyPackLeGamma1(&p0, buf[:]) - PolyUnpackLeGamma1(&p1, buf[:]) - if p0 != p1 { - t.Fatalf("%v != %v", p0, p1) - } - } -} diff --git a/sign/dilithium/mode5aes/internal/params.go b/sign/dilithium/mode5aes/internal/params.go deleted file mode 100644 index 340b6d73a..000000000 --- a/sign/dilithium/mode5aes/internal/params.go +++ /dev/null @@ -1,19 +0,0 @@ -// Code generated from params.templ.go. DO NOT EDIT. - -package internal - -const ( - Name = "Dilithium5-AES" - UseAES = true - K = 8 - L = 7 - Eta = 2 - DoubleEtaBits = 3 - Omega = 75 - Tau = 60 - Gamma1Bits = 19 - Gamma2 = 261888 - NIST = false - TRSize = 32 - CTildeSize = 32 -) diff --git a/sign/dilithium/mode5aes/internal/params_test.go b/sign/dilithium/mode5aes/internal/params_test.go deleted file mode 100644 index 57e14f820..000000000 --- a/sign/dilithium/mode5aes/internal/params_test.go +++ /dev/null @@ -1,100 +0,0 @@ -package internal - -import ( - "testing" - - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// Tests specific to the current mode - -func TestVectorDeriveUniformLeqEta(t *testing.T) { - var p common.Poly - var seed [64]byte - p2 := common.Poly{ - 8380416, 0, 2, 8380415, 1, 1, 0, 1, 0, 1, 8380415, 2, - 8380415, 8380415, 2, 2, 2, 1, 0, 2, 8380416, 1, 8380415, - 8380415, 8380416, 8380415, 8380416, 8380415, 1, 1, 0, 1, - 0, 1, 2, 8380416, 2, 1, 8380416, 1, 1, 2, 0, 8380416, - 8380416, 2, 0, 2, 8380415, 0, 1, 2, 1, 1, 1, 0, 8380415, - 1, 2, 8380415, 8380416, 1, 8380415, 0, 1, 8380416, 8380416, - 8380415, 0, 2, 8380415, 1, 8380416, 0, 8380416, 8380416, - 8380416, 2, 2, 1, 2, 8380415, 2, 0, 8380415, 8380415, 0, - 2, 8380415, 8380415, 1, 8380415, 2, 8380415, 0, 1, 2, - 8380415, 8380416, 8380415, 0, 8380416, 1, 0, 2, 0, 2, - 8380415, 8380416, 2, 1, 8380415, 1, 8380416, 1, 8380415, - 8380415, 0, 8380416, 0, 0, 0, 0, 0, 2, 1, 2, 0, 0, 8380415, - 8380416, 2, 0, 1, 8380416, 2, 1, 8380416, 2, 1, 8380416, - 0, 2, 8380416, 2, 0, 8380415, 0, 2, 0, 8380415, 1, 0, - 8380415, 2, 8380416, 8380416, 8380415, 0, 0, 8380416, 2, - 2, 1, 8380416, 2, 1, 2, 0, 8380415, 1, 0, 2, 2, 1, 0, 0, - 1, 2, 0, 2, 0, 2, 2, 0, 0, 2, 2, 8380416, 2, 2, 0, 8380415, - 1, 2, 2, 1, 1, 8380415, 8380415, 2, 2, 1, 8380416, 8380415, - 2, 1, 0, 8380416, 8380415, 8380415, 0, 1, 0, 8380416, - 8380416, 8380416, 8380416, 2, 8380415, 1, 8380415, 0, 1, - 0, 8380416, 2, 8380415, 2, 1, 2, 1, 1, 0, 8380415, 2, - 8380416, 8380416, 8380415, 8380415, 0, 2, 8380416, 1, - 8380416, 8380415, 8380416, 8380415, 2, 8380416, 2, 8380415, - 2, 2, 1, 8380415, - } - for i := 0; i < 64; i++ { - seed[i] = byte(i) - } - PolyDeriveUniformLeqEta(&p, &seed, 30000) - p.Normalize() - if p != p2 { - t.Fatalf("%v != %v", p, p2) - } -} - -func TestVectorDeriveUniformLeGamma1(t *testing.T) { - var p, p2 common.Poly - var seed [64]byte - p2 = common.Poly{ - 91453, 8134283, 8211453, 8218977, 8362980, 431655, 98537, - 320966, 7892886, 144675, 495826, 7910635, 308711, 8024934, - 8314212, 8323958, 8242606, 7947101, 419492, 427692, 354075, - 21485, 456475, 213575, 362300, 8142303, 8322444, 7885879, - 89158, 181715, 8094655, 8303634, 8060028, 7920325, 192378, - 7910586, 7897074, 8097343, 7899868, 8339413, 73206, 237312, - 8183555, 348083, 8154041, 8364746, 8078364, 8312790, 105195, - 8037823, 8356712, 7994594, 240882, 70742, 8109371, 8176349, - 467152, 51422, 340432, 8030176, 342172, 154911, 64858, - 97614, 212758, 8285880, 521738, 326395, 296748, 8111442, - 8016327, 7953747, 158922, 330421, 8331843, 449771, 168214, - 8198309, 8228760, 7940533, 2498, 305217, 475829, 8037995, - 8250962, 305070, 8217080, 432779, 213808, 8162729, 381514, - 7995827, 7989202, 129047, 246099, 67554, 8233257, 398954, - 223629, 444125, 150369, 223365, 159236, 55259, 172419, - 163583, 354428, 8263789, 8017325, 8229594, 32340, 490228, - 450684, 8069619, 53733, 7932894, 7955848, 8197876, 201557, - 8307246, 446889, 8211538, 7889784, 8071108, 496027, 8159198, - 8037, 7973907, 248186, 4806, 185437, 457847, 138862, 8124477, - 284692, 8255820, 8068729, 8292005, 244272, 8061114, 21475, - 8058902, 421466, 8306487, 455649, 8218652, 7634, 148216, - 7951766, 394889, 8127579, 366374, 8062903, 8139245, 367068, - 8281027, 734, 396374, 7969282, 7977632, 8098596, 343569, - 8191282, 223874, 163783, 203572, 109732, 8229113, 8128208, - 321529, 296492, 8202474, 50404, 8336017, 8190899, 8191497, - 8279167, 336877, 7878526, 7922949, 7974614, 8076047, 8201365, - 8334333, 416495, 8090175, 150066, 7947253, 474615, 7937629, - 8027358, 356569, 191566, 87441, 8219157, 8375553, 8029697, - 8026188, 8193863, 295873, 7906281, 487687, 8363474, 386621, - 282726, 8373831, 50680, 8239505, 7912018, 493972, 8335677, - 8079840, 251210, 263667, 221541, 41291, 88028, 8373098, - 505241, 7981448, 8308113, 299485, 428036, 93865, 90428, - 392003, 80833, 7975521, 336649, 7950328, 8049195, 8332757, - 8205291, 8178296, 7911197, 7925805, 519154, 60176, 54121, - 222738, 464285, 8022604, 8174235, 7856202, 8291898, 473254, - 8106411, 7943812, 267650, 7958173, 372387, 409597, 204263, - 477847, 83925, 111791, - } - for i := 0; i < 64; i++ { - seed[i] = byte(i) - } - PolyDeriveUniformLeGamma1(&p, &seed, 30000) - p.Normalize() - if p != p2 { - t.Fatalf("%v != %v", p, p2) - } -} diff --git a/sign/dilithium/mode5aes/internal/rounding.go b/sign/dilithium/mode5aes/internal/rounding.go deleted file mode 100644 index 58123c090..000000000 --- a/sign/dilithium/mode5aes/internal/rounding.go +++ /dev/null @@ -1,142 +0,0 @@ -// Code generated from mode3/internal/rounding.go by gen.go - -package internal - -import ( - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// Splits 0 ≤ a < q into a₀ and a₁ with a = a₁*α + a₀ with -α/2 < a₀ ≤ α/2, -// except for when we would have a₁ = (q-1)/α in which case a₁=0 is taken -// and -α/2 ≤ a₀ < 0. Returns a₀ + q. Note 0 ≤ a₁ < (q-1)/α. -// Recall α = 2γ₂. -func decompose(a uint32) (a0plusQ, a1 uint32) { - // a₁ = ⌈a / 128⌉ - a1 = (a + 127) >> 7 - - if Alpha == 523776 { - // 1025/2²² is close enough to 1/4092 so that a₁ - // becomes a/α rounded down. - a1 = ((a1*1025 + (1 << 21)) >> 22) - - // For the corner-case a₁ = (q-1)/α = 16, we have to set a₁=0. - a1 &= 15 - } else if Alpha == 190464 { - // 1488/2²⁴ is close enough to 1/1488 so that a₁ - // becomes a/α rounded down. - a1 = ((a1 * 11275) + (1 << 23)) >> 24 - - // For the corner-case a₁ = (q-1)/α = 44, we have to set a₁=0. - a1 ^= uint32(int32(43-a1)>>31) & a1 - } else { - panic("unsupported α") - } - - a0plusQ = a - a1*Alpha - - // In the corner-case, when we set a₁=0, we will incorrectly - // have a₀ > (q-1)/2 and we'll need to subtract q. As we - // return a₀ + q, that comes down to adding q if a₀ < (q-1)/2. - a0plusQ += uint32(int32(a0plusQ-(common.Q-1)/2)>>31) & common.Q - - return -} - -// Assume 0 ≤ r, f < Q with ‖f‖_∞ ≤ α/2. Decompose r as r = r1*α + r0 as -// computed by decompose(). Write r' := r - f (mod Q). Now, decompose -// r'=r-f again as r' = r'1*α + r'0 using decompose(). As f is small, we -// have r'1 = r1 + h, where h ∈ {-1, 0, 1}. makeHint() computes |h| -// given z0 := r0 - f (mod Q) and r1. With |h|, which is called the hint, -// we can reconstruct r1 using only r' = r - f, which is done by useHint(). -// To wit: -// -// useHint( r - f, makeHint( r0 - f, r1 ) ) = r1. -// -// Assumes 0 ≤ z0 < Q. -func makeHint(z0, r1 uint32) uint32 { - // If -α/2 < r0 - f ≤ α/2, then r1*α + r0 - f is a valid decomposition of r' - // with the restrictions of decompose() and so r'1 = r1. So the hint - // should be 0. This is covered by the first two inequalities. - // There is one other case: if r0 - f = -α/2, then r1*α + r0 - f is also - // a valid decomposition if r1 = 0. In the other cases a one is carried - // and the hint should be 1. - if z0 <= Gamma2 || z0 > common.Q-Gamma2 || (z0 == common.Q-Gamma2 && r1 == 0) { - return 0 - } - return 1 -} - -// Uses the hint created by makeHint() to reconstruct r1 from r'=r-f; see -// documentation of makeHint() for context. -// Assumes 0 ≤ r' < Q. -func useHint(rp uint32, hint uint32) uint32 { - rp0plusQ, rp1 := decompose(rp) - if hint == 0 { - return rp1 - } - if rp0plusQ > common.Q { - return (rp1 + 1) & 15 - } - return (rp1 - 1) & 15 -} - -// Sets p to the hint polynomial for p0 the modified low bits and p1 -// the unmodified high bits --- see makeHint(). -// -// Returns the number of ones in the hint polynomial. -func PolyMakeHint(p, p0, p1 *common.Poly) (pop uint32) { - for i := 0; i < common.N; i++ { - h := makeHint(p0[i], p1[i]) - pop += h - p[i] = h - } - return -} - -// Computes corrections to the high bits of the polynomial q according -// to the hints in h and sets p to the corrected high bits. Returns p. -func PolyUseHint(p, q, hint *common.Poly) { - var q0PlusQ common.Poly - - // See useHint() and makeHint() for an explanation. We reimplement it - // here so that we can call Poly.Decompose(), which might be way faster - // than calling decompose() in a loop (for instance when having AVX2.) - - PolyDecompose(q, &q0PlusQ, p) - - for i := 0; i < common.N; i++ { - if hint[i] == 0 { - continue - } - if Gamma2 == 261888 { - if q0PlusQ[i] > common.Q { - p[i] = (p[i] + 1) & 15 - } else { - p[i] = (p[i] - 1) & 15 - } - } else if Gamma2 == 95232 { - if q0PlusQ[i] > common.Q { - if p[i] == 43 { - p[i] = 0 - } else { - p[i]++ - } - } else { - if p[i] == 0 { - p[i] = 43 - } else { - p[i]-- - } - } - } else { - panic("unsupported γ₂") - } - } -} - -// Splits each of the coefficients of p using decompose. -func PolyDecompose(p, p0PlusQ, p1 *common.Poly) { - for i := 0; i < common.N; i++ { - p0PlusQ[i], p1[i] = decompose(p[i]) - } -} diff --git a/sign/dilithium/mode5aes/internal/rounding_test.go b/sign/dilithium/mode5aes/internal/rounding_test.go deleted file mode 100644 index ad653ca3f..000000000 --- a/sign/dilithium/mode5aes/internal/rounding_test.go +++ /dev/null @@ -1,81 +0,0 @@ -// Code generated from mode3/internal/rounding_test.go by gen.go - -package internal - -import ( - "flag" - "testing" - - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -var runVeryLongTest = flag.Bool("very-long", false, "runs very long tests") - -func TestDecompose(t *testing.T) { - for a := uint32(0); a < common.Q; a++ { - a0PlusQ, a1 := decompose(a) - a0 := int32(a0PlusQ) - int32(common.Q) - recombined := a0 + int32(Alpha*a1) - if a1 == 0 && recombined < 0 { - recombined += common.Q - if -(Alpha/2) > a0 || a0 >= 0 { - t.Fatalf("decompose(%v): a0 out of bounds", a) - } - } else { - if (-(Alpha / 2) >= a0) || (a0 > Alpha/2) { - t.Fatalf("decompose(%v): a0 out of bounds", a) - } - } - if int32(a) != recombined { - t.Fatalf("decompose(%v) doesn't recombine %v %v", a, a0, a1) - } - } -} - -func TestMakeHint(t *testing.T) { - if !*runVeryLongTest { - t.SkipNow() - } - for w := uint32(0); w < common.Q; w++ { - w0, w1 := decompose(w) - for fn := uint32(0); fn <= Gamma2; fn++ { - fsign := false - for { - var f uint32 - if fsign { - if fn == 0 { - break - } - f = common.Q - fn - } else { - f = fn - } - - hint := makeHint(common.ReduceLe2Q(w0+common.Q-f), w1) - w1p := useHint(common.ReduceLe2Q(w+common.Q-f), hint) - if w1p != w1 { - t.Fatal() - } - - if fsign { - break - } - fsign = true - } - } - } -} - -func BenchmarkDecompose(b *testing.B) { - var p, p0, p1 common.Poly - for i := 0; i < b.N; i++ { - PolyDecompose(&p, &p0, &p1) - } -} - -func BenchmarkMakeHint(b *testing.B) { - var p, p0, p1 common.Poly - for i := 0; i < b.N; i++ { - PolyMakeHint(&p, &p0, &p1) - } -} diff --git a/sign/dilithium/mode5aes/internal/sample.go b/sign/dilithium/mode5aes/internal/sample.go deleted file mode 100644 index 62c261332..000000000 --- a/sign/dilithium/mode5aes/internal/sample.go +++ /dev/null @@ -1,370 +0,0 @@ -// Code generated from mode3/internal/sample.go by gen.go - -package internal - -import ( - "encoding/binary" - - "github.com/cloudflare/circl/internal/sha3" - common "github.com/cloudflare/circl/sign/internal/dilithium" - "github.com/cloudflare/circl/simd/keccakf1600" -) - -// DeriveX4Available indicates whether the system supports the quick fourway -// sampling variants like PolyDeriveUniformX4. -var DeriveX4Available = keccakf1600.IsEnabledX4() && !UseAES - -// For each i, sample ps[i] uniformly from the given seed and nonces[i]. -// ps[i] may be nil and is ignored in that case. -// -// Can only be called when DeriveX4Available is true. -func PolyDeriveUniformX4(ps [4]*common.Poly, seed *[32]byte, nonces [4]uint16) { - var perm keccakf1600.StateX4 - state := perm.Initialize(false) - - // Absorb the seed in the four states - for i := 0; i < 4; i++ { - v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) - for j := 0; j < 4; j++ { - state[i*4+j] = v - } - } - - // Absorb the nonces, the SHAKE128 domain separator (0b1111), the - // start of the padding (0b...001) and the end of the padding 0b100... - // Recall that the rate of SHAKE128 is 168 --- i.e. 21 uint64s. - for j := 0; j < 4; j++ { - state[4*4+j] = uint64(nonces[j]) | (0x1f << 16) - state[20*4+j] = 0x80 << 56 - } - - var idx [4]int // indices into ps - for j := 0; j < 4; j++ { - if ps[j] == nil { - idx[j] = common.N // mark nil polynomial as completed - } - } - - done := false - for !done { - // Applies KeccaK-f[1600] to state to get the next 21 uint64s of each - // of the four SHAKE128 streams. - perm.Permute() - - done = true - - PolyLoop: - for j := 0; j < 4; j++ { - if idx[j] == common.N { - continue - } - for i := 0; i < 7; i++ { - var t [8]uint32 - t[0] = uint32(state[i*3*4+j] & 0x7fffff) - t[1] = uint32((state[i*3*4+j] >> 24) & 0x7fffff) - t[2] = uint32((state[i*3*4+j] >> 48) | - ((state[(i*3+1)*4+j] & 0x7f) << 16)) - t[3] = uint32((state[(i*3+1)*4+j] >> 8) & 0x7fffff) - t[4] = uint32((state[(i*3+1)*4+j] >> 32) & 0x7fffff) - t[5] = uint32((state[(i*3+1)*4+j] >> 56) | - ((state[(i*3+2)*4+j] & 0x7fff) << 8)) - t[6] = uint32((state[(i*3+2)*4+j] >> 16) & 0x7fffff) - t[7] = uint32((state[(i*3+2)*4+j] >> 40) & 0x7fffff) - - for k := 0; k < 8; k++ { - if t[k] < common.Q { - ps[j][idx[j]] = t[k] - idx[j]++ - if idx[j] == common.N { - continue PolyLoop - } - } - } - } - done = false - } - } -} - -// Sample p uniformly from the given seed and nonce. -// -// p will be normalized. -func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { - var i, length int - var buf [12 * 16]byte // fits 168B SHAKE-128 rate and 12 16B AES blocks - - if UseAES { - length = 12 * 16 - } else { - length = 168 - } - - sample := func() { - // Note that 3 divides into 168 and 12*16, so we use up buf completely. - for j := 0; j < length && i < common.N; j += 3 { - t := (uint32(buf[j]) | (uint32(buf[j+1]) << 8) | - (uint32(buf[j+2]) << 16)) & 0x7fffff - - // We use rejection sampling - if t < common.Q { - p[i] = t - i++ - } - } - } - - if UseAES { - h := common.NewAesStream128(seed, nonce) - - for i < common.N { - h.SqueezeInto(buf[:length]) - sample() - } - } else { - var iv [32 + 2]byte // 32 byte seed + uint16 nonce - h := sha3.NewShake128() - copy(iv[:32], seed[:]) - iv[32] = uint8(nonce) - iv[33] = uint8(nonce >> 8) - _, _ = h.Write(iv[:]) - - for i < common.N { - _, _ = h.Read(buf[:168]) - sample() - } - } -} - -// Sample p uniformly with coefficients of norm less than or equal η, -// using the given seed and nonce. -// -// p will not be normalized, but will have coefficients in [q-η,q+η]. -func PolyDeriveUniformLeqEta(p *common.Poly, seed *[64]byte, nonce uint16) { - // Assumes 2 < η < 8. - var i, length int - var buf [9 * 16]byte // fits 136B SHAKE-256 rate and 9 16B AES blocks - - if UseAES { - length = 9 * 16 - } else { - length = 136 - } - - sample := func() { - // We use rejection sampling - for j := 0; j < length && i < common.N; j++ { - t1 := uint32(buf[j]) & 15 - t2 := uint32(buf[j]) >> 4 - if Eta == 2 { // branch is eliminated by compiler - if t1 <= 14 { - t1 -= ((205 * t1) >> 10) * 5 // reduce mod 5 - p[i] = common.Q + Eta - t1 - i++ - } - if t2 <= 14 && i < common.N { - t2 -= ((205 * t2) >> 10) * 5 // reduce mod 5 - p[i] = common.Q + Eta - t2 - i++ - } - } else if Eta == 4 { - if t1 <= 2*Eta { - p[i] = common.Q + Eta - t1 - i++ - } - if t2 <= 2*Eta && i < common.N { - p[i] = common.Q + Eta - t2 - i++ - } - } else { - panic("unsupported η") - } - } - } - - if UseAES { - h := common.NewAesStream256(seed, nonce) - - for i < common.N { - h.SqueezeInto(buf[:length]) - sample() - } - } else { - var iv [64 + 2]byte // 64 byte seed + uint16 nonce - - h := sha3.NewShake256() - copy(iv[:64], seed[:]) - iv[64] = uint8(nonce) - iv[65] = uint8(nonce >> 8) - - // 136 is SHAKE-256 rate - _, _ = h.Write(iv[:]) - - for i < common.N { - _, _ = h.Read(buf[:136]) - sample() - } - } -} - -// Sample v[i] uniformly with coefficients in (-γ₁,…,γ₁] using the -// given seed and nonce+i -// -// p will be normalized. -func VecLDeriveUniformLeGamma1(v *VecL, seed *[64]byte, nonce uint16) { - for i := 0; i < L; i++ { - PolyDeriveUniformLeGamma1(&v[i], seed, nonce+uint16(i)) - } -} - -// Sample p uniformly with coefficients in (-γ₁,…,γK1s] using the -// given seed and nonce. -// -// p will be normalized. -func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { - var buf [PolyLeGamma1Size]byte - - if UseAES { - h := common.NewAesStream256(seed, nonce) - h.SqueezeInto(buf[:]) - } else { - var iv [66]byte - h := sha3.NewShake256() - copy(iv[:64], seed[:]) - iv[64] = uint8(nonce) - iv[65] = uint8(nonce >> 8) - _, _ = h.Write(iv[:]) - _, _ = h.Read(buf[:]) - } - - PolyUnpackLeGamma1(p, buf[:]) -} - -// For each i, sample ps[i] uniformly with τ non-zero coefficients in {q-1,1} -// using the given seed and w1[i]. ps[i] may be nil and is ignored -// in that case. ps[i] will be normalized. -// -// Can only be called when DeriveX4Available is true. -// -// This function is currently not used (yet). -func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed []byte) { - var perm keccakf1600.StateX4 - state := perm.Initialize(false) - - // Absorb the seed in the four states - for i := 0; i < 32/8; i++ { - v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) - for j := 0; j < 4; j++ { - state[i*4+j] = v - } - } - - // SHAKE256 domain separator and padding - for j := 0; j < 4; j++ { - state[(32/8)*4+j] ^= 0x1f - state[16*4+j] ^= 0x80 << 56 - } - perm.Permute() - - var signs [4]uint64 - var idx [4]uint16 // indices into ps - - for j := 0; j < 4; j++ { - if ps[j] != nil { - signs[j] = state[j] - *ps[j] = common.Poly{} // zero ps[j] - idx[j] = common.N - Tau - } else { - idx[j] = common.N // mark as completed - } - } - - stateOffset := 1 - for { - done := true - - PolyLoop: - for j := 0; j < 4; j++ { - if idx[j] == common.N { - continue - } - - for i := stateOffset; i < 17; i++ { - var bs [8]byte - binary.LittleEndian.PutUint64(bs[:], state[4*i+j]) - for k := 0; k < 8; k++ { - b := uint16(bs[k]) - - if b > idx[j] { - continue - } - - ps[j][idx[j]] = ps[j][b] - ps[j][b] = 1 - // Takes least significant bit of signs and uses it for the sign. - // Note 1 ^ (1 | (Q-1)) = Q-1. - ps[j][b] ^= uint32((-(signs[j] & 1)) & (1 | (common.Q - 1))) - signs[j] >>= 1 - - idx[j]++ - if idx[j] == common.N { - continue PolyLoop - } - } - } - - done = false - } - - if done { - break - } - - perm.Permute() - stateOffset = 0 - } -} - -// Samples p uniformly with τ non-zero coefficients in {q-1,1}. -// -// The polynomial p will be normalized. -func PolyDeriveUniformBall(p *common.Poly, seed []byte) { - var buf [136]byte // SHAKE-256 rate is 136 - - h := sha3.NewShake256() - _, _ = h.Write(seed[:]) - _, _ = h.Read(buf[:]) - - // Essentially we generate a sequence of τ ones or minus ones, - // prepend 196 zeroes and shuffle the concatenation using the - // usual algorithm (Fisher--Yates.) - signs := binary.LittleEndian.Uint64(buf[:]) - bufOff := 8 // offset into buf - - *p = common.Poly{} // zero p - for i := uint16(common.N - Tau); i < common.N; i++ { - var b uint16 - - // Find location of where to move the new coefficient to using - // rejection sampling. - for { - if bufOff >= 136 { - _, _ = h.Read(buf[:]) - bufOff = 0 - } - - b = uint16(buf[bufOff]) - bufOff++ - - if b <= i { - break - } - } - - p[i] = p[b] - p[b] = 1 - // Takes least significant bit of signs and uses it for the sign. - // Note 1 ^ (1 | (Q-1)) = Q-1. - p[b] ^= uint32((-(signs & 1)) & (1 | (common.Q - 1))) - signs >>= 1 - } -} diff --git a/sign/dilithium/mode5aes/internal/sample_test.go b/sign/dilithium/mode5aes/internal/sample_test.go deleted file mode 100644 index 2059599eb..000000000 --- a/sign/dilithium/mode5aes/internal/sample_test.go +++ /dev/null @@ -1,266 +0,0 @@ -// Code generated from mode3/internal/sample_test.go by gen.go - -package internal - -import ( - "encoding/binary" - "testing" - - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -func TestVectorDeriveUniform(t *testing.T) { - var p, p2 common.Poly - var seed [32]byte - if UseAES { - p2 = common.Poly{ - 6724291, 310295, 6949524, 4464039, 1482136, 2522903, - 7025059, 3006320, 7286364, 7516512, 3361305, 1955529, - 4765954, 1725325, 6933066, 4299100, 6625173, 4272792, - 583034, 4971409, 2259140, 7715362, 3975394, 2341624, - 5481174, 8150082, 365246, 5491939, 1083120, 7517301, - 3104783, 2475292, 184149, 6425226, 4591622, 5964030, - 4729604, 5471092, 1828227, 1082044, 2516245, 1692580, - 3274844, 5443294, 7256740, 4989638, 3191250, 7479519, - 5124211, 5603858, 1230692, 2513454, 2828034, 4254312, - 1512596, 5245430, 5517392, 2814840, 932545, 6826733, - 3511094, 4075348, 3233981, 7268882, 2913733, 4870249, - 4123492, 8124406, 4016949, 5478752, 2750895, 603525, - 5724798, 3985430, 3483012, 6434230, 3136996, 8297976, - 4107616, 7307748, 6962904, 7544473, 1193110, 3448595, - 4814773, 5607932, 8221314, 1054046, 1541208, 1866050, - 8227412, 2925778, 5293953, 2065416, 4972769, 3616283, - 7990594, 1105530, 7121836, 1170740, 7417431, 633146, - 253820, 7235019, 3539504, 6807707, 451390, 5481526, - 2859902, 1063061, 4579730, 7126652, 7033767, 4294814, - 1414604, 7620048, 1953268, 8304556, 1156814, 1182881, - 5311519, 3057534, 5277666, 682843, 2070398, 2874278, - 4859533, 6376664, 6694074, 1590242, 2620706, 8331066, - 5643845, 5037538, 2891516, 7004879, 3754327, 5031296, - 5463118, 2420870, 8116529, 5517696, 7435129, 3873963, - 710407, 713806, 175647, 4274571, 2655021, 7319503, - 3027243, 7129679, 4213435, 2429323, 4643873, 4568526, - 649664, 1720514, 6497260, 2683517, 7672754, 7105190, - 3148405, 5898369, 5667677, 8050874, 1587139, 7315260, - 4337416, 2202680, 2338714, 557467, 6752058, 2469794, - 485071, 1617604, 3590498, 2151466, 2005823, 7727956, - 7776292, 6783433, 6787146, 1732833, 3596857, 7436284, - 4483349, 4970142, 4472608, 6478342, 1236215, 5695744, - 2280717, 2889355, 3233946, 5187812, 978685, 5177364, - 2922353, 4824807, 5302883, 6739803, 8092453, 5883903, - 816553, 6041174, 8317591, 1459178, 5332455, 1835058, - 1368601, 2820950, 3479224, 2589540, 7992934, 3421045, - 4657128, 8292902, 4153567, 3553988, 7830320, 6722913, - 2555309, 4149801, 8328975, 1560545, 7757473, 3106458, - 4310856, 7135453, 3481032, 652626, 1841361, 8126828, - 6250018, 300536, 7380070, 8174419, 1418793, 6208185, - 3906256, 6679016, 1605701, 3561489, 5819724, 5746996, - 8044214, 7087187, 7102330, 4962927, 4253983, 7108567, - 4119736, 6584065, 441634, 6941656, - } - } else { - p2 = common.Poly{ - 2901364, 562527, 5258502, 3885002, 4190126, 4460268, 6884052, - 3514511, 5383040, 213206, 2155865, 5179607, 3551954, 2312357, - 6066350, 8126097, 1179080, 4787182, 6552182, 6713644, - 1561067, 7626063, 7859743, 5052321, 7032876, 7815031, 157938, - 1865184, 490802, 5717642, 3451902, 7000218, 3743250, 1677431, - 1875427, 5596150, 671623, 3819041, 6247594, 1014875, 4933545, - 7122446, 6682963, 3388398, 3335295, 943002, 1145083, 3113071, - 105967, 1916675, 7474561, 1107006, 700548, 2147909, 1603855, - 5049181, 437882, 6118899, 5656914, 6731065, 3066622, 865453, - 5427634, 981549, 4650873, 861291, 4003872, 5104220, 6171453, - 3723302, 7426315, 6137283, 4874820, 6052561, 53441, 5032874, - 5614778, 2248550, 1756499, 8280764, 8263880, 7600081, - 5118374, 795344, 7543392, 6869925, 1841187, 4181568, 584562, - 7483939, 4938664, 6863397, 5126354, 5218129, 6236086, - 4149293, 379169, 4368487, 7490569, 3409215, 1580463, 3081737, - 1278732, 7109719, 7371700, 2097931, 399836, 1700274, 7188595, - 6830029, 1548850, 6593138, 6849097, 1518037, 2859442, - 7772265, 7325153, 3281191, 7856131, 4995056, 4684325, - 1351194, 8223904, 6817307, 2484146, 131782, 397032, 7436778, - 7973479, 3171829, 5624626, 3540123, 7150120, 8313283, - 3604714, 1043574, 117692, 7797783, 7909392, 903315, 7335342, - 7501562, 5826142, 2709813, 8245473, 2369045, 2782257, - 5762833, 6474114, 6862031, 424522, 594248, 2626630, 7659983, - 5642869, 4075194, 1592129, 245547, 5271031, 3205046, 982375, - 267873, 1286496, 7230481, 3208972, 7485411, 676111, 4944500, - 2959742, 5934456, 1414847, 6067948, 1709895, 4648315, 126008, - 8258986, 2183134, 2302072, 4674924, 4306056, 7465311, - 6500270, 4247428, 4016815, 4973426, 294287, 2456847, 3289700, - 2732169, 1159447, 5569724, 140001, 3237977, 8007761, 5874533, - 255652, 3119586, 2102434, 6248250, 8152822, 8006066, 7708625, - 6997719, 6260212, 6186962, 6636650, 7836834, 7998017, - 2061516, 1197591, 1706544, 733027, 2392907, 2700000, 8254598, - 4488002, 160495, 2985325, 2036837, 2703633, 6406550, 3579947, - 6195178, 5552390, 6804584, 6305468, 5731980, 6095195, - 3323409, 1322661, 6690942, 3374630, 5615167, 479044, 3136054, - 4380418, 2833144, 7829577, 1770522, 6056687, 240415, 14780, - 3740517, 5224226, 3547288, 2083124, 4699398, 3654239, - 5624978, 585593, 3655369, 2281739, 3338565, 1908093, 7784706, - 4352830, - } - } - for i := 0; i < 32; i++ { - seed[i] = byte(i) - } - PolyDeriveUniform(&p, &seed, 30000) - if p != p2 { - t.Fatalf("%v != %v", p, p2) - } -} - -func TestDeriveUniform(t *testing.T) { - var p common.Poly - var seed [32]byte - for i := 0; i < 100; i++ { - binary.LittleEndian.PutUint64(seed[:], uint64(i)) - PolyDeriveUniform(&p, &seed, uint16(i)) - if !PolyNormalized(&p) { - t.Fatal() - } - } -} - -func TestDeriveUniformLeqEta(t *testing.T) { - var p common.Poly - var seed [64]byte - for i := 0; i < 100; i++ { - binary.LittleEndian.PutUint64(seed[:], uint64(i)) - PolyDeriveUniformLeqEta(&p, &seed, uint16(i)) - for j := 0; j < common.N; j++ { - if p[j] < common.Q-Eta || p[j] > common.Q+Eta { - t.Fatal() - } - } - } -} - -func TestDeriveUniformLeGamma1(t *testing.T) { - var p common.Poly - var seed [64]byte - for i := 0; i < 100; i++ { - binary.LittleEndian.PutUint64(seed[:], uint64(i)) - PolyDeriveUniformLeGamma1(&p, &seed, uint16(i)) - for j := 0; j < common.N; j++ { - if (p[j] > Gamma1 && p[j] <= common.Q-Gamma1) || p[j] >= common.Q { - t.Fatal() - } - } - } -} - -func TestDeriveUniformBall(t *testing.T) { - var p common.Poly - var seed [32]byte - for i := 0; i < 100; i++ { - binary.LittleEndian.PutUint64(seed[:], uint64(i)) - PolyDeriveUniformBall(&p, seed[:]) - nonzero := 0 - for j := 0; j < common.N; j++ { - if p[j] != 0 { - if p[j] != 1 && p[j] != common.Q-1 { - t.Fatal() - } - nonzero++ - } - } - if nonzero != Tau { - t.Fatal() - } - } -} - -func TestDeriveUniformX4(t *testing.T) { - if !DeriveX4Available { - t.SkipNow() - } - var ps [4]common.Poly - var p common.Poly - var seed [32]byte - nonces := [4]uint16{12345, 54321, 13532, 37377} - - for i := 0; i < len(seed); i++ { - seed[i] = byte(i) - } - - PolyDeriveUniformX4([4]*common.Poly{&ps[0], &ps[1], &ps[2], &ps[3]}, &seed, - nonces) - for i := 0; i < 4; i++ { - PolyDeriveUniform(&p, &seed, nonces[i]) - if ps[i] != p { - t.Fatal() - } - } -} - -func TestDeriveUniformBallX4(t *testing.T) { - if !DeriveX4Available { - t.SkipNow() - } - var ps [4]common.Poly - var p common.Poly - var seed [32]byte - PolyDeriveUniformBallX4( - [4]*common.Poly{&ps[0], &ps[1], &ps[2], &ps[3]}, - seed[:], - ) - for j := 0; j < 4; j++ { - PolyDeriveUniformBall(&p, seed[:]) - if ps[j] != p { - t.Fatalf("%d\n%v\n%v", j, ps[j], p) - } - } -} - -func BenchmarkPolyDeriveUniformBall(b *testing.B) { - var seed [32]byte - var p common.Poly - var w1 VecK - for i := 0; i < b.N; i++ { - w1[0][0] = uint32(i) - PolyDeriveUniformBall(&p, seed[:]) - } -} - -func BenchmarkPolyDeriveUniformBallX4(b *testing.B) { - var seed [32]byte - var p common.Poly - var w1 VecK - for i := 0; i < b.N; i++ { - w1[0][0] = uint32(i) - PolyDeriveUniformBallX4( - [4]*common.Poly{&p, &p, &p, &p}, - seed[:], - ) - } -} - -func BenchmarkPolyDeriveUniform(b *testing.B) { - var seed [32]byte - var p common.Poly - for i := 0; i < b.N; i++ { - PolyDeriveUniform(&p, &seed, uint16(i)) - } -} - -func BenchmarkPolyDeriveUniformX4(b *testing.B) { - if !DeriveX4Available { - b.SkipNow() - } - var seed [32]byte - var p [4]common.Poly - for i := 0; i < b.N; i++ { - nonce := uint16(4 * i) - PolyDeriveUniformX4([4]*common.Poly{&p[0], &p[1], &p[2], &p[3]}, - &seed, [4]uint16{nonce, nonce + 1, nonce + 2, nonce + 3}) - } -} - -func BenchmarkPolyDeriveUniformLeGamma1(b *testing.B) { - var seed [64]byte - var p common.Poly - for i := 0; i < b.N; i++ { - PolyDeriveUniformLeGamma1(&p, &seed, uint16(i)) - } -} diff --git a/sign/dilithium/mode5aes/internal/vec.go b/sign/dilithium/mode5aes/internal/vec.go deleted file mode 100644 index d07d3b245..000000000 --- a/sign/dilithium/mode5aes/internal/vec.go +++ /dev/null @@ -1,281 +0,0 @@ -// Code generated from mode3/internal/vec.go by gen.go - -package internal - -import ( - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// A vector of L polynomials. -type VecL [L]common.Poly - -// A vector of K polynomials. -type VecK [K]common.Poly - -// Normalize the polynomials in this vector. -func (v *VecL) Normalize() { - for i := 0; i < L; i++ { - v[i].Normalize() - } -} - -// Normalize the polynomials in this vector assuming their coefficients -// are already bounded by 2q. -func (v *VecL) NormalizeAssumingLe2Q() { - for i := 0; i < L; i++ { - v[i].NormalizeAssumingLe2Q() - } -} - -// Sets v to w + u. Does not normalize. -func (v *VecL) Add(w, u *VecL) { - for i := 0; i < L; i++ { - v[i].Add(&w[i], &u[i]) - } -} - -// Applies NTT componentwise. See Poly.NTT() for details. -func (v *VecL) NTT() { - for i := 0; i < L; i++ { - v[i].NTT() - } -} - -// Checks whether any of the coefficients exceeds the given bound in supnorm -// -// Requires the vector to be normalized. -func (v *VecL) Exceeds(bound uint32) bool { - for i := 0; i < L; i++ { - if v[i].Exceeds(bound) { - return true - } - } - return false -} - -// Applies Poly.Power2Round componentwise. -// -// Requires the vector to be normalized. -func (v *VecL) Power2Round(v0PlusQ, v1 *VecL) { - for i := 0; i < L; i++ { - v[i].Power2Round(&v0PlusQ[i], &v1[i]) - } -} - -// Applies Poly.Decompose componentwise. -// -// Requires the vector to be normalized. -func (v *VecL) Decompose(v0PlusQ, v1 *VecL) { - for i := 0; i < L; i++ { - PolyDecompose(&v[i], &v0PlusQ[i], &v1[i]) - } -} - -// Sequentially packs each polynomial using Poly.PackLeqEta(). -func (v *VecL) PackLeqEta(buf []byte) { - offset := 0 - for i := 0; i < L; i++ { - PolyPackLeqEta(&v[i], buf[offset:]) - offset += PolyLeqEtaSize - } -} - -// Sets v to the polynomials packed in buf using VecL.PackLeqEta(). -func (v *VecL) UnpackLeqEta(buf []byte) { - offset := 0 - for i := 0; i < L; i++ { - PolyUnpackLeqEta(&v[i], buf[offset:]) - offset += PolyLeqEtaSize - } -} - -// Sequentially packs each polynomial using PolyPackLeGamma1(). -func (v *VecL) PackLeGamma1(buf []byte) { - offset := 0 - for i := 0; i < L; i++ { - PolyPackLeGamma1(&v[i], buf[offset:]) - offset += PolyLeGamma1Size - } -} - -// Sets v to the polynomials packed in buf using VecL.PackLeGamma1(). -func (v *VecL) UnpackLeGamma1(buf []byte) { - offset := 0 - for i := 0; i < L; i++ { - PolyUnpackLeGamma1(&v[i], buf[offset:]) - offset += PolyLeGamma1Size - } -} - -// Normalize the polynomials in this vector. -func (v *VecK) Normalize() { - for i := 0; i < K; i++ { - v[i].Normalize() - } -} - -// Normalize the polynomials in this vector assuming their coefficients -// are already bounded by 2q. -func (v *VecK) NormalizeAssumingLe2Q() { - for i := 0; i < K; i++ { - v[i].NormalizeAssumingLe2Q() - } -} - -// Sets v to w + u. Does not normalize. -func (v *VecK) Add(w, u *VecK) { - for i := 0; i < K; i++ { - v[i].Add(&w[i], &u[i]) - } -} - -// Checks whether any of the coefficients exceeds the given bound in supnorm -// -// Requires the vector to be normalized. -func (v *VecK) Exceeds(bound uint32) bool { - for i := 0; i < K; i++ { - if v[i].Exceeds(bound) { - return true - } - } - return false -} - -// Applies Poly.Power2Round componentwise. -// -// Requires the vector to be normalized. -func (v *VecK) Power2Round(v0PlusQ, v1 *VecK) { - for i := 0; i < K; i++ { - v[i].Power2Round(&v0PlusQ[i], &v1[i]) - } -} - -// Applies Poly.Decompose componentwise. -// -// Requires the vector to be normalized. -func (v *VecK) Decompose(v0PlusQ, v1 *VecK) { - for i := 0; i < K; i++ { - PolyDecompose(&v[i], &v0PlusQ[i], &v1[i]) - } -} - -// Sets v to the hint vector for v0 the modified low bits and v1 -// the unmodified high bits --- see makeHint(). -// -// Returns the number of ones in the hint vector. -func (v *VecK) MakeHint(v0, v1 *VecK) (pop uint32) { - for i := 0; i < K; i++ { - pop += PolyMakeHint(&v[i], &v0[i], &v1[i]) - } - return -} - -// Computes corrections to the high bits of the polynomials in the vector -// w using the hints in h and sets v to the corrected high bits. Returns v. -// See useHint(). -func (v *VecK) UseHint(q, hint *VecK) *VecK { - for i := 0; i < K; i++ { - PolyUseHint(&v[i], &q[i], &hint[i]) - } - return v -} - -// Sequentially packs each polynomial using Poly.PackT1(). -func (v *VecK) PackT1(buf []byte) { - offset := 0 - for i := 0; i < K; i++ { - v[i].PackT1(buf[offset:]) - offset += common.PolyT1Size - } -} - -// Sets v to the vector packed into buf by PackT1(). -func (v *VecK) UnpackT1(buf []byte) { - offset := 0 - for i := 0; i < K; i++ { - v[i].UnpackT1(buf[offset:]) - offset += common.PolyT1Size - } -} - -// Sequentially packs each polynomial using Poly.PackT0(). -func (v *VecK) PackT0(buf []byte) { - offset := 0 - for i := 0; i < K; i++ { - v[i].PackT0(buf[offset:]) - offset += common.PolyT0Size - } -} - -// Sets v to the vector packed into buf by PackT0(). -func (v *VecK) UnpackT0(buf []byte) { - offset := 0 - for i := 0; i < K; i++ { - v[i].UnpackT0(buf[offset:]) - offset += common.PolyT0Size - } -} - -// Sequentially packs each polynomial using Poly.PackLeqEta(). -func (v *VecK) PackLeqEta(buf []byte) { - offset := 0 - for i := 0; i < K; i++ { - PolyPackLeqEta(&v[i], buf[offset:]) - offset += PolyLeqEtaSize - } -} - -// Sets v to the polynomials packed in buf using VecK.PackLeqEta(). -func (v *VecK) UnpackLeqEta(buf []byte) { - offset := 0 - for i := 0; i < K; i++ { - PolyUnpackLeqEta(&v[i], buf[offset:]) - offset += PolyLeqEtaSize - } -} - -// Applies NTT componentwise. See Poly.NTT() for details. -func (v *VecK) NTT() { - for i := 0; i < K; i++ { - v[i].NTT() - } -} - -// Sequentially packs each polynomial using PolyPackW1(). -func (v *VecK) PackW1(buf []byte) { - offset := 0 - for i := 0; i < K; i++ { - PolyPackW1(&v[i], buf[offset:]) - offset += PolyW1Size - } -} - -// Sets v to a - b. -// -// Warning: assumes coefficients of the polynomials of b are less than 2q. -func (v *VecK) Sub(a, b *VecK) { - for i := 0; i < K; i++ { - v[i].Sub(&a[i], &b[i]) - } -} - -// Sets v to 2ᵈ w without reducing. -func (v *VecK) MulBy2toD(w *VecK) { - for i := 0; i < K; i++ { - v[i].MulBy2toD(&w[i]) - } -} - -// Applies InvNTT componentwise. See Poly.InvNTT() for details. -func (v *VecK) InvNTT() { - for i := 0; i < K; i++ { - v[i].InvNTT() - } -} - -// Applies Poly.ReduceLe2Q() componentwise. -func (v *VecK) ReduceLe2Q() { - for i := 0; i < K; i++ { - v[i].ReduceLe2Q() - } -} diff --git a/sign/dilithium/templates/mode.templ.go b/sign/dilithium/templates/mode.templ.go deleted file mode 100644 index 445514bcc..000000000 --- a/sign/dilithium/templates/mode.templ.go +++ /dev/null @@ -1,100 +0,0 @@ -// +build ignore -// The previous line (and this one up to the warning below) is removed by the -// template generator. - -// Code generated from mode.templ.go. DO NOT EDIT. - -package dilithium - -import ( - "fmt" - "io" -{{ if .NIST }} - "github.com/cloudflare/circl/sign/mldsa/{{.Pkg}}" -{{ else }} - "github.com/cloudflare/circl/sign/dilithium/{{.Pkg}}" -{{- end }} - common "github.com/cloudflare/circl/sign/internal/dilithium" -) - -// {{.Impl}} implements the mode.Mode interface for {{.Name}}. -type {{.Impl}} struct{} -{{ if .NIST }} -// {{.Mode}} is {{.Name}}. -{{- else }} -// {{.Mode}} is Dilithium in mode "{{.Name}}". -{{- end }} -var {{.Mode}} Mode = &{{.Impl}}{} - -func (m *{{.Impl}}) GenerateKey(rand io.Reader) ( - PublicKey, PrivateKey, error) { - return {{.Pkg}}.GenerateKey(rand) -} - -func (m *{{.Impl}}) NewKeyFromSeed(seed []byte) (PublicKey, - PrivateKey) { - if len(seed) != common.SeedSize { - panic(fmt.Sprintf("seed must be of length %d", common.SeedSize)) - } - seedBuf := [common.SeedSize]byte{} - copy(seedBuf[:], seed) - return {{.Pkg}}.NewKeyFromSeed(&seedBuf) -} - -func (m *{{.Impl}}) Sign(sk PrivateKey, msg []byte) []byte { - isk := sk.(*{{.Pkg}}.PrivateKey) - ret := [{{.Pkg}}.SignatureSize]byte{} - {{.Pkg}}.SignTo(isk, msg, ret[:]) - return ret[:] -} - -func (m *{{.Impl}}) Verify(pk PublicKey, msg []byte, signature []byte) bool { - ipk := pk.(*{{.Pkg}}.PublicKey) - return {{.Pkg}}.Verify(ipk, msg, signature) -} - -func (m *{{.Impl}}) PublicKeyFromBytes(data []byte) PublicKey { - var ret {{.Pkg}}.PublicKey - if len(data) != {{.Pkg}}.PublicKeySize { - panic("packed public key must be of {{.Pkg}}.PublicKeySize bytes") - } - var buf [{{.Pkg}}.PublicKeySize]byte - copy(buf[:], data) - ret.Unpack(&buf) - return &ret -} - -func (m *{{.Impl}}) PrivateKeyFromBytes(data []byte) PrivateKey { - var ret {{.Pkg}}.PrivateKey - if len(data) != {{.Pkg}}.PrivateKeySize { - panic("packed private key must be of {{.Pkg}}.PrivateKeySize bytes") - } - var buf [{{.Pkg}}.PrivateKeySize]byte - copy(buf[:], data) - ret.Unpack(&buf) - return &ret -} - -func (m *{{.Impl}}) SeedSize() int { - return common.SeedSize -} - -func (m *{{.Impl}}) PublicKeySize() int { - return {{.Pkg}}.PublicKeySize -} - -func (m *{{.Impl}}) PrivateKeySize() int { - return {{.Pkg}}.PrivateKeySize -} - -func (m *{{.Impl}}) SignatureSize() int { - return {{.Pkg}}.SignatureSize -} - -func (m *{{.Impl}}) Name() string { - return "{{.Name}}" -} - -func init() { - modes["{{.Name}}"] = {{.Mode}} -} diff --git a/sign/dilithium/templates/params.templ.go b/sign/dilithium/templates/params.templ.go index faeae3aac..a7154bae8 100644 --- a/sign/dilithium/templates/params.templ.go +++ b/sign/dilithium/templates/params.templ.go @@ -8,7 +8,6 @@ package internal const ( Name = "{{.Name}}" - UseAES = {{.UseAES}} K = {{.K}} L = {{.L}} Eta = {{.Eta}} diff --git a/sign/dilithium/templates/modePkg.templ.go b/sign/dilithium/templates/pkg.templ.go similarity index 53% rename from sign/dilithium/templates/modePkg.templ.go rename to sign/dilithium/templates/pkg.templ.go index fbaa89746..4ad538565 100644 --- a/sign/dilithium/templates/modePkg.templ.go +++ b/sign/dilithium/templates/pkg.templ.go @@ -2,16 +2,16 @@ // The previous line (and this one up to the warning below) is removed by the // template generator. -// Code generated from modePkg.templ.go. DO NOT EDIT. +// Code generated from pkg.templ.go. DO NOT EDIT. {{ if .NIST }} // {{.Pkg}} implements NIST signature scheme {{.Name}} as defined in FIPS204. -{{ else }} +{{- else }} // {{.Pkg}} implements the CRYSTALS-Dilithium signature scheme {{.Name}} // as submitted to round3 of the NIST PQC competition and described in // // https://pq-crystals.org/dilithium/data/dilithium-specification-round3-20210208.pdf -{{ end }} +{{- end }} package {{.Pkg}} import ( @@ -19,12 +19,18 @@ import ( "errors" "io" - common "github.com/cloudflare/circl/sign/internal/dilithium" -{{ if .NIST }} +{{- if .NIST }} + cryptoRand "crypto/rand" +{{- end }} + + "github.com/cloudflare/circl/sign" + +{{- if .NIST }} "github.com/cloudflare/circl/sign/mldsa/{{.Pkg}}/internal" -{{ else }} +{{- else }} "github.com/cloudflare/circl/sign/dilithium/{{.Pkg}}/internal" -{{ end }} +{{- end }} + common "github.com/cloudflare/circl/sign/internal/dilithium" ) const ( @@ -62,20 +68,79 @@ func NewKeyFromSeed(seed *[SeedSize]byte) (*PublicKey, *PrivateKey) { // SignTo signs the given message and writes the signature into signature. // It will panic if signature is not of length at least SignatureSize. -func SignTo(sk *PrivateKey, msg []byte, signature []byte) { +{{- if .NIST }} +// +// ctx is the optional context string. Errors if ctx is larger than 255 bytes. +// A nil context string is equivalent to an empty context string. +func SignTo(sk *PrivateKey, msg, ctx []byte, randomized bool, sig []byte) error { +{{- else }} +func SignTo(sk *PrivateKey, msg, sig []byte) { +{{- end }} + var rnd [32]byte + + {{- if .NIST }} + if randomized { + _, err := cryptoRand.Read(rnd[:]) + if err != nil { + return err + } + } + + if len(ctx) > 255 { + return sign.ErrContextTooLong + } + {{- end }} + internal.SignTo( (*internal.PrivateKey)(sk), - msg, - signature, + func (w io.Writer) { + {{- if .NIST }} + _, _ = w.Write([]byte{0}) + _, _ = w.Write([]byte{byte(len(ctx))}) + + if ctx != nil { + _, _ = w.Write(ctx) + } + + {{- end }} + w.Write(msg) + }, + rnd, + sig, ) + + {{- if .NIST }} + return nil + {{- end }} } // Verify checks whether the given signature by pk on msg is valid. -func Verify(pk *PublicKey, msg []byte, signature []byte) bool { +{{- if .NIST }} +// +// ctx is the optional context string. Fails if ctx is larger than 255 bytes. +// A nil context string is equivalent to an empty context string. +func Verify(pk *PublicKey, msg, ctx, sig []byte) bool { + if len(ctx) > 255 { + return false + } +{{- else }} +func Verify(pk *PublicKey, msg, sig []byte) bool { +{{- end }} return internal.Verify( (*internal.PublicKey)(pk), - msg, - signature, + func (w io.Writer) { + {{- if .NIST }} + _, _ = w.Write([]byte{0}) + _, _ = w.Write([]byte{byte(len(ctx))}) + + if ctx != nil { + _, _ = w.Write(ctx) + } + + {{- end }} + _, _ = w.Write(msg) + }, + sig, ) } @@ -155,15 +220,22 @@ func (sk *PrivateKey) UnmarshalBinary(data []byte) error { // interface. The package-level SignTo function might be more convenient // to use. func (sk *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ( - signature []byte, err error) { - var sig [SignatureSize]byte + sig []byte, err error) { + var ret [SignatureSize]byte if opts.HashFunc() != crypto.Hash(0) { return nil, errors.New("dilithium: cannot sign hashed message") } - SignTo(sk, msg, sig[:]) - return sig[:], nil + {{- if .NIST }} + if err = SignTo(sk, msg, nil, false, ret[:]); err != nil { + return nil, err + } + {{- else }} + SignTo(sk, msg, ret[:]) + {{- end }} + + return ret[:], nil } // Computes the public key corresponding to this private key. @@ -191,3 +263,138 @@ func (pk *PublicKey) Equal(other crypto.PublicKey) bool { } return (*internal.PublicKey)(pk).Equal((*internal.PublicKey)(castOther)) } + + +// Boilerplate for generic signatures API + +type scheme struct{} +var sch sign.Scheme = &scheme{} + +// Scheme returns a generic signature interface for {{ .Name }}. +func Scheme() sign.Scheme { return sch } + +func (*scheme) Name() string { return "{{ .Name }}" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SignatureSize() int { return SignatureSize } +func (*scheme) SeedSize() int { return SeedSize } +// TODO TLSIdentifier() and OID() + +func (*scheme) SupportsContext() bool { + {{- if .NIST }} + return true + {{- else }} + return false + {{- end }} +} + +func (*scheme) GenerateKey() (sign.PublicKey, sign.PrivateKey, error) { + return GenerateKey(nil) +} + +func (*scheme) Sign( + sk sign.PrivateKey, + msg []byte, + opts *sign.SignatureOpts, +) []byte { + {{- if .NIST }} + var ctx []byte + {{- end }} + sig := make([]byte, SignatureSize) + + priv, ok := sk.(*PrivateKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + {{- if .NIST }} + ctx = []byte(opts.Context) + {{- else }} + panic(sign.ErrContextNotSupported) + {{- end }} + } + + {{- if .NIST }} + err := SignTo(priv, msg, ctx, false, sig) + if err != nil { + panic(err) + } + {{- else }} + SignTo(priv, msg, sig) + {{ end }} + + return sig +} + +func (*scheme) Verify( + pk sign.PublicKey, + msg, sig []byte, + opts *sign.SignatureOpts, +) bool { + {{- if .NIST }} + var ctx []byte + {{- end }} + pub, ok := pk.(*PublicKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + {{- if .NIST }} + ctx = []byte(opts.Context) + {{- else }} + panic(sign.ErrContextNotSupported) + {{- end }} + } + {{- if .NIST }} + return Verify(pub, msg, ctx, sig) + {{- else }} + return Verify(pub, msg, sig) + {{- end }} +} + +func (*scheme) DeriveKey(seed []byte) (sign.PublicKey, sign.PrivateKey) { + if len(seed) != SeedSize { + panic(sign.ErrSeedSize) + } + var seed2 [SeedSize]byte + copy(seed2[:], seed) + return NewKeyFromSeed(&seed2) +} + +func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (sign.PublicKey, error) { + if len(buf) != PublicKeySize { + return nil, sign.ErrPubKeySize + } + + var ( + buf2 [PublicKeySize]byte + ret PublicKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (sign.PrivateKey, error) { + if len(buf) != PrivateKeySize { + return nil, sign.ErrPrivKeySize + } + + var ( + buf2 [PrivateKeySize]byte + ret PrivateKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (sk *PrivateKey) Scheme() sign.Scheme { + return sch +} + +func (sk *PublicKey) Scheme() sign.Scheme { + return sch +} diff --git a/sign/mldsa/mldsa44/dilithium.go b/sign/mldsa/mldsa44/dilithium.go index 71e2b7906..866f8b6ee 100644 --- a/sign/mldsa/mldsa44/dilithium.go +++ b/sign/mldsa/mldsa44/dilithium.go @@ -1,19 +1,17 @@ -// Code generated from modePkg.templ.go. DO NOT EDIT. - +// Code generated from pkg.templ.go. DO NOT EDIT. // mldsa44 implements NIST signature scheme ML-DSA-44 as defined in FIPS204. - package mldsa44 import ( "crypto" + cryptoRand "crypto/rand" "errors" "io" + "github.com/cloudflare/circl/sign" common "github.com/cloudflare/circl/sign/internal/dilithium" - "github.com/cloudflare/circl/sign/mldsa/mldsa44/internal" - ) const ( @@ -51,20 +49,59 @@ func NewKeyFromSeed(seed *[SeedSize]byte) (*PublicKey, *PrivateKey) { // SignTo signs the given message and writes the signature into signature. // It will panic if signature is not of length at least SignatureSize. -func SignTo(sk *PrivateKey, msg []byte, signature []byte) { +// +// ctx is the optional context string. Errors if ctx is larger than 255 bytes. +// A nil context string is equivalent to an empty context string. +func SignTo(sk *PrivateKey, msg, ctx []byte, randomized bool, sig []byte) error { + var rnd [32]byte + if randomized { + _, err := cryptoRand.Read(rnd[:]) + if err != nil { + return err + } + } + + if len(ctx) > 255 { + return sign.ErrContextTooLong + } + internal.SignTo( (*internal.PrivateKey)(sk), - msg, - signature, + func(w io.Writer) { + _, _ = w.Write([]byte{0}) + _, _ = w.Write([]byte{byte(len(ctx))}) + + if ctx != nil { + _, _ = w.Write(ctx) + } + w.Write(msg) + }, + rnd, + sig, ) + return nil } // Verify checks whether the given signature by pk on msg is valid. -func Verify(pk *PublicKey, msg []byte, signature []byte) bool { +// +// ctx is the optional context string. Fails if ctx is larger than 255 bytes. +// A nil context string is equivalent to an empty context string. +func Verify(pk *PublicKey, msg, ctx, sig []byte) bool { + if len(ctx) > 255 { + return false + } return internal.Verify( (*internal.PublicKey)(pk), - msg, - signature, + func(w io.Writer) { + _, _ = w.Write([]byte{0}) + _, _ = w.Write([]byte{byte(len(ctx))}) + + if ctx != nil { + _, _ = w.Write(ctx) + } + _, _ = w.Write(msg) + }, + sig, ) } @@ -144,15 +181,17 @@ func (sk *PrivateKey) UnmarshalBinary(data []byte) error { // interface. The package-level SignTo function might be more convenient // to use. func (sk *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ( - signature []byte, err error) { - var sig [SignatureSize]byte + sig []byte, err error) { + var ret [SignatureSize]byte if opts.HashFunc() != crypto.Hash(0) { return nil, errors.New("dilithium: cannot sign hashed message") } + if err = SignTo(sk, msg, nil, false, ret[:]); err != nil { + return nil, err + } - SignTo(sk, msg, sig[:]) - return sig[:], nil + return ret[:], nil } // Computes the public key corresponding to this private key. @@ -180,3 +219,114 @@ func (pk *PublicKey) Equal(other crypto.PublicKey) bool { } return (*internal.PublicKey)(pk).Equal((*internal.PublicKey)(castOther)) } + +// Boilerplate for generic signatures API + +type scheme struct{} + +var sch sign.Scheme = &scheme{} + +// Scheme returns a generic signature interface for ML-DSA-44. +func Scheme() sign.Scheme { return sch } + +func (*scheme) Name() string { return "ML-DSA-44" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SignatureSize() int { return SignatureSize } +func (*scheme) SeedSize() int { return SeedSize } + +// TODO TLSIdentifier() and OID() + +func (*scheme) SupportsContext() bool { + return true +} + +func (*scheme) GenerateKey() (sign.PublicKey, sign.PrivateKey, error) { + return GenerateKey(nil) +} + +func (*scheme) Sign( + sk sign.PrivateKey, + msg []byte, + opts *sign.SignatureOpts, +) []byte { + var ctx []byte + sig := make([]byte, SignatureSize) + + priv, ok := sk.(*PrivateKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + ctx = []byte(opts.Context) + } + err := SignTo(priv, msg, ctx, false, sig) + if err != nil { + panic(err) + } + + return sig +} + +func (*scheme) Verify( + pk sign.PublicKey, + msg, sig []byte, + opts *sign.SignatureOpts, +) bool { + var ctx []byte + pub, ok := pk.(*PublicKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + ctx = []byte(opts.Context) + } + return Verify(pub, msg, ctx, sig) +} + +func (*scheme) DeriveKey(seed []byte) (sign.PublicKey, sign.PrivateKey) { + if len(seed) != SeedSize { + panic(sign.ErrSeedSize) + } + var seed2 [SeedSize]byte + copy(seed2[:], seed) + return NewKeyFromSeed(&seed2) +} + +func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (sign.PublicKey, error) { + if len(buf) != PublicKeySize { + return nil, sign.ErrPubKeySize + } + + var ( + buf2 [PublicKeySize]byte + ret PublicKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (sign.PrivateKey, error) { + if len(buf) != PrivateKeySize { + return nil, sign.ErrPrivKeySize + } + + var ( + buf2 [PrivateKeySize]byte + ret PrivateKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (sk *PrivateKey) Scheme() sign.Scheme { + return sch +} + +func (sk *PublicKey) Scheme() sign.Scheme { + return sch +} diff --git a/sign/mldsa/mldsa44/internal/dilithium.go b/sign/mldsa/mldsa44/internal/dilithium.go index 7869d0475..609ab3a4c 100644 --- a/sign/mldsa/mldsa44/internal/dilithium.go +++ b/sign/mldsa/mldsa44/internal/dilithium.go @@ -244,7 +244,10 @@ func (sk *PrivateKey) computeT0andT1(t0, t1 *VecK) { } // Verify checks whether the given signature by pk on msg is valid. -func Verify(pk *PublicKey, msg []byte, signature []byte) bool { +// +// For Dilithium this is the top-level verification function. +// In ML-DSA, this is ML-DSA.Verify_internal. +func Verify(pk *PublicKey, msg func(io.Writer), signature []byte) bool { var sig unpackedSignature var mu [64]byte var zh VecL @@ -262,7 +265,7 @@ func Verify(pk *PublicKey, msg []byte, signature []byte) bool { // μ = CRH(tr ‖ msg) h := sha3.NewShake256() _, _ = h.Write(pk.tr[:]) - _, _ = h.Write(msg) + msg(&h) _, _ = h.Read(mu[:]) // Compute Az @@ -279,7 +282,7 @@ func Verify(pk *PublicKey, msg []byte, signature []byte) bool { // which is small enough for NTT(). Az2dct1.MulBy2toD(&pk.t1) Az2dct1.NTT() - PolyDeriveUniformBall(&ch, sig.c[:32]) + PolyDeriveUniformBall(&ch, sig.c[:]) ch.NTT() for i := 0; i < K; i++ { Az2dct1[i].MulHat(&Az2dct1[i], &ch) @@ -307,8 +310,11 @@ func Verify(pk *PublicKey, msg []byte, signature []byte) bool { // SignTo signs the given message and writes the signature into signature. // +// For Dilithium this is the top-level signing function. For ML-DSA +// this is ML-DSA.Sign_internal. +// //nolint:funlen -func SignTo(sk *PrivateKey, msg []byte, signature []byte) { +func SignTo(sk *PrivateKey, msg func(io.Writer), rnd [32]byte, signature []byte) { var mu, rhop [64]byte var w1Packed [PolyW1Size * K]byte var y, yh VecL @@ -324,16 +330,14 @@ func SignTo(sk *PrivateKey, msg []byte, signature []byte) { // μ = CRH(tr ‖ msg) h := sha3.NewShake256() _, _ = h.Write(sk.tr[:]) - _, _ = h.Write(msg) + msg(&h) _, _ = h.Read(mu[:]) // ρ' = CRH(key ‖ μ) h.Reset() _, _ = h.Write(sk.key[:]) if NIST { - // We implement the deterministic variant where rnd is all zeroes. - // TODO expose randomized variant? - _, _ = h.Write(make([]byte, 32)) + _, _ = h.Write(rnd[:]) } _, _ = h.Write(mu[:]) _, _ = h.Read(rhop[:]) @@ -373,7 +377,7 @@ func SignTo(sk *PrivateKey, msg []byte, signature []byte) { _, _ = h.Write(w1Packed[:]) _, _ = h.Read(sig.c[:]) - PolyDeriveUniformBall(&ch, sig.c[:32]) + PolyDeriveUniformBall(&ch, sig.c[:]) ch.NTT() // Ensure ‖ w₀ - c·s2 ‖_∞ < γ₂ - β. diff --git a/sign/mldsa/mldsa44/internal/dilithium_test.go b/sign/mldsa/mldsa44/internal/dilithium_test.go index 825e7da08..91dd478e0 100644 --- a/sign/mldsa/mldsa44/internal/dilithium_test.go +++ b/sign/mldsa/mldsa44/internal/dilithium_test.go @@ -4,6 +4,7 @@ package internal import ( "encoding/binary" + "io" "testing" common "github.com/cloudflare/circl/sign/internal/dilithium" @@ -36,32 +37,38 @@ func BenchmarkVerify(b *testing.B) { // Note that the expansion of the matrix A is done at Unpacking/Keygen // instead of at the moment of verification (as in the reference // implementation.) - var seed [32]byte - var msg [8]byte - var sig [SignatureSize]byte + var ( + seed [32]byte + msg [8]byte + sig [SignatureSize]byte + rnd [32]byte + ) pk, sk := NewKeyFromSeed(&seed) - SignTo(sk, msg[:], sig[:]) + SignTo(sk, func(w io.Writer) { w.Write(msg[:]) }, rnd, sig[:]) b.ResetTimer() for i := 0; i < b.N; i++ { // We should generate a new signature for every verify attempt, // as this influences the time a little bit. This difference, however, // is small and generating a new signature in between creates a lot // pressure on the allocator which makes an accurate measurement hard. - Verify(pk, msg[:], sig[:]) + Verify(pk, func(w io.Writer) { w.Write(msg[:]) }, sig[:]) } } func BenchmarkSign(b *testing.B) { // Note that the expansion of the matrix A is done at Unpacking/Keygen // instead of at the moment of signing (as in the reference implementation.) - var seed [32]byte - var msg [8]byte - var sig [SignatureSize]byte + var ( + seed [32]byte + msg [8]byte + sig [SignatureSize]byte + rnd [32]byte + ) _, sk := NewKeyFromSeed(&seed) b.ResetTimer() for i := 0; i < b.N; i++ { binary.LittleEndian.PutUint64(msg[:], uint64(i)) - SignTo(sk, msg[:], sig[:]) + SignTo(sk, func(w io.Writer) { w.Write(msg[:]) }, rnd, sig[:]) } } @@ -85,13 +92,16 @@ func BenchmarkPublicFromPrivate(b *testing.B) { } func TestSignThenVerifyAndPkSkPacking(t *testing.T) { - var seed [common.SeedSize]byte - var sig [SignatureSize]byte - var msg [8]byte - var pkb [PublicKeySize]byte - var skb [PrivateKeySize]byte - var pk2 PublicKey - var sk2 PrivateKey + var ( + seed [common.SeedSize]byte + sig [SignatureSize]byte + msg [8]byte + pkb [PublicKeySize]byte + skb [PrivateKeySize]byte + pk2 PublicKey + sk2 PrivateKey + rnd [32]byte + ) for i := uint64(0); i < 100; i++ { binary.LittleEndian.PutUint64(seed[:], i) pk, sk := NewKeyFromSeed(&seed) @@ -100,8 +110,8 @@ func TestSignThenVerifyAndPkSkPacking(t *testing.T) { } for j := uint64(0); j < 10; j++ { binary.LittleEndian.PutUint64(msg[:], j) - SignTo(sk, msg[:], sig[:]) - if !Verify(pk, msg[:], sig[:]) { + SignTo(sk, func(w io.Writer) { w.Write(msg[:]) }, rnd, sig[:]) + if !Verify(pk, func(w io.Writer) { w.Write(msg[:]) }, sig[:]) { t.Fatal() } } diff --git a/sign/mldsa/mldsa44/internal/params.go b/sign/mldsa/mldsa44/internal/params.go index fec07cbbe..0485ff0c3 100644 --- a/sign/mldsa/mldsa44/internal/params.go +++ b/sign/mldsa/mldsa44/internal/params.go @@ -4,7 +4,6 @@ package internal const ( Name = "ML-DSA-44" - UseAES = false K = 4 L = 4 Eta = 2 diff --git a/sign/mldsa/mldsa44/internal/sample.go b/sign/mldsa/mldsa44/internal/sample.go index 62c261332..b37370a4e 100644 --- a/sign/mldsa/mldsa44/internal/sample.go +++ b/sign/mldsa/mldsa44/internal/sample.go @@ -12,7 +12,7 @@ import ( // DeriveX4Available indicates whether the system supports the quick fourway // sampling variants like PolyDeriveUniformX4. -var DeriveX4Available = keccakf1600.IsEnabledX4() && !UseAES +var DeriveX4Available = keccakf1600.IsEnabledX4() // For each i, sample ps[i] uniformly from the given seed and nonces[i]. // ps[i] may be nil and is ignored in that case. @@ -91,13 +91,9 @@ func PolyDeriveUniformX4(ps [4]*common.Poly, seed *[32]byte, nonces [4]uint16) { // p will be normalized. func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { var i, length int - var buf [12 * 16]byte // fits 168B SHAKE-128 rate and 12 16B AES blocks + var buf [12 * 16]byte // fits 168B SHAKE-128 rate - if UseAES { - length = 12 * 16 - } else { - length = 168 - } + length = 168 sample := func() { // Note that 3 divides into 168 and 12*16, so we use up buf completely. @@ -113,25 +109,16 @@ func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { } } - if UseAES { - h := common.NewAesStream128(seed, nonce) + var iv [32 + 2]byte // 32 byte seed + uint16 nonce + h := sha3.NewShake128() + copy(iv[:32], seed[:]) + iv[32] = uint8(nonce) + iv[33] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) - for i < common.N { - h.SqueezeInto(buf[:length]) - sample() - } - } else { - var iv [32 + 2]byte // 32 byte seed + uint16 nonce - h := sha3.NewShake128() - copy(iv[:32], seed[:]) - iv[32] = uint8(nonce) - iv[33] = uint8(nonce >> 8) - _, _ = h.Write(iv[:]) - - for i < common.N { - _, _ = h.Read(buf[:168]) - sample() - } + for i < common.N { + _, _ = h.Read(buf[:168]) + sample() } } @@ -142,13 +129,9 @@ func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { func PolyDeriveUniformLeqEta(p *common.Poly, seed *[64]byte, nonce uint16) { // Assumes 2 < η < 8. var i, length int - var buf [9 * 16]byte // fits 136B SHAKE-256 rate and 9 16B AES blocks + var buf [9 * 16]byte // fits 136B SHAKE-256 rate - if UseAES { - length = 9 * 16 - } else { - length = 136 - } + length = 136 sample := func() { // We use rejection sampling @@ -181,28 +164,19 @@ func PolyDeriveUniformLeqEta(p *common.Poly, seed *[64]byte, nonce uint16) { } } - if UseAES { - h := common.NewAesStream256(seed, nonce) - - for i < common.N { - h.SqueezeInto(buf[:length]) - sample() - } - } else { - var iv [64 + 2]byte // 64 byte seed + uint16 nonce + var iv [64 + 2]byte // 64 byte seed + uint16 nonce - h := sha3.NewShake256() - copy(iv[:64], seed[:]) - iv[64] = uint8(nonce) - iv[65] = uint8(nonce >> 8) + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) - // 136 is SHAKE-256 rate - _, _ = h.Write(iv[:]) + // 136 is SHAKE-256 rate + _, _ = h.Write(iv[:]) - for i < common.N { - _, _ = h.Read(buf[:136]) - sample() - } + for i < common.N { + _, _ = h.Read(buf[:136]) + sample() } } @@ -223,18 +197,13 @@ func VecLDeriveUniformLeGamma1(v *VecL, seed *[64]byte, nonce uint16) { func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { var buf [PolyLeGamma1Size]byte - if UseAES { - h := common.NewAesStream256(seed, nonce) - h.SqueezeInto(buf[:]) - } else { - var iv [66]byte - h := sha3.NewShake256() - copy(iv[:64], seed[:]) - iv[64] = uint8(nonce) - iv[65] = uint8(nonce >> 8) - _, _ = h.Write(iv[:]) - _, _ = h.Read(buf[:]) - } + var iv [66]byte + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) + _, _ = h.Read(buf[:]) PolyUnpackLeGamma1(p, buf[:]) } @@ -251,7 +220,7 @@ func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed []byte) { state := perm.Initialize(false) // Absorb the seed in the four states - for i := 0; i < 32/8; i++ { + for i := 0; i < CTildeSize/8; i++ { v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) for j := 0; j < 4; j++ { state[i*4+j] = v @@ -260,7 +229,7 @@ func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed []byte) { // SHAKE256 domain separator and padding for j := 0; j < 4; j++ { - state[(32/8)*4+j] ^= 0x1f + state[(CTildeSize/8)*4+j] ^= 0x1f state[16*4+j] ^= 0x80 << 56 } perm.Permute() diff --git a/sign/mldsa/mldsa44/internal/sample_test.go b/sign/mldsa/mldsa44/internal/sample_test.go index 2059599eb..32931c94f 100644 --- a/sign/mldsa/mldsa44/internal/sample_test.go +++ b/sign/mldsa/mldsa44/internal/sample_test.go @@ -12,94 +12,46 @@ import ( func TestVectorDeriveUniform(t *testing.T) { var p, p2 common.Poly var seed [32]byte - if UseAES { - p2 = common.Poly{ - 6724291, 310295, 6949524, 4464039, 1482136, 2522903, - 7025059, 3006320, 7286364, 7516512, 3361305, 1955529, - 4765954, 1725325, 6933066, 4299100, 6625173, 4272792, - 583034, 4971409, 2259140, 7715362, 3975394, 2341624, - 5481174, 8150082, 365246, 5491939, 1083120, 7517301, - 3104783, 2475292, 184149, 6425226, 4591622, 5964030, - 4729604, 5471092, 1828227, 1082044, 2516245, 1692580, - 3274844, 5443294, 7256740, 4989638, 3191250, 7479519, - 5124211, 5603858, 1230692, 2513454, 2828034, 4254312, - 1512596, 5245430, 5517392, 2814840, 932545, 6826733, - 3511094, 4075348, 3233981, 7268882, 2913733, 4870249, - 4123492, 8124406, 4016949, 5478752, 2750895, 603525, - 5724798, 3985430, 3483012, 6434230, 3136996, 8297976, - 4107616, 7307748, 6962904, 7544473, 1193110, 3448595, - 4814773, 5607932, 8221314, 1054046, 1541208, 1866050, - 8227412, 2925778, 5293953, 2065416, 4972769, 3616283, - 7990594, 1105530, 7121836, 1170740, 7417431, 633146, - 253820, 7235019, 3539504, 6807707, 451390, 5481526, - 2859902, 1063061, 4579730, 7126652, 7033767, 4294814, - 1414604, 7620048, 1953268, 8304556, 1156814, 1182881, - 5311519, 3057534, 5277666, 682843, 2070398, 2874278, - 4859533, 6376664, 6694074, 1590242, 2620706, 8331066, - 5643845, 5037538, 2891516, 7004879, 3754327, 5031296, - 5463118, 2420870, 8116529, 5517696, 7435129, 3873963, - 710407, 713806, 175647, 4274571, 2655021, 7319503, - 3027243, 7129679, 4213435, 2429323, 4643873, 4568526, - 649664, 1720514, 6497260, 2683517, 7672754, 7105190, - 3148405, 5898369, 5667677, 8050874, 1587139, 7315260, - 4337416, 2202680, 2338714, 557467, 6752058, 2469794, - 485071, 1617604, 3590498, 2151466, 2005823, 7727956, - 7776292, 6783433, 6787146, 1732833, 3596857, 7436284, - 4483349, 4970142, 4472608, 6478342, 1236215, 5695744, - 2280717, 2889355, 3233946, 5187812, 978685, 5177364, - 2922353, 4824807, 5302883, 6739803, 8092453, 5883903, - 816553, 6041174, 8317591, 1459178, 5332455, 1835058, - 1368601, 2820950, 3479224, 2589540, 7992934, 3421045, - 4657128, 8292902, 4153567, 3553988, 7830320, 6722913, - 2555309, 4149801, 8328975, 1560545, 7757473, 3106458, - 4310856, 7135453, 3481032, 652626, 1841361, 8126828, - 6250018, 300536, 7380070, 8174419, 1418793, 6208185, - 3906256, 6679016, 1605701, 3561489, 5819724, 5746996, - 8044214, 7087187, 7102330, 4962927, 4253983, 7108567, - 4119736, 6584065, 441634, 6941656, - } - } else { - p2 = common.Poly{ - 2901364, 562527, 5258502, 3885002, 4190126, 4460268, 6884052, - 3514511, 5383040, 213206, 2155865, 5179607, 3551954, 2312357, - 6066350, 8126097, 1179080, 4787182, 6552182, 6713644, - 1561067, 7626063, 7859743, 5052321, 7032876, 7815031, 157938, - 1865184, 490802, 5717642, 3451902, 7000218, 3743250, 1677431, - 1875427, 5596150, 671623, 3819041, 6247594, 1014875, 4933545, - 7122446, 6682963, 3388398, 3335295, 943002, 1145083, 3113071, - 105967, 1916675, 7474561, 1107006, 700548, 2147909, 1603855, - 5049181, 437882, 6118899, 5656914, 6731065, 3066622, 865453, - 5427634, 981549, 4650873, 861291, 4003872, 5104220, 6171453, - 3723302, 7426315, 6137283, 4874820, 6052561, 53441, 5032874, - 5614778, 2248550, 1756499, 8280764, 8263880, 7600081, - 5118374, 795344, 7543392, 6869925, 1841187, 4181568, 584562, - 7483939, 4938664, 6863397, 5126354, 5218129, 6236086, - 4149293, 379169, 4368487, 7490569, 3409215, 1580463, 3081737, - 1278732, 7109719, 7371700, 2097931, 399836, 1700274, 7188595, - 6830029, 1548850, 6593138, 6849097, 1518037, 2859442, - 7772265, 7325153, 3281191, 7856131, 4995056, 4684325, - 1351194, 8223904, 6817307, 2484146, 131782, 397032, 7436778, - 7973479, 3171829, 5624626, 3540123, 7150120, 8313283, - 3604714, 1043574, 117692, 7797783, 7909392, 903315, 7335342, - 7501562, 5826142, 2709813, 8245473, 2369045, 2782257, - 5762833, 6474114, 6862031, 424522, 594248, 2626630, 7659983, - 5642869, 4075194, 1592129, 245547, 5271031, 3205046, 982375, - 267873, 1286496, 7230481, 3208972, 7485411, 676111, 4944500, - 2959742, 5934456, 1414847, 6067948, 1709895, 4648315, 126008, - 8258986, 2183134, 2302072, 4674924, 4306056, 7465311, - 6500270, 4247428, 4016815, 4973426, 294287, 2456847, 3289700, - 2732169, 1159447, 5569724, 140001, 3237977, 8007761, 5874533, - 255652, 3119586, 2102434, 6248250, 8152822, 8006066, 7708625, - 6997719, 6260212, 6186962, 6636650, 7836834, 7998017, - 2061516, 1197591, 1706544, 733027, 2392907, 2700000, 8254598, - 4488002, 160495, 2985325, 2036837, 2703633, 6406550, 3579947, - 6195178, 5552390, 6804584, 6305468, 5731980, 6095195, - 3323409, 1322661, 6690942, 3374630, 5615167, 479044, 3136054, - 4380418, 2833144, 7829577, 1770522, 6056687, 240415, 14780, - 3740517, 5224226, 3547288, 2083124, 4699398, 3654239, - 5624978, 585593, 3655369, 2281739, 3338565, 1908093, 7784706, - 4352830, - } + p2 = common.Poly{ + 2901364, 562527, 5258502, 3885002, 4190126, 4460268, 6884052, + 3514511, 5383040, 213206, 2155865, 5179607, 3551954, 2312357, + 6066350, 8126097, 1179080, 4787182, 6552182, 6713644, + 1561067, 7626063, 7859743, 5052321, 7032876, 7815031, 157938, + 1865184, 490802, 5717642, 3451902, 7000218, 3743250, 1677431, + 1875427, 5596150, 671623, 3819041, 6247594, 1014875, 4933545, + 7122446, 6682963, 3388398, 3335295, 943002, 1145083, 3113071, + 105967, 1916675, 7474561, 1107006, 700548, 2147909, 1603855, + 5049181, 437882, 6118899, 5656914, 6731065, 3066622, 865453, + 5427634, 981549, 4650873, 861291, 4003872, 5104220, 6171453, + 3723302, 7426315, 6137283, 4874820, 6052561, 53441, 5032874, + 5614778, 2248550, 1756499, 8280764, 8263880, 7600081, + 5118374, 795344, 7543392, 6869925, 1841187, 4181568, 584562, + 7483939, 4938664, 6863397, 5126354, 5218129, 6236086, + 4149293, 379169, 4368487, 7490569, 3409215, 1580463, 3081737, + 1278732, 7109719, 7371700, 2097931, 399836, 1700274, 7188595, + 6830029, 1548850, 6593138, 6849097, 1518037, 2859442, + 7772265, 7325153, 3281191, 7856131, 4995056, 4684325, + 1351194, 8223904, 6817307, 2484146, 131782, 397032, 7436778, + 7973479, 3171829, 5624626, 3540123, 7150120, 8313283, + 3604714, 1043574, 117692, 7797783, 7909392, 903315, 7335342, + 7501562, 5826142, 2709813, 8245473, 2369045, 2782257, + 5762833, 6474114, 6862031, 424522, 594248, 2626630, 7659983, + 5642869, 4075194, 1592129, 245547, 5271031, 3205046, 982375, + 267873, 1286496, 7230481, 3208972, 7485411, 676111, 4944500, + 2959742, 5934456, 1414847, 6067948, 1709895, 4648315, 126008, + 8258986, 2183134, 2302072, 4674924, 4306056, 7465311, + 6500270, 4247428, 4016815, 4973426, 294287, 2456847, 3289700, + 2732169, 1159447, 5569724, 140001, 3237977, 8007761, 5874533, + 255652, 3119586, 2102434, 6248250, 8152822, 8006066, 7708625, + 6997719, 6260212, 6186962, 6636650, 7836834, 7998017, + 2061516, 1197591, 1706544, 733027, 2392907, 2700000, 8254598, + 4488002, 160495, 2985325, 2036837, 2703633, 6406550, 3579947, + 6195178, 5552390, 6804584, 6305468, 5731980, 6095195, + 3323409, 1322661, 6690942, 3374630, 5615167, 479044, 3136054, + 4380418, 2833144, 7829577, 1770522, 6056687, 240415, 14780, + 3740517, 5224226, 3547288, 2083124, 4699398, 3654239, + 5624978, 585593, 3655369, 2281739, 3338565, 1908093, 7784706, + 4352830, } for i := 0; i < 32; i++ { seed[i] = byte(i) @@ -152,7 +104,7 @@ func TestDeriveUniformLeGamma1(t *testing.T) { func TestDeriveUniformBall(t *testing.T) { var p common.Poly - var seed [32]byte + var seed [CTildeSize]byte for i := 0; i < 100; i++ { binary.LittleEndian.PutUint64(seed[:], uint64(i)) PolyDeriveUniformBall(&p, seed[:]) @@ -200,7 +152,7 @@ func TestDeriveUniformBallX4(t *testing.T) { } var ps [4]common.Poly var p common.Poly - var seed [32]byte + var seed [CTildeSize]byte PolyDeriveUniformBallX4( [4]*common.Poly{&ps[0], &ps[1], &ps[2], &ps[3]}, seed[:], diff --git a/sign/mldsa/mldsa65/dilithium.go b/sign/mldsa/mldsa65/dilithium.go index 9411e84a7..7d6312a15 100644 --- a/sign/mldsa/mldsa65/dilithium.go +++ b/sign/mldsa/mldsa65/dilithium.go @@ -1,19 +1,17 @@ -// Code generated from modePkg.templ.go. DO NOT EDIT. - +// Code generated from pkg.templ.go. DO NOT EDIT. // mldsa65 implements NIST signature scheme ML-DSA-65 as defined in FIPS204. - package mldsa65 import ( "crypto" + cryptoRand "crypto/rand" "errors" "io" + "github.com/cloudflare/circl/sign" common "github.com/cloudflare/circl/sign/internal/dilithium" - "github.com/cloudflare/circl/sign/mldsa/mldsa65/internal" - ) const ( @@ -51,20 +49,59 @@ func NewKeyFromSeed(seed *[SeedSize]byte) (*PublicKey, *PrivateKey) { // SignTo signs the given message and writes the signature into signature. // It will panic if signature is not of length at least SignatureSize. -func SignTo(sk *PrivateKey, msg []byte, signature []byte) { +// +// ctx is the optional context string. Errors if ctx is larger than 255 bytes. +// A nil context string is equivalent to an empty context string. +func SignTo(sk *PrivateKey, msg, ctx []byte, randomized bool, sig []byte) error { + var rnd [32]byte + if randomized { + _, err := cryptoRand.Read(rnd[:]) + if err != nil { + return err + } + } + + if len(ctx) > 255 { + return sign.ErrContextTooLong + } + internal.SignTo( (*internal.PrivateKey)(sk), - msg, - signature, + func(w io.Writer) { + _, _ = w.Write([]byte{0}) + _, _ = w.Write([]byte{byte(len(ctx))}) + + if ctx != nil { + _, _ = w.Write(ctx) + } + w.Write(msg) + }, + rnd, + sig, ) + return nil } // Verify checks whether the given signature by pk on msg is valid. -func Verify(pk *PublicKey, msg []byte, signature []byte) bool { +// +// ctx is the optional context string. Fails if ctx is larger than 255 bytes. +// A nil context string is equivalent to an empty context string. +func Verify(pk *PublicKey, msg, ctx, sig []byte) bool { + if len(ctx) > 255 { + return false + } return internal.Verify( (*internal.PublicKey)(pk), - msg, - signature, + func(w io.Writer) { + _, _ = w.Write([]byte{0}) + _, _ = w.Write([]byte{byte(len(ctx))}) + + if ctx != nil { + _, _ = w.Write(ctx) + } + _, _ = w.Write(msg) + }, + sig, ) } @@ -144,15 +181,17 @@ func (sk *PrivateKey) UnmarshalBinary(data []byte) error { // interface. The package-level SignTo function might be more convenient // to use. func (sk *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ( - signature []byte, err error) { - var sig [SignatureSize]byte + sig []byte, err error) { + var ret [SignatureSize]byte if opts.HashFunc() != crypto.Hash(0) { return nil, errors.New("dilithium: cannot sign hashed message") } + if err = SignTo(sk, msg, nil, false, ret[:]); err != nil { + return nil, err + } - SignTo(sk, msg, sig[:]) - return sig[:], nil + return ret[:], nil } // Computes the public key corresponding to this private key. @@ -180,3 +219,114 @@ func (pk *PublicKey) Equal(other crypto.PublicKey) bool { } return (*internal.PublicKey)(pk).Equal((*internal.PublicKey)(castOther)) } + +// Boilerplate for generic signatures API + +type scheme struct{} + +var sch sign.Scheme = &scheme{} + +// Scheme returns a generic signature interface for ML-DSA-65. +func Scheme() sign.Scheme { return sch } + +func (*scheme) Name() string { return "ML-DSA-65" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SignatureSize() int { return SignatureSize } +func (*scheme) SeedSize() int { return SeedSize } + +// TODO TLSIdentifier() and OID() + +func (*scheme) SupportsContext() bool { + return true +} + +func (*scheme) GenerateKey() (sign.PublicKey, sign.PrivateKey, error) { + return GenerateKey(nil) +} + +func (*scheme) Sign( + sk sign.PrivateKey, + msg []byte, + opts *sign.SignatureOpts, +) []byte { + var ctx []byte + sig := make([]byte, SignatureSize) + + priv, ok := sk.(*PrivateKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + ctx = []byte(opts.Context) + } + err := SignTo(priv, msg, ctx, false, sig) + if err != nil { + panic(err) + } + + return sig +} + +func (*scheme) Verify( + pk sign.PublicKey, + msg, sig []byte, + opts *sign.SignatureOpts, +) bool { + var ctx []byte + pub, ok := pk.(*PublicKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + ctx = []byte(opts.Context) + } + return Verify(pub, msg, ctx, sig) +} + +func (*scheme) DeriveKey(seed []byte) (sign.PublicKey, sign.PrivateKey) { + if len(seed) != SeedSize { + panic(sign.ErrSeedSize) + } + var seed2 [SeedSize]byte + copy(seed2[:], seed) + return NewKeyFromSeed(&seed2) +} + +func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (sign.PublicKey, error) { + if len(buf) != PublicKeySize { + return nil, sign.ErrPubKeySize + } + + var ( + buf2 [PublicKeySize]byte + ret PublicKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (sign.PrivateKey, error) { + if len(buf) != PrivateKeySize { + return nil, sign.ErrPrivKeySize + } + + var ( + buf2 [PrivateKeySize]byte + ret PrivateKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (sk *PrivateKey) Scheme() sign.Scheme { + return sch +} + +func (sk *PublicKey) Scheme() sign.Scheme { + return sch +} diff --git a/sign/mldsa/mldsa65/internal/dilithium.go b/sign/mldsa/mldsa65/internal/dilithium.go index 7869d0475..609ab3a4c 100644 --- a/sign/mldsa/mldsa65/internal/dilithium.go +++ b/sign/mldsa/mldsa65/internal/dilithium.go @@ -244,7 +244,10 @@ func (sk *PrivateKey) computeT0andT1(t0, t1 *VecK) { } // Verify checks whether the given signature by pk on msg is valid. -func Verify(pk *PublicKey, msg []byte, signature []byte) bool { +// +// For Dilithium this is the top-level verification function. +// In ML-DSA, this is ML-DSA.Verify_internal. +func Verify(pk *PublicKey, msg func(io.Writer), signature []byte) bool { var sig unpackedSignature var mu [64]byte var zh VecL @@ -262,7 +265,7 @@ func Verify(pk *PublicKey, msg []byte, signature []byte) bool { // μ = CRH(tr ‖ msg) h := sha3.NewShake256() _, _ = h.Write(pk.tr[:]) - _, _ = h.Write(msg) + msg(&h) _, _ = h.Read(mu[:]) // Compute Az @@ -279,7 +282,7 @@ func Verify(pk *PublicKey, msg []byte, signature []byte) bool { // which is small enough for NTT(). Az2dct1.MulBy2toD(&pk.t1) Az2dct1.NTT() - PolyDeriveUniformBall(&ch, sig.c[:32]) + PolyDeriveUniformBall(&ch, sig.c[:]) ch.NTT() for i := 0; i < K; i++ { Az2dct1[i].MulHat(&Az2dct1[i], &ch) @@ -307,8 +310,11 @@ func Verify(pk *PublicKey, msg []byte, signature []byte) bool { // SignTo signs the given message and writes the signature into signature. // +// For Dilithium this is the top-level signing function. For ML-DSA +// this is ML-DSA.Sign_internal. +// //nolint:funlen -func SignTo(sk *PrivateKey, msg []byte, signature []byte) { +func SignTo(sk *PrivateKey, msg func(io.Writer), rnd [32]byte, signature []byte) { var mu, rhop [64]byte var w1Packed [PolyW1Size * K]byte var y, yh VecL @@ -324,16 +330,14 @@ func SignTo(sk *PrivateKey, msg []byte, signature []byte) { // μ = CRH(tr ‖ msg) h := sha3.NewShake256() _, _ = h.Write(sk.tr[:]) - _, _ = h.Write(msg) + msg(&h) _, _ = h.Read(mu[:]) // ρ' = CRH(key ‖ μ) h.Reset() _, _ = h.Write(sk.key[:]) if NIST { - // We implement the deterministic variant where rnd is all zeroes. - // TODO expose randomized variant? - _, _ = h.Write(make([]byte, 32)) + _, _ = h.Write(rnd[:]) } _, _ = h.Write(mu[:]) _, _ = h.Read(rhop[:]) @@ -373,7 +377,7 @@ func SignTo(sk *PrivateKey, msg []byte, signature []byte) { _, _ = h.Write(w1Packed[:]) _, _ = h.Read(sig.c[:]) - PolyDeriveUniformBall(&ch, sig.c[:32]) + PolyDeriveUniformBall(&ch, sig.c[:]) ch.NTT() // Ensure ‖ w₀ - c·s2 ‖_∞ < γ₂ - β. diff --git a/sign/mldsa/mldsa65/internal/dilithium_test.go b/sign/mldsa/mldsa65/internal/dilithium_test.go index 825e7da08..91dd478e0 100644 --- a/sign/mldsa/mldsa65/internal/dilithium_test.go +++ b/sign/mldsa/mldsa65/internal/dilithium_test.go @@ -4,6 +4,7 @@ package internal import ( "encoding/binary" + "io" "testing" common "github.com/cloudflare/circl/sign/internal/dilithium" @@ -36,32 +37,38 @@ func BenchmarkVerify(b *testing.B) { // Note that the expansion of the matrix A is done at Unpacking/Keygen // instead of at the moment of verification (as in the reference // implementation.) - var seed [32]byte - var msg [8]byte - var sig [SignatureSize]byte + var ( + seed [32]byte + msg [8]byte + sig [SignatureSize]byte + rnd [32]byte + ) pk, sk := NewKeyFromSeed(&seed) - SignTo(sk, msg[:], sig[:]) + SignTo(sk, func(w io.Writer) { w.Write(msg[:]) }, rnd, sig[:]) b.ResetTimer() for i := 0; i < b.N; i++ { // We should generate a new signature for every verify attempt, // as this influences the time a little bit. This difference, however, // is small and generating a new signature in between creates a lot // pressure on the allocator which makes an accurate measurement hard. - Verify(pk, msg[:], sig[:]) + Verify(pk, func(w io.Writer) { w.Write(msg[:]) }, sig[:]) } } func BenchmarkSign(b *testing.B) { // Note that the expansion of the matrix A is done at Unpacking/Keygen // instead of at the moment of signing (as in the reference implementation.) - var seed [32]byte - var msg [8]byte - var sig [SignatureSize]byte + var ( + seed [32]byte + msg [8]byte + sig [SignatureSize]byte + rnd [32]byte + ) _, sk := NewKeyFromSeed(&seed) b.ResetTimer() for i := 0; i < b.N; i++ { binary.LittleEndian.PutUint64(msg[:], uint64(i)) - SignTo(sk, msg[:], sig[:]) + SignTo(sk, func(w io.Writer) { w.Write(msg[:]) }, rnd, sig[:]) } } @@ -85,13 +92,16 @@ func BenchmarkPublicFromPrivate(b *testing.B) { } func TestSignThenVerifyAndPkSkPacking(t *testing.T) { - var seed [common.SeedSize]byte - var sig [SignatureSize]byte - var msg [8]byte - var pkb [PublicKeySize]byte - var skb [PrivateKeySize]byte - var pk2 PublicKey - var sk2 PrivateKey + var ( + seed [common.SeedSize]byte + sig [SignatureSize]byte + msg [8]byte + pkb [PublicKeySize]byte + skb [PrivateKeySize]byte + pk2 PublicKey + sk2 PrivateKey + rnd [32]byte + ) for i := uint64(0); i < 100; i++ { binary.LittleEndian.PutUint64(seed[:], i) pk, sk := NewKeyFromSeed(&seed) @@ -100,8 +110,8 @@ func TestSignThenVerifyAndPkSkPacking(t *testing.T) { } for j := uint64(0); j < 10; j++ { binary.LittleEndian.PutUint64(msg[:], j) - SignTo(sk, msg[:], sig[:]) - if !Verify(pk, msg[:], sig[:]) { + SignTo(sk, func(w io.Writer) { w.Write(msg[:]) }, rnd, sig[:]) + if !Verify(pk, func(w io.Writer) { w.Write(msg[:]) }, sig[:]) { t.Fatal() } } diff --git a/sign/mldsa/mldsa65/internal/params.go b/sign/mldsa/mldsa65/internal/params.go index c7872fc11..8a1f866e6 100644 --- a/sign/mldsa/mldsa65/internal/params.go +++ b/sign/mldsa/mldsa65/internal/params.go @@ -4,7 +4,6 @@ package internal const ( Name = "ML-DSA-65" - UseAES = false K = 6 L = 5 Eta = 4 diff --git a/sign/mldsa/mldsa65/internal/sample.go b/sign/mldsa/mldsa65/internal/sample.go index 62c261332..b37370a4e 100644 --- a/sign/mldsa/mldsa65/internal/sample.go +++ b/sign/mldsa/mldsa65/internal/sample.go @@ -12,7 +12,7 @@ import ( // DeriveX4Available indicates whether the system supports the quick fourway // sampling variants like PolyDeriveUniformX4. -var DeriveX4Available = keccakf1600.IsEnabledX4() && !UseAES +var DeriveX4Available = keccakf1600.IsEnabledX4() // For each i, sample ps[i] uniformly from the given seed and nonces[i]. // ps[i] may be nil and is ignored in that case. @@ -91,13 +91,9 @@ func PolyDeriveUniformX4(ps [4]*common.Poly, seed *[32]byte, nonces [4]uint16) { // p will be normalized. func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { var i, length int - var buf [12 * 16]byte // fits 168B SHAKE-128 rate and 12 16B AES blocks + var buf [12 * 16]byte // fits 168B SHAKE-128 rate - if UseAES { - length = 12 * 16 - } else { - length = 168 - } + length = 168 sample := func() { // Note that 3 divides into 168 and 12*16, so we use up buf completely. @@ -113,25 +109,16 @@ func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { } } - if UseAES { - h := common.NewAesStream128(seed, nonce) + var iv [32 + 2]byte // 32 byte seed + uint16 nonce + h := sha3.NewShake128() + copy(iv[:32], seed[:]) + iv[32] = uint8(nonce) + iv[33] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) - for i < common.N { - h.SqueezeInto(buf[:length]) - sample() - } - } else { - var iv [32 + 2]byte // 32 byte seed + uint16 nonce - h := sha3.NewShake128() - copy(iv[:32], seed[:]) - iv[32] = uint8(nonce) - iv[33] = uint8(nonce >> 8) - _, _ = h.Write(iv[:]) - - for i < common.N { - _, _ = h.Read(buf[:168]) - sample() - } + for i < common.N { + _, _ = h.Read(buf[:168]) + sample() } } @@ -142,13 +129,9 @@ func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { func PolyDeriveUniformLeqEta(p *common.Poly, seed *[64]byte, nonce uint16) { // Assumes 2 < η < 8. var i, length int - var buf [9 * 16]byte // fits 136B SHAKE-256 rate and 9 16B AES blocks + var buf [9 * 16]byte // fits 136B SHAKE-256 rate - if UseAES { - length = 9 * 16 - } else { - length = 136 - } + length = 136 sample := func() { // We use rejection sampling @@ -181,28 +164,19 @@ func PolyDeriveUniformLeqEta(p *common.Poly, seed *[64]byte, nonce uint16) { } } - if UseAES { - h := common.NewAesStream256(seed, nonce) - - for i < common.N { - h.SqueezeInto(buf[:length]) - sample() - } - } else { - var iv [64 + 2]byte // 64 byte seed + uint16 nonce + var iv [64 + 2]byte // 64 byte seed + uint16 nonce - h := sha3.NewShake256() - copy(iv[:64], seed[:]) - iv[64] = uint8(nonce) - iv[65] = uint8(nonce >> 8) + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) - // 136 is SHAKE-256 rate - _, _ = h.Write(iv[:]) + // 136 is SHAKE-256 rate + _, _ = h.Write(iv[:]) - for i < common.N { - _, _ = h.Read(buf[:136]) - sample() - } + for i < common.N { + _, _ = h.Read(buf[:136]) + sample() } } @@ -223,18 +197,13 @@ func VecLDeriveUniformLeGamma1(v *VecL, seed *[64]byte, nonce uint16) { func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { var buf [PolyLeGamma1Size]byte - if UseAES { - h := common.NewAesStream256(seed, nonce) - h.SqueezeInto(buf[:]) - } else { - var iv [66]byte - h := sha3.NewShake256() - copy(iv[:64], seed[:]) - iv[64] = uint8(nonce) - iv[65] = uint8(nonce >> 8) - _, _ = h.Write(iv[:]) - _, _ = h.Read(buf[:]) - } + var iv [66]byte + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) + _, _ = h.Read(buf[:]) PolyUnpackLeGamma1(p, buf[:]) } @@ -251,7 +220,7 @@ func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed []byte) { state := perm.Initialize(false) // Absorb the seed in the four states - for i := 0; i < 32/8; i++ { + for i := 0; i < CTildeSize/8; i++ { v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) for j := 0; j < 4; j++ { state[i*4+j] = v @@ -260,7 +229,7 @@ func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed []byte) { // SHAKE256 domain separator and padding for j := 0; j < 4; j++ { - state[(32/8)*4+j] ^= 0x1f + state[(CTildeSize/8)*4+j] ^= 0x1f state[16*4+j] ^= 0x80 << 56 } perm.Permute() diff --git a/sign/mldsa/mldsa65/internal/sample_test.go b/sign/mldsa/mldsa65/internal/sample_test.go index 2059599eb..32931c94f 100644 --- a/sign/mldsa/mldsa65/internal/sample_test.go +++ b/sign/mldsa/mldsa65/internal/sample_test.go @@ -12,94 +12,46 @@ import ( func TestVectorDeriveUniform(t *testing.T) { var p, p2 common.Poly var seed [32]byte - if UseAES { - p2 = common.Poly{ - 6724291, 310295, 6949524, 4464039, 1482136, 2522903, - 7025059, 3006320, 7286364, 7516512, 3361305, 1955529, - 4765954, 1725325, 6933066, 4299100, 6625173, 4272792, - 583034, 4971409, 2259140, 7715362, 3975394, 2341624, - 5481174, 8150082, 365246, 5491939, 1083120, 7517301, - 3104783, 2475292, 184149, 6425226, 4591622, 5964030, - 4729604, 5471092, 1828227, 1082044, 2516245, 1692580, - 3274844, 5443294, 7256740, 4989638, 3191250, 7479519, - 5124211, 5603858, 1230692, 2513454, 2828034, 4254312, - 1512596, 5245430, 5517392, 2814840, 932545, 6826733, - 3511094, 4075348, 3233981, 7268882, 2913733, 4870249, - 4123492, 8124406, 4016949, 5478752, 2750895, 603525, - 5724798, 3985430, 3483012, 6434230, 3136996, 8297976, - 4107616, 7307748, 6962904, 7544473, 1193110, 3448595, - 4814773, 5607932, 8221314, 1054046, 1541208, 1866050, - 8227412, 2925778, 5293953, 2065416, 4972769, 3616283, - 7990594, 1105530, 7121836, 1170740, 7417431, 633146, - 253820, 7235019, 3539504, 6807707, 451390, 5481526, - 2859902, 1063061, 4579730, 7126652, 7033767, 4294814, - 1414604, 7620048, 1953268, 8304556, 1156814, 1182881, - 5311519, 3057534, 5277666, 682843, 2070398, 2874278, - 4859533, 6376664, 6694074, 1590242, 2620706, 8331066, - 5643845, 5037538, 2891516, 7004879, 3754327, 5031296, - 5463118, 2420870, 8116529, 5517696, 7435129, 3873963, - 710407, 713806, 175647, 4274571, 2655021, 7319503, - 3027243, 7129679, 4213435, 2429323, 4643873, 4568526, - 649664, 1720514, 6497260, 2683517, 7672754, 7105190, - 3148405, 5898369, 5667677, 8050874, 1587139, 7315260, - 4337416, 2202680, 2338714, 557467, 6752058, 2469794, - 485071, 1617604, 3590498, 2151466, 2005823, 7727956, - 7776292, 6783433, 6787146, 1732833, 3596857, 7436284, - 4483349, 4970142, 4472608, 6478342, 1236215, 5695744, - 2280717, 2889355, 3233946, 5187812, 978685, 5177364, - 2922353, 4824807, 5302883, 6739803, 8092453, 5883903, - 816553, 6041174, 8317591, 1459178, 5332455, 1835058, - 1368601, 2820950, 3479224, 2589540, 7992934, 3421045, - 4657128, 8292902, 4153567, 3553988, 7830320, 6722913, - 2555309, 4149801, 8328975, 1560545, 7757473, 3106458, - 4310856, 7135453, 3481032, 652626, 1841361, 8126828, - 6250018, 300536, 7380070, 8174419, 1418793, 6208185, - 3906256, 6679016, 1605701, 3561489, 5819724, 5746996, - 8044214, 7087187, 7102330, 4962927, 4253983, 7108567, - 4119736, 6584065, 441634, 6941656, - } - } else { - p2 = common.Poly{ - 2901364, 562527, 5258502, 3885002, 4190126, 4460268, 6884052, - 3514511, 5383040, 213206, 2155865, 5179607, 3551954, 2312357, - 6066350, 8126097, 1179080, 4787182, 6552182, 6713644, - 1561067, 7626063, 7859743, 5052321, 7032876, 7815031, 157938, - 1865184, 490802, 5717642, 3451902, 7000218, 3743250, 1677431, - 1875427, 5596150, 671623, 3819041, 6247594, 1014875, 4933545, - 7122446, 6682963, 3388398, 3335295, 943002, 1145083, 3113071, - 105967, 1916675, 7474561, 1107006, 700548, 2147909, 1603855, - 5049181, 437882, 6118899, 5656914, 6731065, 3066622, 865453, - 5427634, 981549, 4650873, 861291, 4003872, 5104220, 6171453, - 3723302, 7426315, 6137283, 4874820, 6052561, 53441, 5032874, - 5614778, 2248550, 1756499, 8280764, 8263880, 7600081, - 5118374, 795344, 7543392, 6869925, 1841187, 4181568, 584562, - 7483939, 4938664, 6863397, 5126354, 5218129, 6236086, - 4149293, 379169, 4368487, 7490569, 3409215, 1580463, 3081737, - 1278732, 7109719, 7371700, 2097931, 399836, 1700274, 7188595, - 6830029, 1548850, 6593138, 6849097, 1518037, 2859442, - 7772265, 7325153, 3281191, 7856131, 4995056, 4684325, - 1351194, 8223904, 6817307, 2484146, 131782, 397032, 7436778, - 7973479, 3171829, 5624626, 3540123, 7150120, 8313283, - 3604714, 1043574, 117692, 7797783, 7909392, 903315, 7335342, - 7501562, 5826142, 2709813, 8245473, 2369045, 2782257, - 5762833, 6474114, 6862031, 424522, 594248, 2626630, 7659983, - 5642869, 4075194, 1592129, 245547, 5271031, 3205046, 982375, - 267873, 1286496, 7230481, 3208972, 7485411, 676111, 4944500, - 2959742, 5934456, 1414847, 6067948, 1709895, 4648315, 126008, - 8258986, 2183134, 2302072, 4674924, 4306056, 7465311, - 6500270, 4247428, 4016815, 4973426, 294287, 2456847, 3289700, - 2732169, 1159447, 5569724, 140001, 3237977, 8007761, 5874533, - 255652, 3119586, 2102434, 6248250, 8152822, 8006066, 7708625, - 6997719, 6260212, 6186962, 6636650, 7836834, 7998017, - 2061516, 1197591, 1706544, 733027, 2392907, 2700000, 8254598, - 4488002, 160495, 2985325, 2036837, 2703633, 6406550, 3579947, - 6195178, 5552390, 6804584, 6305468, 5731980, 6095195, - 3323409, 1322661, 6690942, 3374630, 5615167, 479044, 3136054, - 4380418, 2833144, 7829577, 1770522, 6056687, 240415, 14780, - 3740517, 5224226, 3547288, 2083124, 4699398, 3654239, - 5624978, 585593, 3655369, 2281739, 3338565, 1908093, 7784706, - 4352830, - } + p2 = common.Poly{ + 2901364, 562527, 5258502, 3885002, 4190126, 4460268, 6884052, + 3514511, 5383040, 213206, 2155865, 5179607, 3551954, 2312357, + 6066350, 8126097, 1179080, 4787182, 6552182, 6713644, + 1561067, 7626063, 7859743, 5052321, 7032876, 7815031, 157938, + 1865184, 490802, 5717642, 3451902, 7000218, 3743250, 1677431, + 1875427, 5596150, 671623, 3819041, 6247594, 1014875, 4933545, + 7122446, 6682963, 3388398, 3335295, 943002, 1145083, 3113071, + 105967, 1916675, 7474561, 1107006, 700548, 2147909, 1603855, + 5049181, 437882, 6118899, 5656914, 6731065, 3066622, 865453, + 5427634, 981549, 4650873, 861291, 4003872, 5104220, 6171453, + 3723302, 7426315, 6137283, 4874820, 6052561, 53441, 5032874, + 5614778, 2248550, 1756499, 8280764, 8263880, 7600081, + 5118374, 795344, 7543392, 6869925, 1841187, 4181568, 584562, + 7483939, 4938664, 6863397, 5126354, 5218129, 6236086, + 4149293, 379169, 4368487, 7490569, 3409215, 1580463, 3081737, + 1278732, 7109719, 7371700, 2097931, 399836, 1700274, 7188595, + 6830029, 1548850, 6593138, 6849097, 1518037, 2859442, + 7772265, 7325153, 3281191, 7856131, 4995056, 4684325, + 1351194, 8223904, 6817307, 2484146, 131782, 397032, 7436778, + 7973479, 3171829, 5624626, 3540123, 7150120, 8313283, + 3604714, 1043574, 117692, 7797783, 7909392, 903315, 7335342, + 7501562, 5826142, 2709813, 8245473, 2369045, 2782257, + 5762833, 6474114, 6862031, 424522, 594248, 2626630, 7659983, + 5642869, 4075194, 1592129, 245547, 5271031, 3205046, 982375, + 267873, 1286496, 7230481, 3208972, 7485411, 676111, 4944500, + 2959742, 5934456, 1414847, 6067948, 1709895, 4648315, 126008, + 8258986, 2183134, 2302072, 4674924, 4306056, 7465311, + 6500270, 4247428, 4016815, 4973426, 294287, 2456847, 3289700, + 2732169, 1159447, 5569724, 140001, 3237977, 8007761, 5874533, + 255652, 3119586, 2102434, 6248250, 8152822, 8006066, 7708625, + 6997719, 6260212, 6186962, 6636650, 7836834, 7998017, + 2061516, 1197591, 1706544, 733027, 2392907, 2700000, 8254598, + 4488002, 160495, 2985325, 2036837, 2703633, 6406550, 3579947, + 6195178, 5552390, 6804584, 6305468, 5731980, 6095195, + 3323409, 1322661, 6690942, 3374630, 5615167, 479044, 3136054, + 4380418, 2833144, 7829577, 1770522, 6056687, 240415, 14780, + 3740517, 5224226, 3547288, 2083124, 4699398, 3654239, + 5624978, 585593, 3655369, 2281739, 3338565, 1908093, 7784706, + 4352830, } for i := 0; i < 32; i++ { seed[i] = byte(i) @@ -152,7 +104,7 @@ func TestDeriveUniformLeGamma1(t *testing.T) { func TestDeriveUniformBall(t *testing.T) { var p common.Poly - var seed [32]byte + var seed [CTildeSize]byte for i := 0; i < 100; i++ { binary.LittleEndian.PutUint64(seed[:], uint64(i)) PolyDeriveUniformBall(&p, seed[:]) @@ -200,7 +152,7 @@ func TestDeriveUniformBallX4(t *testing.T) { } var ps [4]common.Poly var p common.Poly - var seed [32]byte + var seed [CTildeSize]byte PolyDeriveUniformBallX4( [4]*common.Poly{&ps[0], &ps[1], &ps[2], &ps[3]}, seed[:], diff --git a/sign/mldsa/mldsa87/dilithium.go b/sign/mldsa/mldsa87/dilithium.go index a0aa0cf99..0c3c2ef7b 100644 --- a/sign/mldsa/mldsa87/dilithium.go +++ b/sign/mldsa/mldsa87/dilithium.go @@ -1,19 +1,17 @@ -// Code generated from modePkg.templ.go. DO NOT EDIT. - +// Code generated from pkg.templ.go. DO NOT EDIT. // mldsa87 implements NIST signature scheme ML-DSA-87 as defined in FIPS204. - package mldsa87 import ( "crypto" + cryptoRand "crypto/rand" "errors" "io" + "github.com/cloudflare/circl/sign" common "github.com/cloudflare/circl/sign/internal/dilithium" - "github.com/cloudflare/circl/sign/mldsa/mldsa87/internal" - ) const ( @@ -51,20 +49,59 @@ func NewKeyFromSeed(seed *[SeedSize]byte) (*PublicKey, *PrivateKey) { // SignTo signs the given message and writes the signature into signature. // It will panic if signature is not of length at least SignatureSize. -func SignTo(sk *PrivateKey, msg []byte, signature []byte) { +// +// ctx is the optional context string. Errors if ctx is larger than 255 bytes. +// A nil context string is equivalent to an empty context string. +func SignTo(sk *PrivateKey, msg, ctx []byte, randomized bool, sig []byte) error { + var rnd [32]byte + if randomized { + _, err := cryptoRand.Read(rnd[:]) + if err != nil { + return err + } + } + + if len(ctx) > 255 { + return sign.ErrContextTooLong + } + internal.SignTo( (*internal.PrivateKey)(sk), - msg, - signature, + func(w io.Writer) { + _, _ = w.Write([]byte{0}) + _, _ = w.Write([]byte{byte(len(ctx))}) + + if ctx != nil { + _, _ = w.Write(ctx) + } + w.Write(msg) + }, + rnd, + sig, ) + return nil } // Verify checks whether the given signature by pk on msg is valid. -func Verify(pk *PublicKey, msg []byte, signature []byte) bool { +// +// ctx is the optional context string. Fails if ctx is larger than 255 bytes. +// A nil context string is equivalent to an empty context string. +func Verify(pk *PublicKey, msg, ctx, sig []byte) bool { + if len(ctx) > 255 { + return false + } return internal.Verify( (*internal.PublicKey)(pk), - msg, - signature, + func(w io.Writer) { + _, _ = w.Write([]byte{0}) + _, _ = w.Write([]byte{byte(len(ctx))}) + + if ctx != nil { + _, _ = w.Write(ctx) + } + _, _ = w.Write(msg) + }, + sig, ) } @@ -144,15 +181,17 @@ func (sk *PrivateKey) UnmarshalBinary(data []byte) error { // interface. The package-level SignTo function might be more convenient // to use. func (sk *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ( - signature []byte, err error) { - var sig [SignatureSize]byte + sig []byte, err error) { + var ret [SignatureSize]byte if opts.HashFunc() != crypto.Hash(0) { return nil, errors.New("dilithium: cannot sign hashed message") } + if err = SignTo(sk, msg, nil, false, ret[:]); err != nil { + return nil, err + } - SignTo(sk, msg, sig[:]) - return sig[:], nil + return ret[:], nil } // Computes the public key corresponding to this private key. @@ -180,3 +219,114 @@ func (pk *PublicKey) Equal(other crypto.PublicKey) bool { } return (*internal.PublicKey)(pk).Equal((*internal.PublicKey)(castOther)) } + +// Boilerplate for generic signatures API + +type scheme struct{} + +var sch sign.Scheme = &scheme{} + +// Scheme returns a generic signature interface for ML-DSA-87. +func Scheme() sign.Scheme { return sch } + +func (*scheme) Name() string { return "ML-DSA-87" } +func (*scheme) PublicKeySize() int { return PublicKeySize } +func (*scheme) PrivateKeySize() int { return PrivateKeySize } +func (*scheme) SignatureSize() int { return SignatureSize } +func (*scheme) SeedSize() int { return SeedSize } + +// TODO TLSIdentifier() and OID() + +func (*scheme) SupportsContext() bool { + return true +} + +func (*scheme) GenerateKey() (sign.PublicKey, sign.PrivateKey, error) { + return GenerateKey(nil) +} + +func (*scheme) Sign( + sk sign.PrivateKey, + msg []byte, + opts *sign.SignatureOpts, +) []byte { + var ctx []byte + sig := make([]byte, SignatureSize) + + priv, ok := sk.(*PrivateKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + ctx = []byte(opts.Context) + } + err := SignTo(priv, msg, ctx, false, sig) + if err != nil { + panic(err) + } + + return sig +} + +func (*scheme) Verify( + pk sign.PublicKey, + msg, sig []byte, + opts *sign.SignatureOpts, +) bool { + var ctx []byte + pub, ok := pk.(*PublicKey) + if !ok { + panic(sign.ErrTypeMismatch) + } + if opts != nil && opts.Context != "" { + ctx = []byte(opts.Context) + } + return Verify(pub, msg, ctx, sig) +} + +func (*scheme) DeriveKey(seed []byte) (sign.PublicKey, sign.PrivateKey) { + if len(seed) != SeedSize { + panic(sign.ErrSeedSize) + } + var seed2 [SeedSize]byte + copy(seed2[:], seed) + return NewKeyFromSeed(&seed2) +} + +func (*scheme) UnmarshalBinaryPublicKey(buf []byte) (sign.PublicKey, error) { + if len(buf) != PublicKeySize { + return nil, sign.ErrPubKeySize + } + + var ( + buf2 [PublicKeySize]byte + ret PublicKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (*scheme) UnmarshalBinaryPrivateKey(buf []byte) (sign.PrivateKey, error) { + if len(buf) != PrivateKeySize { + return nil, sign.ErrPrivKeySize + } + + var ( + buf2 [PrivateKeySize]byte + ret PrivateKey + ) + + copy(buf2[:], buf) + ret.Unpack(&buf2) + return &ret, nil +} + +func (sk *PrivateKey) Scheme() sign.Scheme { + return sch +} + +func (sk *PublicKey) Scheme() sign.Scheme { + return sch +} diff --git a/sign/mldsa/mldsa87/internal/dilithium.go b/sign/mldsa/mldsa87/internal/dilithium.go index 7869d0475..609ab3a4c 100644 --- a/sign/mldsa/mldsa87/internal/dilithium.go +++ b/sign/mldsa/mldsa87/internal/dilithium.go @@ -244,7 +244,10 @@ func (sk *PrivateKey) computeT0andT1(t0, t1 *VecK) { } // Verify checks whether the given signature by pk on msg is valid. -func Verify(pk *PublicKey, msg []byte, signature []byte) bool { +// +// For Dilithium this is the top-level verification function. +// In ML-DSA, this is ML-DSA.Verify_internal. +func Verify(pk *PublicKey, msg func(io.Writer), signature []byte) bool { var sig unpackedSignature var mu [64]byte var zh VecL @@ -262,7 +265,7 @@ func Verify(pk *PublicKey, msg []byte, signature []byte) bool { // μ = CRH(tr ‖ msg) h := sha3.NewShake256() _, _ = h.Write(pk.tr[:]) - _, _ = h.Write(msg) + msg(&h) _, _ = h.Read(mu[:]) // Compute Az @@ -279,7 +282,7 @@ func Verify(pk *PublicKey, msg []byte, signature []byte) bool { // which is small enough for NTT(). Az2dct1.MulBy2toD(&pk.t1) Az2dct1.NTT() - PolyDeriveUniformBall(&ch, sig.c[:32]) + PolyDeriveUniformBall(&ch, sig.c[:]) ch.NTT() for i := 0; i < K; i++ { Az2dct1[i].MulHat(&Az2dct1[i], &ch) @@ -307,8 +310,11 @@ func Verify(pk *PublicKey, msg []byte, signature []byte) bool { // SignTo signs the given message and writes the signature into signature. // +// For Dilithium this is the top-level signing function. For ML-DSA +// this is ML-DSA.Sign_internal. +// //nolint:funlen -func SignTo(sk *PrivateKey, msg []byte, signature []byte) { +func SignTo(sk *PrivateKey, msg func(io.Writer), rnd [32]byte, signature []byte) { var mu, rhop [64]byte var w1Packed [PolyW1Size * K]byte var y, yh VecL @@ -324,16 +330,14 @@ func SignTo(sk *PrivateKey, msg []byte, signature []byte) { // μ = CRH(tr ‖ msg) h := sha3.NewShake256() _, _ = h.Write(sk.tr[:]) - _, _ = h.Write(msg) + msg(&h) _, _ = h.Read(mu[:]) // ρ' = CRH(key ‖ μ) h.Reset() _, _ = h.Write(sk.key[:]) if NIST { - // We implement the deterministic variant where rnd is all zeroes. - // TODO expose randomized variant? - _, _ = h.Write(make([]byte, 32)) + _, _ = h.Write(rnd[:]) } _, _ = h.Write(mu[:]) _, _ = h.Read(rhop[:]) @@ -373,7 +377,7 @@ func SignTo(sk *PrivateKey, msg []byte, signature []byte) { _, _ = h.Write(w1Packed[:]) _, _ = h.Read(sig.c[:]) - PolyDeriveUniformBall(&ch, sig.c[:32]) + PolyDeriveUniformBall(&ch, sig.c[:]) ch.NTT() // Ensure ‖ w₀ - c·s2 ‖_∞ < γ₂ - β. diff --git a/sign/mldsa/mldsa87/internal/dilithium_test.go b/sign/mldsa/mldsa87/internal/dilithium_test.go index 825e7da08..91dd478e0 100644 --- a/sign/mldsa/mldsa87/internal/dilithium_test.go +++ b/sign/mldsa/mldsa87/internal/dilithium_test.go @@ -4,6 +4,7 @@ package internal import ( "encoding/binary" + "io" "testing" common "github.com/cloudflare/circl/sign/internal/dilithium" @@ -36,32 +37,38 @@ func BenchmarkVerify(b *testing.B) { // Note that the expansion of the matrix A is done at Unpacking/Keygen // instead of at the moment of verification (as in the reference // implementation.) - var seed [32]byte - var msg [8]byte - var sig [SignatureSize]byte + var ( + seed [32]byte + msg [8]byte + sig [SignatureSize]byte + rnd [32]byte + ) pk, sk := NewKeyFromSeed(&seed) - SignTo(sk, msg[:], sig[:]) + SignTo(sk, func(w io.Writer) { w.Write(msg[:]) }, rnd, sig[:]) b.ResetTimer() for i := 0; i < b.N; i++ { // We should generate a new signature for every verify attempt, // as this influences the time a little bit. This difference, however, // is small and generating a new signature in between creates a lot // pressure on the allocator which makes an accurate measurement hard. - Verify(pk, msg[:], sig[:]) + Verify(pk, func(w io.Writer) { w.Write(msg[:]) }, sig[:]) } } func BenchmarkSign(b *testing.B) { // Note that the expansion of the matrix A is done at Unpacking/Keygen // instead of at the moment of signing (as in the reference implementation.) - var seed [32]byte - var msg [8]byte - var sig [SignatureSize]byte + var ( + seed [32]byte + msg [8]byte + sig [SignatureSize]byte + rnd [32]byte + ) _, sk := NewKeyFromSeed(&seed) b.ResetTimer() for i := 0; i < b.N; i++ { binary.LittleEndian.PutUint64(msg[:], uint64(i)) - SignTo(sk, msg[:], sig[:]) + SignTo(sk, func(w io.Writer) { w.Write(msg[:]) }, rnd, sig[:]) } } @@ -85,13 +92,16 @@ func BenchmarkPublicFromPrivate(b *testing.B) { } func TestSignThenVerifyAndPkSkPacking(t *testing.T) { - var seed [common.SeedSize]byte - var sig [SignatureSize]byte - var msg [8]byte - var pkb [PublicKeySize]byte - var skb [PrivateKeySize]byte - var pk2 PublicKey - var sk2 PrivateKey + var ( + seed [common.SeedSize]byte + sig [SignatureSize]byte + msg [8]byte + pkb [PublicKeySize]byte + skb [PrivateKeySize]byte + pk2 PublicKey + sk2 PrivateKey + rnd [32]byte + ) for i := uint64(0); i < 100; i++ { binary.LittleEndian.PutUint64(seed[:], i) pk, sk := NewKeyFromSeed(&seed) @@ -100,8 +110,8 @@ func TestSignThenVerifyAndPkSkPacking(t *testing.T) { } for j := uint64(0); j < 10; j++ { binary.LittleEndian.PutUint64(msg[:], j) - SignTo(sk, msg[:], sig[:]) - if !Verify(pk, msg[:], sig[:]) { + SignTo(sk, func(w io.Writer) { w.Write(msg[:]) }, rnd, sig[:]) + if !Verify(pk, func(w io.Writer) { w.Write(msg[:]) }, sig[:]) { t.Fatal() } } diff --git a/sign/mldsa/mldsa87/internal/params.go b/sign/mldsa/mldsa87/internal/params.go index e60c4d35f..b5dc669ca 100644 --- a/sign/mldsa/mldsa87/internal/params.go +++ b/sign/mldsa/mldsa87/internal/params.go @@ -4,7 +4,6 @@ package internal const ( Name = "ML-DSA-87" - UseAES = false K = 8 L = 7 Eta = 2 diff --git a/sign/mldsa/mldsa87/internal/sample.go b/sign/mldsa/mldsa87/internal/sample.go index 62c261332..b37370a4e 100644 --- a/sign/mldsa/mldsa87/internal/sample.go +++ b/sign/mldsa/mldsa87/internal/sample.go @@ -12,7 +12,7 @@ import ( // DeriveX4Available indicates whether the system supports the quick fourway // sampling variants like PolyDeriveUniformX4. -var DeriveX4Available = keccakf1600.IsEnabledX4() && !UseAES +var DeriveX4Available = keccakf1600.IsEnabledX4() // For each i, sample ps[i] uniformly from the given seed and nonces[i]. // ps[i] may be nil and is ignored in that case. @@ -91,13 +91,9 @@ func PolyDeriveUniformX4(ps [4]*common.Poly, seed *[32]byte, nonces [4]uint16) { // p will be normalized. func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { var i, length int - var buf [12 * 16]byte // fits 168B SHAKE-128 rate and 12 16B AES blocks + var buf [12 * 16]byte // fits 168B SHAKE-128 rate - if UseAES { - length = 12 * 16 - } else { - length = 168 - } + length = 168 sample := func() { // Note that 3 divides into 168 and 12*16, so we use up buf completely. @@ -113,25 +109,16 @@ func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { } } - if UseAES { - h := common.NewAesStream128(seed, nonce) + var iv [32 + 2]byte // 32 byte seed + uint16 nonce + h := sha3.NewShake128() + copy(iv[:32], seed[:]) + iv[32] = uint8(nonce) + iv[33] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) - for i < common.N { - h.SqueezeInto(buf[:length]) - sample() - } - } else { - var iv [32 + 2]byte // 32 byte seed + uint16 nonce - h := sha3.NewShake128() - copy(iv[:32], seed[:]) - iv[32] = uint8(nonce) - iv[33] = uint8(nonce >> 8) - _, _ = h.Write(iv[:]) - - for i < common.N { - _, _ = h.Read(buf[:168]) - sample() - } + for i < common.N { + _, _ = h.Read(buf[:168]) + sample() } } @@ -142,13 +129,9 @@ func PolyDeriveUniform(p *common.Poly, seed *[32]byte, nonce uint16) { func PolyDeriveUniformLeqEta(p *common.Poly, seed *[64]byte, nonce uint16) { // Assumes 2 < η < 8. var i, length int - var buf [9 * 16]byte // fits 136B SHAKE-256 rate and 9 16B AES blocks + var buf [9 * 16]byte // fits 136B SHAKE-256 rate - if UseAES { - length = 9 * 16 - } else { - length = 136 - } + length = 136 sample := func() { // We use rejection sampling @@ -181,28 +164,19 @@ func PolyDeriveUniformLeqEta(p *common.Poly, seed *[64]byte, nonce uint16) { } } - if UseAES { - h := common.NewAesStream256(seed, nonce) - - for i < common.N { - h.SqueezeInto(buf[:length]) - sample() - } - } else { - var iv [64 + 2]byte // 64 byte seed + uint16 nonce + var iv [64 + 2]byte // 64 byte seed + uint16 nonce - h := sha3.NewShake256() - copy(iv[:64], seed[:]) - iv[64] = uint8(nonce) - iv[65] = uint8(nonce >> 8) + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) - // 136 is SHAKE-256 rate - _, _ = h.Write(iv[:]) + // 136 is SHAKE-256 rate + _, _ = h.Write(iv[:]) - for i < common.N { - _, _ = h.Read(buf[:136]) - sample() - } + for i < common.N { + _, _ = h.Read(buf[:136]) + sample() } } @@ -223,18 +197,13 @@ func VecLDeriveUniformLeGamma1(v *VecL, seed *[64]byte, nonce uint16) { func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { var buf [PolyLeGamma1Size]byte - if UseAES { - h := common.NewAesStream256(seed, nonce) - h.SqueezeInto(buf[:]) - } else { - var iv [66]byte - h := sha3.NewShake256() - copy(iv[:64], seed[:]) - iv[64] = uint8(nonce) - iv[65] = uint8(nonce >> 8) - _, _ = h.Write(iv[:]) - _, _ = h.Read(buf[:]) - } + var iv [66]byte + h := sha3.NewShake256() + copy(iv[:64], seed[:]) + iv[64] = uint8(nonce) + iv[65] = uint8(nonce >> 8) + _, _ = h.Write(iv[:]) + _, _ = h.Read(buf[:]) PolyUnpackLeGamma1(p, buf[:]) } @@ -251,7 +220,7 @@ func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed []byte) { state := perm.Initialize(false) // Absorb the seed in the four states - for i := 0; i < 32/8; i++ { + for i := 0; i < CTildeSize/8; i++ { v := binary.LittleEndian.Uint64(seed[8*i : 8*(i+1)]) for j := 0; j < 4; j++ { state[i*4+j] = v @@ -260,7 +229,7 @@ func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed []byte) { // SHAKE256 domain separator and padding for j := 0; j < 4; j++ { - state[(32/8)*4+j] ^= 0x1f + state[(CTildeSize/8)*4+j] ^= 0x1f state[16*4+j] ^= 0x80 << 56 } perm.Permute() diff --git a/sign/mldsa/mldsa87/internal/sample_test.go b/sign/mldsa/mldsa87/internal/sample_test.go index 2059599eb..32931c94f 100644 --- a/sign/mldsa/mldsa87/internal/sample_test.go +++ b/sign/mldsa/mldsa87/internal/sample_test.go @@ -12,94 +12,46 @@ import ( func TestVectorDeriveUniform(t *testing.T) { var p, p2 common.Poly var seed [32]byte - if UseAES { - p2 = common.Poly{ - 6724291, 310295, 6949524, 4464039, 1482136, 2522903, - 7025059, 3006320, 7286364, 7516512, 3361305, 1955529, - 4765954, 1725325, 6933066, 4299100, 6625173, 4272792, - 583034, 4971409, 2259140, 7715362, 3975394, 2341624, - 5481174, 8150082, 365246, 5491939, 1083120, 7517301, - 3104783, 2475292, 184149, 6425226, 4591622, 5964030, - 4729604, 5471092, 1828227, 1082044, 2516245, 1692580, - 3274844, 5443294, 7256740, 4989638, 3191250, 7479519, - 5124211, 5603858, 1230692, 2513454, 2828034, 4254312, - 1512596, 5245430, 5517392, 2814840, 932545, 6826733, - 3511094, 4075348, 3233981, 7268882, 2913733, 4870249, - 4123492, 8124406, 4016949, 5478752, 2750895, 603525, - 5724798, 3985430, 3483012, 6434230, 3136996, 8297976, - 4107616, 7307748, 6962904, 7544473, 1193110, 3448595, - 4814773, 5607932, 8221314, 1054046, 1541208, 1866050, - 8227412, 2925778, 5293953, 2065416, 4972769, 3616283, - 7990594, 1105530, 7121836, 1170740, 7417431, 633146, - 253820, 7235019, 3539504, 6807707, 451390, 5481526, - 2859902, 1063061, 4579730, 7126652, 7033767, 4294814, - 1414604, 7620048, 1953268, 8304556, 1156814, 1182881, - 5311519, 3057534, 5277666, 682843, 2070398, 2874278, - 4859533, 6376664, 6694074, 1590242, 2620706, 8331066, - 5643845, 5037538, 2891516, 7004879, 3754327, 5031296, - 5463118, 2420870, 8116529, 5517696, 7435129, 3873963, - 710407, 713806, 175647, 4274571, 2655021, 7319503, - 3027243, 7129679, 4213435, 2429323, 4643873, 4568526, - 649664, 1720514, 6497260, 2683517, 7672754, 7105190, - 3148405, 5898369, 5667677, 8050874, 1587139, 7315260, - 4337416, 2202680, 2338714, 557467, 6752058, 2469794, - 485071, 1617604, 3590498, 2151466, 2005823, 7727956, - 7776292, 6783433, 6787146, 1732833, 3596857, 7436284, - 4483349, 4970142, 4472608, 6478342, 1236215, 5695744, - 2280717, 2889355, 3233946, 5187812, 978685, 5177364, - 2922353, 4824807, 5302883, 6739803, 8092453, 5883903, - 816553, 6041174, 8317591, 1459178, 5332455, 1835058, - 1368601, 2820950, 3479224, 2589540, 7992934, 3421045, - 4657128, 8292902, 4153567, 3553988, 7830320, 6722913, - 2555309, 4149801, 8328975, 1560545, 7757473, 3106458, - 4310856, 7135453, 3481032, 652626, 1841361, 8126828, - 6250018, 300536, 7380070, 8174419, 1418793, 6208185, - 3906256, 6679016, 1605701, 3561489, 5819724, 5746996, - 8044214, 7087187, 7102330, 4962927, 4253983, 7108567, - 4119736, 6584065, 441634, 6941656, - } - } else { - p2 = common.Poly{ - 2901364, 562527, 5258502, 3885002, 4190126, 4460268, 6884052, - 3514511, 5383040, 213206, 2155865, 5179607, 3551954, 2312357, - 6066350, 8126097, 1179080, 4787182, 6552182, 6713644, - 1561067, 7626063, 7859743, 5052321, 7032876, 7815031, 157938, - 1865184, 490802, 5717642, 3451902, 7000218, 3743250, 1677431, - 1875427, 5596150, 671623, 3819041, 6247594, 1014875, 4933545, - 7122446, 6682963, 3388398, 3335295, 943002, 1145083, 3113071, - 105967, 1916675, 7474561, 1107006, 700548, 2147909, 1603855, - 5049181, 437882, 6118899, 5656914, 6731065, 3066622, 865453, - 5427634, 981549, 4650873, 861291, 4003872, 5104220, 6171453, - 3723302, 7426315, 6137283, 4874820, 6052561, 53441, 5032874, - 5614778, 2248550, 1756499, 8280764, 8263880, 7600081, - 5118374, 795344, 7543392, 6869925, 1841187, 4181568, 584562, - 7483939, 4938664, 6863397, 5126354, 5218129, 6236086, - 4149293, 379169, 4368487, 7490569, 3409215, 1580463, 3081737, - 1278732, 7109719, 7371700, 2097931, 399836, 1700274, 7188595, - 6830029, 1548850, 6593138, 6849097, 1518037, 2859442, - 7772265, 7325153, 3281191, 7856131, 4995056, 4684325, - 1351194, 8223904, 6817307, 2484146, 131782, 397032, 7436778, - 7973479, 3171829, 5624626, 3540123, 7150120, 8313283, - 3604714, 1043574, 117692, 7797783, 7909392, 903315, 7335342, - 7501562, 5826142, 2709813, 8245473, 2369045, 2782257, - 5762833, 6474114, 6862031, 424522, 594248, 2626630, 7659983, - 5642869, 4075194, 1592129, 245547, 5271031, 3205046, 982375, - 267873, 1286496, 7230481, 3208972, 7485411, 676111, 4944500, - 2959742, 5934456, 1414847, 6067948, 1709895, 4648315, 126008, - 8258986, 2183134, 2302072, 4674924, 4306056, 7465311, - 6500270, 4247428, 4016815, 4973426, 294287, 2456847, 3289700, - 2732169, 1159447, 5569724, 140001, 3237977, 8007761, 5874533, - 255652, 3119586, 2102434, 6248250, 8152822, 8006066, 7708625, - 6997719, 6260212, 6186962, 6636650, 7836834, 7998017, - 2061516, 1197591, 1706544, 733027, 2392907, 2700000, 8254598, - 4488002, 160495, 2985325, 2036837, 2703633, 6406550, 3579947, - 6195178, 5552390, 6804584, 6305468, 5731980, 6095195, - 3323409, 1322661, 6690942, 3374630, 5615167, 479044, 3136054, - 4380418, 2833144, 7829577, 1770522, 6056687, 240415, 14780, - 3740517, 5224226, 3547288, 2083124, 4699398, 3654239, - 5624978, 585593, 3655369, 2281739, 3338565, 1908093, 7784706, - 4352830, - } + p2 = common.Poly{ + 2901364, 562527, 5258502, 3885002, 4190126, 4460268, 6884052, + 3514511, 5383040, 213206, 2155865, 5179607, 3551954, 2312357, + 6066350, 8126097, 1179080, 4787182, 6552182, 6713644, + 1561067, 7626063, 7859743, 5052321, 7032876, 7815031, 157938, + 1865184, 490802, 5717642, 3451902, 7000218, 3743250, 1677431, + 1875427, 5596150, 671623, 3819041, 6247594, 1014875, 4933545, + 7122446, 6682963, 3388398, 3335295, 943002, 1145083, 3113071, + 105967, 1916675, 7474561, 1107006, 700548, 2147909, 1603855, + 5049181, 437882, 6118899, 5656914, 6731065, 3066622, 865453, + 5427634, 981549, 4650873, 861291, 4003872, 5104220, 6171453, + 3723302, 7426315, 6137283, 4874820, 6052561, 53441, 5032874, + 5614778, 2248550, 1756499, 8280764, 8263880, 7600081, + 5118374, 795344, 7543392, 6869925, 1841187, 4181568, 584562, + 7483939, 4938664, 6863397, 5126354, 5218129, 6236086, + 4149293, 379169, 4368487, 7490569, 3409215, 1580463, 3081737, + 1278732, 7109719, 7371700, 2097931, 399836, 1700274, 7188595, + 6830029, 1548850, 6593138, 6849097, 1518037, 2859442, + 7772265, 7325153, 3281191, 7856131, 4995056, 4684325, + 1351194, 8223904, 6817307, 2484146, 131782, 397032, 7436778, + 7973479, 3171829, 5624626, 3540123, 7150120, 8313283, + 3604714, 1043574, 117692, 7797783, 7909392, 903315, 7335342, + 7501562, 5826142, 2709813, 8245473, 2369045, 2782257, + 5762833, 6474114, 6862031, 424522, 594248, 2626630, 7659983, + 5642869, 4075194, 1592129, 245547, 5271031, 3205046, 982375, + 267873, 1286496, 7230481, 3208972, 7485411, 676111, 4944500, + 2959742, 5934456, 1414847, 6067948, 1709895, 4648315, 126008, + 8258986, 2183134, 2302072, 4674924, 4306056, 7465311, + 6500270, 4247428, 4016815, 4973426, 294287, 2456847, 3289700, + 2732169, 1159447, 5569724, 140001, 3237977, 8007761, 5874533, + 255652, 3119586, 2102434, 6248250, 8152822, 8006066, 7708625, + 6997719, 6260212, 6186962, 6636650, 7836834, 7998017, + 2061516, 1197591, 1706544, 733027, 2392907, 2700000, 8254598, + 4488002, 160495, 2985325, 2036837, 2703633, 6406550, 3579947, + 6195178, 5552390, 6804584, 6305468, 5731980, 6095195, + 3323409, 1322661, 6690942, 3374630, 5615167, 479044, 3136054, + 4380418, 2833144, 7829577, 1770522, 6056687, 240415, 14780, + 3740517, 5224226, 3547288, 2083124, 4699398, 3654239, + 5624978, 585593, 3655369, 2281739, 3338565, 1908093, 7784706, + 4352830, } for i := 0; i < 32; i++ { seed[i] = byte(i) @@ -152,7 +104,7 @@ func TestDeriveUniformLeGamma1(t *testing.T) { func TestDeriveUniformBall(t *testing.T) { var p common.Poly - var seed [32]byte + var seed [CTildeSize]byte for i := 0; i < 100; i++ { binary.LittleEndian.PutUint64(seed[:], uint64(i)) PolyDeriveUniformBall(&p, seed[:]) @@ -200,7 +152,7 @@ func TestDeriveUniformBallX4(t *testing.T) { } var ps [4]common.Poly var p common.Poly - var seed [32]byte + var seed [CTildeSize]byte PolyDeriveUniformBallX4( [4]*common.Poly{&ps[0], &ps[1], &ps[2], &ps[3]}, seed[:], diff --git a/sign/schemes/schemes.go b/sign/schemes/schemes.go index 66ee61253..1abdd9532 100644 --- a/sign/schemes/schemes.go +++ b/sign/schemes/schemes.go @@ -16,6 +16,13 @@ import ( "github.com/cloudflare/circl/sign/ed448" "github.com/cloudflare/circl/sign/eddilithium2" "github.com/cloudflare/circl/sign/eddilithium3" + + dilithium2 "github.com/cloudflare/circl/sign/dilithium/mode2" + dilithium3 "github.com/cloudflare/circl/sign/dilithium/mode3" + dilithium5 "github.com/cloudflare/circl/sign/dilithium/mode5" + "github.com/cloudflare/circl/sign/mldsa/mldsa44" + "github.com/cloudflare/circl/sign/mldsa/mldsa65" + "github.com/cloudflare/circl/sign/mldsa/mldsa87" ) var allSchemes = [...]sign.Scheme{ @@ -23,6 +30,13 @@ var allSchemes = [...]sign.Scheme{ ed448.Scheme(), eddilithium2.Scheme(), eddilithium3.Scheme(), + + dilithium2.Scheme(), + dilithium3.Scheme(), + dilithium5.Scheme(), + mldsa44.Scheme(), + mldsa65.Scheme(), + mldsa87.Scheme(), } var allSchemeNames map[string]sign.Scheme diff --git a/sign/schemes/schemes_test.go b/sign/schemes/schemes_test.go index 2d8e86512..244e9b750 100644 --- a/sign/schemes/schemes_test.go +++ b/sign/schemes/schemes_test.go @@ -117,6 +117,12 @@ func Example() { // Ed448 // Ed25519-Dilithium2 // Ed448-Dilithium3 + // Dilithium2 + // Dilithium3 + // Dilithium5 + // ML-DSA-44 + // ML-DSA-65 + // ML-DSA-87 } func BenchmarkGenerateKeyPair(b *testing.B) { diff --git a/sign/sign.go b/sign/sign.go index 13b20fa4b..557d6f096 100644 --- a/sign/sign.go +++ b/sign/sign.go @@ -107,4 +107,7 @@ var ( // ErrContextNotSupported is the error used if a context is not // supported. ErrContextNotSupported = errors.New("context not supported") + + // ErrContextTooLong is the error used if the context string is too long. + ErrContextTooLong = errors.New("context string too long") )