diff --git a/README.md b/README.md index a4fd64f95..271a7d67c 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ Alternatively, look at the [Cloudflare Go](https://github.com/cloudflare/go/tree |:---:| - [Dilithium](./sign/dilithium): modes 2, 3, 5 ([Dilithium](https://pq-crystals.org/dilithium/)). + - [ML-DSA](./sign/mldsa): modes 44, 65, 87 ([FIPS 204](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf)). ### Zero-knowledge Proofs 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 4f4de0d99..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] - // O.K. -} diff --git a/sign/dilithium/gen.go b/sign/dilithium/gen.go index c0d0df378..6b136ec07 100644 --- a/sign/dilithium/gen.go +++ b/sign/dilithium/gen.go @@ -14,12 +14,11 @@ import ( "strings" "text/template" - "github.com/cloudflare/circl/sign/dilithium/internal/common/params" + "github.com/cloudflare/circl/sign/internal/dilithium/params" ) type Mode struct { Name string - UseAES bool K int L int Eta int @@ -28,38 +27,42 @@ type Mode struct { Tau int Gamma1Bits int Gamma2 int + TRSize int + CTildeSize int } func (m Mode) Pkg() string { return strings.ToLower(m.Mode()) } +func (m Mode) PkgPath() string { + if m.NIST() { + return path.Join("..", "mldsa", m.Pkg()) + } + + return m.Pkg() +} + func (m Mode) Impl() string { return "impl" + m.Mode() } func (m Mode) Mode() string { - return strings.ReplaceAll(strings.ReplaceAll(m.Name, - "Dilithium", "Mode"), "-AES", "AES") + if m.NIST() { + return strings.ReplaceAll(m.Name, "-", "") + } + + return strings.ReplaceAll(m.Name, "Dilithium", "Mode") +} + +func (m Mode) NIST() bool { + return strings.HasPrefix(m.Name, "ML-DSA-") } var ( Modes = []Mode{ { Name: "Dilithium2", - UseAES: false, - K: 4, - L: 4, - Eta: 2, - DoubleEtaBits: 3, - Omega: 80, - Tau: 39, - Gamma1Bits: 17, - Gamma2: (params.Q - 1) / 88, - }, - { - Name: "Dilithium2-AES", - UseAES: true, K: 4, L: 4, Eta: 2, @@ -68,22 +71,11 @@ var ( Tau: 39, Gamma1Bits: 17, Gamma2: (params.Q - 1) / 88, + TRSize: 32, + CTildeSize: 32, }, { Name: "Dilithium3", - UseAES: false, - K: 6, - L: 5, - Eta: 4, - DoubleEtaBits: 4, - Omega: 55, - Tau: 49, - Gamma1Bits: 19, - Gamma2: (params.Q - 1) / 32, - }, - { - Name: "Dilithium3-AES", - UseAES: true, K: 6, L: 5, Eta: 4, @@ -92,10 +84,11 @@ var ( Tau: 49, Gamma1Bits: 19, Gamma2: (params.Q - 1) / 32, + TRSize: 32, + CTildeSize: 32, }, { Name: "Dilithium5", - UseAES: false, K: 8, L: 7, Eta: 2, @@ -104,10 +97,37 @@ var ( Tau: 60, Gamma1Bits: 19, Gamma2: (params.Q - 1) / 32, + TRSize: 32, + CTildeSize: 32, }, { - Name: "Dilithium5-AES", - UseAES: true, + Name: "ML-DSA-44", + K: 4, + L: 4, + Eta: 2, + DoubleEtaBits: 3, + Omega: 80, + Tau: 39, + Gamma1Bits: 17, + Gamma2: (params.Q - 1) / 88, + TRSize: 64, + CTildeSize: 32, + }, + { + Name: "ML-DSA-65", + K: 6, + L: 5, + Eta: 4, + DoubleEtaBits: 4, + Omega: 55, + Tau: 49, + Gamma1Bits: 19, + Gamma2: (params.Q - 1) / 32, + TRSize: 64, + CTildeSize: 48, + }, + { + Name: "ML-DSA-87", K: 8, L: 7, Eta: 2, @@ -116,6 +136,8 @@ var ( Tau: 60, Gamma1Bits: 19, Gamma2: (params.Q - 1) / 32, + TRSize: 64, + CTildeSize: 64, }, } TemplateWarning = "// Code generated from" @@ -123,7 +145,6 @@ var ( func main() { generateModePackageFiles() - generateModeToplevelFiles() generateParamsFiles() generateSourceFiles() } @@ -153,7 +174,7 @@ func generateParamsFiles() { if offset == -1 { panic("Missing template warning in params.templ.go") } - err = os.WriteFile(mode.Pkg()+"/internal/params.go", + err = os.WriteFile(mode.PkgPath()+"/internal/params.go", []byte(res[offset:]), 0o644) if err != nil { panic(err) @@ -161,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) } @@ -175,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) - 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) + res, err := format.Source(buf.Bytes()) 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.Pkg()+"/dilithium.go", []byte(res[offset:]), 0o644) + err = os.WriteFile(mode.PkgPath()+"/dilithium.go", res[offset:], 0o644) if err != nil { panic(err) } @@ -246,10 +245,10 @@ func generateSourceFiles() { continue } - fs, err = os.ReadDir(path.Join(mode.Pkg(), "internal")) + fs, err = os.ReadDir(path.Join(mode.PkgPath(), "internal")) for _, f := range fs { name := f.Name() - fn := path.Join(mode.Pkg(), "internal", name) + fn := path.Join(mode.PkgPath(), "internal", name) if ignored(name) { continue } @@ -273,7 +272,7 @@ func generateSourceFiles() { } } for name, expected := range files { - fn := path.Join(mode.Pkg(), "internal", name) + fn := path.Join(mode.PkgPath(), "internal", name) expected = []byte(fmt.Sprintf( "%s mode3/internal/%s by gen.go\n\n%s", TemplateWarning, diff --git a/sign/dilithium/kat_test.go b/sign/dilithium/kat_test.go index 2280e988d..35571dfea 100644 --- a/sign/dilithium/kat_test.go +++ b/sign/dilithium/kat_test.go @@ -6,27 +6,34 @@ package dilithium import ( "crypto/sha256" "fmt" + "strings" "testing" "github.com/cloudflare/circl/internal/nist" + "github.com/cloudflare/circl/sign/schemes" ) func TestPQCgenKATSign(t *testing.T) { - // Generated from reference implementation commit 61b51a71701b8ae9f546a1e5, - // which can be found at https://github.com/pq-crystals/dilithium for _, tc := range []struct { name string want string }{ + // Generated from reference implementation commit 61b51a71701b8ae9f546a1e5, + // which can be found at https://github.com/pq-crystals/dilithium {"Dilithium2", "38ed991c5ca11e39ab23945ca37af89e059d16c5474bf8ba96b15cb4e948af2a"}, {"Dilithium3", "8196b32212753f525346201ffec1c7a0a852596fa0b57bd4e2746231dab44d55"}, {"Dilithium5", "7ded97a6e6c809b43b54c248171d7504fa6a0cab651bf288bb00034782667481"}, - {"Dilithium2-AES", "b6673f8da5bba7dfae63adbbdf559f4fcfb715d1f91da98d4b52e26203d69196"}, - {"Dilithium3-AES", "482f4d672a9f1dc38cc8bcf8b1731b03fe99fcb6f2b73aa4a376b99faf89ccbe"}, - {"Dilithium5-AES", "54dfa85013d1b3da4f1d7c6dd270bc91a083cfece3d320c97906da125fd2a48f"}, + + // Generated from reference implementation commit cbcd8753a43402885c90343c + // which can be found at https://github.com/pq-crystals/dilithium + // with the DILITHIUM_RANDOMIZED_SIGNING macro unset in ref/config.h + // to disable randomized signing. + {"ML-DSA-44", "14f92c48abc0d63ea263cce3c83183c8360c6ede7cbd5b65bd7c6f31e38f0ea5"}, + {"ML-DSA-65", "595a8eff6988159c94eb5398294458c5d27d21c994fb64cadbee339173abcf63"}, + {"ML-DSA-87", "35e2ce3d88b3311517bf8d41aa2cd24aa0fbda2bb8052ca8af4ad8d7c7344074"}, } { t.Run(tc.name, func(t *testing.T) { - mode := ModeByName(tc.name) + mode := schemes.ByName(tc.name) if mode == nil { t.Fatal() } @@ -38,7 +45,18 @@ func TestPQCgenKATSign(t *testing.T) { } f := sha256.New() g := nist.NewDRBG(&seed) - fmt.Fprintf(f, "# %s\n\n", tc.name) + nameInKat := tc.name + if !strings.HasPrefix(tc.name, "Dilithium") { + switch tc.name { + case "ML-DSA-44": + nameInKat = "Dilithium2" + case "ML-DSA-65": + nameInKat = "Dilithium3" + case "ML-DSA-87": + nameInKat = "Dilithium5" + } + } + fmt.Fprintf(f, "# %s\n\n", nameInKat) for i := 0; i < 100; i++ { mlen := 33 * (i + 1) g.Fill(seed[:]) @@ -52,17 +70,26 @@ func TestPQCgenKATSign(t *testing.T) { g2 := nist.NewDRBG(&seed) g2.Fill(eseed[:]) - pk, sk := mode.NewKeyFromSeed(eseed[:]) + pk, sk := mode.DeriveKey(eseed[:]) + + 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", pk.Bytes()) - fmt.Fprintf(f, "sk = %X\n", sk.Bytes()) + 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/mode2.go b/sign/dilithium/mode2.go deleted file mode 100644 index e88d090b0..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/internal/common" - "github.com/cloudflare/circl/sign/dilithium/mode2" -) - -// 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 public 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 13ac869a5..113708a32 100644 --- a/sign/dilithium/mode2/dilithium.go +++ b/sign/dilithium/mode2/dilithium.go @@ -1,4 +1,4 @@ -// 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 @@ -11,8 +11,9 @@ import ( "errors" "io" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + "github.com/cloudflare/circl/sign" "github.com/cloudflare/circl/sign/dilithium/mode2/internal" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) const ( @@ -50,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, ) } @@ -143,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. @@ -179,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 79a17d504..8f1c8e5cb 100644 --- a/sign/dilithium/mode2/internal/dilithium.go +++ b/sign/dilithium/mode2/internal/dilithium.go @@ -8,7 +8,7 @@ import ( "io" "github.com/cloudflare/circl/internal/sha3" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) const ( @@ -29,13 +29,13 @@ const ( Alpha = 2 * Gamma2 // Size of a packed private key - PrivateKeySize = 32 + 32 + 32 + PolyLeqEtaSize*(L+K) + common.PolyT0Size*K + 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 + 32 + SignatureSize = L*PolyLeGamma1Size + Omega + K + CTildeSize // Size of packed w₁ PolyW1Size = (common.N * (common.QBits - Gamma1Bits)) / 8 @@ -49,7 +49,7 @@ type PublicKey struct { // Cached values t1p [common.PolyT1Size * K]byte A *Mat - tr *[32]byte + tr *[TRSize]byte } // PrivateKey is the type of Dilithium private keys. @@ -59,7 +59,7 @@ type PrivateKey struct { s1 VecL s2 VecK t0 VecK - tr [32]byte + tr [TRSize]byte // Cached values A Mat // ExpandA(ρ) @@ -71,14 +71,14 @@ type PrivateKey struct { type unpackedSignature struct { z VecL hint VecK - c [32]byte + c [CTildeSize]byte } // Packs the signature into buf. func (sig *unpackedSignature) Pack(buf []byte) { copy(buf[:], sig.c[:]) - sig.z.PackLeGamma1(buf[32:]) - sig.hint.PackHint(buf[32+L*PolyLeGamma1Size:]) + sig.z.PackLeGamma1(buf[CTildeSize:]) + sig.hint.PackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) } // Sets sig to the signature encoded in the buffer. @@ -89,11 +89,11 @@ func (sig *unpackedSignature) Unpack(buf []byte) bool { return false } copy(sig.c[:], buf[:]) - sig.z.UnpackLeGamma1(buf[32:]) + sig.z.UnpackLeGamma1(buf[CTildeSize:]) if sig.z.Exceeds(Gamma1 - Beta) { return false } - if !sig.hint.UnpackHint(buf[32+L*PolyLeGamma1Size:]) { + if !sig.hint.UnpackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) { return false } return true @@ -115,7 +115,7 @@ func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { pk.A.Derive(&pk.rho) // tr = CRH(ρ ‖ t1) = CRH(pk) - pk.tr = new([32]byte) + pk.tr = new([TRSize]byte) h := sha3.NewShake256() _, _ = h.Write(buf[:]) _, _ = h.Read(pk.tr[:]) @@ -125,8 +125,8 @@ func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { copy(buf[:32], sk.rho[:]) copy(buf[32:64], sk.key[:]) - copy(buf[64:96], sk.tr[:]) - offset := 96 + copy(buf[64:64+TRSize], sk.tr[:]) + offset := 64 + TRSize sk.s1.PackLeqEta(buf[offset:]) offset += PolyLeqEtaSize * L sk.s2.PackLeqEta(buf[offset:]) @@ -138,8 +138,8 @@ func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { copy(sk.rho[:], buf[:32]) copy(sk.key[:], buf[32:64]) - copy(sk.tr[:], buf[64:96]) - offset := 96 + copy(sk.tr[:], buf[64:64+TRSize]) + offset := 64 + TRSize sk.s1.UnpackLeqEta(buf[offset:]) offset += PolyLeqEtaSize * L sk.s2.UnpackLeqEta(buf[offset:]) @@ -180,6 +180,11 @@ func NewKeyFromSeed(seed *[common.SeedSize]byte) (*PublicKey, *PrivateKey) { h := sha3.NewShake256() _, _ = h.Write(seed[:]) + + if NIST { + _, _ = h.Write([]byte{byte(K), byte(L)}) + } + _, _ = h.Read(eSeed[:]) copy(pk.rho[:], eSeed[:32]) @@ -244,13 +249,16 @@ 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 var Az, Az2dct1, w1 VecK var ch common.Poly - var cp [32]byte + var cp [CTildeSize]byte var w1Packed [PolyW1Size * K]byte // Note that Unpack() checked whether ‖z‖_∞ < γ₁ - β @@ -262,7 +270,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 +287,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) + PolyDeriveUniformBall(&ch, sig.c[:]) ch.NTT() for i := 0; i < K; i++ { Az2dct1[i].MulHat(&Az2dct1[i], &ch) @@ -307,8 +315,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,12 +335,15 @@ 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 { + _, _ = h.Write(rnd[:]) + } _, _ = h.Write(mu[:]) _, _ = h.Read(rhop[:]) @@ -368,7 +382,7 @@ func SignTo(sk *PrivateKey, msg []byte, signature []byte) { _, _ = h.Write(w1Packed[:]) _, _ = h.Read(sig.c[:]) - PolyDeriveUniformBall(&ch, &sig.c) + 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 ca347a831..47f53d3a0 100644 --- a/sign/dilithium/mode2/internal/dilithium_test.go +++ b/sign/dilithium/mode2/internal/dilithium_test.go @@ -4,9 +4,10 @@ package internal import ( "encoding/binary" + "io" "testing" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // Checks whether p is normalized. Only used in tests. @@ -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/mat.go b/sign/dilithium/mode2/internal/mat.go index cb473c149..ceaf634fa 100644 --- a/sign/dilithium/mode2/internal/mat.go +++ b/sign/dilithium/mode2/internal/mat.go @@ -3,7 +3,7 @@ package internal import ( - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // A k by l matrix of polynomials. diff --git a/sign/dilithium/mode2/internal/pack.go b/sign/dilithium/mode2/internal/pack.go index 0285dfd8e..1854b4197 100644 --- a/sign/dilithium/mode2/internal/pack.go +++ b/sign/dilithium/mode2/internal/pack.go @@ -3,7 +3,7 @@ package internal import ( - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // Writes p with norm less than or equal η into buf, which must be of diff --git a/sign/dilithium/mode2/internal/pack_test.go b/sign/dilithium/mode2/internal/pack_test.go index 24f568e4d..f952c6a09 100644 --- a/sign/dilithium/mode2/internal/pack_test.go +++ b/sign/dilithium/mode2/internal/pack_test.go @@ -5,7 +5,7 @@ package internal import ( "testing" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) func TestPolyPackLeqEta(t *testing.T) { diff --git a/sign/dilithium/mode2/internal/params.go b/sign/dilithium/mode2/internal/params.go index b49db55b3..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 @@ -13,4 +12,7 @@ const ( Tau = 39 Gamma1Bits = 17 Gamma2 = 95232 + NIST = false + TRSize = 32 + CTildeSize = 32 ) diff --git a/sign/dilithium/mode2/internal/params_test.go b/sign/dilithium/mode2/internal/params_test.go index 6dbc04cb8..f1f1715b7 100644 --- a/sign/dilithium/mode2/internal/params_test.go +++ b/sign/dilithium/mode2/internal/params_test.go @@ -3,7 +3,7 @@ package internal import ( "testing" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // Tests specific to the current mode diff --git a/sign/dilithium/mode2/internal/rounding.go b/sign/dilithium/mode2/internal/rounding.go index 71360cb29..58123c090 100644 --- a/sign/dilithium/mode2/internal/rounding.go +++ b/sign/dilithium/mode2/internal/rounding.go @@ -3,7 +3,7 @@ package internal import ( - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // Splits 0 ≤ a < q into a₀ and a₁ with a = a₁*α + a₀ with -α/2 < a₀ ≤ α/2, diff --git a/sign/dilithium/mode2/internal/rounding_test.go b/sign/dilithium/mode2/internal/rounding_test.go index 5824f2656..ad653ca3f 100644 --- a/sign/dilithium/mode2/internal/rounding_test.go +++ b/sign/dilithium/mode2/internal/rounding_test.go @@ -6,7 +6,7 @@ import ( "flag" "testing" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) var runVeryLongTest = flag.Bool("very-long", false, "runs very long tests") diff --git a/sign/dilithium/mode2/internal/sample.go b/sign/dilithium/mode2/internal/sample.go index c47185ada..b37370a4e 100644 --- a/sign/dilithium/mode2/internal/sample.go +++ b/sign/dilithium/mode2/internal/sample.go @@ -6,13 +6,13 @@ import ( "encoding/binary" "github.com/cloudflare/circl/internal/sha3" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + 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 +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[:]) } @@ -246,12 +215,12 @@ func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { // Can only be called when DeriveX4Available is true. // // This function is currently not used (yet). -func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed *[32]byte) { +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 < 4; 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 *[32]byte) { // SHAKE256 domain separator and padding for j := 0; j < 4; j++ { - state[4*4+j] ^= 0x1f + state[(CTildeSize/8)*4+j] ^= 0x1f state[16*4+j] ^= 0x80 << 56 } perm.Permute() @@ -327,7 +296,7 @@ func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed *[32]byte) { // Samples p uniformly with τ non-zero coefficients in {q-1,1}. // // The polynomial p will be normalized. -func PolyDeriveUniformBall(p *common.Poly, seed *[32]byte) { +func PolyDeriveUniformBall(p *common.Poly, seed []byte) { var buf [136]byte // SHAKE-256 rate is 136 h := sha3.NewShake256() diff --git a/sign/dilithium/mode2/internal/sample_test.go b/sign/dilithium/mode2/internal/sample_test.go index 1a0a4f72c..32931c94f 100644 --- a/sign/dilithium/mode2/internal/sample_test.go +++ b/sign/dilithium/mode2/internal/sample_test.go @@ -6,100 +6,52 @@ import ( "encoding/binary" "testing" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + 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, - } + 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,10 +104,10 @@ 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) + PolyDeriveUniformBall(&p, seed[:]) nonzero := 0 for j := 0; j < common.N; j++ { if p[j] != 0 { @@ -200,13 +152,13 @@ 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, + seed[:], ) for j := 0; j < 4; j++ { - PolyDeriveUniformBall(&p, &seed) + PolyDeriveUniformBall(&p, seed[:]) if ps[j] != p { t.Fatalf("%d\n%v\n%v", j, ps[j], p) } @@ -219,7 +171,7 @@ func BenchmarkPolyDeriveUniformBall(b *testing.B) { var w1 VecK for i := 0; i < b.N; i++ { w1[0][0] = uint32(i) - PolyDeriveUniformBall(&p, &seed) + PolyDeriveUniformBall(&p, seed[:]) } } @@ -231,7 +183,7 @@ func BenchmarkPolyDeriveUniformBallX4(b *testing.B) { w1[0][0] = uint32(i) PolyDeriveUniformBallX4( [4]*common.Poly{&p, &p, &p, &p}, - &seed, + seed[:], ) } } diff --git a/sign/dilithium/mode2/internal/vec.go b/sign/dilithium/mode2/internal/vec.go index f52973e45..d07d3b245 100644 --- a/sign/dilithium/mode2/internal/vec.go +++ b/sign/dilithium/mode2/internal/vec.go @@ -3,7 +3,7 @@ package internal import ( - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // A vector of L polynomials. diff --git a/sign/dilithium/mode2aes.go b/sign/dilithium/mode2aes.go deleted file mode 100644 index e3c996d92..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/internal/common" - "github.com/cloudflare/circl/sign/dilithium/mode2aes" -) - -// 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 public 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/internal/params_test.go b/sign/dilithium/mode2aes/internal/params_test.go deleted file mode 100644 index 50665d6a9..000000000 --- a/sign/dilithium/mode2aes/internal/params_test.go +++ /dev/null @@ -1,99 +0,0 @@ -package internal - -import ( - "testing" - - "github.com/cloudflare/circl/sign/dilithium/internal/common" -) - -// 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/sample_test.go b/sign/dilithium/mode2aes/internal/sample_test.go deleted file mode 100644 index 1a0a4f72c..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" - - "github.com/cloudflare/circl/sign/dilithium/internal/common" -) - -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/mode3.go b/sign/dilithium/mode3.go deleted file mode 100644 index fb45a29c2..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/internal/common" - "github.com/cloudflare/circl/sign/dilithium/mode3" -) - -// 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 public 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 3ab9d6b53..2e93e9c50 100644 --- a/sign/dilithium/mode3/dilithium.go +++ b/sign/dilithium/mode3/dilithium.go @@ -1,4 +1,4 @@ -// 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 @@ -11,8 +11,9 @@ import ( "errors" "io" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + "github.com/cloudflare/circl/sign" "github.com/cloudflare/circl/sign/dilithium/mode3/internal" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) const ( @@ -50,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, ) } @@ -143,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. @@ -179,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 59e43cc13..0f9b76dae 100644 --- a/sign/dilithium/mode3/internal/dilithium.go +++ b/sign/dilithium/mode3/internal/dilithium.go @@ -6,7 +6,7 @@ import ( "io" "github.com/cloudflare/circl/internal/sha3" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) const ( @@ -27,13 +27,13 @@ const ( Alpha = 2 * Gamma2 // Size of a packed private key - PrivateKeySize = 32 + 32 + 32 + PolyLeqEtaSize*(L+K) + common.PolyT0Size*K + 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 + 32 + SignatureSize = L*PolyLeGamma1Size + Omega + K + CTildeSize // Size of packed w₁ PolyW1Size = (common.N * (common.QBits - Gamma1Bits)) / 8 @@ -47,7 +47,7 @@ type PublicKey struct { // Cached values t1p [common.PolyT1Size * K]byte A *Mat - tr *[32]byte + tr *[TRSize]byte } // PrivateKey is the type of Dilithium private keys. @@ -57,7 +57,7 @@ type PrivateKey struct { s1 VecL s2 VecK t0 VecK - tr [32]byte + tr [TRSize]byte // Cached values A Mat // ExpandA(ρ) @@ -69,14 +69,14 @@ type PrivateKey struct { type unpackedSignature struct { z VecL hint VecK - c [32]byte + c [CTildeSize]byte } // Packs the signature into buf. func (sig *unpackedSignature) Pack(buf []byte) { copy(buf[:], sig.c[:]) - sig.z.PackLeGamma1(buf[32:]) - sig.hint.PackHint(buf[32+L*PolyLeGamma1Size:]) + sig.z.PackLeGamma1(buf[CTildeSize:]) + sig.hint.PackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) } // Sets sig to the signature encoded in the buffer. @@ -87,11 +87,11 @@ func (sig *unpackedSignature) Unpack(buf []byte) bool { return false } copy(sig.c[:], buf[:]) - sig.z.UnpackLeGamma1(buf[32:]) + sig.z.UnpackLeGamma1(buf[CTildeSize:]) if sig.z.Exceeds(Gamma1 - Beta) { return false } - if !sig.hint.UnpackHint(buf[32+L*PolyLeGamma1Size:]) { + if !sig.hint.UnpackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) { return false } return true @@ -113,7 +113,7 @@ func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { pk.A.Derive(&pk.rho) // tr = CRH(ρ ‖ t1) = CRH(pk) - pk.tr = new([32]byte) + pk.tr = new([TRSize]byte) h := sha3.NewShake256() _, _ = h.Write(buf[:]) _, _ = h.Read(pk.tr[:]) @@ -123,8 +123,8 @@ func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { copy(buf[:32], sk.rho[:]) copy(buf[32:64], sk.key[:]) - copy(buf[64:96], sk.tr[:]) - offset := 96 + copy(buf[64:64+TRSize], sk.tr[:]) + offset := 64 + TRSize sk.s1.PackLeqEta(buf[offset:]) offset += PolyLeqEtaSize * L sk.s2.PackLeqEta(buf[offset:]) @@ -136,8 +136,8 @@ func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { copy(sk.rho[:], buf[:32]) copy(sk.key[:], buf[32:64]) - copy(sk.tr[:], buf[64:96]) - offset := 96 + copy(sk.tr[:], buf[64:64+TRSize]) + offset := 64 + TRSize sk.s1.UnpackLeqEta(buf[offset:]) offset += PolyLeqEtaSize * L sk.s2.UnpackLeqEta(buf[offset:]) @@ -178,6 +178,11 @@ func NewKeyFromSeed(seed *[common.SeedSize]byte) (*PublicKey, *PrivateKey) { h := sha3.NewShake256() _, _ = h.Write(seed[:]) + + if NIST { + _, _ = h.Write([]byte{byte(K), byte(L)}) + } + _, _ = h.Read(eSeed[:]) copy(pk.rho[:], eSeed[:32]) @@ -242,13 +247,16 @@ 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 var Az, Az2dct1, w1 VecK var ch common.Poly - var cp [32]byte + var cp [CTildeSize]byte var w1Packed [PolyW1Size * K]byte // Note that Unpack() checked whether ‖z‖_∞ < γ₁ - β @@ -260,7 +268,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 +285,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) + PolyDeriveUniformBall(&ch, sig.c[:]) ch.NTT() for i := 0; i < K; i++ { Az2dct1[i].MulHat(&Az2dct1[i], &ch) @@ -305,8 +313,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,12 +333,15 @@ 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 { + _, _ = h.Write(rnd[:]) + } _, _ = h.Write(mu[:]) _, _ = h.Read(rhop[:]) @@ -366,7 +380,7 @@ func SignTo(sk *PrivateKey, msg []byte, signature []byte) { _, _ = h.Write(w1Packed[:]) _, _ = h.Read(sig.c[:]) - PolyDeriveUniformBall(&ch, &sig.c) + 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 05320495d..a3f1126dd 100644 --- a/sign/dilithium/mode3/internal/dilithium_test.go +++ b/sign/dilithium/mode3/internal/dilithium_test.go @@ -2,9 +2,10 @@ package internal import ( "encoding/binary" + "io" "testing" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // Checks whether p is normalized. Only used in tests. @@ -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/mat.go b/sign/dilithium/mode3/internal/mat.go index ce39b7f9a..3d6cc47b2 100644 --- a/sign/dilithium/mode3/internal/mat.go +++ b/sign/dilithium/mode3/internal/mat.go @@ -1,7 +1,7 @@ package internal import ( - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // A k by l matrix of polynomials. diff --git a/sign/dilithium/mode3/internal/pack.go b/sign/dilithium/mode3/internal/pack.go index 6a152d73e..d9c80d0e1 100644 --- a/sign/dilithium/mode3/internal/pack.go +++ b/sign/dilithium/mode3/internal/pack.go @@ -1,7 +1,7 @@ package internal import ( - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // Writes p with norm less than or equal η into buf, which must be of diff --git a/sign/dilithium/mode3/internal/pack_test.go b/sign/dilithium/mode3/internal/pack_test.go index 1b6b2a613..d8143c810 100644 --- a/sign/dilithium/mode3/internal/pack_test.go +++ b/sign/dilithium/mode3/internal/pack_test.go @@ -3,7 +3,7 @@ package internal import ( "testing" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) func TestPolyPackLeqEta(t *testing.T) { diff --git a/sign/dilithium/mode3/internal/params.go b/sign/dilithium/mode3/internal/params.go index c22925234..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 @@ -13,4 +12,7 @@ const ( Tau = 49 Gamma1Bits = 19 Gamma2 = 261888 + NIST = false + TRSize = 32 + CTildeSize = 32 ) diff --git a/sign/dilithium/mode3/internal/params_test.go b/sign/dilithium/mode3/internal/params_test.go index 43d91c3f4..f1c93e297 100644 --- a/sign/dilithium/mode3/internal/params_test.go +++ b/sign/dilithium/mode3/internal/params_test.go @@ -3,7 +3,7 @@ package internal import ( "testing" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // Tests specific to the current mode diff --git a/sign/dilithium/mode3/internal/rounding.go b/sign/dilithium/mode3/internal/rounding.go index f44c951d2..4005e569c 100644 --- a/sign/dilithium/mode3/internal/rounding.go +++ b/sign/dilithium/mode3/internal/rounding.go @@ -1,7 +1,7 @@ package internal import ( - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // Splits 0 ≤ a < q into a₀ and a₁ with a = a₁*α + a₀ with -α/2 < a₀ ≤ α/2, diff --git a/sign/dilithium/mode3/internal/rounding_test.go b/sign/dilithium/mode3/internal/rounding_test.go index 387815592..8d2310cb2 100644 --- a/sign/dilithium/mode3/internal/rounding_test.go +++ b/sign/dilithium/mode3/internal/rounding_test.go @@ -4,7 +4,7 @@ import ( "flag" "testing" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) var runVeryLongTest = flag.Bool("very-long", false, "runs very long tests") diff --git a/sign/dilithium/mode3/internal/sample.go b/sign/dilithium/mode3/internal/sample.go index 256ec731f..f90d211d8 100644 --- a/sign/dilithium/mode3/internal/sample.go +++ b/sign/dilithium/mode3/internal/sample.go @@ -4,13 +4,13 @@ import ( "encoding/binary" "github.com/cloudflare/circl/internal/sha3" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + 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 +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[:]) } @@ -244,12 +213,12 @@ func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { // Can only be called when DeriveX4Available is true. // // This function is currently not used (yet). -func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed *[32]byte) { +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 < 4; 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 *[32]byte) { // SHAKE256 domain separator and padding for j := 0; j < 4; j++ { - state[4*4+j] ^= 0x1f + state[(CTildeSize/8)*4+j] ^= 0x1f state[16*4+j] ^= 0x80 << 56 } perm.Permute() @@ -325,7 +294,7 @@ func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed *[32]byte) { // Samples p uniformly with τ non-zero coefficients in {q-1,1}. // // The polynomial p will be normalized. -func PolyDeriveUniformBall(p *common.Poly, seed *[32]byte) { +func PolyDeriveUniformBall(p *common.Poly, seed []byte) { var buf [136]byte // SHAKE-256 rate is 136 h := sha3.NewShake256() diff --git a/sign/dilithium/mode3/internal/sample_test.go b/sign/dilithium/mode3/internal/sample_test.go index bae9d4055..69e56d31a 100644 --- a/sign/dilithium/mode3/internal/sample_test.go +++ b/sign/dilithium/mode3/internal/sample_test.go @@ -4,100 +4,52 @@ import ( "encoding/binary" "testing" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + 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, - } + 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,10 +102,10 @@ 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) + PolyDeriveUniformBall(&p, seed[:]) nonzero := 0 for j := 0; j < common.N; j++ { if p[j] != 0 { @@ -198,13 +150,13 @@ 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, + seed[:], ) for j := 0; j < 4; j++ { - PolyDeriveUniformBall(&p, &seed) + PolyDeriveUniformBall(&p, seed[:]) if ps[j] != p { t.Fatalf("%d\n%v\n%v", j, ps[j], p) } @@ -217,7 +169,7 @@ func BenchmarkPolyDeriveUniformBall(b *testing.B) { var w1 VecK for i := 0; i < b.N; i++ { w1[0][0] = uint32(i) - PolyDeriveUniformBall(&p, &seed) + PolyDeriveUniformBall(&p, seed[:]) } } @@ -229,7 +181,7 @@ func BenchmarkPolyDeriveUniformBallX4(b *testing.B) { w1[0][0] = uint32(i) PolyDeriveUniformBallX4( [4]*common.Poly{&p, &p, &p, &p}, - &seed, + seed[:], ) } } diff --git a/sign/dilithium/mode3/internal/vec.go b/sign/dilithium/mode3/internal/vec.go index 1a5fe4ca5..5817acb7f 100644 --- a/sign/dilithium/mode3/internal/vec.go +++ b/sign/dilithium/mode3/internal/vec.go @@ -1,7 +1,7 @@ package internal import ( - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // A vector of L polynomials. diff --git a/sign/dilithium/mode3aes.go b/sign/dilithium/mode3aes.go deleted file mode 100644 index c4cca1863..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/internal/common" - "github.com/cloudflare/circl/sign/dilithium/mode3aes" -) - -// 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 public 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/internal/params_test.go b/sign/dilithium/mode3aes/internal/params_test.go deleted file mode 100644 index fc246ce73..000000000 --- a/sign/dilithium/mode3aes/internal/params_test.go +++ /dev/null @@ -1,101 +0,0 @@ -package internal - -import ( - "testing" - - "github.com/cloudflare/circl/sign/dilithium/internal/common" -) - -// 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/sample_test.go b/sign/dilithium/mode3aes/internal/sample_test.go deleted file mode 100644 index 1a0a4f72c..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" - - "github.com/cloudflare/circl/sign/dilithium/internal/common" -) - -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/mode5.go b/sign/dilithium/mode5.go deleted file mode 100644 index d6b7a9c73..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/internal/common" - "github.com/cloudflare/circl/sign/dilithium/mode5" -) - -// 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 public 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 3a6a0cb93..ce3ec7546 100644 --- a/sign/dilithium/mode5/dilithium.go +++ b/sign/dilithium/mode5/dilithium.go @@ -1,4 +1,4 @@ -// 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 @@ -11,8 +11,9 @@ import ( "errors" "io" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + "github.com/cloudflare/circl/sign" "github.com/cloudflare/circl/sign/dilithium/mode5/internal" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) const ( @@ -50,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, ) } @@ -143,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. @@ -179,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 79a17d504..8f1c8e5cb 100644 --- a/sign/dilithium/mode5/internal/dilithium.go +++ b/sign/dilithium/mode5/internal/dilithium.go @@ -8,7 +8,7 @@ import ( "io" "github.com/cloudflare/circl/internal/sha3" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) const ( @@ -29,13 +29,13 @@ const ( Alpha = 2 * Gamma2 // Size of a packed private key - PrivateKeySize = 32 + 32 + 32 + PolyLeqEtaSize*(L+K) + common.PolyT0Size*K + 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 + 32 + SignatureSize = L*PolyLeGamma1Size + Omega + K + CTildeSize // Size of packed w₁ PolyW1Size = (common.N * (common.QBits - Gamma1Bits)) / 8 @@ -49,7 +49,7 @@ type PublicKey struct { // Cached values t1p [common.PolyT1Size * K]byte A *Mat - tr *[32]byte + tr *[TRSize]byte } // PrivateKey is the type of Dilithium private keys. @@ -59,7 +59,7 @@ type PrivateKey struct { s1 VecL s2 VecK t0 VecK - tr [32]byte + tr [TRSize]byte // Cached values A Mat // ExpandA(ρ) @@ -71,14 +71,14 @@ type PrivateKey struct { type unpackedSignature struct { z VecL hint VecK - c [32]byte + c [CTildeSize]byte } // Packs the signature into buf. func (sig *unpackedSignature) Pack(buf []byte) { copy(buf[:], sig.c[:]) - sig.z.PackLeGamma1(buf[32:]) - sig.hint.PackHint(buf[32+L*PolyLeGamma1Size:]) + sig.z.PackLeGamma1(buf[CTildeSize:]) + sig.hint.PackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) } // Sets sig to the signature encoded in the buffer. @@ -89,11 +89,11 @@ func (sig *unpackedSignature) Unpack(buf []byte) bool { return false } copy(sig.c[:], buf[:]) - sig.z.UnpackLeGamma1(buf[32:]) + sig.z.UnpackLeGamma1(buf[CTildeSize:]) if sig.z.Exceeds(Gamma1 - Beta) { return false } - if !sig.hint.UnpackHint(buf[32+L*PolyLeGamma1Size:]) { + if !sig.hint.UnpackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) { return false } return true @@ -115,7 +115,7 @@ func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { pk.A.Derive(&pk.rho) // tr = CRH(ρ ‖ t1) = CRH(pk) - pk.tr = new([32]byte) + pk.tr = new([TRSize]byte) h := sha3.NewShake256() _, _ = h.Write(buf[:]) _, _ = h.Read(pk.tr[:]) @@ -125,8 +125,8 @@ func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { copy(buf[:32], sk.rho[:]) copy(buf[32:64], sk.key[:]) - copy(buf[64:96], sk.tr[:]) - offset := 96 + copy(buf[64:64+TRSize], sk.tr[:]) + offset := 64 + TRSize sk.s1.PackLeqEta(buf[offset:]) offset += PolyLeqEtaSize * L sk.s2.PackLeqEta(buf[offset:]) @@ -138,8 +138,8 @@ func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { copy(sk.rho[:], buf[:32]) copy(sk.key[:], buf[32:64]) - copy(sk.tr[:], buf[64:96]) - offset := 96 + copy(sk.tr[:], buf[64:64+TRSize]) + offset := 64 + TRSize sk.s1.UnpackLeqEta(buf[offset:]) offset += PolyLeqEtaSize * L sk.s2.UnpackLeqEta(buf[offset:]) @@ -180,6 +180,11 @@ func NewKeyFromSeed(seed *[common.SeedSize]byte) (*PublicKey, *PrivateKey) { h := sha3.NewShake256() _, _ = h.Write(seed[:]) + + if NIST { + _, _ = h.Write([]byte{byte(K), byte(L)}) + } + _, _ = h.Read(eSeed[:]) copy(pk.rho[:], eSeed[:32]) @@ -244,13 +249,16 @@ 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 var Az, Az2dct1, w1 VecK var ch common.Poly - var cp [32]byte + var cp [CTildeSize]byte var w1Packed [PolyW1Size * K]byte // Note that Unpack() checked whether ‖z‖_∞ < γ₁ - β @@ -262,7 +270,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 +287,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) + PolyDeriveUniformBall(&ch, sig.c[:]) ch.NTT() for i := 0; i < K; i++ { Az2dct1[i].MulHat(&Az2dct1[i], &ch) @@ -307,8 +315,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,12 +335,15 @@ 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 { + _, _ = h.Write(rnd[:]) + } _, _ = h.Write(mu[:]) _, _ = h.Read(rhop[:]) @@ -368,7 +382,7 @@ func SignTo(sk *PrivateKey, msg []byte, signature []byte) { _, _ = h.Write(w1Packed[:]) _, _ = h.Read(sig.c[:]) - PolyDeriveUniformBall(&ch, &sig.c) + 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 ca347a831..47f53d3a0 100644 --- a/sign/dilithium/mode5/internal/dilithium_test.go +++ b/sign/dilithium/mode5/internal/dilithium_test.go @@ -4,9 +4,10 @@ package internal import ( "encoding/binary" + "io" "testing" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // Checks whether p is normalized. Only used in tests. @@ -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/mat.go b/sign/dilithium/mode5/internal/mat.go index cb473c149..ceaf634fa 100644 --- a/sign/dilithium/mode5/internal/mat.go +++ b/sign/dilithium/mode5/internal/mat.go @@ -3,7 +3,7 @@ package internal import ( - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // A k by l matrix of polynomials. diff --git a/sign/dilithium/mode5/internal/pack.go b/sign/dilithium/mode5/internal/pack.go index 0285dfd8e..1854b4197 100644 --- a/sign/dilithium/mode5/internal/pack.go +++ b/sign/dilithium/mode5/internal/pack.go @@ -3,7 +3,7 @@ package internal import ( - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // Writes p with norm less than or equal η into buf, which must be of diff --git a/sign/dilithium/mode5/internal/pack_test.go b/sign/dilithium/mode5/internal/pack_test.go index 24f568e4d..f952c6a09 100644 --- a/sign/dilithium/mode5/internal/pack_test.go +++ b/sign/dilithium/mode5/internal/pack_test.go @@ -5,7 +5,7 @@ package internal import ( "testing" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) func TestPolyPackLeqEta(t *testing.T) { diff --git a/sign/dilithium/mode5/internal/params.go b/sign/dilithium/mode5/internal/params.go index bad43e320..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 @@ -13,4 +12,7 @@ const ( Tau = 60 Gamma1Bits = 19 Gamma2 = 261888 + NIST = false + TRSize = 32 + CTildeSize = 32 ) diff --git a/sign/dilithium/mode5/internal/params_test.go b/sign/dilithium/mode5/internal/params_test.go index daabe6969..ac891117e 100644 --- a/sign/dilithium/mode5/internal/params_test.go +++ b/sign/dilithium/mode5/internal/params_test.go @@ -3,7 +3,7 @@ package internal import ( "testing" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // Tests specific to the current mode diff --git a/sign/dilithium/mode5/internal/rounding.go b/sign/dilithium/mode5/internal/rounding.go index 71360cb29..58123c090 100644 --- a/sign/dilithium/mode5/internal/rounding.go +++ b/sign/dilithium/mode5/internal/rounding.go @@ -3,7 +3,7 @@ package internal import ( - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // Splits 0 ≤ a < q into a₀ and a₁ with a = a₁*α + a₀ with -α/2 < a₀ ≤ α/2, diff --git a/sign/dilithium/mode5/internal/rounding_test.go b/sign/dilithium/mode5/internal/rounding_test.go index 5824f2656..ad653ca3f 100644 --- a/sign/dilithium/mode5/internal/rounding_test.go +++ b/sign/dilithium/mode5/internal/rounding_test.go @@ -6,7 +6,7 @@ import ( "flag" "testing" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) var runVeryLongTest = flag.Bool("very-long", false, "runs very long tests") diff --git a/sign/dilithium/mode5/internal/sample.go b/sign/dilithium/mode5/internal/sample.go index c47185ada..b37370a4e 100644 --- a/sign/dilithium/mode5/internal/sample.go +++ b/sign/dilithium/mode5/internal/sample.go @@ -6,13 +6,13 @@ import ( "encoding/binary" "github.com/cloudflare/circl/internal/sha3" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + 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 +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[:]) } @@ -246,12 +215,12 @@ func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { // Can only be called when DeriveX4Available is true. // // This function is currently not used (yet). -func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed *[32]byte) { +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 < 4; 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 *[32]byte) { // SHAKE256 domain separator and padding for j := 0; j < 4; j++ { - state[4*4+j] ^= 0x1f + state[(CTildeSize/8)*4+j] ^= 0x1f state[16*4+j] ^= 0x80 << 56 } perm.Permute() @@ -327,7 +296,7 @@ func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed *[32]byte) { // Samples p uniformly with τ non-zero coefficients in {q-1,1}. // // The polynomial p will be normalized. -func PolyDeriveUniformBall(p *common.Poly, seed *[32]byte) { +func PolyDeriveUniformBall(p *common.Poly, seed []byte) { var buf [136]byte // SHAKE-256 rate is 136 h := sha3.NewShake256() diff --git a/sign/dilithium/mode5/internal/sample_test.go b/sign/dilithium/mode5/internal/sample_test.go index 1a0a4f72c..32931c94f 100644 --- a/sign/dilithium/mode5/internal/sample_test.go +++ b/sign/dilithium/mode5/internal/sample_test.go @@ -6,100 +6,52 @@ import ( "encoding/binary" "testing" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + 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, - } + 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,10 +104,10 @@ 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) + PolyDeriveUniformBall(&p, seed[:]) nonzero := 0 for j := 0; j < common.N; j++ { if p[j] != 0 { @@ -200,13 +152,13 @@ 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, + seed[:], ) for j := 0; j < 4; j++ { - PolyDeriveUniformBall(&p, &seed) + PolyDeriveUniformBall(&p, seed[:]) if ps[j] != p { t.Fatalf("%d\n%v\n%v", j, ps[j], p) } @@ -219,7 +171,7 @@ func BenchmarkPolyDeriveUniformBall(b *testing.B) { var w1 VecK for i := 0; i < b.N; i++ { w1[0][0] = uint32(i) - PolyDeriveUniformBall(&p, &seed) + PolyDeriveUniformBall(&p, seed[:]) } } @@ -231,7 +183,7 @@ func BenchmarkPolyDeriveUniformBallX4(b *testing.B) { w1[0][0] = uint32(i) PolyDeriveUniformBallX4( [4]*common.Poly{&p, &p, &p, &p}, - &seed, + seed[:], ) } } diff --git a/sign/dilithium/mode5/internal/vec.go b/sign/dilithium/mode5/internal/vec.go index f52973e45..d07d3b245 100644 --- a/sign/dilithium/mode5/internal/vec.go +++ b/sign/dilithium/mode5/internal/vec.go @@ -3,7 +3,7 @@ package internal import ( - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // A vector of L polynomials. diff --git a/sign/dilithium/mode5aes.go b/sign/dilithium/mode5aes.go deleted file mode 100644 index 258b8a825..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/internal/common" - "github.com/cloudflare/circl/sign/dilithium/mode5aes" -) - -// 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 public 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/internal/params_test.go b/sign/dilithium/mode5aes/internal/params_test.go deleted file mode 100644 index a5e746f68..000000000 --- a/sign/dilithium/mode5aes/internal/params_test.go +++ /dev/null @@ -1,100 +0,0 @@ -package internal - -import ( - "testing" - - "github.com/cloudflare/circl/sign/dilithium/internal/common" -) - -// 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/sample_test.go b/sign/dilithium/mode5aes/internal/sample_test.go deleted file mode 100644 index 1a0a4f72c..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" - - "github.com/cloudflare/circl/sign/dilithium/internal/common" -) - -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/templates/mode.templ.go b/sign/dilithium/templates/mode.templ.go deleted file mode 100644 index 8c76b2512..000000000 --- a/sign/dilithium/templates/mode.templ.go +++ /dev/null @@ -1,94 +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" - - "github.com/cloudflare/circl/sign/dilithium/internal/common" - "github.com/cloudflare/circl/sign/dilithium/{{.Pkg}}" -) - -// {{.Impl}} implements the mode.Mode interface for {{.Name}}. -type {{.Impl}} struct{} - -// {{.Mode}} is Dilithium in mode "{{.Name}}". -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 public 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 1e0331c25..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}} @@ -17,4 +16,7 @@ const ( Tau = {{.Tau}} Gamma1Bits = {{.Gamma1Bits}} Gamma2 = {{.Gamma2}} + NIST = {{.NIST}} + TRSize = {{.TRSize}} + CTildeSize = {{.CTildeSize}} ) diff --git a/sign/dilithium/templates/modePkg.templ.go b/sign/dilithium/templates/pkg.templ.go similarity index 50% rename from sign/dilithium/templates/modePkg.templ.go rename to sign/dilithium/templates/pkg.templ.go index 29dc73556..4ad538565 100644 --- a/sign/dilithium/templates/modePkg.templ.go +++ b/sign/dilithium/templates/pkg.templ.go @@ -2,12 +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 }} // {{.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 }} package {{.Pkg}} import ( @@ -15,8 +19,18 @@ import ( "errors" "io" - "github.com/cloudflare/circl/sign/dilithium/internal/common" +{{- if .NIST }} + cryptoRand "crypto/rand" +{{- end }} + + "github.com/cloudflare/circl/sign" + +{{- if .NIST }} + "github.com/cloudflare/circl/sign/mldsa/{{.Pkg}}/internal" +{{- else }} "github.com/cloudflare/circl/sign/dilithium/{{.Pkg}}/internal" +{{- end }} + common "github.com/cloudflare/circl/sign/internal/dilithium" ) const ( @@ -54,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, ) } @@ -147,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. @@ -183,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/dilithium/internal/common/aes.go b/sign/internal/dilithium/aes.go similarity index 98% rename from sign/dilithium/internal/common/aes.go rename to sign/internal/dilithium/aes.go index f5de25425..895a20597 100644 --- a/sign/dilithium/internal/common/aes.go +++ b/sign/internal/dilithium/aes.go @@ -1,4 +1,4 @@ -package common +package dilithium import ( "crypto/aes" diff --git a/sign/dilithium/internal/common/amd64.go b/sign/internal/dilithium/amd64.go similarity index 99% rename from sign/dilithium/internal/common/amd64.go rename to sign/internal/dilithium/amd64.go index 11f0e3dcf..d5d224ee8 100644 --- a/sign/dilithium/internal/common/amd64.go +++ b/sign/internal/dilithium/amd64.go @@ -1,7 +1,7 @@ //go:build amd64 && !purego // +build amd64,!purego -package common +package dilithium import ( "golang.org/x/sys/cpu" diff --git a/sign/dilithium/internal/common/amd64.s b/sign/internal/dilithium/amd64.s similarity index 100% rename from sign/dilithium/internal/common/amd64.s rename to sign/internal/dilithium/amd64.s diff --git a/sign/dilithium/internal/common/asm/go.mod b/sign/internal/dilithium/asm/go.mod similarity index 59% rename from sign/dilithium/internal/common/asm/go.mod rename to sign/internal/dilithium/asm/go.mod index 5638957e6..41948fce3 100644 --- a/sign/dilithium/internal/common/asm/go.mod +++ b/sign/internal/dilithium/asm/go.mod @@ -1,4 +1,4 @@ -module github.com/cloudflare/circl/sign/dilithium/internal/common/asm +module github.com/cloudflare/circl/sign/internal/dilithium/asm go 1.21 @@ -12,4 +12,4 @@ require ( golang.org/x/tools v0.17.0 // indirect ) -replace github.com/cloudflare/circl => ../../../../../ +replace github.com/cloudflare/circl => ../../../../ diff --git a/sign/dilithium/internal/common/asm/go.sum b/sign/internal/dilithium/asm/go.sum similarity index 100% rename from sign/dilithium/internal/common/asm/go.sum rename to sign/internal/dilithium/asm/go.sum diff --git a/sign/dilithium/internal/common/asm/src.go b/sign/internal/dilithium/asm/src.go similarity index 99% rename from sign/dilithium/internal/common/asm/src.go rename to sign/internal/dilithium/asm/src.go index ef5f9b7de..31a171a5a 100644 --- a/sign/dilithium/internal/common/asm/src.go +++ b/sign/internal/dilithium/asm/src.go @@ -1,4 +1,4 @@ -//go:generate go run src.go -out ../amd64.s -stubs ../stubs_amd64.go -pkg common +//go:generate go run src.go -out ../amd64.s -stubs ../stubs_amd64.go -pkg dilithium // AVX2 optimized version of Poly.[Inv]NTT(). See the comments on the generic // implementation for details on the maths involved. @@ -9,7 +9,7 @@ import ( . "github.com/mmcloughlin/avo/operand" // nolint:golint,stylecheck . "github.com/mmcloughlin/avo/reg" // nolint:golint,stylecheck - "github.com/cloudflare/circl/sign/dilithium/internal/common/params" + "github.com/cloudflare/circl/sign/internal/dilithium/params" ) // XXX align Poly on 16 bytes such that we can use aligned moves diff --git a/sign/dilithium/internal/common/field.go b/sign/internal/dilithium/field.go similarity index 98% rename from sign/dilithium/internal/common/field.go rename to sign/internal/dilithium/field.go index 2aab16ecb..c2fc6ca72 100644 --- a/sign/dilithium/internal/common/field.go +++ b/sign/internal/dilithium/field.go @@ -1,4 +1,4 @@ -package common +package dilithium // Returns a y with y < 2q and y = x mod q. // Note that in general *not*: ReduceLe2Q(ReduceLe2Q(x)) == x. diff --git a/sign/dilithium/internal/common/field_test.go b/sign/internal/dilithium/field_test.go similarity index 98% rename from sign/dilithium/internal/common/field_test.go rename to sign/internal/dilithium/field_test.go index f9864eabe..85db87960 100644 --- a/sign/dilithium/internal/common/field_test.go +++ b/sign/internal/dilithium/field_test.go @@ -1,4 +1,4 @@ -package common +package dilithium import ( "crypto/rand" diff --git a/sign/dilithium/internal/common/generic.go b/sign/internal/dilithium/generic.go similarity index 99% rename from sign/dilithium/internal/common/generic.go rename to sign/internal/dilithium/generic.go index 2736e1617..25321f5d5 100644 --- a/sign/dilithium/internal/common/generic.go +++ b/sign/internal/dilithium/generic.go @@ -1,7 +1,7 @@ //go:build !amd64 || purego // +build !amd64 purego -package common +package dilithium // Execute an in-place forward NTT on as. // diff --git a/sign/dilithium/internal/common/ntt.go b/sign/internal/dilithium/ntt.go similarity index 99% rename from sign/dilithium/internal/common/ntt.go rename to sign/internal/dilithium/ntt.go index 6f5370ae0..1568ccb4b 100644 --- a/sign/dilithium/internal/common/ntt.go +++ b/sign/internal/dilithium/ntt.go @@ -1,4 +1,4 @@ -package common +package dilithium // Zetas lists precomputed powers of the root of unity in Montgomery // representation used for the NTT: diff --git a/sign/dilithium/internal/common/ntt_test.go b/sign/internal/dilithium/ntt_test.go similarity index 98% rename from sign/dilithium/internal/common/ntt_test.go rename to sign/internal/dilithium/ntt_test.go index 4524f245d..71d736a92 100644 --- a/sign/dilithium/internal/common/ntt_test.go +++ b/sign/internal/dilithium/ntt_test.go @@ -1,4 +1,4 @@ -package common +package dilithium import "testing" diff --git a/sign/dilithium/internal/common/pack.go b/sign/internal/dilithium/pack.go similarity index 99% rename from sign/dilithium/internal/common/pack.go rename to sign/internal/dilithium/pack.go index 6c366089c..4b952a004 100644 --- a/sign/dilithium/internal/common/pack.go +++ b/sign/internal/dilithium/pack.go @@ -1,4 +1,4 @@ -package common +package dilithium // Sets p to the polynomial whose coefficients are less than 1024 encoded // into buf (which must be of size PolyT1Size). diff --git a/sign/dilithium/internal/common/pack_test.go b/sign/internal/dilithium/pack_test.go similarity index 96% rename from sign/dilithium/internal/common/pack_test.go rename to sign/internal/dilithium/pack_test.go index 140d3f134..37d37ce46 100644 --- a/sign/dilithium/internal/common/pack_test.go +++ b/sign/internal/dilithium/pack_test.go @@ -1,4 +1,4 @@ -package common +package dilithium import "testing" diff --git a/sign/dilithium/internal/common/params.go b/sign/internal/dilithium/params.go similarity index 79% rename from sign/dilithium/internal/common/params.go rename to sign/internal/dilithium/params.go index 7713c6da9..f423217f0 100644 --- a/sign/dilithium/internal/common/params.go +++ b/sign/internal/dilithium/params.go @@ -1,7 +1,7 @@ -package common +package dilithium import ( - "github.com/cloudflare/circl/sign/dilithium/internal/common/params" + "github.com/cloudflare/circl/sign/internal/dilithium/params" ) const ( diff --git a/sign/dilithium/internal/common/params/params.go b/sign/internal/dilithium/params/params.go similarity index 100% rename from sign/dilithium/internal/common/params/params.go rename to sign/internal/dilithium/params/params.go diff --git a/sign/dilithium/internal/common/poly.go b/sign/internal/dilithium/poly.go similarity index 99% rename from sign/dilithium/internal/common/poly.go rename to sign/internal/dilithium/poly.go index 7ac8e57da..96c0551b3 100644 --- a/sign/dilithium/internal/common/poly.go +++ b/sign/internal/dilithium/poly.go @@ -1,4 +1,4 @@ -package common +package dilithium // An element of our base ring R which are polynomials over Z_q modulo // the equation Xᴺ = -1, where q=2²³ - 2¹³ + 1 and N=256. diff --git a/sign/dilithium/internal/common/poly_test.go b/sign/internal/dilithium/poly_test.go similarity index 99% rename from sign/dilithium/internal/common/poly_test.go rename to sign/internal/dilithium/poly_test.go index 5601aa276..42e5fc46d 100644 --- a/sign/dilithium/internal/common/poly_test.go +++ b/sign/internal/dilithium/poly_test.go @@ -1,4 +1,4 @@ -package common +package dilithium import "testing" diff --git a/sign/dilithium/internal/common/stubs_amd64.go b/sign/internal/dilithium/stubs_amd64.go similarity index 91% rename from sign/dilithium/internal/common/stubs_amd64.go rename to sign/internal/dilithium/stubs_amd64.go index 3afeda4dd..ca92f15ef 100644 --- a/sign/dilithium/internal/common/stubs_amd64.go +++ b/sign/internal/dilithium/stubs_amd64.go @@ -1,8 +1,8 @@ -// Code generated by command: go run src.go -out ../amd64.s -stubs ../stubs_amd64.go -pkg common. DO NOT EDIT. +// Code generated by command: go run src.go -out ../amd64.s -stubs ../stubs_amd64.go -pkg dilithium. DO NOT EDIT. //go:build amd64 && !purego -package common +package dilithium //go:noescape func nttAVX2(p *[256]uint32) diff --git a/sign/mldsa/doc.go b/sign/mldsa/doc.go new file mode 100644 index 000000000..d5dce5749 --- /dev/null +++ b/sign/mldsa/doc.go @@ -0,0 +1,2 @@ +// mldsa implements NIST post-quantum signature scheme ML-DSA. +package mldsa diff --git a/sign/dilithium/mode2aes/dilithium.go b/sign/mldsa/mldsa44/dilithium.go similarity index 50% rename from sign/dilithium/mode2aes/dilithium.go rename to sign/mldsa/mldsa44/dilithium.go index 0b44077bb..866f8b6ee 100644 --- a/sign/dilithium/mode2aes/dilithium.go +++ b/sign/mldsa/mldsa44/dilithium.go @@ -1,18 +1,17 @@ -// Code generated from modePkg.templ.go. DO NOT EDIT. +// Code generated from pkg.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 +// 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/dilithium/internal/common" - "github.com/cloudflare/circl/sign/dilithium/mode2aes/internal" + "github.com/cloudflare/circl/sign" + common "github.com/cloudflare/circl/sign/internal/dilithium" + "github.com/cloudflare/circl/sign/mldsa/mldsa44/internal" ) const ( @@ -29,10 +28,10 @@ const ( SignatureSize = internal.SignatureSize ) -// PublicKey is the type of Dilithium2-AES public key +// PublicKey is the type of ML-DSA-44 public key type PublicKey internal.PublicKey -// PrivateKey is the type of Dilithium2-AES private key +// PrivateKey is the type of ML-DSA-44 private key type PrivateKey internal.PrivateKey // GenerateKey generates a public/private key pair using entropy from rand. @@ -50,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, ) } @@ -114,7 +152,7 @@ func (sk *PrivateKey) MarshalBinary() ([]byte, error) { // 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") + return errors.New("packed public key must be of mldsa44.PublicKeySize bytes") } var buf [PublicKeySize]byte copy(buf[:], data) @@ -125,7 +163,7 @@ func (pk *PublicKey) UnmarshalBinary(data []byte) error { // 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") + return errors.New("packed private key must be of mldsa44.PrivateKeySize bytes") } var buf [PrivateKeySize]byte copy(buf[:], data) @@ -143,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. @@ -179,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/dilithium/mode3aes/internal/dilithium.go b/sign/mldsa/mldsa44/internal/dilithium.go similarity index 89% rename from sign/dilithium/mode3aes/internal/dilithium.go rename to sign/mldsa/mldsa44/internal/dilithium.go index 79a17d504..8f1c8e5cb 100644 --- a/sign/dilithium/mode3aes/internal/dilithium.go +++ b/sign/mldsa/mldsa44/internal/dilithium.go @@ -8,7 +8,7 @@ import ( "io" "github.com/cloudflare/circl/internal/sha3" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) const ( @@ -29,13 +29,13 @@ const ( Alpha = 2 * Gamma2 // Size of a packed private key - PrivateKeySize = 32 + 32 + 32 + PolyLeqEtaSize*(L+K) + common.PolyT0Size*K + 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 + 32 + SignatureSize = L*PolyLeGamma1Size + Omega + K + CTildeSize // Size of packed w₁ PolyW1Size = (common.N * (common.QBits - Gamma1Bits)) / 8 @@ -49,7 +49,7 @@ type PublicKey struct { // Cached values t1p [common.PolyT1Size * K]byte A *Mat - tr *[32]byte + tr *[TRSize]byte } // PrivateKey is the type of Dilithium private keys. @@ -59,7 +59,7 @@ type PrivateKey struct { s1 VecL s2 VecK t0 VecK - tr [32]byte + tr [TRSize]byte // Cached values A Mat // ExpandA(ρ) @@ -71,14 +71,14 @@ type PrivateKey struct { type unpackedSignature struct { z VecL hint VecK - c [32]byte + c [CTildeSize]byte } // Packs the signature into buf. func (sig *unpackedSignature) Pack(buf []byte) { copy(buf[:], sig.c[:]) - sig.z.PackLeGamma1(buf[32:]) - sig.hint.PackHint(buf[32+L*PolyLeGamma1Size:]) + sig.z.PackLeGamma1(buf[CTildeSize:]) + sig.hint.PackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) } // Sets sig to the signature encoded in the buffer. @@ -89,11 +89,11 @@ func (sig *unpackedSignature) Unpack(buf []byte) bool { return false } copy(sig.c[:], buf[:]) - sig.z.UnpackLeGamma1(buf[32:]) + sig.z.UnpackLeGamma1(buf[CTildeSize:]) if sig.z.Exceeds(Gamma1 - Beta) { return false } - if !sig.hint.UnpackHint(buf[32+L*PolyLeGamma1Size:]) { + if !sig.hint.UnpackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) { return false } return true @@ -115,7 +115,7 @@ func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { pk.A.Derive(&pk.rho) // tr = CRH(ρ ‖ t1) = CRH(pk) - pk.tr = new([32]byte) + pk.tr = new([TRSize]byte) h := sha3.NewShake256() _, _ = h.Write(buf[:]) _, _ = h.Read(pk.tr[:]) @@ -125,8 +125,8 @@ func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { copy(buf[:32], sk.rho[:]) copy(buf[32:64], sk.key[:]) - copy(buf[64:96], sk.tr[:]) - offset := 96 + copy(buf[64:64+TRSize], sk.tr[:]) + offset := 64 + TRSize sk.s1.PackLeqEta(buf[offset:]) offset += PolyLeqEtaSize * L sk.s2.PackLeqEta(buf[offset:]) @@ -138,8 +138,8 @@ func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { copy(sk.rho[:], buf[:32]) copy(sk.key[:], buf[32:64]) - copy(sk.tr[:], buf[64:96]) - offset := 96 + copy(sk.tr[:], buf[64:64+TRSize]) + offset := 64 + TRSize sk.s1.UnpackLeqEta(buf[offset:]) offset += PolyLeqEtaSize * L sk.s2.UnpackLeqEta(buf[offset:]) @@ -180,6 +180,11 @@ func NewKeyFromSeed(seed *[common.SeedSize]byte) (*PublicKey, *PrivateKey) { h := sha3.NewShake256() _, _ = h.Write(seed[:]) + + if NIST { + _, _ = h.Write([]byte{byte(K), byte(L)}) + } + _, _ = h.Read(eSeed[:]) copy(pk.rho[:], eSeed[:32]) @@ -244,13 +249,16 @@ 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 var Az, Az2dct1, w1 VecK var ch common.Poly - var cp [32]byte + var cp [CTildeSize]byte var w1Packed [PolyW1Size * K]byte // Note that Unpack() checked whether ‖z‖_∞ < γ₁ - β @@ -262,7 +270,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 +287,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) + PolyDeriveUniformBall(&ch, sig.c[:]) ch.NTT() for i := 0; i < K; i++ { Az2dct1[i].MulHat(&Az2dct1[i], &ch) @@ -307,8 +315,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,12 +335,15 @@ 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 { + _, _ = h.Write(rnd[:]) + } _, _ = h.Write(mu[:]) _, _ = h.Read(rhop[:]) @@ -368,7 +382,7 @@ func SignTo(sk *PrivateKey, msg []byte, signature []byte) { _, _ = h.Write(w1Packed[:]) _, _ = h.Read(sig.c[:]) - PolyDeriveUniformBall(&ch, &sig.c) + PolyDeriveUniformBall(&ch, sig.c[:]) ch.NTT() // Ensure ‖ w₀ - c·s2 ‖_∞ < γ₂ - β. diff --git a/sign/dilithium/mode5aes/internal/dilithium_test.go b/sign/mldsa/mldsa44/internal/dilithium_test.go similarity index 77% rename from sign/dilithium/mode5aes/internal/dilithium_test.go rename to sign/mldsa/mldsa44/internal/dilithium_test.go index ca347a831..47f53d3a0 100644 --- a/sign/dilithium/mode5aes/internal/dilithium_test.go +++ b/sign/mldsa/mldsa44/internal/dilithium_test.go @@ -4,9 +4,10 @@ package internal import ( "encoding/binary" + "io" "testing" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // Checks whether p is normalized. Only used in tests. @@ -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/mode5aes/internal/mat.go b/sign/mldsa/mldsa44/internal/mat.go similarity index 95% rename from sign/dilithium/mode5aes/internal/mat.go rename to sign/mldsa/mldsa44/internal/mat.go index cb473c149..ceaf634fa 100644 --- a/sign/dilithium/mode5aes/internal/mat.go +++ b/sign/mldsa/mldsa44/internal/mat.go @@ -3,7 +3,7 @@ package internal import ( - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // A k by l matrix of polynomials. diff --git a/sign/dilithium/mode5aes/internal/pack.go b/sign/mldsa/mldsa44/internal/pack.go similarity index 99% rename from sign/dilithium/mode5aes/internal/pack.go rename to sign/mldsa/mldsa44/internal/pack.go index 0285dfd8e..1854b4197 100644 --- a/sign/dilithium/mode5aes/internal/pack.go +++ b/sign/mldsa/mldsa44/internal/pack.go @@ -3,7 +3,7 @@ package internal import ( - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // Writes p with norm less than or equal η into buf, which must be of diff --git a/sign/dilithium/mode3aes/internal/pack_test.go b/sign/mldsa/mldsa44/internal/pack_test.go similarity index 96% rename from sign/dilithium/mode3aes/internal/pack_test.go rename to sign/mldsa/mldsa44/internal/pack_test.go index 24f568e4d..f952c6a09 100644 --- a/sign/dilithium/mode3aes/internal/pack_test.go +++ b/sign/mldsa/mldsa44/internal/pack_test.go @@ -5,7 +5,7 @@ package internal import ( "testing" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) func TestPolyPackLeqEta(t *testing.T) { diff --git a/sign/dilithium/mode2aes/internal/params.go b/sign/mldsa/mldsa44/internal/params.go similarity index 72% rename from sign/dilithium/mode2aes/internal/params.go rename to sign/mldsa/mldsa44/internal/params.go index 751ad149b..0485ff0c3 100644 --- a/sign/dilithium/mode2aes/internal/params.go +++ b/sign/mldsa/mldsa44/internal/params.go @@ -3,8 +3,7 @@ package internal const ( - Name = "Dilithium2-AES" - UseAES = true + Name = "ML-DSA-44" K = 4 L = 4 Eta = 2 @@ -13,4 +12,7 @@ const ( Tau = 39 Gamma1Bits = 17 Gamma2 = 95232 + NIST = true + TRSize = 64 + CTildeSize = 32 ) diff --git a/sign/dilithium/mode5aes/internal/rounding.go b/sign/mldsa/mldsa44/internal/rounding.go similarity index 98% rename from sign/dilithium/mode5aes/internal/rounding.go rename to sign/mldsa/mldsa44/internal/rounding.go index 71360cb29..58123c090 100644 --- a/sign/dilithium/mode5aes/internal/rounding.go +++ b/sign/mldsa/mldsa44/internal/rounding.go @@ -3,7 +3,7 @@ package internal import ( - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // Splits 0 ≤ a < q into a₀ and a₁ with a = a₁*α + a₀ with -α/2 < a₀ ≤ α/2, diff --git a/sign/dilithium/mode5aes/internal/rounding_test.go b/sign/mldsa/mldsa44/internal/rounding_test.go similarity index 96% rename from sign/dilithium/mode5aes/internal/rounding_test.go rename to sign/mldsa/mldsa44/internal/rounding_test.go index 5824f2656..ad653ca3f 100644 --- a/sign/dilithium/mode5aes/internal/rounding_test.go +++ b/sign/mldsa/mldsa44/internal/rounding_test.go @@ -6,7 +6,7 @@ import ( "flag" "testing" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) var runVeryLongTest = flag.Bool("very-long", false, "runs very long tests") diff --git a/sign/dilithium/mode3aes/internal/sample.go b/sign/mldsa/mldsa44/internal/sample.go similarity index 81% rename from sign/dilithium/mode3aes/internal/sample.go rename to sign/mldsa/mldsa44/internal/sample.go index c47185ada..b37370a4e 100644 --- a/sign/dilithium/mode3aes/internal/sample.go +++ b/sign/mldsa/mldsa44/internal/sample.go @@ -6,13 +6,13 @@ import ( "encoding/binary" "github.com/cloudflare/circl/internal/sha3" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + 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 +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[:]) } @@ -246,12 +215,12 @@ func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { // Can only be called when DeriveX4Available is true. // // This function is currently not used (yet). -func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed *[32]byte) { +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 < 4; 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 *[32]byte) { // SHAKE256 domain separator and padding for j := 0; j < 4; j++ { - state[4*4+j] ^= 0x1f + state[(CTildeSize/8)*4+j] ^= 0x1f state[16*4+j] ^= 0x80 << 56 } perm.Permute() @@ -327,7 +296,7 @@ func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed *[32]byte) { // Samples p uniformly with τ non-zero coefficients in {q-1,1}. // // The polynomial p will be normalized. -func PolyDeriveUniformBall(p *common.Poly, seed *[32]byte) { +func PolyDeriveUniformBall(p *common.Poly, seed []byte) { var buf [136]byte // SHAKE-256 rate is 136 h := sha3.NewShake256() diff --git a/sign/mldsa/mldsa44/internal/sample_test.go b/sign/mldsa/mldsa44/internal/sample_test.go new file mode 100644 index 000000000..32931c94f --- /dev/null +++ b/sign/mldsa/mldsa44/internal/sample_test.go @@ -0,0 +1,218 @@ +// 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 + 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 [CTildeSize]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 [CTildeSize]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/mldsa/mldsa44/internal/vec.go similarity index 99% rename from sign/dilithium/mode2aes/internal/vec.go rename to sign/mldsa/mldsa44/internal/vec.go index f52973e45..d07d3b245 100644 --- a/sign/dilithium/mode2aes/internal/vec.go +++ b/sign/mldsa/mldsa44/internal/vec.go @@ -3,7 +3,7 @@ package internal import ( - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // A vector of L polynomials. diff --git a/sign/dilithium/mode5aes/dilithium.go b/sign/mldsa/mldsa65/dilithium.go similarity index 50% rename from sign/dilithium/mode5aes/dilithium.go rename to sign/mldsa/mldsa65/dilithium.go index 2a0f05e7a..7d6312a15 100644 --- a/sign/dilithium/mode5aes/dilithium.go +++ b/sign/mldsa/mldsa65/dilithium.go @@ -1,18 +1,17 @@ -// Code generated from modePkg.templ.go. DO NOT EDIT. +// Code generated from pkg.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 +// 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/dilithium/internal/common" - "github.com/cloudflare/circl/sign/dilithium/mode5aes/internal" + "github.com/cloudflare/circl/sign" + common "github.com/cloudflare/circl/sign/internal/dilithium" + "github.com/cloudflare/circl/sign/mldsa/mldsa65/internal" ) const ( @@ -29,10 +28,10 @@ const ( SignatureSize = internal.SignatureSize ) -// PublicKey is the type of Dilithium5-AES public key +// PublicKey is the type of ML-DSA-65 public key type PublicKey internal.PublicKey -// PrivateKey is the type of Dilithium5-AES private key +// PrivateKey is the type of ML-DSA-65 private key type PrivateKey internal.PrivateKey // GenerateKey generates a public/private key pair using entropy from rand. @@ -50,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, ) } @@ -114,7 +152,7 @@ func (sk *PrivateKey) MarshalBinary() ([]byte, error) { // 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") + return errors.New("packed public key must be of mldsa65.PublicKeySize bytes") } var buf [PublicKeySize]byte copy(buf[:], data) @@ -125,7 +163,7 @@ func (pk *PublicKey) UnmarshalBinary(data []byte) error { // 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") + return errors.New("packed private key must be of mldsa65.PrivateKeySize bytes") } var buf [PrivateKeySize]byte copy(buf[:], data) @@ -143,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. @@ -179,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/dilithium/mode2aes/internal/dilithium.go b/sign/mldsa/mldsa65/internal/dilithium.go similarity index 89% rename from sign/dilithium/mode2aes/internal/dilithium.go rename to sign/mldsa/mldsa65/internal/dilithium.go index 79a17d504..8f1c8e5cb 100644 --- a/sign/dilithium/mode2aes/internal/dilithium.go +++ b/sign/mldsa/mldsa65/internal/dilithium.go @@ -8,7 +8,7 @@ import ( "io" "github.com/cloudflare/circl/internal/sha3" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) const ( @@ -29,13 +29,13 @@ const ( Alpha = 2 * Gamma2 // Size of a packed private key - PrivateKeySize = 32 + 32 + 32 + PolyLeqEtaSize*(L+K) + common.PolyT0Size*K + 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 + 32 + SignatureSize = L*PolyLeGamma1Size + Omega + K + CTildeSize // Size of packed w₁ PolyW1Size = (common.N * (common.QBits - Gamma1Bits)) / 8 @@ -49,7 +49,7 @@ type PublicKey struct { // Cached values t1p [common.PolyT1Size * K]byte A *Mat - tr *[32]byte + tr *[TRSize]byte } // PrivateKey is the type of Dilithium private keys. @@ -59,7 +59,7 @@ type PrivateKey struct { s1 VecL s2 VecK t0 VecK - tr [32]byte + tr [TRSize]byte // Cached values A Mat // ExpandA(ρ) @@ -71,14 +71,14 @@ type PrivateKey struct { type unpackedSignature struct { z VecL hint VecK - c [32]byte + c [CTildeSize]byte } // Packs the signature into buf. func (sig *unpackedSignature) Pack(buf []byte) { copy(buf[:], sig.c[:]) - sig.z.PackLeGamma1(buf[32:]) - sig.hint.PackHint(buf[32+L*PolyLeGamma1Size:]) + sig.z.PackLeGamma1(buf[CTildeSize:]) + sig.hint.PackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) } // Sets sig to the signature encoded in the buffer. @@ -89,11 +89,11 @@ func (sig *unpackedSignature) Unpack(buf []byte) bool { return false } copy(sig.c[:], buf[:]) - sig.z.UnpackLeGamma1(buf[32:]) + sig.z.UnpackLeGamma1(buf[CTildeSize:]) if sig.z.Exceeds(Gamma1 - Beta) { return false } - if !sig.hint.UnpackHint(buf[32+L*PolyLeGamma1Size:]) { + if !sig.hint.UnpackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) { return false } return true @@ -115,7 +115,7 @@ func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { pk.A.Derive(&pk.rho) // tr = CRH(ρ ‖ t1) = CRH(pk) - pk.tr = new([32]byte) + pk.tr = new([TRSize]byte) h := sha3.NewShake256() _, _ = h.Write(buf[:]) _, _ = h.Read(pk.tr[:]) @@ -125,8 +125,8 @@ func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { copy(buf[:32], sk.rho[:]) copy(buf[32:64], sk.key[:]) - copy(buf[64:96], sk.tr[:]) - offset := 96 + copy(buf[64:64+TRSize], sk.tr[:]) + offset := 64 + TRSize sk.s1.PackLeqEta(buf[offset:]) offset += PolyLeqEtaSize * L sk.s2.PackLeqEta(buf[offset:]) @@ -138,8 +138,8 @@ func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { copy(sk.rho[:], buf[:32]) copy(sk.key[:], buf[32:64]) - copy(sk.tr[:], buf[64:96]) - offset := 96 + copy(sk.tr[:], buf[64:64+TRSize]) + offset := 64 + TRSize sk.s1.UnpackLeqEta(buf[offset:]) offset += PolyLeqEtaSize * L sk.s2.UnpackLeqEta(buf[offset:]) @@ -180,6 +180,11 @@ func NewKeyFromSeed(seed *[common.SeedSize]byte) (*PublicKey, *PrivateKey) { h := sha3.NewShake256() _, _ = h.Write(seed[:]) + + if NIST { + _, _ = h.Write([]byte{byte(K), byte(L)}) + } + _, _ = h.Read(eSeed[:]) copy(pk.rho[:], eSeed[:32]) @@ -244,13 +249,16 @@ 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 var Az, Az2dct1, w1 VecK var ch common.Poly - var cp [32]byte + var cp [CTildeSize]byte var w1Packed [PolyW1Size * K]byte // Note that Unpack() checked whether ‖z‖_∞ < γ₁ - β @@ -262,7 +270,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 +287,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) + PolyDeriveUniformBall(&ch, sig.c[:]) ch.NTT() for i := 0; i < K; i++ { Az2dct1[i].MulHat(&Az2dct1[i], &ch) @@ -307,8 +315,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,12 +335,15 @@ 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 { + _, _ = h.Write(rnd[:]) + } _, _ = h.Write(mu[:]) _, _ = h.Read(rhop[:]) @@ -368,7 +382,7 @@ func SignTo(sk *PrivateKey, msg []byte, signature []byte) { _, _ = h.Write(w1Packed[:]) _, _ = h.Read(sig.c[:]) - PolyDeriveUniformBall(&ch, &sig.c) + PolyDeriveUniformBall(&ch, sig.c[:]) ch.NTT() // Ensure ‖ w₀ - c·s2 ‖_∞ < γ₂ - β. diff --git a/sign/dilithium/mode3aes/internal/dilithium_test.go b/sign/mldsa/mldsa65/internal/dilithium_test.go similarity index 77% rename from sign/dilithium/mode3aes/internal/dilithium_test.go rename to sign/mldsa/mldsa65/internal/dilithium_test.go index ca347a831..47f53d3a0 100644 --- a/sign/dilithium/mode3aes/internal/dilithium_test.go +++ b/sign/mldsa/mldsa65/internal/dilithium_test.go @@ -4,9 +4,10 @@ package internal import ( "encoding/binary" + "io" "testing" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // Checks whether p is normalized. Only used in tests. @@ -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/mode3aes/internal/mat.go b/sign/mldsa/mldsa65/internal/mat.go similarity index 95% rename from sign/dilithium/mode3aes/internal/mat.go rename to sign/mldsa/mldsa65/internal/mat.go index cb473c149..ceaf634fa 100644 --- a/sign/dilithium/mode3aes/internal/mat.go +++ b/sign/mldsa/mldsa65/internal/mat.go @@ -3,7 +3,7 @@ package internal import ( - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // A k by l matrix of polynomials. diff --git a/sign/dilithium/mode3aes/internal/pack.go b/sign/mldsa/mldsa65/internal/pack.go similarity index 99% rename from sign/dilithium/mode3aes/internal/pack.go rename to sign/mldsa/mldsa65/internal/pack.go index 0285dfd8e..1854b4197 100644 --- a/sign/dilithium/mode3aes/internal/pack.go +++ b/sign/mldsa/mldsa65/internal/pack.go @@ -3,7 +3,7 @@ package internal import ( - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // Writes p with norm less than or equal η into buf, which must be of diff --git a/sign/dilithium/mode5aes/internal/pack_test.go b/sign/mldsa/mldsa65/internal/pack_test.go similarity index 96% rename from sign/dilithium/mode5aes/internal/pack_test.go rename to sign/mldsa/mldsa65/internal/pack_test.go index 24f568e4d..f952c6a09 100644 --- a/sign/dilithium/mode5aes/internal/pack_test.go +++ b/sign/mldsa/mldsa65/internal/pack_test.go @@ -5,7 +5,7 @@ package internal import ( "testing" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) func TestPolyPackLeqEta(t *testing.T) { diff --git a/sign/dilithium/mode3aes/internal/params.go b/sign/mldsa/mldsa65/internal/params.go similarity index 72% rename from sign/dilithium/mode3aes/internal/params.go rename to sign/mldsa/mldsa65/internal/params.go index 7523dc09e..8a1f866e6 100644 --- a/sign/dilithium/mode3aes/internal/params.go +++ b/sign/mldsa/mldsa65/internal/params.go @@ -3,8 +3,7 @@ package internal const ( - Name = "Dilithium3-AES" - UseAES = true + Name = "ML-DSA-65" K = 6 L = 5 Eta = 4 @@ -13,4 +12,7 @@ const ( Tau = 49 Gamma1Bits = 19 Gamma2 = 261888 + NIST = true + TRSize = 64 + CTildeSize = 48 ) diff --git a/sign/dilithium/mode2aes/internal/rounding.go b/sign/mldsa/mldsa65/internal/rounding.go similarity index 98% rename from sign/dilithium/mode2aes/internal/rounding.go rename to sign/mldsa/mldsa65/internal/rounding.go index 71360cb29..58123c090 100644 --- a/sign/dilithium/mode2aes/internal/rounding.go +++ b/sign/mldsa/mldsa65/internal/rounding.go @@ -3,7 +3,7 @@ package internal import ( - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // Splits 0 ≤ a < q into a₀ and a₁ with a = a₁*α + a₀ with -α/2 < a₀ ≤ α/2, diff --git a/sign/dilithium/mode2aes/internal/rounding_test.go b/sign/mldsa/mldsa65/internal/rounding_test.go similarity index 96% rename from sign/dilithium/mode2aes/internal/rounding_test.go rename to sign/mldsa/mldsa65/internal/rounding_test.go index 5824f2656..ad653ca3f 100644 --- a/sign/dilithium/mode2aes/internal/rounding_test.go +++ b/sign/mldsa/mldsa65/internal/rounding_test.go @@ -6,7 +6,7 @@ import ( "flag" "testing" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) var runVeryLongTest = flag.Bool("very-long", false, "runs very long tests") diff --git a/sign/dilithium/mode5aes/internal/sample.go b/sign/mldsa/mldsa65/internal/sample.go similarity index 81% rename from sign/dilithium/mode5aes/internal/sample.go rename to sign/mldsa/mldsa65/internal/sample.go index c47185ada..b37370a4e 100644 --- a/sign/dilithium/mode5aes/internal/sample.go +++ b/sign/mldsa/mldsa65/internal/sample.go @@ -6,13 +6,13 @@ import ( "encoding/binary" "github.com/cloudflare/circl/internal/sha3" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + 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 +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[:]) } @@ -246,12 +215,12 @@ func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { // Can only be called when DeriveX4Available is true. // // This function is currently not used (yet). -func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed *[32]byte) { +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 < 4; 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 *[32]byte) { // SHAKE256 domain separator and padding for j := 0; j < 4; j++ { - state[4*4+j] ^= 0x1f + state[(CTildeSize/8)*4+j] ^= 0x1f state[16*4+j] ^= 0x80 << 56 } perm.Permute() @@ -327,7 +296,7 @@ func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed *[32]byte) { // Samples p uniformly with τ non-zero coefficients in {q-1,1}. // // The polynomial p will be normalized. -func PolyDeriveUniformBall(p *common.Poly, seed *[32]byte) { +func PolyDeriveUniformBall(p *common.Poly, seed []byte) { var buf [136]byte // SHAKE-256 rate is 136 h := sha3.NewShake256() diff --git a/sign/mldsa/mldsa65/internal/sample_test.go b/sign/mldsa/mldsa65/internal/sample_test.go new file mode 100644 index 000000000..32931c94f --- /dev/null +++ b/sign/mldsa/mldsa65/internal/sample_test.go @@ -0,0 +1,218 @@ +// 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 + 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 [CTildeSize]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 [CTildeSize]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/mldsa/mldsa65/internal/vec.go similarity index 99% rename from sign/dilithium/mode5aes/internal/vec.go rename to sign/mldsa/mldsa65/internal/vec.go index f52973e45..d07d3b245 100644 --- a/sign/dilithium/mode5aes/internal/vec.go +++ b/sign/mldsa/mldsa65/internal/vec.go @@ -3,7 +3,7 @@ package internal import ( - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // A vector of L polynomials. diff --git a/sign/dilithium/mode3aes/dilithium.go b/sign/mldsa/mldsa87/dilithium.go similarity index 50% rename from sign/dilithium/mode3aes/dilithium.go rename to sign/mldsa/mldsa87/dilithium.go index afc5e3e92..0c3c2ef7b 100644 --- a/sign/dilithium/mode3aes/dilithium.go +++ b/sign/mldsa/mldsa87/dilithium.go @@ -1,18 +1,17 @@ -// Code generated from modePkg.templ.go. DO NOT EDIT. +// Code generated from pkg.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 +// 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/dilithium/internal/common" - "github.com/cloudflare/circl/sign/dilithium/mode3aes/internal" + "github.com/cloudflare/circl/sign" + common "github.com/cloudflare/circl/sign/internal/dilithium" + "github.com/cloudflare/circl/sign/mldsa/mldsa87/internal" ) const ( @@ -29,10 +28,10 @@ const ( SignatureSize = internal.SignatureSize ) -// PublicKey is the type of Dilithium3-AES public key +// PublicKey is the type of ML-DSA-87 public key type PublicKey internal.PublicKey -// PrivateKey is the type of Dilithium3-AES private key +// PrivateKey is the type of ML-DSA-87 private key type PrivateKey internal.PrivateKey // GenerateKey generates a public/private key pair using entropy from rand. @@ -50,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, ) } @@ -114,7 +152,7 @@ func (sk *PrivateKey) MarshalBinary() ([]byte, error) { // 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") + return errors.New("packed public key must be of mldsa87.PublicKeySize bytes") } var buf [PublicKeySize]byte copy(buf[:], data) @@ -125,7 +163,7 @@ func (pk *PublicKey) UnmarshalBinary(data []byte) error { // 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") + return errors.New("packed private key must be of mldsa87.PrivateKeySize bytes") } var buf [PrivateKeySize]byte copy(buf[:], data) @@ -143,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. @@ -179,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/dilithium/mode5aes/internal/dilithium.go b/sign/mldsa/mldsa87/internal/dilithium.go similarity index 89% rename from sign/dilithium/mode5aes/internal/dilithium.go rename to sign/mldsa/mldsa87/internal/dilithium.go index 79a17d504..8f1c8e5cb 100644 --- a/sign/dilithium/mode5aes/internal/dilithium.go +++ b/sign/mldsa/mldsa87/internal/dilithium.go @@ -8,7 +8,7 @@ import ( "io" "github.com/cloudflare/circl/internal/sha3" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) const ( @@ -29,13 +29,13 @@ const ( Alpha = 2 * Gamma2 // Size of a packed private key - PrivateKeySize = 32 + 32 + 32 + PolyLeqEtaSize*(L+K) + common.PolyT0Size*K + 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 + 32 + SignatureSize = L*PolyLeGamma1Size + Omega + K + CTildeSize // Size of packed w₁ PolyW1Size = (common.N * (common.QBits - Gamma1Bits)) / 8 @@ -49,7 +49,7 @@ type PublicKey struct { // Cached values t1p [common.PolyT1Size * K]byte A *Mat - tr *[32]byte + tr *[TRSize]byte } // PrivateKey is the type of Dilithium private keys. @@ -59,7 +59,7 @@ type PrivateKey struct { s1 VecL s2 VecK t0 VecK - tr [32]byte + tr [TRSize]byte // Cached values A Mat // ExpandA(ρ) @@ -71,14 +71,14 @@ type PrivateKey struct { type unpackedSignature struct { z VecL hint VecK - c [32]byte + c [CTildeSize]byte } // Packs the signature into buf. func (sig *unpackedSignature) Pack(buf []byte) { copy(buf[:], sig.c[:]) - sig.z.PackLeGamma1(buf[32:]) - sig.hint.PackHint(buf[32+L*PolyLeGamma1Size:]) + sig.z.PackLeGamma1(buf[CTildeSize:]) + sig.hint.PackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) } // Sets sig to the signature encoded in the buffer. @@ -89,11 +89,11 @@ func (sig *unpackedSignature) Unpack(buf []byte) bool { return false } copy(sig.c[:], buf[:]) - sig.z.UnpackLeGamma1(buf[32:]) + sig.z.UnpackLeGamma1(buf[CTildeSize:]) if sig.z.Exceeds(Gamma1 - Beta) { return false } - if !sig.hint.UnpackHint(buf[32+L*PolyLeGamma1Size:]) { + if !sig.hint.UnpackHint(buf[CTildeSize+L*PolyLeGamma1Size:]) { return false } return true @@ -115,7 +115,7 @@ func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { pk.A.Derive(&pk.rho) // tr = CRH(ρ ‖ t1) = CRH(pk) - pk.tr = new([32]byte) + pk.tr = new([TRSize]byte) h := sha3.NewShake256() _, _ = h.Write(buf[:]) _, _ = h.Read(pk.tr[:]) @@ -125,8 +125,8 @@ func (pk *PublicKey) Unpack(buf *[PublicKeySize]byte) { func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { copy(buf[:32], sk.rho[:]) copy(buf[32:64], sk.key[:]) - copy(buf[64:96], sk.tr[:]) - offset := 96 + copy(buf[64:64+TRSize], sk.tr[:]) + offset := 64 + TRSize sk.s1.PackLeqEta(buf[offset:]) offset += PolyLeqEtaSize * L sk.s2.PackLeqEta(buf[offset:]) @@ -138,8 +138,8 @@ func (sk *PrivateKey) Pack(buf *[PrivateKeySize]byte) { func (sk *PrivateKey) Unpack(buf *[PrivateKeySize]byte) { copy(sk.rho[:], buf[:32]) copy(sk.key[:], buf[32:64]) - copy(sk.tr[:], buf[64:96]) - offset := 96 + copy(sk.tr[:], buf[64:64+TRSize]) + offset := 64 + TRSize sk.s1.UnpackLeqEta(buf[offset:]) offset += PolyLeqEtaSize * L sk.s2.UnpackLeqEta(buf[offset:]) @@ -180,6 +180,11 @@ func NewKeyFromSeed(seed *[common.SeedSize]byte) (*PublicKey, *PrivateKey) { h := sha3.NewShake256() _, _ = h.Write(seed[:]) + + if NIST { + _, _ = h.Write([]byte{byte(K), byte(L)}) + } + _, _ = h.Read(eSeed[:]) copy(pk.rho[:], eSeed[:32]) @@ -244,13 +249,16 @@ 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 var Az, Az2dct1, w1 VecK var ch common.Poly - var cp [32]byte + var cp [CTildeSize]byte var w1Packed [PolyW1Size * K]byte // Note that Unpack() checked whether ‖z‖_∞ < γ₁ - β @@ -262,7 +270,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 +287,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) + PolyDeriveUniformBall(&ch, sig.c[:]) ch.NTT() for i := 0; i < K; i++ { Az2dct1[i].MulHat(&Az2dct1[i], &ch) @@ -307,8 +315,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,12 +335,15 @@ 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 { + _, _ = h.Write(rnd[:]) + } _, _ = h.Write(mu[:]) _, _ = h.Read(rhop[:]) @@ -368,7 +382,7 @@ func SignTo(sk *PrivateKey, msg []byte, signature []byte) { _, _ = h.Write(w1Packed[:]) _, _ = h.Read(sig.c[:]) - PolyDeriveUniformBall(&ch, &sig.c) + PolyDeriveUniformBall(&ch, sig.c[:]) ch.NTT() // Ensure ‖ w₀ - c·s2 ‖_∞ < γ₂ - β. diff --git a/sign/dilithium/mode2aes/internal/dilithium_test.go b/sign/mldsa/mldsa87/internal/dilithium_test.go similarity index 77% rename from sign/dilithium/mode2aes/internal/dilithium_test.go rename to sign/mldsa/mldsa87/internal/dilithium_test.go index ca347a831..47f53d3a0 100644 --- a/sign/dilithium/mode2aes/internal/dilithium_test.go +++ b/sign/mldsa/mldsa87/internal/dilithium_test.go @@ -4,9 +4,10 @@ package internal import ( "encoding/binary" + "io" "testing" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // Checks whether p is normalized. Only used in tests. @@ -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/mode2aes/internal/mat.go b/sign/mldsa/mldsa87/internal/mat.go similarity index 95% rename from sign/dilithium/mode2aes/internal/mat.go rename to sign/mldsa/mldsa87/internal/mat.go index cb473c149..ceaf634fa 100644 --- a/sign/dilithium/mode2aes/internal/mat.go +++ b/sign/mldsa/mldsa87/internal/mat.go @@ -3,7 +3,7 @@ package internal import ( - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // A k by l matrix of polynomials. diff --git a/sign/dilithium/mode2aes/internal/pack.go b/sign/mldsa/mldsa87/internal/pack.go similarity index 99% rename from sign/dilithium/mode2aes/internal/pack.go rename to sign/mldsa/mldsa87/internal/pack.go index 0285dfd8e..1854b4197 100644 --- a/sign/dilithium/mode2aes/internal/pack.go +++ b/sign/mldsa/mldsa87/internal/pack.go @@ -3,7 +3,7 @@ package internal import ( - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // Writes p with norm less than or equal η into buf, which must be of diff --git a/sign/dilithium/mode2aes/internal/pack_test.go b/sign/mldsa/mldsa87/internal/pack_test.go similarity index 96% rename from sign/dilithium/mode2aes/internal/pack_test.go rename to sign/mldsa/mldsa87/internal/pack_test.go index 24f568e4d..f952c6a09 100644 --- a/sign/dilithium/mode2aes/internal/pack_test.go +++ b/sign/mldsa/mldsa87/internal/pack_test.go @@ -5,7 +5,7 @@ package internal import ( "testing" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) func TestPolyPackLeqEta(t *testing.T) { diff --git a/sign/dilithium/mode5aes/internal/params.go b/sign/mldsa/mldsa87/internal/params.go similarity index 72% rename from sign/dilithium/mode5aes/internal/params.go rename to sign/mldsa/mldsa87/internal/params.go index 419cb2a2b..b5dc669ca 100644 --- a/sign/dilithium/mode5aes/internal/params.go +++ b/sign/mldsa/mldsa87/internal/params.go @@ -3,8 +3,7 @@ package internal const ( - Name = "Dilithium5-AES" - UseAES = true + Name = "ML-DSA-87" K = 8 L = 7 Eta = 2 @@ -13,4 +12,7 @@ const ( Tau = 60 Gamma1Bits = 19 Gamma2 = 261888 + NIST = true + TRSize = 64 + CTildeSize = 64 ) diff --git a/sign/dilithium/mode3aes/internal/rounding.go b/sign/mldsa/mldsa87/internal/rounding.go similarity index 98% rename from sign/dilithium/mode3aes/internal/rounding.go rename to sign/mldsa/mldsa87/internal/rounding.go index 71360cb29..58123c090 100644 --- a/sign/dilithium/mode3aes/internal/rounding.go +++ b/sign/mldsa/mldsa87/internal/rounding.go @@ -3,7 +3,7 @@ package internal import ( - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // Splits 0 ≤ a < q into a₀ and a₁ with a = a₁*α + a₀ with -α/2 < a₀ ≤ α/2, diff --git a/sign/dilithium/mode3aes/internal/rounding_test.go b/sign/mldsa/mldsa87/internal/rounding_test.go similarity index 96% rename from sign/dilithium/mode3aes/internal/rounding_test.go rename to sign/mldsa/mldsa87/internal/rounding_test.go index 5824f2656..ad653ca3f 100644 --- a/sign/dilithium/mode3aes/internal/rounding_test.go +++ b/sign/mldsa/mldsa87/internal/rounding_test.go @@ -6,7 +6,7 @@ import ( "flag" "testing" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) var runVeryLongTest = flag.Bool("very-long", false, "runs very long tests") diff --git a/sign/dilithium/mode2aes/internal/sample.go b/sign/mldsa/mldsa87/internal/sample.go similarity index 81% rename from sign/dilithium/mode2aes/internal/sample.go rename to sign/mldsa/mldsa87/internal/sample.go index c47185ada..b37370a4e 100644 --- a/sign/dilithium/mode2aes/internal/sample.go +++ b/sign/mldsa/mldsa87/internal/sample.go @@ -6,13 +6,13 @@ import ( "encoding/binary" "github.com/cloudflare/circl/internal/sha3" - "github.com/cloudflare/circl/sign/dilithium/internal/common" + 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 +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[:]) } @@ -246,12 +215,12 @@ func PolyDeriveUniformLeGamma1(p *common.Poly, seed *[64]byte, nonce uint16) { // Can only be called when DeriveX4Available is true. // // This function is currently not used (yet). -func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed *[32]byte) { +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 < 4; 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 *[32]byte) { // SHAKE256 domain separator and padding for j := 0; j < 4; j++ { - state[4*4+j] ^= 0x1f + state[(CTildeSize/8)*4+j] ^= 0x1f state[16*4+j] ^= 0x80 << 56 } perm.Permute() @@ -327,7 +296,7 @@ func PolyDeriveUniformBallX4(ps [4]*common.Poly, seed *[32]byte) { // Samples p uniformly with τ non-zero coefficients in {q-1,1}. // // The polynomial p will be normalized. -func PolyDeriveUniformBall(p *common.Poly, seed *[32]byte) { +func PolyDeriveUniformBall(p *common.Poly, seed []byte) { var buf [136]byte // SHAKE-256 rate is 136 h := sha3.NewShake256() diff --git a/sign/mldsa/mldsa87/internal/sample_test.go b/sign/mldsa/mldsa87/internal/sample_test.go new file mode 100644 index 000000000..32931c94f --- /dev/null +++ b/sign/mldsa/mldsa87/internal/sample_test.go @@ -0,0 +1,218 @@ +// 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 + 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 [CTildeSize]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 [CTildeSize]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/mldsa/mldsa87/internal/vec.go similarity index 99% rename from sign/dilithium/mode3aes/internal/vec.go rename to sign/mldsa/mldsa87/internal/vec.go index f52973e45..d07d3b245 100644 --- a/sign/dilithium/mode3aes/internal/vec.go +++ b/sign/mldsa/mldsa87/internal/vec.go @@ -3,7 +3,7 @@ package internal import ( - "github.com/cloudflare/circl/sign/dilithium/internal/common" + common "github.com/cloudflare/circl/sign/internal/dilithium" ) // A vector of L polynomials. 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") )